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