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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/esm2022/src/compiler.mjs +4 -4
  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 +8 -3
  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/abstract_emitter.mjs +4 -1
  17. package/esm2022/src/output/output_ast.mjs +30 -1
  18. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  19. package/esm2022/src/render3/partial/directive.mjs +1 -1
  20. package/esm2022/src/render3/partial/factory.mjs +1 -1
  21. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  22. package/esm2022/src/render3/partial/injector.mjs +1 -1
  23. package/esm2022/src/render3/partial/ng_module.mjs +6 -3
  24. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  25. package/esm2022/src/render3/r3_ast.mjs +109 -1
  26. package/esm2022/src/render3/r3_deferred_blocks.mjs +156 -0
  27. package/esm2022/src/render3/r3_deferred_triggers.mjs +275 -0
  28. package/esm2022/src/render3/r3_module_compiler.mjs +69 -27
  29. package/esm2022/src/render3/r3_template_transform.mjs +48 -2
  30. package/esm2022/src/render3/view/i18n/meta.mjs +12 -1
  31. package/esm2022/src/render3/view/t2_binder.mjs +61 -6
  32. package/esm2022/src/render3/view/template.mjs +17 -3
  33. package/esm2022/src/shadow_css.mjs +2 -2
  34. package/esm2022/src/template/pipeline/ir/src/enums.mjs +32 -8
  35. package/esm2022/src/template/pipeline/ir/src/expression.mjs +83 -6
  36. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +57 -1
  37. package/esm2022/src/template/pipeline/src/emit.mjs +10 -6
  38. package/esm2022/src/template/pipeline/src/ingest.mjs +42 -3
  39. package/esm2022/src/template/pipeline/src/instruction.mjs +64 -7
  40. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +2 -1
  41. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +12 -1
  42. package/esm2022/src/template/pipeline/src/phases/expand_safe_reads.mjs +102 -10
  43. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +1 -6
  44. package/esm2022/src/template/pipeline/src/phases/naming.mjs +38 -9
  45. package/esm2022/src/template/pipeline/src/phases/nullish_coalescing.mjs +6 -5
  46. package/esm2022/src/template/pipeline/src/phases/property_ordering.mjs +82 -0
  47. package/esm2022/src/template/pipeline/src/phases/reify.mjs +26 -1
  48. package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +8 -1
  49. package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +32 -19
  50. package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +53 -0
  51. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +16 -5
  52. package/esm2022/src/template_parser/binding_parser.mjs +4 -4
  53. package/esm2022/src/util.mjs +2 -8
  54. package/esm2022/src/version.mjs +1 -1
  55. package/fesm2022/compiler.mjs +1909 -357
  56. package/fesm2022/compiler.mjs.map +1 -1
  57. package/fesm2022/testing.mjs +1 -1
  58. package/index.d.ts +232 -16
  59. package/package.json +2 -2
  60. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.2.0-next.1
2
+ * @license Angular v16.2.0-next.3
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;
@@ -1617,6 +1621,24 @@ class ConditionalExpr extends Expression {
1617
1621
  return new ConditionalExpr(this.condition.clone(), this.trueCase.clone(), this.falseCase?.clone(), this.type, this.sourceSpan);
1618
1622
  }
1619
1623
  }
1624
+ class DynamicImportExpr extends Expression {
1625
+ constructor(url, sourceSpan) {
1626
+ super(null, sourceSpan);
1627
+ this.url = url;
1628
+ }
1629
+ isEquivalent(e) {
1630
+ return e instanceof DynamicImportExpr && this.url === e.url;
1631
+ }
1632
+ isConstant() {
1633
+ return false;
1634
+ }
1635
+ visitExpression(visitor, context) {
1636
+ return visitor.visitDynamicImportExpr(this, context);
1637
+ }
1638
+ clone() {
1639
+ return new DynamicImportExpr(this.url, this.sourceSpan);
1640
+ }
1641
+ }
1620
1642
  class NotExpr extends Expression {
1621
1643
  constructor(condition, sourceSpan) {
1622
1644
  super(BOOL_TYPE, sourceSpan);
@@ -1721,6 +1743,10 @@ class ReadPropExpr extends Expression {
1721
1743
  this.receiver = receiver;
1722
1744
  this.name = name;
1723
1745
  }
1746
+ // An alias for name, which allows other logic to handle property reads and keyed reads together.
1747
+ get index() {
1748
+ return this.name;
1749
+ }
1724
1750
  isEquivalent(e) {
1725
1751
  return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
1726
1752
  this.name === e.name;
@@ -2001,6 +2027,9 @@ class RecursiveAstVisitor$1 {
2001
2027
  ast.value.visitExpression(this, context);
2002
2028
  return this.visitExpression(ast, context);
2003
2029
  }
2030
+ visitDynamicImportExpr(ast, context) {
2031
+ return this.visitExpression(ast, context);
2032
+ }
2004
2033
  visitInvokeFunctionExpr(ast, context) {
2005
2034
  ast.fn.visitExpression(this, context);
2006
2035
  this.visitAllExpressions(ast.args, context);
@@ -2239,6 +2268,7 @@ var output_ast = /*#__PURE__*/Object.freeze({
2239
2268
  ExternalExpr: ExternalExpr,
2240
2269
  ExternalReference: ExternalReference,
2241
2270
  ConditionalExpr: ConditionalExpr,
2271
+ DynamicImportExpr: DynamicImportExpr,
2242
2272
  NotExpr: NotExpr,
2243
2273
  FnParam: FnParam,
2244
2274
  FunctionExpr: FunctionExpr,
@@ -2817,13 +2847,7 @@ class Version {
2817
2847
  this.patch = splits.slice(2).join('.');
2818
2848
  }
2819
2849
  }
2820
- // Check `global` first, because in Node tests both `global` and `window` may be defined and our
2821
- // `_global` variable should point to the NodeJS `global` in that case. Note: Typeof/Instanceof
2822
- // checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
2823
- // https://github.com/terser/terser/issues/250.
2824
- const _global = ( /* @__PURE__ */(() => (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
2825
- (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
2826
- self instanceof WorkerGlobalScope && self))());
2850
+ const _global = globalThis;
2827
2851
  function newArray(size, value) {
2828
2852
  const list = [];
2829
2853
  for (let i = 0; i < size; i++) {
@@ -3305,6 +3329,9 @@ class AbstractEmitterVisitor {
3305
3329
  ctx.print(ast, `)`);
3306
3330
  return null;
3307
3331
  }
3332
+ visitDynamicImportExpr(ast, ctx) {
3333
+ ctx.print(ast, `import(${ast.url})`);
3334
+ }
3308
3335
  visitNotExpr(ast, ctx) {
3309
3336
  ctx.print(ast, '!');
3310
3337
  ast.condition.visitExpression(this, ctx);
@@ -3878,6 +3905,96 @@ class Element$1 {
3878
3905
  return visitor.visitElement(this);
3879
3906
  }
3880
3907
  }
3908
+ class DeferredTrigger {
3909
+ constructor(sourceSpan) {
3910
+ this.sourceSpan = sourceSpan;
3911
+ }
3912
+ visit(visitor) {
3913
+ return visitor.visitDeferredTrigger(this);
3914
+ }
3915
+ }
3916
+ class BoundDeferredTrigger extends DeferredTrigger {
3917
+ constructor(value, sourceSpan) {
3918
+ super(sourceSpan);
3919
+ this.value = value;
3920
+ }
3921
+ }
3922
+ class IdleDeferredTrigger extends DeferredTrigger {
3923
+ }
3924
+ class ImmediateDeferredTrigger extends DeferredTrigger {
3925
+ }
3926
+ class HoverDeferredTrigger extends DeferredTrigger {
3927
+ }
3928
+ class TimerDeferredTrigger extends DeferredTrigger {
3929
+ constructor(delay, sourceSpan) {
3930
+ super(sourceSpan);
3931
+ this.delay = delay;
3932
+ }
3933
+ }
3934
+ class InteractionDeferredTrigger extends DeferredTrigger {
3935
+ constructor(reference, sourceSpan) {
3936
+ super(sourceSpan);
3937
+ this.reference = reference;
3938
+ }
3939
+ }
3940
+ class ViewportDeferredTrigger extends DeferredTrigger {
3941
+ constructor(reference, sourceSpan) {
3942
+ super(sourceSpan);
3943
+ this.reference = reference;
3944
+ }
3945
+ }
3946
+ class DeferredBlockPlaceholder {
3947
+ constructor(children, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
3948
+ this.children = children;
3949
+ this.minimumTime = minimumTime;
3950
+ this.sourceSpan = sourceSpan;
3951
+ this.startSourceSpan = startSourceSpan;
3952
+ this.endSourceSpan = endSourceSpan;
3953
+ }
3954
+ visit(visitor) {
3955
+ return visitor.visitDeferredBlockPlaceholder(this);
3956
+ }
3957
+ }
3958
+ class DeferredBlockLoading {
3959
+ constructor(children, afterTime, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
3960
+ this.children = children;
3961
+ this.afterTime = afterTime;
3962
+ this.minimumTime = minimumTime;
3963
+ this.sourceSpan = sourceSpan;
3964
+ this.startSourceSpan = startSourceSpan;
3965
+ this.endSourceSpan = endSourceSpan;
3966
+ }
3967
+ visit(visitor) {
3968
+ return visitor.visitDeferredBlockLoading(this);
3969
+ }
3970
+ }
3971
+ class DeferredBlockError {
3972
+ constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
3973
+ this.children = children;
3974
+ this.sourceSpan = sourceSpan;
3975
+ this.startSourceSpan = startSourceSpan;
3976
+ this.endSourceSpan = endSourceSpan;
3977
+ }
3978
+ visit(visitor) {
3979
+ return visitor.visitDeferredBlockError(this);
3980
+ }
3981
+ }
3982
+ class DeferredBlock {
3983
+ constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
3984
+ this.children = children;
3985
+ this.triggers = triggers;
3986
+ this.prefetchTriggers = prefetchTriggers;
3987
+ this.placeholder = placeholder;
3988
+ this.loading = loading;
3989
+ this.error = error;
3990
+ this.sourceSpan = sourceSpan;
3991
+ this.startSourceSpan = startSourceSpan;
3992
+ this.endSourceSpan = endSourceSpan;
3993
+ }
3994
+ visit(visitor) {
3995
+ return visitor.visitDeferredBlock(this);
3996
+ }
3997
+ }
3881
3998
  class Template {
3882
3999
  constructor(
3883
4000
  // tagName is the name of the container element, if applicable.
@@ -3965,6 +4082,23 @@ class RecursiveVisitor$1 {
3965
4082
  visitAll$1(this, template.references);
3966
4083
  visitAll$1(this, template.variables);
3967
4084
  }
4085
+ visitDeferredBlock(deferred) {
4086
+ visitAll$1(this, deferred.triggers);
4087
+ visitAll$1(this, deferred.prefetchTriggers);
4088
+ visitAll$1(this, deferred.children);
4089
+ deferred.placeholder?.visit(this);
4090
+ deferred.loading?.visit(this);
4091
+ deferred.error?.visit(this);
4092
+ }
4093
+ visitDeferredBlockPlaceholder(block) {
4094
+ visitAll$1(this, block.children);
4095
+ }
4096
+ visitDeferredBlockError(block) {
4097
+ visitAll$1(this, block.children);
4098
+ }
4099
+ visitDeferredBlockLoading(block) {
4100
+ visitAll$1(this, block.children);
4101
+ }
3968
4102
  visitContent(content) { }
3969
4103
  visitVariable(variable) { }
3970
4104
  visitReference(reference) { }
@@ -3974,6 +4108,7 @@ class RecursiveVisitor$1 {
3974
4108
  visitText(text) { }
3975
4109
  visitBoundText(text) { }
3976
4110
  visitIcu(icu) { }
4111
+ visitDeferredTrigger(trigger) { }
3977
4112
  }
3978
4113
  function visitAll$1(visitor, nodes) {
3979
4114
  const result = [];
@@ -5717,31 +5852,49 @@ var R3SelectorScopeMode;
5717
5852
  */
5718
5853
  R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit";
5719
5854
  })(R3SelectorScopeMode || (R3SelectorScopeMode = {}));
5855
+ /**
5856
+ * The type of the NgModule meta data.
5857
+ * - Global: Used for full and partial compilation modes which mainly includes R3References.
5858
+ * - Local: Used for the local compilation mode which mainly includes the raw expressions as appears
5859
+ * in the NgModule decorator.
5860
+ */
5861
+ var R3NgModuleMetadataKind;
5862
+ (function (R3NgModuleMetadataKind) {
5863
+ R3NgModuleMetadataKind[R3NgModuleMetadataKind["Global"] = 0] = "Global";
5864
+ R3NgModuleMetadataKind[R3NgModuleMetadataKind["Local"] = 1] = "Local";
5865
+ })(R3NgModuleMetadataKind || (R3NgModuleMetadataKind = {}));
5720
5866
  /**
5721
5867
  * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
5722
5868
  */
5723
5869
  function compileNgModule(meta) {
5724
- const { type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, selectorScopeMode, id } = meta;
5725
5870
  const statements = [];
5726
5871
  const definitionMap = new DefinitionMap();
5727
- definitionMap.set('type', moduleType.value);
5728
- if (bootstrap.length > 0) {
5729
- definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls));
5872
+ definitionMap.set('type', meta.type.value);
5873
+ // Assign bootstrap definition
5874
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5875
+ if (meta.bootstrap.length > 0) {
5876
+ definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
5877
+ }
5878
+ }
5879
+ else {
5880
+ if (meta.bootstrapExpression) {
5881
+ definitionMap.set('bootstrap', meta.bootstrapExpression);
5882
+ }
5730
5883
  }
5731
- if (selectorScopeMode === R3SelectorScopeMode.Inline) {
5884
+ if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
5732
5885
  // If requested to emit scope information inline, pass the `declarations`, `imports` and
5733
5886
  // `exports` to the `ɵɵdefineNgModule()` call directly.
5734
- if (declarations.length > 0) {
5735
- definitionMap.set('declarations', refsToArray(declarations, containsForwardDecls));
5887
+ if (meta.declarations.length > 0) {
5888
+ definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
5736
5889
  }
5737
- if (imports.length > 0) {
5738
- definitionMap.set('imports', refsToArray(imports, containsForwardDecls));
5890
+ if (meta.imports.length > 0) {
5891
+ definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
5739
5892
  }
5740
- if (exports.length > 0) {
5741
- definitionMap.set('exports', refsToArray(exports, containsForwardDecls));
5893
+ if (meta.exports.length > 0) {
5894
+ definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
5742
5895
  }
5743
5896
  }
5744
- else if (selectorScopeMode === R3SelectorScopeMode.SideEffect) {
5897
+ else if (meta.selectorScopeMode === R3SelectorScopeMode.SideEffect) {
5745
5898
  // In this mode, scope information is not passed into `ɵɵdefineNgModule` as it
5746
5899
  // would prevent tree-shaking of the declarations, imports and exports references. Instead, it's
5747
5900
  // patched onto the NgModule definition with a `ɵɵsetNgModuleScope` call that's guarded by the
@@ -5754,14 +5907,14 @@ function compileNgModule(meta) {
5754
5907
  else {
5755
5908
  // Selector scope emit was not requested, so skip it.
5756
5909
  }
5757
- if (schemas !== null && schemas.length > 0) {
5758
- definitionMap.set('schemas', literalArr(schemas.map(ref => ref.value)));
5910
+ if (meta.schemas !== null && meta.schemas.length > 0) {
5911
+ definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
5759
5912
  }
5760
- if (id !== null) {
5761
- definitionMap.set('id', id);
5913
+ if (meta.id !== null) {
5914
+ definitionMap.set('id', meta.id);
5762
5915
  // Generate a side-effectful call to register this NgModule by its id, as per the semantics of
5763
5916
  // NgModule ids.
5764
- statements.push(importExpr(Identifiers.registerNgModuleType).callFn([moduleType.value, id]).toStmt());
5917
+ statements.push(importExpr(Identifiers.registerNgModuleType).callFn([meta.type.value, meta.id]).toStmt());
5765
5918
  }
5766
5919
  const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
5767
5920
  const type = createNgModuleType(meta);
@@ -5794,7 +5947,11 @@ function compileNgModuleDeclarationExpression(meta) {
5794
5947
  }
5795
5948
  return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]);
5796
5949
  }
5797
- function createNgModuleType({ type: moduleType, declarations, exports, imports, includeImportTypes, publicDeclarationTypes }) {
5950
+ function createNgModuleType(meta) {
5951
+ if (meta.kind === R3NgModuleMetadataKind.Local) {
5952
+ return new ExpressionType(meta.type.value);
5953
+ }
5954
+ const { type: moduleType, declarations, exports, imports, includeImportTypes, publicDeclarationTypes } = meta;
5798
5955
  return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [
5799
5956
  new ExpressionType(moduleType.type),
5800
5957
  publicDeclarationTypes === null ? tupleTypeOf(declarations) :
@@ -5810,16 +5967,36 @@ function createNgModuleType({ type: moduleType, declarations, exports, imports,
5810
5967
  * symbols to become tree-shakeable.
5811
5968
  */
5812
5969
  function generateSetNgModuleScopeCall(meta) {
5813
- const { type: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
5814
5970
  const scopeMap = new DefinitionMap();
5815
- if (declarations.length > 0) {
5816
- scopeMap.set('declarations', refsToArray(declarations, containsForwardDecls));
5971
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5972
+ if (meta.declarations.length > 0) {
5973
+ scopeMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
5974
+ }
5975
+ }
5976
+ else {
5977
+ if (meta.declarationsExpression) {
5978
+ scopeMap.set('declarations', meta.declarationsExpression);
5979
+ }
5980
+ }
5981
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5982
+ if (meta.imports.length > 0) {
5983
+ scopeMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
5984
+ }
5985
+ }
5986
+ else {
5987
+ if (meta.importsExpression) {
5988
+ scopeMap.set('imports', meta.importsExpression);
5989
+ }
5817
5990
  }
5818
- if (imports.length > 0) {
5819
- scopeMap.set('imports', refsToArray(imports, containsForwardDecls));
5991
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5992
+ if (meta.exports.length > 0) {
5993
+ scopeMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
5994
+ }
5820
5995
  }
5821
- if (exports.length > 0) {
5822
- scopeMap.set('exports', refsToArray(exports, containsForwardDecls));
5996
+ else {
5997
+ if (meta.exportsExpression) {
5998
+ scopeMap.set('exports', meta.exportsExpression);
5999
+ }
5823
6000
  }
5824
6001
  if (Object.keys(scopeMap.values).length === 0) {
5825
6002
  return null;
@@ -5827,7 +6004,7 @@ function generateSetNgModuleScopeCall(meta) {
5827
6004
  // setNgModuleScope(...)
5828
6005
  const fnCall = new InvokeFunctionExpr(
5829
6006
  /* fn */ importExpr(Identifiers.setNgModuleScope),
5830
- /* args */ [moduleType.value, scopeMap.toLiteralMap()]);
6007
+ /* args */ [meta.type.value, scopeMap.toLiteralMap()]);
5831
6008
  // (ngJitMode guard) && setNgModuleScope(...)
5832
6009
  const guardedCall = jitOnlyGuardedExpression(fnCall);
5833
6010
  // function() { (ngJitMode guard) && setNgModuleScope(...); }
@@ -7946,7 +8123,7 @@ class ShadowCss {
7946
8123
  }
7947
8124
  else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
7948
8125
  rule.selector.startsWith('@document') || rule.selector.startsWith('@layer') ||
7949
- rule.selector.startsWith('@container')) {
8126
+ rule.selector.startsWith('@container') || rule.selector.startsWith('@scope')) {
7950
8127
  content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
7951
8128
  }
7952
8129
  else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) {
@@ -8635,34 +8812,50 @@ var OpKind;
8635
8812
  * An operation to bind an expression to a style property of an element.
8636
8813
  */
8637
8814
  OpKind[OpKind["StyleProp"] = 14] = "StyleProp";
8815
+ /**
8816
+ * An operation to bind an expression to a class property of an element.
8817
+ */
8818
+ OpKind[OpKind["ClassProp"] = 15] = "ClassProp";
8638
8819
  /**
8639
8820
  * An operation to bind an expression to the styles of an element.
8640
8821
  */
8641
- OpKind[OpKind["StyleMap"] = 15] = "StyleMap";
8822
+ OpKind[OpKind["StyleMap"] = 16] = "StyleMap";
8823
+ /**
8824
+ * An operation to bind an expression to the classes of an element.
8825
+ */
8826
+ OpKind[OpKind["ClassMap"] = 17] = "ClassMap";
8642
8827
  /**
8643
8828
  * An operation to interpolate text into a property binding.
8644
8829
  */
8645
- OpKind[OpKind["InterpolateProperty"] = 16] = "InterpolateProperty";
8830
+ OpKind[OpKind["InterpolateProperty"] = 18] = "InterpolateProperty";
8646
8831
  /**
8647
8832
  * An operation to interpolate text into a style property binding.
8648
8833
  */
8649
- OpKind[OpKind["InterpolateStyleProp"] = 17] = "InterpolateStyleProp";
8834
+ OpKind[OpKind["InterpolateStyleProp"] = 19] = "InterpolateStyleProp";
8650
8835
  /**
8651
8836
  * An operation to interpolate text into a style mapping.
8652
8837
  */
8653
- OpKind[OpKind["InterpolateStyleMap"] = 18] = "InterpolateStyleMap";
8838
+ OpKind[OpKind["InterpolateStyleMap"] = 20] = "InterpolateStyleMap";
8839
+ /**
8840
+ * An operation to interpolate text into a class mapping.
8841
+ */
8842
+ OpKind[OpKind["InterpolateClassMap"] = 21] = "InterpolateClassMap";
8654
8843
  /**
8655
8844
  * An operation to advance the runtime's implicit slot context during the update phase of a view.
8656
8845
  */
8657
- OpKind[OpKind["Advance"] = 19] = "Advance";
8846
+ OpKind[OpKind["Advance"] = 22] = "Advance";
8658
8847
  /**
8659
8848
  * An operation to instantiate a pipe.
8660
8849
  */
8661
- OpKind[OpKind["Pipe"] = 20] = "Pipe";
8850
+ OpKind[OpKind["Pipe"] = 23] = "Pipe";
8662
8851
  /**
8663
8852
  * An operation to associate an attribute with an element.
8664
8853
  */
8665
- OpKind[OpKind["Attribute"] = 21] = "Attribute";
8854
+ OpKind[OpKind["Attribute"] = 24] = "Attribute";
8855
+ /**
8856
+ * An operation to interpolate text into an attribute binding.
8857
+ */
8858
+ OpKind[OpKind["InterpolateAttribute"] = 25] = "InterpolateAttribute";
8666
8859
  })(OpKind || (OpKind = {}));
8667
8860
  /**
8668
8861
  * Distinguishes different kinds of IR expressions.
@@ -8737,6 +8930,14 @@ var ExpressionKind;
8737
8930
  * An empty expression that will be stipped before generating the final output.
8738
8931
  */
8739
8932
  ExpressionKind[ExpressionKind["EmptyExpr"] = 16] = "EmptyExpr";
8933
+ /*
8934
+ * An assignment to a temporary variable.
8935
+ */
8936
+ ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 17] = "AssignTemporaryExpr";
8937
+ /**
8938
+ * A reference to a temporary variable.
8939
+ */
8940
+ ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 18] = "ReadTemporaryExpr";
8740
8941
  })(ExpressionKind || (ExpressionKind = {}));
8741
8942
  /**
8742
8943
  * Distinguishes between different kinds of `SemanticVariable`s.
@@ -9204,7 +9405,13 @@ class SafePropertyReadExpr extends ExpressionBase {
9204
9405
  this.name = name;
9205
9406
  this.kind = ExpressionKind.SafePropertyRead;
9206
9407
  }
9207
- visitExpression(visitor, context) { }
9408
+ // An alias for name, which allows other logic to handle property reads and keyed reads together.
9409
+ get index() {
9410
+ return this.name;
9411
+ }
9412
+ visitExpression(visitor, context) {
9413
+ this.receiver.visitExpression(visitor, context);
9414
+ }
9208
9415
  isEquivalent() {
9209
9416
  return false;
9210
9417
  }
@@ -9225,7 +9432,10 @@ class SafeKeyedReadExpr extends ExpressionBase {
9225
9432
  this.index = index;
9226
9433
  this.kind = ExpressionKind.SafeKeyedRead;
9227
9434
  }
9228
- visitExpression(visitor, context) { }
9435
+ visitExpression(visitor, context) {
9436
+ this.receiver.visitExpression(visitor, context);
9437
+ this.index.visitExpression(visitor, context);
9438
+ }
9229
9439
  isEquivalent() {
9230
9440
  return false;
9231
9441
  }
@@ -9247,7 +9457,12 @@ class SafeInvokeFunctionExpr extends ExpressionBase {
9247
9457
  this.args = args;
9248
9458
  this.kind = ExpressionKind.SafeInvokeFunction;
9249
9459
  }
9250
- visitExpression(visitor, context) { }
9460
+ visitExpression(visitor, context) {
9461
+ this.receiver.visitExpression(visitor, context);
9462
+ for (const a of this.args) {
9463
+ a.visitExpression(visitor, context);
9464
+ }
9465
+ }
9251
9466
  isEquivalent() {
9252
9467
  return false;
9253
9468
  }
@@ -9271,7 +9486,10 @@ class SafeTernaryExpr extends ExpressionBase {
9271
9486
  this.expr = expr;
9272
9487
  this.kind = ExpressionKind.SafeTernaryExpr;
9273
9488
  }
9274
- visitExpression(visitor, context) { }
9489
+ visitExpression(visitor, context) {
9490
+ this.guard.visitExpression(visitor, context);
9491
+ this.expr.visitExpression(visitor, context);
9492
+ }
9275
9493
  isEquivalent() {
9276
9494
  return false;
9277
9495
  }
@@ -9303,6 +9521,53 @@ class EmptyExpr extends ExpressionBase {
9303
9521
  }
9304
9522
  transformInternalExpressions() { }
9305
9523
  }
9524
+ class AssignTemporaryExpr extends ExpressionBase {
9525
+ constructor(expr, xref) {
9526
+ super();
9527
+ this.expr = expr;
9528
+ this.xref = xref;
9529
+ this.kind = ExpressionKind.AssignTemporaryExpr;
9530
+ this.name = null;
9531
+ }
9532
+ visitExpression(visitor, context) {
9533
+ this.expr.visitExpression(visitor, context);
9534
+ }
9535
+ isEquivalent() {
9536
+ return false;
9537
+ }
9538
+ isConstant() {
9539
+ return false;
9540
+ }
9541
+ transformInternalExpressions(transform, flags) {
9542
+ this.expr = transformExpressionsInExpression(this.expr, transform, flags);
9543
+ }
9544
+ clone() {
9545
+ const a = new AssignTemporaryExpr(this.expr, this.xref);
9546
+ a.name = this.name;
9547
+ return a;
9548
+ }
9549
+ }
9550
+ class ReadTemporaryExpr extends ExpressionBase {
9551
+ constructor(xref) {
9552
+ super();
9553
+ this.xref = xref;
9554
+ this.kind = ExpressionKind.ReadTemporaryExpr;
9555
+ this.name = null;
9556
+ }
9557
+ visitExpression(visitor, context) { }
9558
+ isEquivalent() {
9559
+ return this.xref === this.xref;
9560
+ }
9561
+ isConstant() {
9562
+ return false;
9563
+ }
9564
+ transformInternalExpressions(transform, flags) { }
9565
+ clone() {
9566
+ const r = new ReadTemporaryExpr(this.xref);
9567
+ r.name = this.name;
9568
+ return r;
9569
+ }
9570
+ }
9306
9571
  /**
9307
9572
  * Visits all `Expression`s in the AST of `op` with the `visitor` function.
9308
9573
  */
@@ -9328,11 +9593,14 @@ function transformExpressionsInOp(op, transform, flags) {
9328
9593
  case OpKind.Property:
9329
9594
  case OpKind.StyleProp:
9330
9595
  case OpKind.StyleMap:
9596
+ case OpKind.ClassProp:
9597
+ case OpKind.ClassMap:
9331
9598
  op.expression = transformExpressionsInExpression(op.expression, transform, flags);
9332
9599
  break;
9333
9600
  case OpKind.InterpolateProperty:
9334
9601
  case OpKind.InterpolateStyleProp:
9335
9602
  case OpKind.InterpolateStyleMap:
9603
+ case OpKind.InterpolateClassMap:
9336
9604
  case OpKind.InterpolateText:
9337
9605
  for (let i = 0; i < op.expressions.length; i++) {
9338
9606
  op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
@@ -9343,7 +9611,12 @@ function transformExpressionsInOp(op, transform, flags) {
9343
9611
  break;
9344
9612
  case OpKind.Attribute:
9345
9613
  if (op.value) {
9346
- transformExpressionsInExpression(op.value, transform, flags);
9614
+ op.value = transformExpressionsInExpression(op.value, transform, flags);
9615
+ }
9616
+ break;
9617
+ case OpKind.InterpolateAttribute:
9618
+ for (let i = 0; i < op.expressions.length; i++) {
9619
+ op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
9347
9620
  }
9348
9621
  break;
9349
9622
  case OpKind.Variable:
@@ -9446,6 +9719,11 @@ function transformExpressionsInStatement(stmt, transform, flags) {
9446
9719
  else if (stmt instanceof ReturnStatement) {
9447
9720
  stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
9448
9721
  }
9722
+ else if (stmt instanceof DeclareVarStmt) {
9723
+ if (stmt.value !== undefined) {
9724
+ stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
9725
+ }
9726
+ }
9449
9727
  else {
9450
9728
  throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
9451
9729
  }
@@ -9841,6 +10119,20 @@ function createStylePropOp(xref, name, expression, unit) {
9841
10119
  ...NEW_OP,
9842
10120
  };
9843
10121
  }
10122
+ /**
10123
+ * Create a `ClassPropOp`.
10124
+ */
10125
+ function createClassPropOp(xref, name, expression) {
10126
+ return {
10127
+ kind: OpKind.ClassProp,
10128
+ target: xref,
10129
+ name,
10130
+ expression,
10131
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10132
+ ...TRAIT_CONSUMES_VARS,
10133
+ ...NEW_OP,
10134
+ };
10135
+ }
9844
10136
  /** Create a `StyleMapOp`. */
9845
10137
  function createStyleMapOp(xref, expression) {
9846
10138
  return {
@@ -9852,6 +10144,19 @@ function createStyleMapOp(xref, expression) {
9852
10144
  ...NEW_OP,
9853
10145
  };
9854
10146
  }
10147
+ /**
10148
+ * Create a `ClassMapOp`.
10149
+ */
10150
+ function createClassMapOp(xref, expression) {
10151
+ return {
10152
+ kind: OpKind.ClassMap,
10153
+ target: xref,
10154
+ expression,
10155
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10156
+ ...TRAIT_CONSUMES_VARS,
10157
+ ...NEW_OP,
10158
+ };
10159
+ }
9855
10160
  /**
9856
10161
  * Create an `AttributeOp`.
9857
10162
  */
@@ -9862,6 +10167,8 @@ function createAttributeOp(target, attributeKind, name, value) {
9862
10167
  attributeKind,
9863
10168
  name,
9864
10169
  value,
10170
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10171
+ ...TRAIT_CONSUMES_VARS,
9865
10172
  ...NEW_OP,
9866
10173
  };
9867
10174
  }
@@ -9881,6 +10188,19 @@ function createInterpolatePropertyOp(xref, bindingKind, name, strings, expressio
9881
10188
  ...NEW_OP,
9882
10189
  };
9883
10190
  }
10191
+ function createInterpolateAttributeOp(target, attributeKind, name, strings, expressions) {
10192
+ return {
10193
+ kind: OpKind.InterpolateAttribute,
10194
+ target: target,
10195
+ attributeKind,
10196
+ name,
10197
+ strings,
10198
+ expressions,
10199
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10200
+ ...TRAIT_CONSUMES_VARS,
10201
+ ...NEW_OP,
10202
+ };
10203
+ }
9884
10204
  /**
9885
10205
  * Create a `InterpolateStyleProp`.
9886
10206
  */
@@ -9911,6 +10231,20 @@ function createInterpolateStyleMapOp(xref, strings, expressions) {
9911
10231
  ...NEW_OP,
9912
10232
  };
9913
10233
  }
10234
+ /**
10235
+ * Create a `InterpolateStyleMap`.
10236
+ */
10237
+ function createInterpolateClassMapOp(xref, strings, expressions) {
10238
+ return {
10239
+ kind: OpKind.InterpolateClassMap,
10240
+ target: xref,
10241
+ strings,
10242
+ expressions,
10243
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10244
+ ...TRAIT_CONSUMES_VARS,
10245
+ ...NEW_OP,
10246
+ };
10247
+ }
9914
10248
  /**
9915
10249
  * Create an `AdvanceOp`.
9916
10250
  */
@@ -9968,19 +10302,30 @@ function phaseVarCounting(cpl) {
9968
10302
  function varsUsedByOp(op) {
9969
10303
  switch (op.kind) {
9970
10304
  case OpKind.Property:
10305
+ case OpKind.Attribute:
10306
+ // Property & attribute bindings use 1 variable slot.
10307
+ return 1;
9971
10308
  case OpKind.StyleProp:
10309
+ case OpKind.ClassProp:
9972
10310
  case OpKind.StyleMap:
9973
- // Property bindings use 1 variable slot.
9974
- return 1;
10311
+ case OpKind.ClassMap:
10312
+ // Style & class bindings use 2 variable slots.
10313
+ return 2;
9975
10314
  case OpKind.InterpolateText:
9976
10315
  // `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
9977
10316
  return op.expressions.length;
9978
10317
  case OpKind.InterpolateProperty:
9979
- case OpKind.InterpolateStyleProp:
9980
- case OpKind.InterpolateStyleMap:
9981
10318
  // `ir.InterpolatePropertyOp`s use a variable slot for each dynamic expression, plus one for
9982
10319
  // the result.
9983
10320
  return 1 + op.expressions.length;
10321
+ case OpKind.InterpolateAttribute:
10322
+ // One variable slot for each dynamic expression, plus one for the result.
10323
+ return 1 + op.expressions.length;
10324
+ case OpKind.InterpolateStyleProp:
10325
+ case OpKind.InterpolateStyleMap:
10326
+ case OpKind.InterpolateClassMap:
10327
+ // One variable slot for each dynamic expression, plus two for binding the result.
10328
+ return 2 + op.expressions.length;
9984
10329
  default:
9985
10330
  throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
9986
10331
  }
@@ -10100,6 +10445,7 @@ function populateElementAttributes(view, compatibility) {
10100
10445
  ownerOp.attributes.add(op.bindingKind, op.name, null);
10101
10446
  break;
10102
10447
  case OpKind.StyleProp:
10448
+ case OpKind.ClassProp:
10103
10449
  ownerOp = lookupElement(elements, op.target);
10104
10450
  assertIsElementAttributes(ownerOp.attributes);
10105
10451
  // The old compiler treated empty style bindings as regular bindings for the purpose of
@@ -10126,6 +10472,17 @@ const CHAINABLE = new Set([
10126
10472
  Identifiers.elementEnd,
10127
10473
  Identifiers.property,
10128
10474
  Identifiers.styleProp,
10475
+ Identifiers.attribute,
10476
+ Identifiers.stylePropInterpolate1,
10477
+ Identifiers.stylePropInterpolate2,
10478
+ Identifiers.stylePropInterpolate3,
10479
+ Identifiers.stylePropInterpolate4,
10480
+ Identifiers.stylePropInterpolate5,
10481
+ Identifiers.stylePropInterpolate6,
10482
+ Identifiers.stylePropInterpolate7,
10483
+ Identifiers.stylePropInterpolate8,
10484
+ Identifiers.stylePropInterpolateV,
10485
+ Identifiers.classProp,
10129
10486
  Identifiers.elementContainerStart,
10130
10487
  Identifiers.elementContainerEnd,
10131
10488
  Identifiers.elementContainer,
@@ -10268,32 +10625,201 @@ function phaseEmptyElements(cpl) {
10268
10625
  }
10269
10626
 
10270
10627
  /**
10271
- * Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
10272
- * context will be advanced correctly.
10628
+ * Finds all unresolved safe read expressions, and converts them into the appropriate output AST
10629
+ * reads, guarded by null checks.
10273
10630
  */
10274
- function phaseGenerateAdvance(cpl) {
10631
+ function phaseExpandSafeReads(cpl, compatibility) {
10275
10632
  for (const [_, view] of cpl.views) {
10276
- // First build a map of all of the declarations in the view that have assigned slots.
10277
- const slotMap = new Map();
10278
- for (const op of view.create) {
10279
- if (!hasConsumesSlotTrait(op)) {
10280
- continue;
10281
- }
10282
- else if (op.slot === null) {
10283
- throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
10284
- }
10285
- slotMap.set(op.xref, op.slot);
10633
+ for (const op of view.ops()) {
10634
+ transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
10635
+ transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
10286
10636
  }
10287
- // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
10288
- // the runtime's implicit slot counter will be set to the correct slot before executing each
10289
- // update operation which depends on it.
10290
- //
10291
- // To do that, we track what the runtime's slot counter will be through the update operations.
10292
- let slotContext = 0;
10293
- for (const op of view.update) {
10294
- if (!hasDependsOnSlotContextTrait(op)) {
10295
- // `op` doesn't depend on the slot counter, so it can be skipped.
10296
- continue;
10637
+ }
10638
+ }
10639
+ // A lookup set of all the expression kinds that require a temporary variable to be generated.
10640
+ const requiresTemporary = [
10641
+ InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr,
10642
+ PipeBindingExpr
10643
+ ].map(e => e.constructor.name);
10644
+ function needsTemporaryInSafeAccess(e) {
10645
+ // TODO: We probably want to use an expression visitor to recursively visit all descendents.
10646
+ // However, that would potentially do a lot of extra work (because it cannot short circuit), so we
10647
+ // implement the logic ourselves for now.
10648
+ if (e instanceof UnaryOperatorExpr) {
10649
+ return needsTemporaryInSafeAccess(e.expr);
10650
+ }
10651
+ else if (e instanceof BinaryOperatorExpr) {
10652
+ return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
10653
+ }
10654
+ else if (e instanceof ConditionalExpr) {
10655
+ if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase))
10656
+ return true;
10657
+ return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
10658
+ }
10659
+ else if (e instanceof NotExpr) {
10660
+ return needsTemporaryInSafeAccess(e.condition);
10661
+ }
10662
+ else if (e instanceof AssignTemporaryExpr) {
10663
+ return needsTemporaryInSafeAccess(e.expr);
10664
+ }
10665
+ else if (e instanceof ReadPropExpr) {
10666
+ return needsTemporaryInSafeAccess(e.receiver);
10667
+ }
10668
+ else if (e instanceof ReadKeyExpr) {
10669
+ return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
10670
+ }
10671
+ // TODO: Switch to a method which is exhaustive of newly added expression subtypes.
10672
+ return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr ||
10673
+ e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr ||
10674
+ e instanceof PipeBindingExpr;
10675
+ }
10676
+ function temporariesIn(e) {
10677
+ const temporaries = new Set();
10678
+ // TODO: Although it's not currently supported by the transform helper, we should be able to
10679
+ // short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
10680
+ // into the subexpressions of temporary assignments.
10681
+ transformExpressionsInExpression(e, e => {
10682
+ if (e instanceof AssignTemporaryExpr) {
10683
+ temporaries.add(e.xref);
10684
+ }
10685
+ return e;
10686
+ }, VisitorContextFlag.None);
10687
+ return temporaries;
10688
+ }
10689
+ function eliminateTemporaryAssignments(e, tmps, ctx) {
10690
+ // TODO: We can be more efficient than the transform helper here. We don't need to visit any
10691
+ // descendents of temporary assignments.
10692
+ transformExpressionsInExpression(e, e => {
10693
+ if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
10694
+ const read = new ReadTemporaryExpr(e.xref);
10695
+ // `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
10696
+ // temporary variables to themselves. This happens because some subexpression that the
10697
+ // temporary refers to, possibly through nested temporaries, has a function call. We copy that
10698
+ // behavior here.
10699
+ return ctx.compatibility ? new AssignTemporaryExpr(read, read.xref) : read;
10700
+ }
10701
+ return e;
10702
+ }, VisitorContextFlag.None);
10703
+ return e;
10704
+ }
10705
+ /**
10706
+ * Creates a safe ternary guarded by the input expression, and with a body generated by the provided
10707
+ * callback on the input expression. Generates a temporary variable assignment if needed, and
10708
+ * deduplicates nested temporary assignments if needed.
10709
+ */
10710
+ function safeTernaryWithTemporary(guard, body, ctx) {
10711
+ let result;
10712
+ if (needsTemporaryInSafeAccess(guard)) {
10713
+ const xref = ctx.cpl.allocateXrefId();
10714
+ result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
10715
+ }
10716
+ else {
10717
+ result = [guard, guard.clone()];
10718
+ // Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
10719
+ // introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
10720
+ // assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
10721
+ // by transforming it from an assignment into a read on the expression side.
10722
+ eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
10723
+ }
10724
+ return new SafeTernaryExpr(result[0], body(result[1]));
10725
+ }
10726
+ function isSafeAccessExpression(e) {
10727
+ return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
10728
+ }
10729
+ function isUnsafeAccessExpression(e) {
10730
+ return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
10731
+ e instanceof InvokeFunctionExpr;
10732
+ }
10733
+ function isAccessExpression(e) {
10734
+ return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
10735
+ }
10736
+ function deepestSafeTernary(e) {
10737
+ if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
10738
+ let st = e.receiver;
10739
+ while (st.expr instanceof SafeTernaryExpr) {
10740
+ st = st.expr;
10741
+ }
10742
+ return st;
10743
+ }
10744
+ return null;
10745
+ }
10746
+ // TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
10747
+ // instead to save some code size.
10748
+ function safeTransform(e, ctx) {
10749
+ if (e instanceof SafeInvokeFunctionExpr) {
10750
+ // TODO: Implement safe function calls in a subsequent commit.
10751
+ return new InvokeFunctionExpr(e.receiver, e.args);
10752
+ }
10753
+ if (!isAccessExpression(e)) {
10754
+ return e;
10755
+ }
10756
+ const dst = deepestSafeTernary(e);
10757
+ if (dst) {
10758
+ if (e instanceof InvokeFunctionExpr) {
10759
+ dst.expr = dst.expr.callFn(e.args);
10760
+ return e.receiver;
10761
+ }
10762
+ if (e instanceof ReadPropExpr) {
10763
+ dst.expr = dst.expr.prop(e.name);
10764
+ return e.receiver;
10765
+ }
10766
+ if (e instanceof ReadKeyExpr) {
10767
+ dst.expr = dst.expr.key(e.index);
10768
+ return e.receiver;
10769
+ }
10770
+ if (e instanceof SafePropertyReadExpr) {
10771
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
10772
+ return e.receiver;
10773
+ }
10774
+ if (e instanceof SafeKeyedReadExpr) {
10775
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
10776
+ return e.receiver;
10777
+ }
10778
+ }
10779
+ else {
10780
+ if (e instanceof SafePropertyReadExpr) {
10781
+ return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
10782
+ }
10783
+ if (e instanceof SafeKeyedReadExpr) {
10784
+ return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
10785
+ }
10786
+ }
10787
+ return e;
10788
+ }
10789
+ function ternaryTransform(e) {
10790
+ if (!(e instanceof SafeTernaryExpr)) {
10791
+ return e;
10792
+ }
10793
+ return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
10794
+ }
10795
+
10796
+ /**
10797
+ * Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
10798
+ * context will be advanced correctly.
10799
+ */
10800
+ function phaseGenerateAdvance(cpl) {
10801
+ for (const [_, view] of cpl.views) {
10802
+ // First build a map of all of the declarations in the view that have assigned slots.
10803
+ const slotMap = new Map();
10804
+ for (const op of view.create) {
10805
+ if (!hasConsumesSlotTrait(op)) {
10806
+ continue;
10807
+ }
10808
+ else if (op.slot === null) {
10809
+ throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
10810
+ }
10811
+ slotMap.set(op.xref, op.slot);
10812
+ }
10813
+ // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
10814
+ // the runtime's implicit slot counter will be set to the correct slot before executing each
10815
+ // update operation which depends on it.
10816
+ //
10817
+ // To do that, we track what the runtime's slot counter will be through the update operations.
10818
+ let slotContext = 0;
10819
+ for (const op of view.update) {
10820
+ if (!hasDependsOnSlotContextTrait(op)) {
10821
+ // `op` doesn't depend on the slot counter, so it can be skipped.
10822
+ continue;
10297
10823
  }
10298
10824
  else if (!slotMap.has(op.target)) {
10299
10825
  // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
@@ -10315,23 +10841,6 @@ function phaseGenerateAdvance(cpl) {
10315
10841
  }
10316
10842
  }
10317
10843
 
10318
- function phaseNullishCoalescing(cpl) {
10319
- for (const view of cpl.views.values()) {
10320
- for (const op of view.ops()) {
10321
- transformExpressionsInOp(op, expr => {
10322
- if (!(expr instanceof BinaryOperatorExpr) ||
10323
- expr.operator !== BinaryOperator.NullishCoalesce) {
10324
- return expr;
10325
- }
10326
- // TODO: We need to unconditionally emit a temporary variable to match
10327
- // TemplateDefinitionBuilder. (We could also emit one conditionally when not in
10328
- // compatibility mode.)
10329
- 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);
10330
- }, VisitorContextFlag.None);
10331
- }
10332
- }
10333
- }
10334
-
10335
10844
  /**
10336
10845
  * Generate a preamble sequence for each view creation block and listener function which declares
10337
10846
  * any variables that be referenced in other operations in the block.
@@ -10359,11 +10868,6 @@ function phaseGenerateVariables(cpl) {
10359
10868
  function recursivelyProcessView(view, parentScope) {
10360
10869
  // Extract a `Scope` from this view.
10361
10870
  const scope = getScopeForView(view, parentScope);
10362
- // Embedded views require an operation to save/restore the view context.
10363
- if (view.parent !== null) {
10364
- // Start the view creation block with an operation to save the current view context. This may be
10365
- // used to restore the view context in any listeners that may be present.
10366
- }
10367
10871
  for (const op of view.create) {
10368
10872
  switch (op.kind) {
10369
10873
  case OpKind.Template:
@@ -10493,18 +10997,97 @@ function serializeLocalRefs(refs) {
10493
10997
  return literalArr(constRefs);
10494
10998
  }
10495
10999
 
11000
+ /**
11001
+ * Parses string representation of a style and converts it into object literal.
11002
+ *
11003
+ * @param value string representation of style as used in the `style` attribute in HTML.
11004
+ * Example: `color: red; height: auto`.
11005
+ * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
11006
+ * 'auto']`
11007
+ */
11008
+ function parse(value) {
11009
+ // we use a string array here instead of a string map
11010
+ // because a string-map is not guaranteed to retain the
11011
+ // order of the entries whereas a string array can be
11012
+ // constructed in a [key, value, key, value] format.
11013
+ const styles = [];
11014
+ let i = 0;
11015
+ let parenDepth = 0;
11016
+ let quote = 0 /* Char.QuoteNone */;
11017
+ let valueStart = 0;
11018
+ let propStart = 0;
11019
+ let currentProp = null;
11020
+ while (i < value.length) {
11021
+ const token = value.charCodeAt(i++);
11022
+ switch (token) {
11023
+ case 40 /* Char.OpenParen */:
11024
+ parenDepth++;
11025
+ break;
11026
+ case 41 /* Char.CloseParen */:
11027
+ parenDepth--;
11028
+ break;
11029
+ case 39 /* Char.QuoteSingle */:
11030
+ // valueStart needs to be there since prop values don't
11031
+ // have quotes in CSS
11032
+ if (quote === 0 /* Char.QuoteNone */) {
11033
+ quote = 39 /* Char.QuoteSingle */;
11034
+ }
11035
+ else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11036
+ quote = 0 /* Char.QuoteNone */;
11037
+ }
11038
+ break;
11039
+ case 34 /* Char.QuoteDouble */:
11040
+ // same logic as above
11041
+ if (quote === 0 /* Char.QuoteNone */) {
11042
+ quote = 34 /* Char.QuoteDouble */;
11043
+ }
11044
+ else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11045
+ quote = 0 /* Char.QuoteNone */;
11046
+ }
11047
+ break;
11048
+ case 58 /* Char.Colon */:
11049
+ if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11050
+ currentProp = hyphenate(value.substring(propStart, i - 1).trim());
11051
+ valueStart = i;
11052
+ }
11053
+ break;
11054
+ case 59 /* Char.Semicolon */:
11055
+ if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11056
+ const styleVal = value.substring(valueStart, i - 1).trim();
11057
+ styles.push(currentProp, styleVal);
11058
+ propStart = i;
11059
+ valueStart = 0;
11060
+ currentProp = null;
11061
+ }
11062
+ break;
11063
+ }
11064
+ }
11065
+ if (currentProp && valueStart) {
11066
+ const styleVal = value.slice(valueStart).trim();
11067
+ styles.push(currentProp, styleVal);
11068
+ }
11069
+ return styles;
11070
+ }
11071
+ function hyphenate(value) {
11072
+ return value
11073
+ .replace(/[a-z][A-Z]/g, v => {
11074
+ return v.charAt(0) + '-' + v.charAt(1);
11075
+ })
11076
+ .toLowerCase();
11077
+ }
11078
+
10496
11079
  /**
10497
11080
  * Generate names for functions and variables across all views.
10498
11081
  *
10499
11082
  * This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
10500
11083
  * the reads can be emitted correctly.
10501
11084
  */
10502
- function phaseNaming(cpl) {
10503
- addNamesToView(cpl.root, cpl.componentName, { index: 0 });
11085
+ function phaseNaming(cpl, compatibility) {
11086
+ addNamesToView(cpl.root, cpl.componentName, { index: 0 }, compatibility);
10504
11087
  }
10505
- function addNamesToView(view, baseName, state) {
11088
+ function addNamesToView(view, baseName, state, compatibility) {
10506
11089
  if (view.fnName === null) {
10507
- view.fnName = `${baseName}_Template`;
11090
+ view.fnName = sanitizeIdentifier(`${baseName}_Template`);
10508
11091
  }
10509
11092
  // Keep track of the names we assign to variables in the view. We'll need to propagate these
10510
11093
  // into reads of those variables afterwards.
@@ -10518,7 +11101,8 @@ function addNamesToView(view, baseName, state) {
10518
11101
  if (op.slot === null) {
10519
11102
  throw new Error(`Expected a slot to be assigned`);
10520
11103
  }
10521
- op.handlerFnName = `${view.fnName}_${op.tag}_${op.name}_${op.slot}_listener`;
11104
+ op.handlerFnName =
11105
+ sanitizeIdentifier(`${view.fnName}_${op.tag}_${op.name}_${op.slot}_listener`);
10522
11106
  }
10523
11107
  break;
10524
11108
  case OpKind.Variable:
@@ -10529,9 +11113,19 @@ function addNamesToView(view, baseName, state) {
10529
11113
  if (op.slot === null) {
10530
11114
  throw new Error(`Expected slot to be assigned`);
10531
11115
  }
10532
- // TODO: properly escape the tag name.
10533
- const safeTagName = op.tag.replace('-', '_');
10534
- addNamesToView(childView, `${baseName}_${safeTagName}_${op.slot}`, state);
11116
+ addNamesToView(childView, `${baseName}_${op.tag}_${op.slot}`, state, compatibility);
11117
+ break;
11118
+ case OpKind.StyleProp:
11119
+ case OpKind.InterpolateStyleProp:
11120
+ op.name = normalizeStylePropName(op.name);
11121
+ if (compatibility) {
11122
+ op.name = stripImportant(op.name);
11123
+ }
11124
+ break;
11125
+ case OpKind.ClassProp:
11126
+ if (compatibility) {
11127
+ op.name = stripImportant(op.name);
11128
+ }
10535
11129
  break;
10536
11130
  }
10537
11131
  }
@@ -10562,6 +11156,22 @@ function getVariableName(variable, state) {
10562
11156
  }
10563
11157
  return variable.name;
10564
11158
  }
11159
+ /**
11160
+ * Normalizes a style prop name by hyphenating it (unless its a CSS variable).
11161
+ */
11162
+ function normalizeStylePropName(name) {
11163
+ return name.startsWith('--') ? name : hyphenate(name);
11164
+ }
11165
+ /**
11166
+ * Strips `!important` out of the given style or class name.
11167
+ */
11168
+ function stripImportant(name) {
11169
+ const importantIndex = name.indexOf('!important');
11170
+ if (importantIndex > -1) {
11171
+ return name.substring(0, importantIndex);
11172
+ }
11173
+ return name;
11174
+ }
10565
11175
 
10566
11176
  /**
10567
11177
  * Merges logically sequential `NextContextExpr` operations.
@@ -10647,6 +11257,24 @@ function phaseNgContainer(cpl) {
10647
11257
  }
10648
11258
  }
10649
11259
 
11260
+ function phaseNullishCoalescing(cpl) {
11261
+ for (const view of cpl.views.values()) {
11262
+ for (const op of view.ops()) {
11263
+ transformExpressionsInOp(op, expr => {
11264
+ if (!(expr instanceof BinaryOperatorExpr) ||
11265
+ expr.operator !== BinaryOperator.NullishCoalesce) {
11266
+ return expr;
11267
+ }
11268
+ const assignment = new AssignTemporaryExpr(expr.lhs.clone(), cpl.allocateXrefId());
11269
+ const read = new ReadTemporaryExpr(assignment.xref);
11270
+ // TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
11271
+ // `t != null` instead of including an undefined check as well.
11272
+ return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
11273
+ }, VisitorContextFlag.None);
11274
+ }
11275
+ }
11276
+ }
11277
+
10650
11278
  function phasePipeCreation(cpl) {
10651
11279
  for (const view of cpl.views.values()) {
10652
11280
  processPipeBindingsInView(view);
@@ -10713,6 +11341,80 @@ function phasePipeVariadic(cpl) {
10713
11341
  }
10714
11342
  }
10715
11343
 
11344
+ /**
11345
+ * Defines the groups based on `OpKind` that ops will be divided into. Ops will be collected into
11346
+ * groups, then optionally transformed, before recombining the groups in the order defined here.
11347
+ */
11348
+ const ORDERING = [
11349
+ { kinds: new Set([OpKind.StyleMap, OpKind.InterpolateStyleMap]), transform: keepLast },
11350
+ { kinds: new Set([OpKind.ClassMap, OpKind.InterpolateClassMap]), transform: keepLast },
11351
+ { kinds: new Set([OpKind.StyleProp, OpKind.InterpolateStyleProp]) },
11352
+ { kinds: new Set([OpKind.ClassProp]) },
11353
+ { kinds: new Set([OpKind.InterpolateProperty]) },
11354
+ { kinds: new Set([OpKind.Property]) },
11355
+ { kinds: new Set([OpKind.Attribute, OpKind.InterpolateAttribute]) },
11356
+ ];
11357
+ /**
11358
+ * The set of all op kinds we handle in the reordering phase.
11359
+ */
11360
+ const handledOpKinds = new Set(ORDERING.flatMap(group => [...group.kinds]));
11361
+ /**
11362
+ * Reorders property and attribute ops according to the following ordering:
11363
+ * 1. styleMap & styleMapInterpolate (drops all but the last op in the group)
11364
+ * 2. classMap & classMapInterpolate (drops all but the last op in the group)
11365
+ * 3. styleProp & stylePropInterpolate (ordering preserved within group)
11366
+ * 4. classProp (ordering preserved within group)
11367
+ * 5. propertyInterpolate (ordering preserved within group)
11368
+ * 6. property (ordering preserved within group)
11369
+ * 7. attribute & attributeInterpolate (ordering preserve within group)
11370
+ */
11371
+ function phasePropertyOrdering(cpl) {
11372
+ for (const [_, view] of cpl.views) {
11373
+ let opsToOrder = [];
11374
+ for (const op of view.update) {
11375
+ if (handledOpKinds.has(op.kind)) {
11376
+ // Pull out ops that need o be ordered.
11377
+ opsToOrder.push(op);
11378
+ OpList.remove(op);
11379
+ }
11380
+ else {
11381
+ // When we encounter an op that shouldn't be reordered, put the ones we've pulled so far
11382
+ // back in the correct order.
11383
+ for (const orderedOp of reorder(opsToOrder)) {
11384
+ OpList.insertBefore(orderedOp, op);
11385
+ }
11386
+ opsToOrder = [];
11387
+ }
11388
+ }
11389
+ // If we still have ops pulled at the end, put them back in the correct order.
11390
+ for (const orderedOp of reorder(opsToOrder)) {
11391
+ view.update.push(orderedOp);
11392
+ }
11393
+ }
11394
+ }
11395
+ /**
11396
+ * Reorders the given list of ops according to the ordering defined by `ORDERING`.
11397
+ */
11398
+ function reorder(ops) {
11399
+ // Break the ops list into groups based on OpKind.
11400
+ const groups = Array.from(ORDERING, () => new Array());
11401
+ for (const op of ops) {
11402
+ const groupIndex = ORDERING.findIndex(o => o.kinds.has(op.kind));
11403
+ groups[groupIndex].push(op);
11404
+ }
11405
+ // Reassemble the groups into a single list, in the correct order.
11406
+ return groups.flatMap((group, i) => {
11407
+ const transform = ORDERING[i].transform;
11408
+ return transform ? transform(group) : group;
11409
+ });
11410
+ }
11411
+ /**
11412
+ * Keeps only the last op in a list of ops.
11413
+ */
11414
+ function keepLast(ops) {
11415
+ return ops.slice(ops.length - 1);
11416
+ }
11417
+
10716
11418
  function phasePureFunctionExtraction(cpl) {
10717
11419
  for (const view of cpl.views.values()) {
10718
11420
  for (const op of view.ops()) {
@@ -10902,6 +11604,9 @@ function property(name, expression) {
10902
11604
  expression,
10903
11605
  ]);
10904
11606
  }
11607
+ function attribute(name, expression) {
11608
+ return call(Identifiers.attribute, [literal(name), expression]);
11609
+ }
10905
11610
  function styleProp(name, expression, unit) {
10906
11611
  const args = [literal(name), expression];
10907
11612
  if (unit !== null) {
@@ -10909,9 +11614,15 @@ function styleProp(name, expression, unit) {
10909
11614
  }
10910
11615
  return call(Identifiers.styleProp, args);
10911
11616
  }
11617
+ function classProp(name, expression) {
11618
+ return call(Identifiers.classProp, [literal(name), expression]);
11619
+ }
10912
11620
  function styleMap(expression) {
10913
11621
  return call(Identifiers.styleMap, [expression]);
10914
11622
  }
11623
+ function classMap(expression) {
11624
+ return call(Identifiers.classMap, [expression]);
11625
+ }
10915
11626
  const PIPE_BINDINGS = [
10916
11627
  Identifiers.pipeBind1,
10917
11628
  Identifiers.pipeBind2,
@@ -10958,6 +11669,10 @@ function propertyInterpolate(name, strings, expressions) {
10958
11669
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
10959
11670
  return callVariadicInstruction(PROPERTY_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs);
10960
11671
  }
11672
+ function attributeInterpolate(name, strings, expressions) {
11673
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11674
+ return callVariadicInstruction(ATTRIBUTE_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs);
11675
+ }
10961
11676
  function stylePropInterpolate(name, strings, expressions, unit) {
10962
11677
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
10963
11678
  const extraArgs = [];
@@ -10970,6 +11685,10 @@ function styleMapInterpolate(strings, expressions) {
10970
11685
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
10971
11686
  return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
10972
11687
  }
11688
+ function classMapInterpolate(strings, expressions) {
11689
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11690
+ return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
11691
+ }
10973
11692
  function pureFunction(varOffset, fn, args) {
10974
11693
  return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
10975
11694
  literal(varOffset),
@@ -11051,7 +11770,7 @@ const PROPERTY_INTERPOLATE_CONFIG = {
11051
11770
  */
11052
11771
  const STYLE_PROP_INTERPOLATE_CONFIG = {
11053
11772
  constant: [
11054
- null,
11773
+ Identifiers.styleProp,
11055
11774
  Identifiers.stylePropInterpolate1,
11056
11775
  Identifiers.stylePropInterpolate2,
11057
11776
  Identifiers.stylePropInterpolate3,
@@ -11061,14 +11780,34 @@ const STYLE_PROP_INTERPOLATE_CONFIG = {
11061
11780
  Identifiers.stylePropInterpolate7,
11062
11781
  Identifiers.stylePropInterpolate8,
11063
11782
  ],
11064
- variable: Identifiers.stylePropInterpolateV,
11783
+ variable: Identifiers.stylePropInterpolateV,
11784
+ mapping: n => {
11785
+ if (n % 2 === 0) {
11786
+ throw new Error(`Expected odd number of arguments`);
11787
+ }
11788
+ return (n - 1) / 2;
11789
+ },
11790
+ };
11791
+ /**
11792
+ * `InterpolationConfig` for the `attributeInterpolate` instruction.
11793
+ */
11794
+ const ATTRIBUTE_INTERPOLATE_CONFIG = {
11795
+ constant: [
11796
+ Identifiers.attribute,
11797
+ Identifiers.attributeInterpolate1,
11798
+ Identifiers.attributeInterpolate2,
11799
+ Identifiers.attributeInterpolate3,
11800
+ Identifiers.attributeInterpolate4,
11801
+ Identifiers.attributeInterpolate5,
11802
+ Identifiers.attributeInterpolate6,
11803
+ Identifiers.attributeInterpolate7,
11804
+ Identifiers.attributeInterpolate8,
11805
+ ],
11806
+ variable: Identifiers.attributeInterpolateV,
11065
11807
  mapping: n => {
11066
11808
  if (n % 2 === 0) {
11067
11809
  throw new Error(`Expected odd number of arguments`);
11068
11810
  }
11069
- if (n < 3) {
11070
- throw new Error(`Expected at least 3 arguments`);
11071
- }
11072
11811
  return (n - 1) / 2;
11073
11812
  },
11074
11813
  };
@@ -11077,7 +11816,7 @@ const STYLE_PROP_INTERPOLATE_CONFIG = {
11077
11816
  */
11078
11817
  const STYLE_MAP_INTERPOLATE_CONFIG = {
11079
11818
  constant: [
11080
- null,
11819
+ Identifiers.styleMap,
11081
11820
  Identifiers.styleMapInterpolate1,
11082
11821
  Identifiers.styleMapInterpolate2,
11083
11822
  Identifiers.styleMapInterpolate3,
@@ -11092,8 +11831,28 @@ const STYLE_MAP_INTERPOLATE_CONFIG = {
11092
11831
  if (n % 2 === 0) {
11093
11832
  throw new Error(`Expected odd number of arguments`);
11094
11833
  }
11095
- if (n < 3) {
11096
- throw new Error(`Expected at least 3 arguments`);
11834
+ return (n - 1) / 2;
11835
+ },
11836
+ };
11837
+ /**
11838
+ * `InterpolationConfig` for the `classMapInterpolate` instruction.
11839
+ */
11840
+ const CLASS_MAP_INTERPOLATE_CONFIG = {
11841
+ constant: [
11842
+ Identifiers.classMap,
11843
+ Identifiers.classMapInterpolate1,
11844
+ Identifiers.classMapInterpolate2,
11845
+ Identifiers.classMapInterpolate3,
11846
+ Identifiers.classMapInterpolate4,
11847
+ Identifiers.classMapInterpolate5,
11848
+ Identifiers.classMapInterpolate6,
11849
+ Identifiers.classMapInterpolate7,
11850
+ Identifiers.classMapInterpolate8,
11851
+ ],
11852
+ variable: Identifiers.classMapInterpolateV,
11853
+ mapping: n => {
11854
+ if (n % 2 === 0) {
11855
+ throw new Error(`Expected odd number of arguments`);
11097
11856
  }
11098
11857
  return (n - 1) / 2;
11099
11858
  },
@@ -11212,9 +11971,15 @@ function reifyUpdateOperations(_view, ops) {
11212
11971
  case OpKind.StyleProp:
11213
11972
  OpList.replace(op, styleProp(op.name, op.expression, op.unit));
11214
11973
  break;
11974
+ case OpKind.ClassProp:
11975
+ OpList.replace(op, classProp(op.name, op.expression));
11976
+ break;
11215
11977
  case OpKind.StyleMap:
11216
11978
  OpList.replace(op, styleMap(op.expression));
11217
11979
  break;
11980
+ case OpKind.ClassMap:
11981
+ OpList.replace(op, classMap(op.expression));
11982
+ break;
11218
11983
  case OpKind.InterpolateProperty:
11219
11984
  OpList.replace(op, propertyInterpolate(op.name, op.strings, op.expressions));
11220
11985
  break;
@@ -11224,9 +11989,18 @@ function reifyUpdateOperations(_view, ops) {
11224
11989
  case OpKind.InterpolateStyleMap:
11225
11990
  OpList.replace(op, styleMapInterpolate(op.strings, op.expressions));
11226
11991
  break;
11992
+ case OpKind.InterpolateClassMap:
11993
+ OpList.replace(op, classMapInterpolate(op.strings, op.expressions));
11994
+ break;
11227
11995
  case OpKind.InterpolateText:
11228
11996
  OpList.replace(op, textInterpolate(op.strings, op.expressions));
11229
11997
  break;
11998
+ case OpKind.Attribute:
11999
+ OpList.replace(op, attribute(op.name, op.value));
12000
+ break;
12001
+ case OpKind.InterpolateAttribute:
12002
+ OpList.replace(op, attributeInterpolate(op.name, op.strings, op.expressions));
12003
+ break;
11230
12004
  case OpKind.Variable:
11231
12005
  if (op.variable.name === null) {
11232
12006
  throw new Error(`AssertionError: unnamed variable ${op.xref}`);
@@ -11266,6 +12040,16 @@ function reifyIrExpression(expr) {
11266
12040
  throw new Error(`Read of unnamed variable ${expr.xref}`);
11267
12041
  }
11268
12042
  return variable(expr.name);
12043
+ case ExpressionKind.ReadTemporaryExpr:
12044
+ if (expr.name === null) {
12045
+ throw new Error(`Read of unnamed temporary ${expr.xref}`);
12046
+ }
12047
+ return variable(expr.name);
12048
+ case ExpressionKind.AssignTemporaryExpr:
12049
+ if (expr.name === null) {
12050
+ throw new Error(`Assign of unnamed temporary ${expr.xref}`);
12051
+ }
12052
+ return variable(expr.name).set(expr.expr);
11269
12053
  case ExpressionKind.PureFunctionExpr:
11270
12054
  if (expr.fn === null) {
11271
12055
  throw new Error(`AssertionError: expected PureFunctions to have been extracted`);
@@ -11453,14 +12237,17 @@ function processLexicalScope(view, ops, savedView) {
11453
12237
  }
11454
12238
  }, VisitorContextFlag.None);
11455
12239
  }
12240
+ for (const op of ops) {
12241
+ visitExpressionsInOp(op, expr => {
12242
+ if (expr instanceof LexicalReadExpr) {
12243
+ throw new Error(`AssertionError: no lexical reads should remain, but found read of ${expr.name}`);
12244
+ }
12245
+ });
12246
+ }
11456
12247
  }
11457
12248
 
11458
12249
  function phaseSaveRestoreView(cpl) {
11459
12250
  for (const view of cpl.views.values()) {
11460
- if (view === cpl.root) {
11461
- // Save/restore operations are not necessary for the root view.
11462
- continue;
11463
- }
11464
12251
  view.create.prepend([
11465
12252
  createVariableOp(view.tpl.allocateXrefId(), {
11466
12253
  kind: SemanticVariableKind.SavedView,
@@ -11472,22 +12259,39 @@ function phaseSaveRestoreView(cpl) {
11472
12259
  if (op.kind !== OpKind.Listener) {
11473
12260
  continue;
11474
12261
  }
11475
- op.handlerOps.prepend([
11476
- createVariableOp(view.tpl.allocateXrefId(), {
11477
- kind: SemanticVariableKind.Context,
11478
- name: null,
11479
- view: view.xref,
11480
- }, new RestoreViewExpr(view.xref)),
11481
- ]);
11482
- // The "restore view" operation in listeners requires a call to `resetView` to reset the
11483
- // context prior to returning from the listener operation. Find any `return` statements in
11484
- // the listener body and wrap them in a call to reset the view.
11485
- for (const handlerOp of op.handlerOps) {
11486
- if (handlerOp.kind === OpKind.Statement &&
11487
- handlerOp.statement instanceof ReturnStatement) {
11488
- handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
12262
+ // Embedded views always need the save/restore view operation.
12263
+ let needsRestoreView = view !== cpl.root;
12264
+ if (!needsRestoreView) {
12265
+ for (const handlerOp of op.handlerOps) {
12266
+ visitExpressionsInOp(handlerOp, expr => {
12267
+ if (expr instanceof ReferenceExpr) {
12268
+ // Listeners that reference() a local ref need the save/restore view operation.
12269
+ needsRestoreView = true;
12270
+ }
12271
+ });
11489
12272
  }
11490
12273
  }
12274
+ if (needsRestoreView) {
12275
+ addSaveRestoreViewOperationToListener(view, op);
12276
+ }
12277
+ }
12278
+ }
12279
+ }
12280
+ function addSaveRestoreViewOperationToListener(view, op) {
12281
+ op.handlerOps.prepend([
12282
+ createVariableOp(view.tpl.allocateXrefId(), {
12283
+ kind: SemanticVariableKind.Context,
12284
+ name: null,
12285
+ view: view.xref,
12286
+ }, new RestoreViewExpr(view.xref)),
12287
+ ]);
12288
+ // The "restore view" operation in listeners requires a call to `resetView` to reset the
12289
+ // context prior to returning from the listener operation. Find any `return` statements in
12290
+ // the listener body and wrap them in a call to reset the view.
12291
+ for (const handlerOp of op.handlerOps) {
12292
+ if (handlerOp.kind === OpKind.Statement &&
12293
+ handlerOp.statement instanceof ReturnStatement) {
12294
+ handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
11491
12295
  }
11492
12296
  }
11493
12297
  }
@@ -11569,6 +12373,50 @@ function phaseSlotAllocation(cpl) {
11569
12373
  }
11570
12374
  }
11571
12375
 
12376
+ /**
12377
+ * Find all assignments and usages of temporary variables, which are linked to each other with cross
12378
+ * references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
12379
+ * them at the beginning of the update block.
12380
+ *
12381
+ * TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
12382
+ * in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
12383
+ * Implement an algorithm for reuse.
12384
+ */
12385
+ function phaseTemporaryVariables(cpl) {
12386
+ for (const view of cpl.views.values()) {
12387
+ let opCount = 0;
12388
+ let generatedStatements = [];
12389
+ for (const op of view.ops()) {
12390
+ let count = 0;
12391
+ let xrefs = new Set();
12392
+ let defs = new Map();
12393
+ visitExpressionsInOp(op, expr => {
12394
+ if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12395
+ xrefs.add(expr.xref);
12396
+ }
12397
+ });
12398
+ for (const xref of xrefs) {
12399
+ // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`. It seems
12400
+ // to rely on an expression index instead of an op index.
12401
+ defs.set(xref, `tmp_${opCount}_${count++}`);
12402
+ }
12403
+ visitExpressionsInOp(op, expr => {
12404
+ if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12405
+ const name = defs.get(expr.xref);
12406
+ if (name === undefined) {
12407
+ throw new Error('Found xref with unassigned name');
12408
+ }
12409
+ expr.name = name;
12410
+ }
12411
+ });
12412
+ generatedStatements.push(...Array.from(defs.values())
12413
+ .map(name => createStatementOp(new DeclareVarStmt(name))));
12414
+ opCount++;
12415
+ }
12416
+ view.update.prepend(generatedStatements);
12417
+ }
12418
+ }
12419
+
11572
12420
  /**
11573
12421
  * Optimize variables declared and used in the IR.
11574
12422
  *
@@ -11932,89 +12780,12 @@ function allowConservativeInlining(decl, target) {
11932
12780
  }
11933
12781
  }
11934
12782
 
11935
- /**
11936
- * Finds all unresolved safe read expressions, and converts them into the appropriate output AST
11937
- * reads, guarded by null checks.
11938
- */
11939
- function phaseExpandSafeReads(cpl) {
11940
- for (const [_, view] of cpl.views) {
11941
- for (const op of view.ops()) {
11942
- transformExpressionsInOp(op, safeTransform, VisitorContextFlag.None);
11943
- transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
11944
- }
11945
- }
11946
- }
11947
- function isSafeAccessExpression(e) {
11948
- return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
11949
- }
11950
- function isUnsafeAccessExpression(e) {
11951
- return e instanceof ReadPropExpr || e instanceof ReadKeyExpr;
11952
- }
11953
- function isAccessExpression(e) {
11954
- return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
11955
- }
11956
- function deepestSafeTernary(e) {
11957
- if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
11958
- let st = e.receiver;
11959
- while (st.expr instanceof SafeTernaryExpr) {
11960
- st = st.expr;
11961
- }
11962
- return st;
11963
- }
11964
- return null;
11965
- }
11966
- // TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
11967
- // instead.
11968
- function safeTransform(e) {
11969
- if (e instanceof SafeInvokeFunctionExpr) {
11970
- // TODO: Implement safe function calls in a subsequent commit.
11971
- return new InvokeFunctionExpr(e.receiver, e.args);
11972
- }
11973
- if (!isAccessExpression(e)) {
11974
- return e;
11975
- }
11976
- const dst = deepestSafeTernary(e);
11977
- if (dst) {
11978
- if (e instanceof ReadPropExpr) {
11979
- dst.expr = dst.expr.prop(e.name);
11980
- return e.receiver;
11981
- }
11982
- if (e instanceof ReadKeyExpr) {
11983
- dst.expr = dst.expr.key(e.index);
11984
- return e.receiver;
11985
- }
11986
- if (e instanceof SafePropertyReadExpr) {
11987
- dst.expr = new SafeTernaryExpr(dst.expr.clone(), dst.expr.prop(e.name));
11988
- return e.receiver;
11989
- }
11990
- if (e instanceof SafeKeyedReadExpr) {
11991
- dst.expr = new SafeTernaryExpr(dst.expr.clone(), dst.expr.key(e.index));
11992
- return e.receiver;
11993
- }
11994
- }
11995
- else {
11996
- if (e instanceof SafePropertyReadExpr) {
11997
- return new SafeTernaryExpr(e.receiver.clone(), e.receiver.prop(e.name));
11998
- }
11999
- if (e instanceof SafeKeyedReadExpr) {
12000
- return new SafeTernaryExpr(e.receiver.clone(), e.receiver.key(e.index));
12001
- }
12002
- }
12003
- return e;
12004
- }
12005
- function ternaryTransform(e) {
12006
- if (!(e instanceof SafeTernaryExpr)) {
12007
- return e;
12008
- }
12009
- return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
12010
- }
12011
-
12012
12783
  /**
12013
12784
  * Run all transformation phases in the correct order against a `ComponentCompilation`. After this
12014
12785
  * processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
12015
12786
  */
12016
12787
  function transformTemplate(cpl) {
12017
- phaseAttributeExtraction(cpl, true);
12788
+ phaseAttributeExtraction(cpl, /* compatibility */ true);
12018
12789
  phasePipeCreation(cpl);
12019
12790
  phasePipeVariadic(cpl);
12020
12791
  phasePureLiteralStructures(cpl);
@@ -12025,17 +12796,19 @@ function transformTemplate(cpl) {
12025
12796
  phaseLocalRefs(cpl);
12026
12797
  phaseConstCollection(cpl);
12027
12798
  phaseNullishCoalescing(cpl);
12028
- phaseExpandSafeReads(cpl);
12799
+ phaseExpandSafeReads(cpl, true);
12800
+ phaseTemporaryVariables(cpl);
12029
12801
  phaseSlotAllocation(cpl);
12030
12802
  phaseVarCounting(cpl);
12031
12803
  phaseGenerateAdvance(cpl);
12032
- phaseNaming(cpl);
12804
+ phaseNaming(cpl, /* compatibility */ true);
12033
12805
  phaseVariableOptimization(cpl, { conservative: true });
12034
12806
  phaseMergeNextContext(cpl);
12035
12807
  phaseNgContainer(cpl);
12036
12808
  phaseEmptyElements(cpl);
12037
12809
  phasePureFunctionExtraction(cpl);
12038
12810
  phaseAlignPipeVariadicVarOffset(cpl);
12811
+ phasePropertyOrdering(cpl);
12039
12812
  phaseReify(cpl);
12040
12813
  phaseChaining(cpl);
12041
12814
  }
@@ -12422,6 +13195,9 @@ function ingestBindings(view, op, element) {
12422
13195
  }
12423
13196
  }
12424
13197
  for (const attr of element.attributes) {
13198
+ // This is only attribute TextLiteral bindings, such as `attr.foo="bar'`. This can never be
13199
+ // `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
13200
+ // `BindingType.Attribute`.
12425
13201
  view.update.push(createAttributeOp(op.xref, ElementAttributeKind.Attribute, attr.name, literal(attr.value)));
12426
13202
  }
12427
13203
  for (const input of element.inputs) {
@@ -12468,6 +13244,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12468
13244
  }
12469
13245
  view.update.push(createInterpolateStyleMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12470
13246
  }
13247
+ else if (name === 'class') {
13248
+ if (bindingKind !== ElementAttributeKind.Binding) {
13249
+ throw Error('Unexpected class binding on ng-template');
13250
+ }
13251
+ view.update.push(createInterpolateClassMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
13252
+ }
12471
13253
  else {
12472
13254
  view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12473
13255
  }
@@ -12478,8 +13260,18 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12478
13260
  }
12479
13261
  view.update.push(createInterpolateStylePropOp(xref, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)), unit));
12480
13262
  break;
13263
+ case 1 /* e.BindingType.Attribute */:
13264
+ if (bindingKind !== ElementAttributeKind.Binding) {
13265
+ throw new Error('Attribute bindings on templates are not expected to be valid');
13266
+ }
13267
+ const attributeInterpolate = createInterpolateAttributeOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)));
13268
+ view.update.push(attributeInterpolate);
13269
+ break;
13270
+ case 2 /* e.BindingType.Class */:
13271
+ throw Error('Unexpected interpolation in class property binding');
13272
+ // TODO: implement remaining binding types.
13273
+ case 4 /* e.BindingType.Animation */:
12481
13274
  default:
12482
- // TODO: implement remaining binding types.
12483
13275
  throw Error(`Interpolated property binding type not handled: ${type}`);
12484
13276
  }
12485
13277
  }
@@ -12493,6 +13285,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12493
13285
  }
12494
13286
  view.update.push(createStyleMapOp(xref, convertAst(value, view.tpl)));
12495
13287
  }
13288
+ else if (name === 'class') {
13289
+ if (bindingKind !== ElementAttributeKind.Binding) {
13290
+ throw Error('Unexpected class binding on ng-template');
13291
+ }
13292
+ view.update.push(createClassMapOp(xref, convertAst(value, view.tpl)));
13293
+ }
12496
13294
  else {
12497
13295
  view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
12498
13296
  }
@@ -12503,8 +13301,22 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12503
13301
  }
12504
13302
  view.update.push(createStylePropOp(xref, name, convertAst(value, view.tpl), unit));
12505
13303
  break;
13304
+ case 1 /* e.BindingType.Attribute */:
13305
+ if (bindingKind !== ElementAttributeKind.Binding) {
13306
+ throw new Error('Attribute bindings on templates are not expected to be valid');
13307
+ }
13308
+ const attrOp = createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
13309
+ view.update.push(attrOp);
13310
+ break;
13311
+ case 2 /* e.BindingType.Class */:
13312
+ if (bindingKind !== ElementAttributeKind.Binding) {
13313
+ throw Error('Unexpected class binding on ng-template');
13314
+ }
13315
+ view.update.push(createClassPropOp(xref, name, convertAst(value, view.tpl)));
13316
+ break;
13317
+ // TODO: implement remaining binding types.
13318
+ case 4 /* e.BindingType.Animation */:
12506
13319
  default:
12507
- // TODO: implement remaining binding types.
12508
13320
  throw Error(`Property binding type not handled: ${type}`);
12509
13321
  }
12510
13322
  }
@@ -12533,85 +13345,6 @@ function assertIsArray(value) {
12533
13345
 
12534
13346
  const USE_TEMPLATE_PIPELINE = false;
12535
13347
 
12536
- /**
12537
- * Parses string representation of a style and converts it into object literal.
12538
- *
12539
- * @param value string representation of style as used in the `style` attribute in HTML.
12540
- * Example: `color: red; height: auto`.
12541
- * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
12542
- * 'auto']`
12543
- */
12544
- function parse(value) {
12545
- // we use a string array here instead of a string map
12546
- // because a string-map is not guaranteed to retain the
12547
- // order of the entries whereas a string array can be
12548
- // constructed in a [key, value, key, value] format.
12549
- const styles = [];
12550
- let i = 0;
12551
- let parenDepth = 0;
12552
- let quote = 0 /* Char.QuoteNone */;
12553
- let valueStart = 0;
12554
- let propStart = 0;
12555
- let currentProp = null;
12556
- while (i < value.length) {
12557
- const token = value.charCodeAt(i++);
12558
- switch (token) {
12559
- case 40 /* Char.OpenParen */:
12560
- parenDepth++;
12561
- break;
12562
- case 41 /* Char.CloseParen */:
12563
- parenDepth--;
12564
- break;
12565
- case 39 /* Char.QuoteSingle */:
12566
- // valueStart needs to be there since prop values don't
12567
- // have quotes in CSS
12568
- if (quote === 0 /* Char.QuoteNone */) {
12569
- quote = 39 /* Char.QuoteSingle */;
12570
- }
12571
- else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
12572
- quote = 0 /* Char.QuoteNone */;
12573
- }
12574
- break;
12575
- case 34 /* Char.QuoteDouble */:
12576
- // same logic as above
12577
- if (quote === 0 /* Char.QuoteNone */) {
12578
- quote = 34 /* Char.QuoteDouble */;
12579
- }
12580
- else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
12581
- quote = 0 /* Char.QuoteNone */;
12582
- }
12583
- break;
12584
- case 58 /* Char.Colon */:
12585
- if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
12586
- currentProp = hyphenate(value.substring(propStart, i - 1).trim());
12587
- valueStart = i;
12588
- }
12589
- break;
12590
- case 59 /* Char.Semicolon */:
12591
- if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
12592
- const styleVal = value.substring(valueStart, i - 1).trim();
12593
- styles.push(currentProp, styleVal);
12594
- propStart = i;
12595
- valueStart = 0;
12596
- currentProp = null;
12597
- }
12598
- break;
12599
- }
12600
- }
12601
- if (currentProp && valueStart) {
12602
- const styleVal = value.slice(valueStart).trim();
12603
- styles.push(currentProp, styleVal);
12604
- }
12605
- return styles;
12606
- }
12607
- function hyphenate(value) {
12608
- return value
12609
- .replace(/[a-z][A-Z]/g, v => {
12610
- return v.charAt(0) + '-' + v.charAt(1);
12611
- })
12612
- .toLowerCase();
12613
- }
12614
-
12615
13348
  const IMPORTANT_FLAG = '!important';
12616
13349
  /**
12617
13350
  * Minimum amount of binding slots required in the runtime for style/class bindings.
@@ -14826,29 +15559,62 @@ class Attribute extends NodeWithI18n {
14826
15559
  this.valueTokens = valueTokens;
14827
15560
  }
14828
15561
  visit(visitor, context) {
14829
- return visitor.visitAttribute(this, context);
15562
+ return visitor.visitAttribute(this, context);
15563
+ }
15564
+ }
15565
+ class Element extends NodeWithI18n {
15566
+ constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
15567
+ super(sourceSpan, i18n);
15568
+ this.name = name;
15569
+ this.attrs = attrs;
15570
+ this.children = children;
15571
+ this.startSourceSpan = startSourceSpan;
15572
+ this.endSourceSpan = endSourceSpan;
15573
+ }
15574
+ visit(visitor, context) {
15575
+ return visitor.visitElement(this, context);
15576
+ }
15577
+ }
15578
+ class Comment {
15579
+ constructor(value, sourceSpan) {
15580
+ this.value = value;
15581
+ this.sourceSpan = sourceSpan;
15582
+ }
15583
+ visit(visitor, context) {
15584
+ return visitor.visitComment(this, context);
15585
+ }
15586
+ }
15587
+ class BlockGroup {
15588
+ constructor(blocks, sourceSpan, startSourceSpan, endSourceSpan = null) {
15589
+ this.blocks = blocks;
15590
+ this.sourceSpan = sourceSpan;
15591
+ this.startSourceSpan = startSourceSpan;
15592
+ this.endSourceSpan = endSourceSpan;
15593
+ }
15594
+ visit(visitor, context) {
15595
+ return visitor.visitBlockGroup(this, context);
14830
15596
  }
14831
15597
  }
14832
- class Element extends NodeWithI18n {
14833
- constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
14834
- super(sourceSpan, i18n);
15598
+ class Block {
15599
+ constructor(name, parameters, children, sourceSpan, startSourceSpan, endSourceSpan = null) {
14835
15600
  this.name = name;
14836
- this.attrs = attrs;
15601
+ this.parameters = parameters;
14837
15602
  this.children = children;
15603
+ this.sourceSpan = sourceSpan;
14838
15604
  this.startSourceSpan = startSourceSpan;
14839
15605
  this.endSourceSpan = endSourceSpan;
14840
15606
  }
14841
15607
  visit(visitor, context) {
14842
- return visitor.visitElement(this, context);
15608
+ return visitor.visitBlock(this, context);
14843
15609
  }
14844
15610
  }
14845
- class Comment {
14846
- constructor(value, sourceSpan) {
14847
- this.value = value;
15611
+ class BlockParameter {
15612
+ constructor(expression, sourceSpan) {
15613
+ this.expression = expression;
14848
15614
  this.sourceSpan = sourceSpan;
14849
15615
  }
14850
15616
  visit(visitor, context) {
14851
- return visitor.visitComment(this, context);
15617
+ return visitor.visitBlockParameter(this, context);
14852
15618
  }
14853
15619
  }
14854
15620
  function visitAll(visitor, nodes, context = null) {
@@ -14881,6 +15647,18 @@ class RecursiveVisitor {
14881
15647
  });
14882
15648
  }
14883
15649
  visitExpansionCase(ast, context) { }
15650
+ visitBlockGroup(ast, context) {
15651
+ this.visitChildren(context, visit => {
15652
+ visit(ast.blocks);
15653
+ });
15654
+ }
15655
+ visitBlock(block, context) {
15656
+ this.visitChildren(context, visit => {
15657
+ visit(block.parameters);
15658
+ visit(block.children);
15659
+ });
15660
+ }
15661
+ visitBlockParameter(ast, context) { }
14884
15662
  visitChildren(context, cb) {
14885
15663
  let results = [];
14886
15664
  let t = this;
@@ -17633,8 +18411,8 @@ class _Tokenizer {
17633
18411
  this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
17634
18412
  new PlainCharacterCursor(_file, range);
17635
18413
  this._preserveLineEndings = options.preserveLineEndings || false;
17636
- this._escapedString = options.escapedString || false;
17637
18414
  this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
18415
+ this._tokenizeBlocks = options.tokenizeBlocks || false;
17638
18416
  try {
17639
18417
  this._cursor.init();
17640
18418
  }
@@ -17675,6 +18453,15 @@ class _Tokenizer {
17675
18453
  this._consumeTagOpen(start);
17676
18454
  }
17677
18455
  }
18456
+ else if (this._tokenizeBlocks && this._attemptStr('{#')) {
18457
+ this._consumeBlockGroupOpen(start);
18458
+ }
18459
+ else if (this._tokenizeBlocks && this._attemptStr('{/')) {
18460
+ this._consumeBlockGroupClose(start);
18461
+ }
18462
+ else if (this._tokenizeBlocks && this._attemptStr('{:')) {
18463
+ this._consumeBlock(start);
18464
+ }
17678
18465
  else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
17679
18466
  // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while
17680
18467
  // the premature end of an interpolation is given by the start of a new HTML element.
@@ -17688,6 +18475,64 @@ class _Tokenizer {
17688
18475
  this._beginToken(24 /* TokenType.EOF */);
17689
18476
  this._endToken([]);
17690
18477
  }
18478
+ _consumeBlockGroupOpen(start) {
18479
+ this._beginToken(25 /* TokenType.BLOCK_GROUP_OPEN_START */, start);
18480
+ const nameCursor = this._cursor.clone();
18481
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18482
+ this._endToken([this._cursor.getChars(nameCursor)]);
18483
+ this._consumeBlockParameters();
18484
+ this._beginToken(26 /* TokenType.BLOCK_GROUP_OPEN_END */);
18485
+ this._requireCharCode($RBRACE);
18486
+ this._endToken([]);
18487
+ }
18488
+ _consumeBlockGroupClose(start) {
18489
+ this._beginToken(27 /* TokenType.BLOCK_GROUP_CLOSE */, start);
18490
+ const nameCursor = this._cursor.clone();
18491
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18492
+ const name = this._cursor.getChars(nameCursor);
18493
+ this._requireCharCode($RBRACE);
18494
+ this._endToken([name]);
18495
+ }
18496
+ _consumeBlock(start) {
18497
+ this._beginToken(29 /* TokenType.BLOCK_OPEN_START */, start);
18498
+ const nameCursor = this._cursor.clone();
18499
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18500
+ this._endToken([this._cursor.getChars(nameCursor)]);
18501
+ this._consumeBlockParameters();
18502
+ this._beginToken(30 /* TokenType.BLOCK_OPEN_END */);
18503
+ this._requireCharCode($RBRACE);
18504
+ this._endToken([]);
18505
+ }
18506
+ _consumeBlockParameters() {
18507
+ // Trim the whitespace until the first parameter.
18508
+ this._attemptCharCodeUntilFn(isBlockParameterChar);
18509
+ while (this._cursor.peek() !== $RBRACE && this._cursor.peek() !== $EOF) {
18510
+ this._beginToken(28 /* TokenType.BLOCK_PARAMETER */);
18511
+ const start = this._cursor.clone();
18512
+ let inQuote = null;
18513
+ // Consume the parameter until the next semicolon or brace.
18514
+ // Note that we skip over semicolons/braces inside of strings.
18515
+ while ((this._cursor.peek() !== $SEMICOLON && this._cursor.peek() !== $RBRACE &&
18516
+ this._cursor.peek() !== $EOF) ||
18517
+ inQuote !== null) {
18518
+ const char = this._cursor.peek();
18519
+ // Skip to the next character if it was escaped.
18520
+ if (char === $BACKSLASH) {
18521
+ this._cursor.advance();
18522
+ }
18523
+ else if (char === inQuote) {
18524
+ inQuote = null;
18525
+ }
18526
+ else if (inQuote === null && isQuote(char)) {
18527
+ inQuote = char;
18528
+ }
18529
+ this._cursor.advance();
18530
+ }
18531
+ this._endToken([this._cursor.getChars(start)]);
18532
+ // Skip to the next parameter.
18533
+ this._attemptCharCodeUntilFn(isBlockParameterChar);
18534
+ }
18535
+ }
17691
18536
  /**
17692
18537
  * @returns whether an ICU token has been created
17693
18538
  * @internal
@@ -18021,7 +18866,6 @@ class _Tokenizer {
18021
18866
  this._endToken(prefixAndName);
18022
18867
  }
18023
18868
  _consumeAttributeValue() {
18024
- let value;
18025
18869
  if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
18026
18870
  const quoteChar = this._cursor.peek();
18027
18871
  this._consumeQuote(quoteChar);
@@ -18210,7 +19054,7 @@ class _Tokenizer {
18210
19054
  return this._processCarriageReturns(end.getChars(start));
18211
19055
  }
18212
19056
  _isTextEnd() {
18213
- if (this._isTagStart() || this._cursor.peek() === $EOF) {
19057
+ if (this._isTagStart() || this._isBlockStart() || this._cursor.peek() === $EOF) {
18214
19058
  return true;
18215
19059
  }
18216
19060
  if (this._tokenizeIcu && !this._inInterpolation) {
@@ -18243,6 +19087,23 @@ class _Tokenizer {
18243
19087
  }
18244
19088
  return false;
18245
19089
  }
19090
+ _isBlockStart() {
19091
+ if (this._tokenizeBlocks && this._cursor.peek() === $LBRACE) {
19092
+ const tmp = this._cursor.clone();
19093
+ // Check that the cursor is on a `{#`, `{/` or `{:`.
19094
+ tmp.advance();
19095
+ const next = tmp.peek();
19096
+ if (next !== $BANG && next !== $SLASH && next !== $COLON) {
19097
+ return false;
19098
+ }
19099
+ // If it is, also verify that the next character is a valid block identifier.
19100
+ tmp.advance();
19101
+ if (isBlockNameChar(tmp.peek())) {
19102
+ return true;
19103
+ }
19104
+ }
19105
+ return false;
19106
+ }
18246
19107
  _readUntil(char) {
18247
19108
  const start = this._cursor.clone();
18248
19109
  this._attemptUntilChar(char);
@@ -18298,6 +19159,12 @@ function compareCharCodeCaseInsensitive(code1, code2) {
18298
19159
  function toUpperCaseCharCode(code) {
18299
19160
  return code >= $a && code <= $z ? code - $a + $A : code;
18300
19161
  }
19162
+ function isBlockNameChar(code) {
19163
+ return isAsciiLetter(code) || isDigit(code) || code === $_;
19164
+ }
19165
+ function isBlockParameterChar(code) {
19166
+ return code !== $SEMICOLON && isNotWhitespace(code);
19167
+ }
18301
19168
  function mergeTextTokens(srcTokens) {
18302
19169
  const dstTokens = [];
18303
19170
  let lastDstToken = undefined;
@@ -18585,7 +19452,7 @@ class _TreeBuilder {
18585
19452
  this.tokens = tokens;
18586
19453
  this.getTagDefinition = getTagDefinition;
18587
19454
  this._index = -1;
18588
- this._elementStack = [];
19455
+ this._containerStack = [];
18589
19456
  this.rootNodes = [];
18590
19457
  this.errors = [];
18591
19458
  this._advance();
@@ -18615,6 +19482,18 @@ class _TreeBuilder {
18615
19482
  else if (this._peek.type === 19 /* TokenType.EXPANSION_FORM_START */) {
18616
19483
  this._consumeExpansion(this._advance());
18617
19484
  }
19485
+ else if (this._peek.type === 25 /* TokenType.BLOCK_GROUP_OPEN_START */) {
19486
+ this._closeVoidElement();
19487
+ this._consumeBlockGroupOpen(this._advance());
19488
+ }
19489
+ else if (this._peek.type === 29 /* TokenType.BLOCK_OPEN_START */) {
19490
+ this._closeVoidElement();
19491
+ this._consumeBlock(this._advance(), 30 /* TokenType.BLOCK_OPEN_END */);
19492
+ }
19493
+ else if (this._peek.type === 27 /* TokenType.BLOCK_GROUP_CLOSE */) {
19494
+ this._closeVoidElement();
19495
+ this._consumeBlockGroupClose(this._advance());
19496
+ }
18618
19497
  else {
18619
19498
  // Skip all other tokens...
18620
19499
  this._advance();
@@ -18731,7 +19610,12 @@ class _TreeBuilder {
18731
19610
  const startSpan = token.sourceSpan;
18732
19611
  let text = token.parts[0];
18733
19612
  if (text.length > 0 && text[0] === '\n') {
18734
- const parent = this._getParentElement();
19613
+ const parent = this._getContainer();
19614
+ // This is unlikely to happen, but we have an assertion just in case.
19615
+ if (parent instanceof BlockGroup) {
19616
+ this.errors.push(TreeError.create(null, startSpan, 'Text cannot be placed directly inside of a block group.'));
19617
+ return null;
19618
+ }
18735
19619
  if (parent != null && parent.children.length === 0 &&
18736
19620
  this.getTagDefinition(parent.name).ignoreFirstLf) {
18737
19621
  text = text.substring(1);
@@ -18762,9 +19646,9 @@ class _TreeBuilder {
18762
19646
  }
18763
19647
  }
18764
19648
  _closeVoidElement() {
18765
- const el = this._getParentElement();
18766
- if (el && this.getTagDefinition(el.name).isVoid) {
18767
- this._elementStack.pop();
19649
+ const el = this._getContainer();
19650
+ if (el instanceof Element && this.getTagDefinition(el.name).isVoid) {
19651
+ this._containerStack.pop();
18768
19652
  }
18769
19653
  }
18770
19654
  _consumeStartTag(startTagToken) {
@@ -18773,7 +19657,7 @@ class _TreeBuilder {
18773
19657
  while (this._peek.type === 14 /* TokenType.ATTR_NAME */) {
18774
19658
  attrs.push(this._consumeAttr(this._advance()));
18775
19659
  }
18776
- const fullName = this._getElementFullName(prefix, name, this._getParentElement());
19660
+ const fullName = this._getElementFullName(prefix, name, this._getClosestParentElement());
18777
19661
  let selfClosing = false;
18778
19662
  // Note: There could have been a tokenizer error
18779
19663
  // so that we don't get a token for the end tag...
@@ -18794,33 +19678,34 @@ class _TreeBuilder {
18794
19678
  // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
18795
19679
  const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
18796
19680
  const el = new Element(fullName, attrs, [], span, startSpan, undefined);
18797
- this._pushElement(el);
19681
+ const parentEl = this._getContainer();
19682
+ this._pushContainer(el, parentEl instanceof Element &&
19683
+ this.getTagDefinition(parentEl.name).isClosedByChild(el.name));
18798
19684
  if (selfClosing) {
18799
19685
  // Elements that are self-closed have their `endSourceSpan` set to the full span, as the
18800
19686
  // element start tag also represents the end tag.
18801
- this._popElement(fullName, span);
19687
+ this._popContainer(fullName, Element, span);
18802
19688
  }
18803
19689
  else if (startTagToken.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
18804
19690
  // We already know the opening tag is not complete, so it is unlikely it has a corresponding
18805
19691
  // close tag. Let's optimistically parse it as a full element and emit an error.
18806
- this._popElement(fullName, null);
19692
+ this._popContainer(fullName, Element, null);
18807
19693
  this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
18808
19694
  }
18809
19695
  }
18810
- _pushElement(el) {
18811
- const parentEl = this._getParentElement();
18812
- if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
18813
- this._elementStack.pop();
19696
+ _pushContainer(node, isClosedByChild) {
19697
+ if (isClosedByChild) {
19698
+ this._containerStack.pop();
18814
19699
  }
18815
- this._addToParent(el);
18816
- this._elementStack.push(el);
19700
+ this._addToParent(node);
19701
+ this._containerStack.push(node);
18817
19702
  }
18818
19703
  _consumeEndTag(endTagToken) {
18819
- const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
19704
+ const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getClosestParentElement());
18820
19705
  if (this.getTagDefinition(fullName).isVoid) {
18821
19706
  this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
18822
19707
  }
18823
- else if (!this._popElement(fullName, endTagToken.sourceSpan)) {
19708
+ else if (!this._popContainer(fullName, Element, endTagToken.sourceSpan)) {
18824
19709
  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`;
18825
19710
  this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
18826
19711
  }
@@ -18831,20 +19716,23 @@ class _TreeBuilder {
18831
19716
  * not have a closing tag (for example, this happens when an incomplete
18832
19717
  * opening tag is recovered).
18833
19718
  */
18834
- _popElement(fullName, endSourceSpan) {
19719
+ _popContainer(fullName, expectedType, endSourceSpan) {
18835
19720
  let unexpectedCloseTagDetected = false;
18836
- for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
18837
- const el = this._elementStack[stackIndex];
18838
- if (el.name === fullName) {
19721
+ for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) {
19722
+ const node = this._containerStack[stackIndex];
19723
+ const name = node instanceof BlockGroup ? node.blocks[0]?.name : node.name;
19724
+ if (name === fullName && node instanceof expectedType) {
18839
19725
  // Record the parse span with the element that is being closed. Any elements that are
18840
19726
  // removed from the element stack at this point are closed implicitly, so they won't get
18841
19727
  // an end source span (as there is no explicit closing element).
18842
- el.endSourceSpan = endSourceSpan;
18843
- el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end;
18844
- this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
19728
+ node.endSourceSpan = endSourceSpan;
19729
+ node.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : node.sourceSpan.end;
19730
+ this._containerStack.splice(stackIndex, this._containerStack.length - stackIndex);
18845
19731
  return !unexpectedCloseTagDetected;
18846
19732
  }
18847
- if (!this.getTagDefinition(el.name).closedByParent) {
19733
+ // Blocks are self-closing while block groups and (most times) elements are not.
19734
+ if (node instanceof BlockGroup ||
19735
+ node instanceof Element && !this.getTagDefinition(node.name).closedByParent) {
18848
19736
  // Note that we encountered an unexpected close tag but continue processing the element
18849
19737
  // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this
18850
19738
  // end tag in the stack.
@@ -18903,16 +19791,92 @@ class _TreeBuilder {
18903
19791
  new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
18904
19792
  return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
18905
19793
  }
18906
- _getParentElement() {
18907
- return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
19794
+ _consumeBlockGroupOpen(token) {
19795
+ const end = this._peek.sourceSpan.fullStart;
19796
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19797
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
19798
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19799
+ const blockGroup = new BlockGroup([], span, startSpan, null);
19800
+ this._pushContainer(blockGroup, false);
19801
+ const implicitBlock = this._consumeBlock(token, 26 /* TokenType.BLOCK_GROUP_OPEN_END */);
19802
+ // Block parameters are consumed as a part of the implicit block so we need to expand the
19803
+ // start source span once the block is parsed to include the full opening tag.
19804
+ startSpan.end = implicitBlock.startSourceSpan.end;
19805
+ }
19806
+ _consumeBlock(token, closeToken) {
19807
+ // The start of a block implicitly closes the previous block.
19808
+ this._conditionallyClosePreviousBlock();
19809
+ const parameters = [];
19810
+ while (this._peek.type === 28 /* TokenType.BLOCK_PARAMETER */) {
19811
+ const paramToken = this._advance();
19812
+ parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
19813
+ }
19814
+ if (this._peek.type === closeToken) {
19815
+ this._advance();
19816
+ }
19817
+ const end = this._peek.sourceSpan.fullStart;
19818
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19819
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
19820
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19821
+ const block = new Block(token.parts[0], parameters, [], span, startSpan);
19822
+ const parent = this._getContainer();
19823
+ if (!(parent instanceof BlockGroup)) {
19824
+ this.errors.push(TreeError.create(block.name, block.sourceSpan, 'Blocks can only be placed inside of block groups.'));
19825
+ }
19826
+ else {
19827
+ parent.blocks.push(block);
19828
+ this._containerStack.push(block);
19829
+ }
19830
+ return block;
19831
+ }
19832
+ _consumeBlockGroupClose(token) {
19833
+ const name = token.parts[0];
19834
+ const previousContainer = this._getContainer();
19835
+ // Blocks are implcitly closed by the block group.
19836
+ this._conditionallyClosePreviousBlock();
19837
+ if (!this._popContainer(name, BlockGroup, token.sourceSpan)) {
19838
+ const context = previousContainer instanceof Element ?
19839
+ `There is an unclosed "${previousContainer.name}" HTML tag named that may have to be closed first.` :
19840
+ `The block may have been closed earlier.`;
19841
+ this.errors.push(TreeError.create(name, token.sourceSpan, `Unexpected closing block "${name}". ${context}`));
19842
+ }
19843
+ }
19844
+ _conditionallyClosePreviousBlock() {
19845
+ const container = this._getContainer();
19846
+ if (container instanceof Block) {
19847
+ // Blocks don't have an explicit closing tag, they're closed either by the next block or
19848
+ // the end of the block group. Infer the end span from the last child node.
19849
+ const lastChild = container.children.length ? container.children[container.children.length - 1] : null;
19850
+ const endSpan = lastChild === null ?
19851
+ null :
19852
+ new ParseSourceSpan(lastChild.sourceSpan.end, lastChild.sourceSpan.end);
19853
+ this._popContainer(container.name, Block, endSpan);
19854
+ }
19855
+ }
19856
+ _getContainer() {
19857
+ return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
19858
+ null;
19859
+ }
19860
+ _getClosestParentElement() {
19861
+ for (let i = this._containerStack.length - 1; i > -1; i--) {
19862
+ if (this._containerStack[i] instanceof Element) {
19863
+ return this._containerStack[i];
19864
+ }
19865
+ }
19866
+ return null;
18908
19867
  }
18909
19868
  _addToParent(node) {
18910
- const parent = this._getParentElement();
18911
- if (parent != null) {
18912
- parent.children.push(node);
19869
+ const parent = this._getContainer();
19870
+ if (parent === null) {
19871
+ this.rootNodes.push(node);
19872
+ }
19873
+ else if (parent instanceof BlockGroup) {
19874
+ // Due to how parsing is set up, we're unlikely to hit this code path, but we
19875
+ // have the assertion here just in case and to satisfy the type checker.
19876
+ this.errors.push(TreeError.create(null, node.sourceSpan, 'Block groups can only contain blocks.'));
18913
19877
  }
18914
19878
  else {
18915
- this.rootNodes.push(node);
19879
+ parent.children.push(node);
18916
19880
  }
18917
19881
  }
18918
19882
  _getElementFullName(prefix, localName, parentElement) {
@@ -19026,6 +19990,15 @@ class WhitespaceVisitor {
19026
19990
  visitExpansionCase(expansionCase, context) {
19027
19991
  return expansionCase;
19028
19992
  }
19993
+ visitBlockGroup(group, context) {
19994
+ return new BlockGroup(visitAllWithSiblings(this, group.blocks), group.sourceSpan, group.startSourceSpan, group.endSourceSpan);
19995
+ }
19996
+ visitBlock(block, context) {
19997
+ return new Block(block.name, block.parameters, visitAllWithSiblings(this, block.children), block.sourceSpan, block.startSourceSpan);
19998
+ }
19999
+ visitBlockParameter(parameter, context) {
20000
+ return parameter;
20001
+ }
19029
20002
  }
19030
20003
  function createWhitespaceProcessedTextToken({ type, parts, sourceSpan }) {
19031
20004
  return { type, parts: [processWhitespace(parts[0])], sourceSpan };
@@ -19290,7 +20263,7 @@ class BindingParser {
19290
20263
  this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19291
20264
  }
19292
20265
  else {
19293
- this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
20266
+ this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19294
20267
  }
19295
20268
  }
19296
20269
  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
@@ -19312,11 +20285,11 @@ class BindingParser {
19312
20285
  // This will occur when a @trigger is not paired with an expression.
19313
20286
  // For animations it is valid to not have an expression since */void
19314
20287
  // states will be applied by angular when the element is attached/detached
19315
- const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
20288
+ const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
19316
20289
  targetMatchableAttrs.push([name, ast.source]);
19317
20290
  targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
19318
20291
  }
19319
- _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
20292
+ parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
19320
20293
  const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
19321
20294
  try {
19322
20295
  const ast = isHostBinding ?
@@ -19593,6 +20566,415 @@ function normalizeNgContentSelect(selectAttr) {
19593
20566
  return selectAttr;
19594
20567
  }
19595
20568
 
20569
+ /** Pattern for a timing value in a trigger. */
20570
+ const TIME_PATTERN = /^\d+(ms|s)?$/;
20571
+ /** Pattern for a separator between keywords in a trigger expression. */
20572
+ const SEPARATOR_PATTERN = /^\s$/;
20573
+ /** Pairs of characters that form syntax that is comma-delimited. */
20574
+ const COMMA_DELIMITED_SYNTAX = new Map([
20575
+ [$LBRACE, $RBRACE],
20576
+ [$LBRACKET, $RBRACKET],
20577
+ [$LPAREN, $RPAREN], // Function calls
20578
+ ]);
20579
+ /** Possible types of `on` triggers. */
20580
+ var OnTriggerType;
20581
+ (function (OnTriggerType) {
20582
+ OnTriggerType["IDLE"] = "idle";
20583
+ OnTriggerType["TIMER"] = "timer";
20584
+ OnTriggerType["INTERACTION"] = "interaction";
20585
+ OnTriggerType["IMMEDIATE"] = "immediate";
20586
+ OnTriggerType["HOVER"] = "hover";
20587
+ OnTriggerType["VIEWPORT"] = "viewport";
20588
+ })(OnTriggerType || (OnTriggerType = {}));
20589
+ /** Parses a `when` deferred trigger. */
20590
+ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
20591
+ const whenIndex = expression.indexOf('when');
20592
+ // This is here just to be safe, we shouldn't enter this function
20593
+ // in the first place if a block doesn't have the "when" keyword.
20594
+ if (whenIndex === -1) {
20595
+ errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
20596
+ return null;
20597
+ }
20598
+ const start = getTriggerParametersStart(expression, whenIndex + 1);
20599
+ const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
20600
+ return new BoundDeferredTrigger(parsed, sourceSpan);
20601
+ }
20602
+ /** Parses an `on` trigger */
20603
+ function parseOnTrigger({ expression, sourceSpan }, errors) {
20604
+ const onIndex = expression.indexOf('on');
20605
+ // This is here just to be safe, we shouldn't enter this function
20606
+ // in the first place if a block doesn't have the "on" keyword.
20607
+ if (onIndex === -1) {
20608
+ errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
20609
+ return [];
20610
+ }
20611
+ const start = getTriggerParametersStart(expression, onIndex + 1);
20612
+ return new OnTriggerParser(expression, start, sourceSpan, errors).parse();
20613
+ }
20614
+ class OnTriggerParser {
20615
+ constructor(expression, start, span, errors) {
20616
+ this.expression = expression;
20617
+ this.start = start;
20618
+ this.span = span;
20619
+ this.errors = errors;
20620
+ this.index = 0;
20621
+ this.triggers = [];
20622
+ this.tokens = new Lexer().tokenize(expression.slice(start));
20623
+ }
20624
+ parse() {
20625
+ while (this.tokens.length > 0 && this.index < this.tokens.length) {
20626
+ const token = this.token();
20627
+ if (!token.isIdentifier()) {
20628
+ this.unexpectedToken(token);
20629
+ break;
20630
+ }
20631
+ // An identifier immediately followed by a comma or the end of
20632
+ // the expression cannot have parameters so we can exit early.
20633
+ if (this.isFollowedByOrLast($COMMA)) {
20634
+ this.consumeTrigger(token, []);
20635
+ this.advance();
20636
+ }
20637
+ else if (this.isFollowedByOrLast($LPAREN)) {
20638
+ this.advance(); // Advance to the opening paren.
20639
+ const prevErrors = this.errors.length;
20640
+ const parameters = this.consumeParameters();
20641
+ if (this.errors.length !== prevErrors) {
20642
+ break;
20643
+ }
20644
+ this.consumeTrigger(token, parameters);
20645
+ this.advance(); // Advance past the closing paren.
20646
+ }
20647
+ else if (this.index < this.tokens.length - 1) {
20648
+ this.unexpectedToken(this.tokens[this.index + 1]);
20649
+ }
20650
+ this.advance();
20651
+ }
20652
+ return this.triggers;
20653
+ }
20654
+ advance() {
20655
+ this.index++;
20656
+ }
20657
+ isFollowedByOrLast(char) {
20658
+ if (this.index === this.tokens.length - 1) {
20659
+ return true;
20660
+ }
20661
+ return this.tokens[this.index + 1].isCharacter(char);
20662
+ }
20663
+ token() {
20664
+ return this.tokens[Math.min(this.index, this.tokens.length - 1)];
20665
+ }
20666
+ consumeTrigger(identifier, parameters) {
20667
+ const startSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
20668
+ const endSpan = startSpan.moveBy(this.token().end - identifier.index);
20669
+ const sourceSpan = new ParseSourceSpan(startSpan, endSpan);
20670
+ try {
20671
+ switch (identifier.toString()) {
20672
+ case OnTriggerType.IDLE:
20673
+ this.triggers.push(createIdleTrigger(parameters, sourceSpan));
20674
+ break;
20675
+ case OnTriggerType.TIMER:
20676
+ this.triggers.push(createTimerTrigger(parameters, sourceSpan));
20677
+ break;
20678
+ case OnTriggerType.INTERACTION:
20679
+ this.triggers.push(createInteractionTrigger(parameters, sourceSpan));
20680
+ break;
20681
+ case OnTriggerType.IMMEDIATE:
20682
+ this.triggers.push(createImmediateTrigger(parameters, sourceSpan));
20683
+ break;
20684
+ case OnTriggerType.HOVER:
20685
+ this.triggers.push(createHoverTrigger(parameters, sourceSpan));
20686
+ break;
20687
+ case OnTriggerType.VIEWPORT:
20688
+ this.triggers.push(createViewportTrigger(parameters, sourceSpan));
20689
+ break;
20690
+ default:
20691
+ throw new Error(`Unrecognized trigger type "${identifier}"`);
20692
+ }
20693
+ }
20694
+ catch (e) {
20695
+ this.error(identifier, e.message);
20696
+ }
20697
+ }
20698
+ consumeParameters() {
20699
+ const parameters = [];
20700
+ if (!this.token().isCharacter($LPAREN)) {
20701
+ this.unexpectedToken(this.token());
20702
+ return parameters;
20703
+ }
20704
+ this.advance();
20705
+ const commaDelimStack = [];
20706
+ let current = '';
20707
+ while (this.index < this.tokens.length) {
20708
+ const token = this.token();
20709
+ // Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
20710
+ // Note that we don't need to account for strings here since the lexer already parsed them
20711
+ // into string tokens.
20712
+ if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
20713
+ if (current.length) {
20714
+ parameters.push(current);
20715
+ }
20716
+ break;
20717
+ }
20718
+ // In the `on` microsyntax "top-level" commas (e.g. ones outside of an parameters) separate
20719
+ // the different triggers (e.g. `on idle,timer(500)`). This is problematic, because the
20720
+ // function-like syntax also implies that multiple parameters can be passed into the
20721
+ // individual trigger (e.g. `on foo(a, b)`). To avoid tripping up the parser with commas that
20722
+ // are part of other sorts of syntax (object literals, arrays), we treat anything inside
20723
+ // a comma-delimited syntax block as plain text.
20724
+ if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
20725
+ commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
20726
+ }
20727
+ if (commaDelimStack.length > 0 &&
20728
+ token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
20729
+ commaDelimStack.pop();
20730
+ }
20731
+ // If we hit a comma outside of a comma-delimited syntax, it means
20732
+ // that we're at the top level and we're starting a new parameter.
20733
+ if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
20734
+ parameters.push(current);
20735
+ current = '';
20736
+ this.advance();
20737
+ continue;
20738
+ }
20739
+ // Otherwise treat the token as a plain text character in the current parameter.
20740
+ current += this.tokenText();
20741
+ this.advance();
20742
+ }
20743
+ if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
20744
+ this.error(this.token(), 'Unexpected end of expression');
20745
+ }
20746
+ if (this.index < this.tokens.length - 1 &&
20747
+ !this.tokens[this.index + 1].isCharacter($COMMA)) {
20748
+ this.unexpectedToken(this.tokens[this.index + 1]);
20749
+ }
20750
+ return parameters;
20751
+ }
20752
+ tokenText() {
20753
+ // Tokens have a toString already which we could use, but for string tokens it omits the quotes.
20754
+ // Eventually we could expose this information on the token directly.
20755
+ return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
20756
+ }
20757
+ error(token, message) {
20758
+ const newStart = this.span.start.moveBy(this.start + token.index);
20759
+ const newEnd = newStart.moveBy(token.end - token.index);
20760
+ this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
20761
+ }
20762
+ unexpectedToken(token) {
20763
+ this.error(token, `Unexpected token "${token}"`);
20764
+ }
20765
+ }
20766
+ function createIdleTrigger(parameters, sourceSpan) {
20767
+ if (parameters.length > 0) {
20768
+ throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
20769
+ }
20770
+ return new IdleDeferredTrigger(sourceSpan);
20771
+ }
20772
+ function createTimerTrigger(parameters, sourceSpan) {
20773
+ if (parameters.length !== 1) {
20774
+ throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
20775
+ }
20776
+ const delay = parseDeferredTime(parameters[0]);
20777
+ if (delay === null) {
20778
+ throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
20779
+ }
20780
+ return new TimerDeferredTrigger(delay, sourceSpan);
20781
+ }
20782
+ function createInteractionTrigger(parameters, sourceSpan) {
20783
+ if (parameters.length > 1) {
20784
+ throw new Error(`"${OnTriggerType.INTERACTION}" trigger can only have zero or one parameters`);
20785
+ }
20786
+ return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
20787
+ }
20788
+ function createImmediateTrigger(parameters, sourceSpan) {
20789
+ if (parameters.length > 0) {
20790
+ throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
20791
+ }
20792
+ return new ImmediateDeferredTrigger(sourceSpan);
20793
+ }
20794
+ function createHoverTrigger(parameters, sourceSpan) {
20795
+ if (parameters.length > 0) {
20796
+ throw new Error(`"${OnTriggerType.HOVER}" trigger cannot have parameters`);
20797
+ }
20798
+ return new HoverDeferredTrigger(sourceSpan);
20799
+ }
20800
+ function createViewportTrigger(parameters, sourceSpan) {
20801
+ // TODO: the RFC has some more potential parameters for `viewport`.
20802
+ if (parameters.length > 1) {
20803
+ throw new Error(`"${OnTriggerType.VIEWPORT}" trigger can only have zero or one parameters`);
20804
+ }
20805
+ return new ViewportDeferredTrigger(parameters[0] ?? null, sourceSpan);
20806
+ }
20807
+ /** Gets the index within an expression at which the trigger parameters start. */
20808
+ function getTriggerParametersStart(value, startPosition = 0) {
20809
+ let hasFoundSeparator = false;
20810
+ for (let i = startPosition; i < value.length; i++) {
20811
+ if (SEPARATOR_PATTERN.test(value[i])) {
20812
+ hasFoundSeparator = true;
20813
+ }
20814
+ else if (hasFoundSeparator) {
20815
+ return i;
20816
+ }
20817
+ }
20818
+ return -1;
20819
+ }
20820
+ /**
20821
+ * Parses a time expression from a deferred trigger to
20822
+ * milliseconds. Returns null if it cannot be parsed.
20823
+ */
20824
+ function parseDeferredTime(value) {
20825
+ const match = value.match(TIME_PATTERN);
20826
+ if (!match) {
20827
+ return null;
20828
+ }
20829
+ const [time, units] = match;
20830
+ return parseInt(time) * (units === 's' ? 1000 : 1);
20831
+ }
20832
+
20833
+ /** Pattern to identify a `prefetch when` trigger. */
20834
+ const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
20835
+ /** Pattern to identify a `prefetch on` trigger. */
20836
+ const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
20837
+ /** Pattern to identify a `minimum` parameter in a block. */
20838
+ const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
20839
+ /** Pattern to identify a `after` parameter in a block. */
20840
+ const AFTER_PARAMETER_PATTERN = /^after\s/;
20841
+ /** Pattern to identify a `when` parameter in a block. */
20842
+ const WHEN_PARAMETER_PATTERN = /^when\s/;
20843
+ /** Pattern to identify a `on` parameter in a block. */
20844
+ const ON_PARAMETER_PATTERN = /^on\s/;
20845
+ /** Possible types of secondary deferred blocks. */
20846
+ var SecondaryDeferredBlockType;
20847
+ (function (SecondaryDeferredBlockType) {
20848
+ SecondaryDeferredBlockType["PLACEHOLDER"] = "placeholder";
20849
+ SecondaryDeferredBlockType["LOADING"] = "loading";
20850
+ SecondaryDeferredBlockType["ERROR"] = "error";
20851
+ })(SecondaryDeferredBlockType || (SecondaryDeferredBlockType = {}));
20852
+ /** Creates a deferred block from an HTML AST node. */
20853
+ function createDeferredBlock(ast, visitor, bindingParser) {
20854
+ const errors = [];
20855
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
20856
+ const { triggers, prefetchTriggers } = parsePrimaryTriggers(primaryBlock.parameters, bindingParser, errors);
20857
+ const { placeholder, loading, error } = parseSecondaryBlocks(secondaryBlocks, errors, visitor);
20858
+ return {
20859
+ node: new DeferredBlock(visitAll(visitor, primaryBlock.children), triggers, prefetchTriggers, placeholder, loading, error, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
20860
+ errors,
20861
+ };
20862
+ }
20863
+ function parseSecondaryBlocks(blocks, errors, visitor) {
20864
+ let placeholder = null;
20865
+ let loading = null;
20866
+ let error = null;
20867
+ for (const block of blocks) {
20868
+ try {
20869
+ switch (block.name) {
20870
+ case SecondaryDeferredBlockType.PLACEHOLDER:
20871
+ if (placeholder !== null) {
20872
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.PLACEHOLDER}" block`));
20873
+ }
20874
+ else {
20875
+ placeholder = parsePlaceholderBlock(block, visitor);
20876
+ }
20877
+ break;
20878
+ case SecondaryDeferredBlockType.LOADING:
20879
+ if (loading !== null) {
20880
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.LOADING}" block`));
20881
+ }
20882
+ else {
20883
+ loading = parseLoadingBlock(block, visitor);
20884
+ }
20885
+ break;
20886
+ case SecondaryDeferredBlockType.ERROR:
20887
+ if (error !== null) {
20888
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.ERROR}" block`));
20889
+ }
20890
+ else {
20891
+ error = parseErrorBlock(block, visitor);
20892
+ }
20893
+ break;
20894
+ default:
20895
+ errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "${block.name}"`));
20896
+ break;
20897
+ }
20898
+ }
20899
+ catch (e) {
20900
+ errors.push(new ParseError(block.startSourceSpan, e.message));
20901
+ }
20902
+ }
20903
+ return { placeholder, loading, error };
20904
+ }
20905
+ function parsePlaceholderBlock(ast, visitor) {
20906
+ let minimumTime = null;
20907
+ for (const param of ast.parameters) {
20908
+ if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20909
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20910
+ if (parsedTime === null) {
20911
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20912
+ }
20913
+ minimumTime = parsedTime;
20914
+ }
20915
+ else {
20916
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.PLACEHOLDER}" block: "${param.expression}"`);
20917
+ }
20918
+ }
20919
+ return new DeferredBlockPlaceholder(visitAll(visitor, ast.children), minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20920
+ }
20921
+ function parseLoadingBlock(ast, visitor) {
20922
+ let afterTime = null;
20923
+ let minimumTime = null;
20924
+ for (const param of ast.parameters) {
20925
+ if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
20926
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20927
+ if (parsedTime === null) {
20928
+ throw new Error(`Could not parse time value of parameter "after"`);
20929
+ }
20930
+ afterTime = parsedTime;
20931
+ }
20932
+ else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20933
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20934
+ if (parsedTime === null) {
20935
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20936
+ }
20937
+ minimumTime = parsedTime;
20938
+ }
20939
+ else {
20940
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.LOADING}" block: "${param.expression}"`);
20941
+ }
20942
+ }
20943
+ return new DeferredBlockLoading(visitAll(visitor, ast.children), afterTime, minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20944
+ }
20945
+ function parseErrorBlock(ast, visitor) {
20946
+ if (ast.parameters.length > 0) {
20947
+ throw new Error(`"${SecondaryDeferredBlockType.ERROR}" block cannot have parameters`);
20948
+ }
20949
+ return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20950
+ }
20951
+ function parsePrimaryTriggers(params, bindingParser, errors) {
20952
+ const triggers = [];
20953
+ const prefetchTriggers = [];
20954
+ for (const param of params) {
20955
+ // The lexer ignores the leading spaces so we can assume
20956
+ // that the expression starts with a keyword.
20957
+ if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
20958
+ const result = parseWhenTrigger(param, bindingParser, errors);
20959
+ result !== null && triggers.push(result);
20960
+ }
20961
+ else if (ON_PARAMETER_PATTERN.test(param.expression)) {
20962
+ triggers.push(...parseOnTrigger(param, errors));
20963
+ }
20964
+ else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
20965
+ const result = parseWhenTrigger(param, bindingParser, errors);
20966
+ result !== null && prefetchTriggers.push(result);
20967
+ }
20968
+ else if (PREFETCH_ON_PATTERN.test(param.expression)) {
20969
+ prefetchTriggers.push(...parseOnTrigger(param, errors));
20970
+ }
20971
+ else {
20972
+ errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
20973
+ }
20974
+ }
20975
+ return { triggers, prefetchTriggers };
20976
+ }
20977
+
19596
20978
  const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
19597
20979
  // Group 1 = "bind-"
19598
20980
  const KW_BIND_IDX = 1;
@@ -19716,7 +21098,16 @@ class HtmlAstToIvyAst {
19716
21098
  attributes.push(this.visitAttribute(attribute));
19717
21099
  }
19718
21100
  }
19719
- const children = visitAll(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children);
21101
+ let children;
21102
+ if (preparsedElement.nonBindable) {
21103
+ // The `NonBindableVisitor` may need to return an array of nodes for block groups so we need
21104
+ // to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
21105
+ // a new array.
21106
+ children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
21107
+ }
21108
+ else {
21109
+ children = visitAll(this, element.children);
21110
+ }
19720
21111
  let parsedElement;
19721
21112
  if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
19722
21113
  // `<ng-content>`
@@ -19814,6 +21205,23 @@ class HtmlAstToIvyAst {
19814
21205
  }
19815
21206
  return null;
19816
21207
  }
21208
+ visitBlockGroup(group, context) {
21209
+ const primaryBlock = group.blocks[0];
21210
+ // The HTML parser ensures that we don't hit this case, but we have an assertion just in case.
21211
+ if (!primaryBlock) {
21212
+ this.reportError('Block group must have at least one block.', group.sourceSpan);
21213
+ return null;
21214
+ }
21215
+ if (primaryBlock.name === 'defer' && this.options.enabledBlockTypes.has(primaryBlock.name)) {
21216
+ const { node, errors } = createDeferredBlock(group, this, this.bindingParser);
21217
+ this.errors.push(...errors);
21218
+ return node;
21219
+ }
21220
+ this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
21221
+ return null;
21222
+ }
21223
+ visitBlock(block, context) { }
21224
+ visitBlockParameter(parameter, context) { }
19817
21225
  // convert view engine `ParsedProperty` to a format suitable for IVY
19818
21226
  extractAttributes(elementName, properties, i18nPropsMeta) {
19819
21227
  const bound = [];
@@ -19991,6 +21399,25 @@ class NonBindableVisitor {
19991
21399
  visitExpansionCase(expansionCase) {
19992
21400
  return null;
19993
21401
  }
21402
+ visitBlockGroup(group, context) {
21403
+ const nodes = visitAll(this, group.blocks);
21404
+ // We only need to do the end tag since the start will be added as a part of the primary block.
21405
+ if (group.endSourceSpan !== null) {
21406
+ nodes.push(new Text$3(group.endSourceSpan.toString(), group.endSourceSpan));
21407
+ }
21408
+ return nodes;
21409
+ }
21410
+ visitBlock(block, context) {
21411
+ return [
21412
+ // In an ngNonBindable context we treat the opening/closing tags of block as plain text.
21413
+ // This is the as if the `tokenizeBlocks` option was disabled.
21414
+ new Text$3(block.startSourceSpan.toString(), block.startSourceSpan),
21415
+ ...visitAll(this, block.children)
21416
+ ];
21417
+ }
21418
+ visitBlockParameter(parameter, context) {
21419
+ return null;
21420
+ }
19994
21421
  }
19995
21422
  const NON_BINDABLE_VISITOR = new NonBindableVisitor();
19996
21423
  function normalizeAttributeName(attrName) {
@@ -20438,6 +21865,17 @@ class _I18nVisitor {
20438
21865
  visitExpansionCase(_icuCase, _context) {
20439
21866
  throw new Error('Unreachable code');
20440
21867
  }
21868
+ visitBlockGroup(group, context) {
21869
+ const children = visitAll(this, group.blocks, context);
21870
+ const node = new Container(children, group.sourceSpan);
21871
+ return context.visitNodeFn(group, node);
21872
+ }
21873
+ visitBlock(block, context) {
21874
+ const children = visitAll(this, block.children, context);
21875
+ const node = new Container(children, block.sourceSpan);
21876
+ return context.visitNodeFn(block, node);
21877
+ }
21878
+ visitBlockParameter(_parameter, _context) { }
20441
21879
  /**
20442
21880
  * Convert, text and interpolated tokens up into text and placeholder pieces.
20443
21881
  *
@@ -20684,6 +22122,17 @@ class I18nMetaVisitor {
20684
22122
  visitExpansionCase(expansionCase) {
20685
22123
  return expansionCase;
20686
22124
  }
22125
+ visitBlockGroup(group, context) {
22126
+ visitAll(this, group.blocks, context);
22127
+ return group;
22128
+ }
22129
+ visitBlock(block, context) {
22130
+ visitAll(this, block.children, context);
22131
+ return block;
22132
+ }
22133
+ visitBlockParameter(parameter, context) {
22134
+ return parameter;
22135
+ }
20687
22136
  /**
20688
22137
  * Parse the general form `meta` passed into extract the explicit metadata needed to create a
20689
22138
  * `Message`.
@@ -21815,6 +23264,12 @@ class TemplateDefinitionBuilder {
21815
23264
  }
21816
23265
  return null;
21817
23266
  }
23267
+ // TODO: implement deferred block instructions.
23268
+ visitDeferredBlock(deferred) { }
23269
+ visitDeferredTrigger(trigger) { }
23270
+ visitDeferredBlockPlaceholder(block) { }
23271
+ visitDeferredBlockError(block) { }
23272
+ visitDeferredBlockLoading(block) { }
21818
23273
  allocateDataSlot() {
21819
23274
  return this._dataIndex++;
21820
23275
  }
@@ -22551,7 +24006,12 @@ function parseTemplate(template, templateUrl, options = {}) {
22551
24006
  const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
22552
24007
  const bindingParser = makeBindingParser(interpolationConfig);
22553
24008
  const htmlParser = new HtmlParser();
22554
- const parseResult = htmlParser.parse(template, templateUrl, { leadingTriviaChars: LEADING_TRIVIA_CHARS, ...options, tokenizeExpansionForms: true });
24009
+ const parseResult = htmlParser.parse(template, templateUrl, {
24010
+ leadingTriviaChars: LEADING_TRIVIA_CHARS,
24011
+ ...options,
24012
+ tokenizeExpansionForms: true,
24013
+ tokenizeBlocks: options.enabledBlockTypes != null && options.enabledBlockTypes.size > 0,
24014
+ });
22555
24015
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
22556
24016
  parseResult.errors.length > 0) {
22557
24017
  const parsedTemplate = {
@@ -22602,7 +24062,10 @@ function parseTemplate(template, templateUrl, options = {}) {
22602
24062
  rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
22603
24063
  }
22604
24064
  }
22605
- const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
24065
+ const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
24066
+ collectCommentNodes: !!options.collectCommentNodes,
24067
+ enabledBlockTypes: options.enabledBlockTypes || new Set(),
24068
+ });
22606
24069
  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
22607
24070
  const parsedTemplate = {
22608
24071
  interpolationConfig,
@@ -23556,6 +25019,7 @@ class CompilerFacadeImpl {
23556
25019
  }
23557
25020
  compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
23558
25021
  const meta = {
25022
+ kind: R3NgModuleMetadataKind.Global,
23559
25023
  type: wrapReference(facade.type),
23560
25024
  bootstrap: facade.bootstrap.map(wrapReference),
23561
25025
  declarations: facade.declarations.map(wrapReference),
@@ -23878,7 +25342,11 @@ function convertPipeDeclarationToMetadata(pipe) {
23878
25342
  function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
23879
25343
  const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
23880
25344
  // Parse the template and check for errors.
23881
- const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
25345
+ const parsed = parseTemplate(template, sourceMapUrl, {
25346
+ preserveWhitespaces,
25347
+ interpolationConfig,
25348
+ enabledBlockTypes: new Set(), // TODO: enable deferred blocks when testing in JIT mode.
25349
+ });
23882
25350
  if (parsed.errors !== null) {
23883
25351
  const errors = parsed.errors.map(err => err.toString()).join(', ');
23884
25352
  throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
@@ -24067,7 +25535,7 @@ function publishFacade(global) {
24067
25535
  * @description
24068
25536
  * Entry point for all public APIs of the compiler package.
24069
25537
  */
24070
- const VERSION = new Version('16.2.0-next.1');
25538
+ const VERSION = new Version('16.2.0-next.3');
24071
25539
 
24072
25540
  class CompilerConfig {
24073
25541
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -24288,6 +25756,13 @@ class _Visitor {
24288
25756
  visitAttribute(attribute, context) {
24289
25757
  throw new Error('unreachable code');
24290
25758
  }
25759
+ visitBlockGroup(group, context) {
25760
+ visitAll(this, group.blocks, context);
25761
+ }
25762
+ visitBlock(block, context) {
25763
+ visitAll(this, block.children, context);
25764
+ }
25765
+ visitBlockParameter(parameter, context) { }
24291
25766
  _init(mode, interpolationConfig) {
24292
25767
  this._mode = mode;
24293
25768
  this._inI18nBlock = false;
@@ -24500,8 +25975,9 @@ class XmlParser extends Parser {
24500
25975
  constructor() {
24501
25976
  super(getXmlTagDefinition);
24502
25977
  }
24503
- parse(source, url, options) {
24504
- return super.parse(source, url, options);
25978
+ parse(source, url, options = {}) {
25979
+ // Blocks aren't supported in an XML context.
25980
+ return super.parse(source, url, { ...options, tokenizeBlocks: false });
24505
25981
  }
24506
25982
  }
24507
25983
 
@@ -24685,6 +26161,9 @@ class XliffParser {
24685
26161
  visitComment(comment, context) { }
24686
26162
  visitExpansion(expansion, context) { }
24687
26163
  visitExpansionCase(expansionCase, context) { }
26164
+ visitBlockGroup(group, context) { }
26165
+ visitBlock(block, context) { }
26166
+ visitBlockParameter(parameter, context) { }
24688
26167
  _addError(node, message) {
24689
26168
  this._errors.push(new I18nError(node.sourceSpan, message));
24690
26169
  }
@@ -24735,6 +26214,9 @@ class XmlToI18n$2 {
24735
26214
  }
24736
26215
  visitComment(comment, context) { }
24737
26216
  visitAttribute(attribute, context) { }
26217
+ visitBlockGroup(group, context) { }
26218
+ visitBlock(block, context) { }
26219
+ visitBlockParameter(parameter, context) { }
24738
26220
  _addError(node, message) {
24739
26221
  this._errors.push(new I18nError(node.sourceSpan, message));
24740
26222
  }
@@ -24958,6 +26440,9 @@ class Xliff2Parser {
24958
26440
  visitComment(comment, context) { }
24959
26441
  visitExpansion(expansion, context) { }
24960
26442
  visitExpansionCase(expansionCase, context) { }
26443
+ visitBlockGroup(group, context) { }
26444
+ visitBlock(block, context) { }
26445
+ visitBlockParameter(parameter, context) { }
24961
26446
  _addError(node, message) {
24962
26447
  this._errors.push(new I18nError(node.sourceSpan, message));
24963
26448
  }
@@ -25025,6 +26510,9 @@ class XmlToI18n$1 {
25025
26510
  }
25026
26511
  visitComment(comment, context) { }
25027
26512
  visitAttribute(attribute, context) { }
26513
+ visitBlockGroup(group, context) { }
26514
+ visitBlock(block, context) { }
26515
+ visitBlockParameter(parameter, context) { }
25028
26516
  _addError(node, message) {
25029
26517
  this._errors.push(new I18nError(node.sourceSpan, message));
25030
26518
  }
@@ -25159,6 +26647,9 @@ class XtbParser {
25159
26647
  visitComment(comment, context) { }
25160
26648
  visitExpansion(expansion, context) { }
25161
26649
  visitExpansionCase(expansionCase, context) { }
26650
+ visitBlockGroup(group, context) { }
26651
+ visitBlock(block, context) { }
26652
+ visitBlockParameter(block, context) { }
25162
26653
  _addError(node, message) {
25163
26654
  this._errors.push(new I18nError(node.sourceSpan, message));
25164
26655
  }
@@ -25207,6 +26698,9 @@ class XmlToI18n {
25207
26698
  }
25208
26699
  visitComment(comment, context) { }
25209
26700
  visitAttribute(attribute, context) { }
26701
+ visitBlockGroup(group, context) { }
26702
+ visitBlock(block, context) { }
26703
+ visitBlockParameter(block, context) { }
25210
26704
  _addError(node, message) {
25211
26705
  this._errors.push(new I18nError(node.sourceSpan, message));
25212
26706
  }
@@ -25586,6 +27080,21 @@ class Scope {
25586
27080
  // Declare the variable if it's not already.
25587
27081
  this.maybeDeclare(reference);
25588
27082
  }
27083
+ visitDeferredBlock(deferred) {
27084
+ deferred.children.forEach(node => node.visit(this));
27085
+ deferred.placeholder?.visit(this);
27086
+ deferred.loading?.visit(this);
27087
+ deferred.error?.visit(this);
27088
+ }
27089
+ visitDeferredBlockPlaceholder(block) {
27090
+ block.children.forEach(node => node.visit(this));
27091
+ }
27092
+ visitDeferredBlockError(block) {
27093
+ block.children.forEach(node => node.visit(this));
27094
+ }
27095
+ visitDeferredBlockLoading(block) {
27096
+ block.children.forEach(node => node.visit(this));
27097
+ }
25589
27098
  // Unused visitors.
25590
27099
  visitContent(content) { }
25591
27100
  visitBoundAttribute(attr) { }
@@ -25594,6 +27103,7 @@ class Scope {
25594
27103
  visitText(text) { }
25595
27104
  visitTextAttribute(attr) { }
25596
27105
  visitIcu(icu) { }
27106
+ visitDeferredTrigger(trigger) { }
25597
27107
  maybeDeclare(thing) {
25598
27108
  // Declare something with a name, as long as that name isn't taken.
25599
27109
  if (!this.namedEntities.has(thing.name)) {
@@ -25731,6 +27241,21 @@ class DirectiveBinder {
25731
27241
  // Recurse into the node's children.
25732
27242
  node.children.forEach(child => child.visit(this));
25733
27243
  }
27244
+ visitDeferredBlock(deferred) {
27245
+ deferred.children.forEach(child => child.visit(this));
27246
+ deferred.placeholder?.visit(this);
27247
+ deferred.loading?.visit(this);
27248
+ deferred.error?.visit(this);
27249
+ }
27250
+ visitDeferredBlockPlaceholder(block) {
27251
+ block.children.forEach(child => child.visit(this));
27252
+ }
27253
+ visitDeferredBlockError(block) {
27254
+ block.children.forEach(child => child.visit(this));
27255
+ }
27256
+ visitDeferredBlockLoading(block) {
27257
+ block.children.forEach(child => child.visit(this));
27258
+ }
25734
27259
  // Unused visitors.
25735
27260
  visitContent(content) { }
25736
27261
  visitVariable(variable) { }
@@ -25742,6 +27267,7 @@ class DirectiveBinder {
25742
27267
  visitText(text) { }
25743
27268
  visitBoundText(text) { }
25744
27269
  visitIcu(icu) { }
27270
+ visitDeferredTrigger(trigger) { }
25745
27271
  }
25746
27272
  /**
25747
27273
  * Processes a template and extract metadata about expressions and symbols within.
@@ -25779,7 +27305,7 @@ class TemplateBinder extends RecursiveAstVisitor {
25779
27305
  /**
25780
27306
  * Process a template and extract metadata about expressions and symbols within.
25781
27307
  *
25782
- * @param template the nodes of the template to process
27308
+ * @param nodes the nodes of the template to process
25783
27309
  * @param scope the `Scope` of the template being processed.
25784
27310
  * @returns three maps which contain metadata about the template: `expressions` which interprets
25785
27311
  * special `AST` nodes in expressions as pointing to references or variables declared within the
@@ -25788,14 +27314,15 @@ class TemplateBinder extends RecursiveAstVisitor {
25788
27314
  * nesting level (how many levels deep within the template structure the `Template` is), starting
25789
27315
  * at 1.
25790
27316
  */
25791
- static applyWithScope(template, scope) {
27317
+ static applyWithScope(nodes, scope) {
25792
27318
  const expressions = new Map();
25793
27319
  const symbols = new Map();
25794
27320
  const nestingLevel = new Map();
25795
27321
  const usedPipes = new Set();
27322
+ const template = nodes instanceof Template ? nodes : null;
25796
27323
  // The top-level template has nesting level 0.
25797
- const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template instanceof Template ? template : null, 0);
25798
- binder.ingest(template);
27324
+ const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template, 0);
27325
+ binder.ingest(nodes);
25799
27326
  return { expressions, symbols, nestingLevel, usedPipes };
25800
27327
  }
25801
27328
  ingest(template) {
@@ -25857,6 +27384,28 @@ class TemplateBinder extends RecursiveAstVisitor {
25857
27384
  visitBoundEvent(event) {
25858
27385
  event.handler.visit(this);
25859
27386
  }
27387
+ visitDeferredBlock(deferred) {
27388
+ deferred.triggers.forEach(this.visitNode);
27389
+ deferred.prefetchTriggers.forEach(this.visitNode);
27390
+ deferred.children.forEach(this.visitNode);
27391
+ deferred.placeholder && this.visitNode(deferred.placeholder);
27392
+ deferred.loading && this.visitNode(deferred.loading);
27393
+ deferred.error && this.visitNode(deferred.error);
27394
+ }
27395
+ visitDeferredTrigger(trigger) {
27396
+ if (trigger instanceof BoundDeferredTrigger) {
27397
+ trigger.value.visit(this);
27398
+ }
27399
+ }
27400
+ visitDeferredBlockPlaceholder(block) {
27401
+ block.children.forEach(this.visitNode);
27402
+ }
27403
+ visitDeferredBlockError(block) {
27404
+ block.children.forEach(this.visitNode);
27405
+ }
27406
+ visitDeferredBlockLoading(block) {
27407
+ block.children.forEach(this.visitNode);
27408
+ }
25860
27409
  visitBoundText(text) {
25861
27410
  text.value.visit(this);
25862
27411
  }
@@ -25995,7 +27544,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
25995
27544
  function compileDeclareClassMetadata(metadata) {
25996
27545
  const definitionMap = new DefinitionMap();
25997
27546
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
25998
- definitionMap.set('version', literal('16.2.0-next.1'));
27547
+ definitionMap.set('version', literal('16.2.0-next.3'));
25999
27548
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26000
27549
  definitionMap.set('type', metadata.type);
26001
27550
  definitionMap.set('decorators', metadata.decorators);
@@ -26098,7 +27647,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
26098
27647
  function createDirectiveDefinitionMap(meta) {
26099
27648
  const definitionMap = new DefinitionMap();
26100
27649
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
26101
- definitionMap.set('version', literal('16.2.0-next.1'));
27650
+ definitionMap.set('version', literal('16.2.0-next.3'));
26102
27651
  // e.g. `type: MyDirective`
26103
27652
  definitionMap.set('type', meta.type.value);
26104
27653
  if (meta.isStandalone) {
@@ -26326,7 +27875,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
26326
27875
  function compileDeclareFactoryFunction(meta) {
26327
27876
  const definitionMap = new DefinitionMap();
26328
27877
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
26329
- definitionMap.set('version', literal('16.2.0-next.1'));
27878
+ definitionMap.set('version', literal('16.2.0-next.3'));
26330
27879
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26331
27880
  definitionMap.set('type', meta.type.value);
26332
27881
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -26361,7 +27910,7 @@ function compileDeclareInjectableFromMetadata(meta) {
26361
27910
  function createInjectableDefinitionMap(meta) {
26362
27911
  const definitionMap = new DefinitionMap();
26363
27912
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
26364
- definitionMap.set('version', literal('16.2.0-next.1'));
27913
+ definitionMap.set('version', literal('16.2.0-next.3'));
26365
27914
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26366
27915
  definitionMap.set('type', meta.type.value);
26367
27916
  // Only generate providedIn property if it has a non-null value
@@ -26412,7 +27961,7 @@ function compileDeclareInjectorFromMetadata(meta) {
26412
27961
  function createInjectorDefinitionMap(meta) {
26413
27962
  const definitionMap = new DefinitionMap();
26414
27963
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
26415
- definitionMap.set('version', literal('16.2.0-next.1'));
27964
+ definitionMap.set('version', literal('16.2.0-next.3'));
26416
27965
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26417
27966
  definitionMap.set('type', meta.type.value);
26418
27967
  definitionMap.set('providers', meta.providers);
@@ -26441,8 +27990,11 @@ function compileDeclareNgModuleFromMetadata(meta) {
26441
27990
  */
26442
27991
  function createNgModuleDefinitionMap(meta) {
26443
27992
  const definitionMap = new DefinitionMap();
27993
+ if (meta.kind === R3NgModuleMetadataKind.Local) {
27994
+ throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
27995
+ }
26444
27996
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
26445
- definitionMap.set('version', literal('16.2.0-next.1'));
27997
+ definitionMap.set('version', literal('16.2.0-next.3'));
26446
27998
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26447
27999
  definitionMap.set('type', meta.type.value);
26448
28000
  // We only generate the keys in the metadata if the arrays contain values.
@@ -26493,7 +28045,7 @@ function compileDeclarePipeFromMetadata(meta) {
26493
28045
  function createPipeDefinitionMap(meta) {
26494
28046
  const definitionMap = new DefinitionMap();
26495
28047
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
26496
- definitionMap.set('version', literal('16.2.0-next.1'));
28048
+ definitionMap.set('version', literal('16.2.0-next.3'));
26497
28049
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26498
28050
  // e.g. `type: MyPipe`
26499
28051
  definitionMap.set('type', meta.type.value);
@@ -26526,5 +28078,5 @@ publishFacade(_global);
26526
28078
 
26527
28079
  // This file is not used to build this module. It is only used during editing
26528
28080
 
26529
- 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$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, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element$1 as TmplAstElement, Icu$1 as TmplAstIcu, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
28081
+ export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
26530
28082
  //# sourceMappingURL=compiler.mjs.map