@angular/compiler 16.2.0-next.4 → 16.2.0-rc.0
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/expression_parser/parser.mjs +2 -1
- package/esm2022/src/jit_compiler_facade.mjs +15 -6
- package/esm2022/src/ml_parser/parser.mjs +6 -3
- package/esm2022/src/output/output_ast.mjs +2 -2
- 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 +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_identifiers.mjs +2 -1
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +24 -8
- package/esm2022/src/render3/view/t2_api.mjs +1 -1
- package/esm2022/src/render3/view/t2_binder.mjs +47 -13
- package/esm2022/src/render3/view/template.mjs +41 -5
- package/esm2022/src/template/pipeline/ir/index.mjs +2 -1
- package/esm2022/src/template/pipeline/ir/src/element.mjs +23 -19
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +59 -30
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +50 -21
- package/esm2022/src/template/pipeline/ir/src/operations.mjs +26 -10
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +64 -5
- package/esm2022/src/template/pipeline/ir/src/ops/host.mjs +21 -0
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +50 -88
- package/esm2022/src/template/pipeline/ir/src/traits.mjs +1 -1
- package/esm2022/src/template/pipeline/src/compilation.mjs +87 -48
- package/esm2022/src/template/pipeline/src/conversion.mjs +23 -1
- package/esm2022/src/template/pipeline/src/emit.mjs +105 -30
- package/esm2022/src/template/pipeline/src/ingest.mjs +92 -104
- package/esm2022/src/template/pipeline/src/instruction.mjs +86 -55
- package/esm2022/src/template/pipeline/src/phases/align_pipe_variadic_var_offset.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/any_cast.mjs +30 -0
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +60 -49
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +64 -0
- package/esm2022/src/template/pipeline/src/phases/chaining.mjs +9 -5
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/expand_safe_reads.mjs +18 -12
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +6 -6
- package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +64 -0
- package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/namespace.mjs +26 -0
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +32 -15
- package/esm2022/src/template/pipeline/src/phases/next_context_merging.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/no_listeners_on_templates.mjs +36 -0
- package/esm2022/src/template/pipeline/src/phases/nonbindable.mjs +47 -0
- package/esm2022/src/template/pipeline/src/phases/nullish_coalescing.mjs +5 -5
- package/esm2022/src/template/pipeline/src/phases/pipe_creation.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/pipe_variadic.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/property_ordering.mjs +30 -13
- package/esm2022/src/template/pipeline/src/phases/pure_function_extraction.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/pure_literal_structures.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +94 -57
- package/esm2022/src/template/pipeline/src/phases/remove_empty_bindings.mjs +28 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_contexts.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/resolve_dollar_event.mjs +33 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +13 -9
- package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +58 -0
- package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +1 -1
- package/esm2022/src/template/pipeline/src/phases/style_binding_specialization.mjs +42 -0
- package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +40 -20
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +33 -30
- package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +10 -9
- package/esm2022/src/template/pipeline/src/util/elements.mjs +22 -0
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1762 -943
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +60 -5
- 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-
|
|
2
|
+
* @license Angular v16.2.0-rc.0
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -1784,7 +1784,7 @@ class ReadKeyExpr extends Expression {
|
|
|
1784
1784
|
return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
|
|
1785
1785
|
}
|
|
1786
1786
|
clone() {
|
|
1787
|
-
return new ReadKeyExpr(this.receiver, this.index.clone(), this.type, this.sourceSpan);
|
|
1787
|
+
return new ReadKeyExpr(this.receiver.clone(), this.index.clone(), this.type, this.sourceSpan);
|
|
1788
1788
|
}
|
|
1789
1789
|
}
|
|
1790
1790
|
class LiteralArrayExpr extends Expression {
|
|
@@ -2613,6 +2613,7 @@ class Identifiers {
|
|
|
2613
2613
|
static { this.nextContext = { name: 'ɵɵnextContext', moduleName: CORE }; }
|
|
2614
2614
|
static { this.resetView = { name: 'ɵɵresetView', moduleName: CORE }; }
|
|
2615
2615
|
static { this.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE }; }
|
|
2616
|
+
static { this.defer = { name: 'ɵɵdefer', moduleName: CORE }; }
|
|
2616
2617
|
static { this.text = { name: 'ɵɵtext', moduleName: CORE }; }
|
|
2617
2618
|
static { this.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; }
|
|
2618
2619
|
static { this.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; }
|
|
@@ -6239,7 +6240,7 @@ class LiteralMap extends AST {
|
|
|
6239
6240
|
return visitor.visitLiteralMap(this, context);
|
|
6240
6241
|
}
|
|
6241
6242
|
}
|
|
6242
|
-
class Interpolation extends AST {
|
|
6243
|
+
class Interpolation$1 extends AST {
|
|
6243
6244
|
constructor(span, sourceSpan, strings, expressions) {
|
|
6244
6245
|
super(span, sourceSpan);
|
|
6245
6246
|
this.strings = strings;
|
|
@@ -6486,7 +6487,7 @@ class AstTransformer {
|
|
|
6486
6487
|
return ast;
|
|
6487
6488
|
}
|
|
6488
6489
|
visitInterpolation(ast, context) {
|
|
6489
|
-
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
|
|
6490
|
+
return new Interpolation$1(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
|
|
6490
6491
|
}
|
|
6491
6492
|
visitLiteralPrimitive(ast, context) {
|
|
6492
6493
|
return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value);
|
|
@@ -6569,7 +6570,7 @@ class AstMemoryEfficientTransformer {
|
|
|
6569
6570
|
visitInterpolation(ast, context) {
|
|
6570
6571
|
const expressions = this.visitAll(ast.expressions);
|
|
6571
6572
|
if (expressions !== ast.expressions)
|
|
6572
|
-
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions);
|
|
6573
|
+
return new Interpolation$1(ast.span, ast.sourceSpan, ast.strings, expressions);
|
|
6573
6574
|
return ast;
|
|
6574
6575
|
}
|
|
6575
6576
|
visitLiteralPrimitive(ast, context) {
|
|
@@ -8652,33 +8653,37 @@ function mergeNsAndName(prefix, localName) {
|
|
|
8652
8653
|
/**
|
|
8653
8654
|
* Enumeration of the types of attributes which can be applied to an element.
|
|
8654
8655
|
*/
|
|
8655
|
-
var
|
|
8656
|
-
(function (
|
|
8656
|
+
var BindingKind;
|
|
8657
|
+
(function (BindingKind) {
|
|
8657
8658
|
/**
|
|
8658
8659
|
* Static attributes.
|
|
8659
8660
|
*/
|
|
8660
|
-
|
|
8661
|
+
BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
|
|
8661
8662
|
/**
|
|
8662
8663
|
* Class bindings.
|
|
8663
8664
|
*/
|
|
8664
|
-
|
|
8665
|
+
BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
|
|
8665
8666
|
/**
|
|
8666
8667
|
* Style bindings.
|
|
8667
8668
|
*/
|
|
8668
|
-
|
|
8669
|
+
BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
|
|
8669
8670
|
/**
|
|
8670
|
-
* Dynamic property
|
|
8671
|
+
* Dynamic property bindings.
|
|
8671
8672
|
*/
|
|
8672
|
-
|
|
8673
|
+
BindingKind[BindingKind["Property"] = 3] = "Property";
|
|
8673
8674
|
/**
|
|
8674
|
-
*
|
|
8675
|
+
* Property or attribute bindings on a template.
|
|
8675
8676
|
*/
|
|
8676
|
-
|
|
8677
|
+
BindingKind[BindingKind["Template"] = 4] = "Template";
|
|
8677
8678
|
/**
|
|
8678
8679
|
* Internationalized attributes.
|
|
8679
8680
|
*/
|
|
8680
|
-
|
|
8681
|
-
|
|
8681
|
+
BindingKind[BindingKind["I18n"] = 5] = "I18n";
|
|
8682
|
+
/**
|
|
8683
|
+
* TODO: Consider how Animations are handled, and if they should be a distinct BindingKind.
|
|
8684
|
+
*/
|
|
8685
|
+
BindingKind[BindingKind["Animation"] = 6] = "Animation";
|
|
8686
|
+
})(BindingKind || (BindingKind = {}));
|
|
8682
8687
|
const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
8683
8688
|
/**
|
|
8684
8689
|
* Container for all of the various kinds of attributes which are applied on an element.
|
|
@@ -8690,22 +8695,22 @@ class ElementAttributes {
|
|
|
8690
8695
|
this.projectAs = null;
|
|
8691
8696
|
}
|
|
8692
8697
|
get attributes() {
|
|
8693
|
-
return this.byKind.get(
|
|
8698
|
+
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
8694
8699
|
}
|
|
8695
8700
|
get classes() {
|
|
8696
|
-
return this.byKind.get(
|
|
8701
|
+
return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
|
|
8697
8702
|
}
|
|
8698
8703
|
get styles() {
|
|
8699
|
-
return this.byKind.get(
|
|
8704
|
+
return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
|
|
8700
8705
|
}
|
|
8701
8706
|
get bindings() {
|
|
8702
|
-
return this.byKind.get(
|
|
8707
|
+
return this.byKind.get(BindingKind.Property) ?? FLYWEIGHT_ARRAY;
|
|
8703
8708
|
}
|
|
8704
8709
|
get template() {
|
|
8705
|
-
return this.byKind.get(
|
|
8710
|
+
return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
|
|
8706
8711
|
}
|
|
8707
8712
|
get i18n() {
|
|
8708
|
-
return this.byKind.get(
|
|
8713
|
+
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
8709
8714
|
}
|
|
8710
8715
|
add(kind, name, value) {
|
|
8711
8716
|
if (this.known.has(name)) {
|
|
@@ -8714,7 +8719,7 @@ class ElementAttributes {
|
|
|
8714
8719
|
this.known.add(name);
|
|
8715
8720
|
const array = this.arrayFor(kind);
|
|
8716
8721
|
array.push(...getAttributeNameLiterals$1(name));
|
|
8717
|
-
if (kind ===
|
|
8722
|
+
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
8718
8723
|
if (value === null) {
|
|
8719
8724
|
throw Error('Attribute & style element attributes must have a value');
|
|
8720
8725
|
}
|
|
@@ -8792,70 +8797,73 @@ var OpKind;
|
|
|
8792
8797
|
* An operation to end an `ng-container`.
|
|
8793
8798
|
*/
|
|
8794
8799
|
OpKind[OpKind["ContainerEnd"] = 9] = "ContainerEnd";
|
|
8800
|
+
/**
|
|
8801
|
+
* An operation disable binding for subsequent elements, which are descendants of a non-bindable
|
|
8802
|
+
* node.
|
|
8803
|
+
*/
|
|
8804
|
+
OpKind[OpKind["DisableBindings"] = 10] = "DisableBindings";
|
|
8805
|
+
/**
|
|
8806
|
+
* An operation to re-enable binding, after it was previously disabled.
|
|
8807
|
+
*/
|
|
8808
|
+
OpKind[OpKind["EnableBindings"] = 11] = "EnableBindings";
|
|
8795
8809
|
/**
|
|
8796
8810
|
* An operation to render a text node.
|
|
8797
8811
|
*/
|
|
8798
|
-
OpKind[OpKind["Text"] =
|
|
8812
|
+
OpKind[OpKind["Text"] = 12] = "Text";
|
|
8799
8813
|
/**
|
|
8800
8814
|
* An operation declaring an event listener for an element.
|
|
8801
8815
|
*/
|
|
8802
|
-
OpKind[OpKind["Listener"] =
|
|
8816
|
+
OpKind[OpKind["Listener"] = 13] = "Listener";
|
|
8803
8817
|
/**
|
|
8804
8818
|
* An operation to interpolate text into a text node.
|
|
8805
8819
|
*/
|
|
8806
|
-
OpKind[OpKind["InterpolateText"] =
|
|
8820
|
+
OpKind[OpKind["InterpolateText"] = 14] = "InterpolateText";
|
|
8821
|
+
/**
|
|
8822
|
+
* An intermediate binding op, that has not yet been processed into an individual property,
|
|
8823
|
+
* attribute, style, etc.
|
|
8824
|
+
*/
|
|
8825
|
+
OpKind[OpKind["Binding"] = 15] = "Binding";
|
|
8807
8826
|
/**
|
|
8808
8827
|
* An operation to bind an expression to a property of an element.
|
|
8809
8828
|
*/
|
|
8810
|
-
OpKind[OpKind["Property"] =
|
|
8829
|
+
OpKind[OpKind["Property"] = 16] = "Property";
|
|
8811
8830
|
/**
|
|
8812
8831
|
* An operation to bind an expression to a style property of an element.
|
|
8813
8832
|
*/
|
|
8814
|
-
OpKind[OpKind["StyleProp"] =
|
|
8833
|
+
OpKind[OpKind["StyleProp"] = 17] = "StyleProp";
|
|
8815
8834
|
/**
|
|
8816
8835
|
* An operation to bind an expression to a class property of an element.
|
|
8817
8836
|
*/
|
|
8818
|
-
OpKind[OpKind["ClassProp"] =
|
|
8837
|
+
OpKind[OpKind["ClassProp"] = 18] = "ClassProp";
|
|
8819
8838
|
/**
|
|
8820
8839
|
* An operation to bind an expression to the styles of an element.
|
|
8821
8840
|
*/
|
|
8822
|
-
OpKind[OpKind["StyleMap"] =
|
|
8841
|
+
OpKind[OpKind["StyleMap"] = 19] = "StyleMap";
|
|
8823
8842
|
/**
|
|
8824
8843
|
* An operation to bind an expression to the classes of an element.
|
|
8825
8844
|
*/
|
|
8826
|
-
OpKind[OpKind["ClassMap"] =
|
|
8827
|
-
/**
|
|
8828
|
-
* An operation to interpolate text into a property binding.
|
|
8829
|
-
*/
|
|
8830
|
-
OpKind[OpKind["InterpolateProperty"] = 18] = "InterpolateProperty";
|
|
8831
|
-
/**
|
|
8832
|
-
* An operation to interpolate text into a style property binding.
|
|
8833
|
-
*/
|
|
8834
|
-
OpKind[OpKind["InterpolateStyleProp"] = 19] = "InterpolateStyleProp";
|
|
8835
|
-
/**
|
|
8836
|
-
* An operation to interpolate text into a style mapping.
|
|
8837
|
-
*/
|
|
8838
|
-
OpKind[OpKind["InterpolateStyleMap"] = 20] = "InterpolateStyleMap";
|
|
8839
|
-
/**
|
|
8840
|
-
* An operation to interpolate text into a class mapping.
|
|
8841
|
-
*/
|
|
8842
|
-
OpKind[OpKind["InterpolateClassMap"] = 21] = "InterpolateClassMap";
|
|
8845
|
+
OpKind[OpKind["ClassMap"] = 20] = "ClassMap";
|
|
8843
8846
|
/**
|
|
8844
8847
|
* An operation to advance the runtime's implicit slot context during the update phase of a view.
|
|
8845
8848
|
*/
|
|
8846
|
-
OpKind[OpKind["Advance"] =
|
|
8849
|
+
OpKind[OpKind["Advance"] = 21] = "Advance";
|
|
8847
8850
|
/**
|
|
8848
8851
|
* An operation to instantiate a pipe.
|
|
8849
8852
|
*/
|
|
8850
|
-
OpKind[OpKind["Pipe"] =
|
|
8853
|
+
OpKind[OpKind["Pipe"] = 22] = "Pipe";
|
|
8851
8854
|
/**
|
|
8852
8855
|
* An operation to associate an attribute with an element.
|
|
8853
8856
|
*/
|
|
8854
|
-
OpKind[OpKind["Attribute"] =
|
|
8857
|
+
OpKind[OpKind["Attribute"] = 23] = "Attribute";
|
|
8855
8858
|
/**
|
|
8856
|
-
*
|
|
8859
|
+
* A host binding property.
|
|
8857
8860
|
*/
|
|
8858
|
-
OpKind[OpKind["
|
|
8861
|
+
OpKind[OpKind["HostProperty"] = 24] = "HostProperty";
|
|
8862
|
+
/**
|
|
8863
|
+
* A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
|
|
8864
|
+
*/
|
|
8865
|
+
OpKind[OpKind["Namespace"] = 25] = "Namespace";
|
|
8866
|
+
// TODO: Add Host Listeners, and possibly other host ops also.
|
|
8859
8867
|
})(OpKind || (OpKind = {}));
|
|
8860
8868
|
/**
|
|
8861
8869
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -8938,6 +8946,10 @@ var ExpressionKind;
|
|
|
8938
8946
|
* A reference to a temporary variable.
|
|
8939
8947
|
*/
|
|
8940
8948
|
ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 18] = "ReadTemporaryExpr";
|
|
8949
|
+
/**
|
|
8950
|
+
* An expression representing a sanitizer function.
|
|
8951
|
+
*/
|
|
8952
|
+
ExpressionKind[ExpressionKind["SanitizerExpr"] = 19] = "SanitizerExpr";
|
|
8941
8953
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
8942
8954
|
/**
|
|
8943
8955
|
* Distinguishes between different kinds of `SemanticVariable`s.
|
|
@@ -8957,6 +8969,28 @@ var SemanticVariableKind;
|
|
|
8957
8969
|
*/
|
|
8958
8970
|
SemanticVariableKind[SemanticVariableKind["SavedView"] = 2] = "SavedView";
|
|
8959
8971
|
})(SemanticVariableKind || (SemanticVariableKind = {}));
|
|
8972
|
+
/**
|
|
8973
|
+
* Whether to compile in compatibilty mode. In compatibility mode, the template pipeline will
|
|
8974
|
+
* attempt to match the output of `TemplateDefinitionBuilder` as exactly as possible, at the cost of
|
|
8975
|
+
* producing quirky or larger code in some cases.
|
|
8976
|
+
*/
|
|
8977
|
+
var CompatibilityMode;
|
|
8978
|
+
(function (CompatibilityMode) {
|
|
8979
|
+
CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
|
|
8980
|
+
CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
|
|
8981
|
+
})(CompatibilityMode || (CompatibilityMode = {}));
|
|
8982
|
+
/**
|
|
8983
|
+
* Represents functions used to sanitize different pieces of a template.
|
|
8984
|
+
*/
|
|
8985
|
+
var SanitizerFn;
|
|
8986
|
+
(function (SanitizerFn) {
|
|
8987
|
+
SanitizerFn[SanitizerFn["Html"] = 0] = "Html";
|
|
8988
|
+
SanitizerFn[SanitizerFn["Script"] = 1] = "Script";
|
|
8989
|
+
SanitizerFn[SanitizerFn["Style"] = 2] = "Style";
|
|
8990
|
+
SanitizerFn[SanitizerFn["Url"] = 3] = "Url";
|
|
8991
|
+
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
8992
|
+
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
8993
|
+
})(SanitizerFn || (SanitizerFn = {}));
|
|
8960
8994
|
|
|
8961
8995
|
/**
|
|
8962
8996
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9042,6 +9076,181 @@ function hasUsesSlotIndexTrait(value) {
|
|
|
9042
9076
|
return value[UsesSlotIndex] === true;
|
|
9043
9077
|
}
|
|
9044
9078
|
|
|
9079
|
+
/**
|
|
9080
|
+
* Create a `StatementOp`.
|
|
9081
|
+
*/
|
|
9082
|
+
function createStatementOp(statement) {
|
|
9083
|
+
return {
|
|
9084
|
+
kind: OpKind.Statement,
|
|
9085
|
+
statement,
|
|
9086
|
+
...NEW_OP,
|
|
9087
|
+
};
|
|
9088
|
+
}
|
|
9089
|
+
/**
|
|
9090
|
+
* Create a `VariableOp`.
|
|
9091
|
+
*/
|
|
9092
|
+
function createVariableOp(xref, variable, initializer) {
|
|
9093
|
+
return {
|
|
9094
|
+
kind: OpKind.Variable,
|
|
9095
|
+
xref,
|
|
9096
|
+
variable,
|
|
9097
|
+
initializer,
|
|
9098
|
+
...NEW_OP,
|
|
9099
|
+
};
|
|
9100
|
+
}
|
|
9101
|
+
/**
|
|
9102
|
+
* Static structure shared by all operations.
|
|
9103
|
+
*
|
|
9104
|
+
* Used as a convenience via the spread operator (`...NEW_OP`) when creating new operations, and
|
|
9105
|
+
* ensures the fields are always in the same order.
|
|
9106
|
+
*/
|
|
9107
|
+
const NEW_OP = {
|
|
9108
|
+
debugListId: null,
|
|
9109
|
+
prev: null,
|
|
9110
|
+
next: null,
|
|
9111
|
+
};
|
|
9112
|
+
|
|
9113
|
+
/**
|
|
9114
|
+
* Create an `InterpolationTextOp`.
|
|
9115
|
+
*/
|
|
9116
|
+
function createInterpolateTextOp(xref, interpolation, sourceSpan) {
|
|
9117
|
+
return {
|
|
9118
|
+
kind: OpKind.InterpolateText,
|
|
9119
|
+
target: xref,
|
|
9120
|
+
interpolation,
|
|
9121
|
+
sourceSpan,
|
|
9122
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9123
|
+
...TRAIT_CONSUMES_VARS,
|
|
9124
|
+
...NEW_OP,
|
|
9125
|
+
};
|
|
9126
|
+
}
|
|
9127
|
+
class Interpolation {
|
|
9128
|
+
constructor(strings, expressions) {
|
|
9129
|
+
this.strings = strings;
|
|
9130
|
+
this.expressions = expressions;
|
|
9131
|
+
}
|
|
9132
|
+
}
|
|
9133
|
+
/**
|
|
9134
|
+
* Create a `BindingOp`, not yet transformed into a particular type of binding.
|
|
9135
|
+
*/
|
|
9136
|
+
function createBindingOp(target, kind, name, expression, unit, securityContext, isTemplate, sourceSpan) {
|
|
9137
|
+
return {
|
|
9138
|
+
kind: OpKind.Binding,
|
|
9139
|
+
bindingKind: kind,
|
|
9140
|
+
target,
|
|
9141
|
+
name,
|
|
9142
|
+
expression,
|
|
9143
|
+
unit,
|
|
9144
|
+
securityContext,
|
|
9145
|
+
isTemplate,
|
|
9146
|
+
sourceSpan,
|
|
9147
|
+
...NEW_OP,
|
|
9148
|
+
};
|
|
9149
|
+
}
|
|
9150
|
+
/**
|
|
9151
|
+
* Create a `PropertyOp`.
|
|
9152
|
+
*/
|
|
9153
|
+
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isTemplate, sourceSpan) {
|
|
9154
|
+
return {
|
|
9155
|
+
kind: OpKind.Property,
|
|
9156
|
+
target,
|
|
9157
|
+
name,
|
|
9158
|
+
expression,
|
|
9159
|
+
isAnimationTrigger,
|
|
9160
|
+
securityContext,
|
|
9161
|
+
sanitizer: null,
|
|
9162
|
+
isTemplate,
|
|
9163
|
+
sourceSpan,
|
|
9164
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9165
|
+
...TRAIT_CONSUMES_VARS,
|
|
9166
|
+
...NEW_OP,
|
|
9167
|
+
};
|
|
9168
|
+
}
|
|
9169
|
+
/** Create a `StylePropOp`. */
|
|
9170
|
+
function createStylePropOp(xref, name, expression, unit, sourceSpan) {
|
|
9171
|
+
return {
|
|
9172
|
+
kind: OpKind.StyleProp,
|
|
9173
|
+
target: xref,
|
|
9174
|
+
name,
|
|
9175
|
+
expression,
|
|
9176
|
+
unit,
|
|
9177
|
+
sourceSpan,
|
|
9178
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9179
|
+
...TRAIT_CONSUMES_VARS,
|
|
9180
|
+
...NEW_OP,
|
|
9181
|
+
};
|
|
9182
|
+
}
|
|
9183
|
+
/**
|
|
9184
|
+
* Create a `ClassPropOp`.
|
|
9185
|
+
*/
|
|
9186
|
+
function createClassPropOp(xref, name, expression, sourceSpan) {
|
|
9187
|
+
return {
|
|
9188
|
+
kind: OpKind.ClassProp,
|
|
9189
|
+
target: xref,
|
|
9190
|
+
name,
|
|
9191
|
+
expression,
|
|
9192
|
+
sourceSpan,
|
|
9193
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9194
|
+
...TRAIT_CONSUMES_VARS,
|
|
9195
|
+
...NEW_OP,
|
|
9196
|
+
};
|
|
9197
|
+
}
|
|
9198
|
+
/** Create a `StyleMapOp`. */
|
|
9199
|
+
function createStyleMapOp(xref, expression, sourceSpan) {
|
|
9200
|
+
return {
|
|
9201
|
+
kind: OpKind.StyleMap,
|
|
9202
|
+
target: xref,
|
|
9203
|
+
expression,
|
|
9204
|
+
sourceSpan,
|
|
9205
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9206
|
+
...TRAIT_CONSUMES_VARS,
|
|
9207
|
+
...NEW_OP,
|
|
9208
|
+
};
|
|
9209
|
+
}
|
|
9210
|
+
/**
|
|
9211
|
+
* Create a `ClassMapOp`.
|
|
9212
|
+
*/
|
|
9213
|
+
function createClassMapOp(xref, expression, sourceSpan) {
|
|
9214
|
+
return {
|
|
9215
|
+
kind: OpKind.ClassMap,
|
|
9216
|
+
target: xref,
|
|
9217
|
+
expression,
|
|
9218
|
+
sourceSpan,
|
|
9219
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9220
|
+
...TRAIT_CONSUMES_VARS,
|
|
9221
|
+
...NEW_OP,
|
|
9222
|
+
};
|
|
9223
|
+
}
|
|
9224
|
+
/**
|
|
9225
|
+
* Create an `AttributeOp`.
|
|
9226
|
+
*/
|
|
9227
|
+
function createAttributeOp(target, name, expression, securityContext, isTemplate, sourceSpan) {
|
|
9228
|
+
return {
|
|
9229
|
+
kind: OpKind.Attribute,
|
|
9230
|
+
target,
|
|
9231
|
+
name,
|
|
9232
|
+
expression,
|
|
9233
|
+
securityContext,
|
|
9234
|
+
sanitizer: null,
|
|
9235
|
+
isTemplate,
|
|
9236
|
+
sourceSpan,
|
|
9237
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9238
|
+
...TRAIT_CONSUMES_VARS,
|
|
9239
|
+
...NEW_OP,
|
|
9240
|
+
};
|
|
9241
|
+
}
|
|
9242
|
+
/**
|
|
9243
|
+
* Create an `AdvanceOp`.
|
|
9244
|
+
*/
|
|
9245
|
+
function createAdvanceOp(delta, sourceSpan) {
|
|
9246
|
+
return {
|
|
9247
|
+
kind: OpKind.Advance,
|
|
9248
|
+
delta,
|
|
9249
|
+
sourceSpan,
|
|
9250
|
+
...NEW_OP,
|
|
9251
|
+
};
|
|
9252
|
+
}
|
|
9253
|
+
|
|
9045
9254
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
9046
9255
|
/**
|
|
9047
9256
|
* Check whether a given `o.Expression` is a logical IR expression type.
|
|
@@ -9542,7 +9751,7 @@ class AssignTemporaryExpr extends ExpressionBase {
|
|
|
9542
9751
|
this.expr = transformExpressionsInExpression(this.expr, transform, flags);
|
|
9543
9752
|
}
|
|
9544
9753
|
clone() {
|
|
9545
|
-
const a = new AssignTemporaryExpr(this.expr, this.xref);
|
|
9754
|
+
const a = new AssignTemporaryExpr(this.expr.clone(), this.xref);
|
|
9546
9755
|
a.name = this.name;
|
|
9547
9756
|
return a;
|
|
9548
9757
|
}
|
|
@@ -9568,6 +9777,24 @@ class ReadTemporaryExpr extends ExpressionBase {
|
|
|
9568
9777
|
return r;
|
|
9569
9778
|
}
|
|
9570
9779
|
}
|
|
9780
|
+
class SanitizerExpr extends ExpressionBase {
|
|
9781
|
+
constructor(fn) {
|
|
9782
|
+
super();
|
|
9783
|
+
this.fn = fn;
|
|
9784
|
+
this.kind = ExpressionKind.SanitizerExpr;
|
|
9785
|
+
}
|
|
9786
|
+
visitExpression(visitor, context) { }
|
|
9787
|
+
isEquivalent(e) {
|
|
9788
|
+
return e instanceof SanitizerExpr && e.fn === this.fn;
|
|
9789
|
+
}
|
|
9790
|
+
isConstant() {
|
|
9791
|
+
return true;
|
|
9792
|
+
}
|
|
9793
|
+
clone() {
|
|
9794
|
+
return new SanitizerExpr(this.fn);
|
|
9795
|
+
}
|
|
9796
|
+
transformInternalExpressions() { }
|
|
9797
|
+
}
|
|
9571
9798
|
/**
|
|
9572
9799
|
* Visits all `Expression`s in the AST of `op` with the `visitor` function.
|
|
9573
9800
|
*/
|
|
@@ -9582,6 +9809,12 @@ var VisitorContextFlag;
|
|
|
9582
9809
|
VisitorContextFlag[VisitorContextFlag["None"] = 0] = "None";
|
|
9583
9810
|
VisitorContextFlag[VisitorContextFlag["InChildOperation"] = 1] = "InChildOperation";
|
|
9584
9811
|
})(VisitorContextFlag || (VisitorContextFlag = {}));
|
|
9812
|
+
function transformExpressionsInInterpolation(interpolation, transform, flags) {
|
|
9813
|
+
for (let i = 0; i < interpolation.expressions.length; i++) {
|
|
9814
|
+
interpolation.expressions[i] =
|
|
9815
|
+
transformExpressionsInExpression(interpolation.expressions[i], transform, flags);
|
|
9816
|
+
}
|
|
9817
|
+
}
|
|
9585
9818
|
/**
|
|
9586
9819
|
* Transform all `Expression`s in the AST of `op` with the `transform` function.
|
|
9587
9820
|
*
|
|
@@ -9590,34 +9823,35 @@ var VisitorContextFlag;
|
|
|
9590
9823
|
*/
|
|
9591
9824
|
function transformExpressionsInOp(op, transform, flags) {
|
|
9592
9825
|
switch (op.kind) {
|
|
9593
|
-
case OpKind.Property:
|
|
9594
9826
|
case OpKind.StyleProp:
|
|
9595
9827
|
case OpKind.StyleMap:
|
|
9596
9828
|
case OpKind.ClassProp:
|
|
9597
9829
|
case OpKind.ClassMap:
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
for (let i = 0; i < op.expressions.length; i++) {
|
|
9606
|
-
op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
|
|
9830
|
+
case OpKind.Binding:
|
|
9831
|
+
case OpKind.HostProperty:
|
|
9832
|
+
if (op.expression instanceof Interpolation) {
|
|
9833
|
+
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
9834
|
+
}
|
|
9835
|
+
else {
|
|
9836
|
+
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
9607
9837
|
}
|
|
9608
9838
|
break;
|
|
9609
|
-
case OpKind.
|
|
9610
|
-
transformExpressionsInStatement(op.statement, transform, flags);
|
|
9611
|
-
break;
|
|
9839
|
+
case OpKind.Property:
|
|
9612
9840
|
case OpKind.Attribute:
|
|
9613
|
-
if (op.
|
|
9614
|
-
|
|
9841
|
+
if (op.expression instanceof Interpolation) {
|
|
9842
|
+
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
9615
9843
|
}
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
for (let i = 0; i < op.expressions.length; i++) {
|
|
9619
|
-
op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
|
|
9844
|
+
else {
|
|
9845
|
+
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
9620
9846
|
}
|
|
9847
|
+
op.sanitizer =
|
|
9848
|
+
op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
|
|
9849
|
+
break;
|
|
9850
|
+
case OpKind.InterpolateText:
|
|
9851
|
+
transformExpressionsInInterpolation(op.interpolation, transform, flags);
|
|
9852
|
+
break;
|
|
9853
|
+
case OpKind.Statement:
|
|
9854
|
+
transformExpressionsInStatement(op.statement, transform, flags);
|
|
9621
9855
|
break;
|
|
9622
9856
|
case OpKind.Variable:
|
|
9623
9857
|
op.initializer = transformExpressionsInExpression(op.initializer, transform, flags);
|
|
@@ -9634,9 +9868,12 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9634
9868
|
case OpKind.ContainerStart:
|
|
9635
9869
|
case OpKind.ContainerEnd:
|
|
9636
9870
|
case OpKind.Template:
|
|
9871
|
+
case OpKind.DisableBindings:
|
|
9872
|
+
case OpKind.EnableBindings:
|
|
9637
9873
|
case OpKind.Text:
|
|
9638
9874
|
case OpKind.Pipe:
|
|
9639
9875
|
case OpKind.Advance:
|
|
9876
|
+
case OpKind.Namespace:
|
|
9640
9877
|
// These operations contain no expressions.
|
|
9641
9878
|
break;
|
|
9642
9879
|
default:
|
|
@@ -9907,22 +10144,38 @@ class OpList {
|
|
|
9907
10144
|
op.next = null;
|
|
9908
10145
|
}
|
|
9909
10146
|
/**
|
|
9910
|
-
* Insert `op` before `
|
|
10147
|
+
* Insert `op` before `target`.
|
|
9911
10148
|
*/
|
|
9912
|
-
static insertBefore(op,
|
|
9913
|
-
OpList.assertIsOwned(
|
|
9914
|
-
if (
|
|
10149
|
+
static insertBefore(op, target) {
|
|
10150
|
+
OpList.assertIsOwned(target);
|
|
10151
|
+
if (target.prev === null) {
|
|
9915
10152
|
throw new Error(`AssertionError: illegal operation on list start`);
|
|
9916
10153
|
}
|
|
9917
10154
|
OpList.assertIsNotEnd(op);
|
|
9918
10155
|
OpList.assertIsUnowned(op);
|
|
9919
|
-
op.debugListId =
|
|
10156
|
+
op.debugListId = target.debugListId;
|
|
9920
10157
|
// Just in case.
|
|
9921
10158
|
op.prev = null;
|
|
9922
|
-
|
|
9923
|
-
op.prev =
|
|
9924
|
-
op.next =
|
|
9925
|
-
|
|
10159
|
+
target.prev.next = op;
|
|
10160
|
+
op.prev = target.prev;
|
|
10161
|
+
op.next = target;
|
|
10162
|
+
target.prev = op;
|
|
10163
|
+
}
|
|
10164
|
+
/**
|
|
10165
|
+
* Insert `op` after `target`.
|
|
10166
|
+
*/
|
|
10167
|
+
static insertAfter(op, target) {
|
|
10168
|
+
OpList.assertIsOwned(target);
|
|
10169
|
+
if (target.next === null) {
|
|
10170
|
+
throw new Error(`AssertionError: illegal operation on list end`);
|
|
10171
|
+
}
|
|
10172
|
+
OpList.assertIsNotEnd(op);
|
|
10173
|
+
OpList.assertIsUnowned(op);
|
|
10174
|
+
op.debugListId = target.debugListId;
|
|
10175
|
+
target.next.prev = op;
|
|
10176
|
+
op.next = target.next;
|
|
10177
|
+
op.prev = target;
|
|
10178
|
+
target.next = op;
|
|
9926
10179
|
}
|
|
9927
10180
|
/**
|
|
9928
10181
|
* Asserts that `op` does not currently belong to a list.
|
|
@@ -9954,40 +10207,6 @@ class OpList {
|
|
|
9954
10207
|
}
|
|
9955
10208
|
}
|
|
9956
10209
|
|
|
9957
|
-
/**
|
|
9958
|
-
* Create a `StatementOp`.
|
|
9959
|
-
*/
|
|
9960
|
-
function createStatementOp(statement) {
|
|
9961
|
-
return {
|
|
9962
|
-
kind: OpKind.Statement,
|
|
9963
|
-
statement,
|
|
9964
|
-
...NEW_OP,
|
|
9965
|
-
};
|
|
9966
|
-
}
|
|
9967
|
-
/**
|
|
9968
|
-
* Create a `VariableOp`.
|
|
9969
|
-
*/
|
|
9970
|
-
function createVariableOp(xref, variable, initializer) {
|
|
9971
|
-
return {
|
|
9972
|
-
kind: OpKind.Variable,
|
|
9973
|
-
xref,
|
|
9974
|
-
variable,
|
|
9975
|
-
initializer,
|
|
9976
|
-
...NEW_OP,
|
|
9977
|
-
};
|
|
9978
|
-
}
|
|
9979
|
-
/**
|
|
9980
|
-
* Static structure shared by all operations.
|
|
9981
|
-
*
|
|
9982
|
-
* Used as a convenience via the spread operator (`...NEW_OP`) when creating new operations, and
|
|
9983
|
-
* ensures the fields are always in the same order.
|
|
9984
|
-
*/
|
|
9985
|
-
const NEW_OP = {
|
|
9986
|
-
debugListId: null,
|
|
9987
|
-
prev: null,
|
|
9988
|
-
next: null,
|
|
9989
|
-
};
|
|
9990
|
-
|
|
9991
10210
|
/**
|
|
9992
10211
|
* The set of OpKinds that represent the creation of an element or container
|
|
9993
10212
|
*/
|
|
@@ -10003,13 +10222,16 @@ function isElementOrContainerOp(op) {
|
|
|
10003
10222
|
/**
|
|
10004
10223
|
* Create an `ElementStartOp`.
|
|
10005
10224
|
*/
|
|
10006
|
-
function createElementStartOp(tag, xref) {
|
|
10225
|
+
function createElementStartOp(tag, xref, namespace, sourceSpan) {
|
|
10007
10226
|
return {
|
|
10008
10227
|
kind: OpKind.ElementStart,
|
|
10009
10228
|
xref,
|
|
10010
10229
|
tag,
|
|
10011
10230
|
attributes: new ElementAttributes(),
|
|
10012
10231
|
localRefs: [],
|
|
10232
|
+
nonBindable: false,
|
|
10233
|
+
namespace,
|
|
10234
|
+
sourceSpan,
|
|
10013
10235
|
...TRAIT_CONSUMES_SLOT,
|
|
10014
10236
|
...NEW_OP,
|
|
10015
10237
|
};
|
|
@@ -10017,7 +10239,7 @@ function createElementStartOp(tag, xref) {
|
|
|
10017
10239
|
/**
|
|
10018
10240
|
* Create a `TemplateOp`.
|
|
10019
10241
|
*/
|
|
10020
|
-
function createTemplateOp(xref, tag) {
|
|
10242
|
+
function createTemplateOp(xref, tag, namespace, sourceSpan) {
|
|
10021
10243
|
return {
|
|
10022
10244
|
kind: OpKind.Template,
|
|
10023
10245
|
xref,
|
|
@@ -10026,6 +10248,9 @@ function createTemplateOp(xref, tag) {
|
|
|
10026
10248
|
decls: null,
|
|
10027
10249
|
vars: null,
|
|
10028
10250
|
localRefs: [],
|
|
10251
|
+
nonBindable: false,
|
|
10252
|
+
namespace,
|
|
10253
|
+
sourceSpan,
|
|
10029
10254
|
...TRAIT_CONSUMES_SLOT,
|
|
10030
10255
|
...NEW_OP,
|
|
10031
10256
|
};
|
|
@@ -10033,21 +10258,37 @@ function createTemplateOp(xref, tag) {
|
|
|
10033
10258
|
/**
|
|
10034
10259
|
* Create an `ElementEndOp`.
|
|
10035
10260
|
*/
|
|
10036
|
-
function createElementEndOp(xref) {
|
|
10261
|
+
function createElementEndOp(xref, sourceSpan) {
|
|
10037
10262
|
return {
|
|
10038
10263
|
kind: OpKind.ElementEnd,
|
|
10039
10264
|
xref,
|
|
10265
|
+
sourceSpan,
|
|
10266
|
+
...NEW_OP,
|
|
10267
|
+
};
|
|
10268
|
+
}
|
|
10269
|
+
function createDisableBindingsOp(xref) {
|
|
10270
|
+
return {
|
|
10271
|
+
kind: OpKind.DisableBindings,
|
|
10272
|
+
xref,
|
|
10273
|
+
...NEW_OP,
|
|
10274
|
+
};
|
|
10275
|
+
}
|
|
10276
|
+
function createEnableBindingsOp(xref) {
|
|
10277
|
+
return {
|
|
10278
|
+
kind: OpKind.EnableBindings,
|
|
10279
|
+
xref,
|
|
10040
10280
|
...NEW_OP,
|
|
10041
10281
|
};
|
|
10042
10282
|
}
|
|
10043
10283
|
/**
|
|
10044
10284
|
* Create a `TextOp`.
|
|
10045
10285
|
*/
|
|
10046
|
-
function createTextOp(xref, initialValue) {
|
|
10286
|
+
function createTextOp(xref, initialValue, sourceSpan) {
|
|
10047
10287
|
return {
|
|
10048
10288
|
kind: OpKind.Text,
|
|
10049
10289
|
xref,
|
|
10050
10290
|
initialValue,
|
|
10291
|
+
sourceSpan,
|
|
10051
10292
|
...TRAIT_CONSUMES_SLOT,
|
|
10052
10293
|
...NEW_OP,
|
|
10053
10294
|
};
|
|
@@ -10063,208 +10304,231 @@ function createListenerOp(target, name, tag) {
|
|
|
10063
10304
|
name,
|
|
10064
10305
|
handlerOps: new OpList(),
|
|
10065
10306
|
handlerFnName: null,
|
|
10307
|
+
consumesDollarEvent: false,
|
|
10308
|
+
isAnimationListener: false,
|
|
10309
|
+
animationPhase: null,
|
|
10066
10310
|
...NEW_OP,
|
|
10067
10311
|
...TRAIT_USES_SLOT_INDEX,
|
|
10068
10312
|
};
|
|
10069
10313
|
}
|
|
10070
|
-
function createPipeOp(xref, name) {
|
|
10071
|
-
return {
|
|
10072
|
-
kind: OpKind.Pipe,
|
|
10073
|
-
xref,
|
|
10074
|
-
name,
|
|
10075
|
-
...NEW_OP,
|
|
10076
|
-
...TRAIT_CONSUMES_SLOT,
|
|
10077
|
-
};
|
|
10078
|
-
}
|
|
10079
|
-
|
|
10080
10314
|
/**
|
|
10081
|
-
* Create an
|
|
10315
|
+
* Create a `ListenerOp` for an animation.
|
|
10082
10316
|
*/
|
|
10083
|
-
function
|
|
10317
|
+
function createListenerOpForAnimation(target, name, animationPhase, tag) {
|
|
10084
10318
|
return {
|
|
10085
|
-
kind: OpKind.
|
|
10086
|
-
target
|
|
10087
|
-
|
|
10088
|
-
expressions,
|
|
10089
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10090
|
-
...TRAIT_CONSUMES_VARS,
|
|
10091
|
-
...NEW_OP,
|
|
10092
|
-
};
|
|
10093
|
-
}
|
|
10094
|
-
/**
|
|
10095
|
-
* Create a `PropertyOp`.
|
|
10096
|
-
*/
|
|
10097
|
-
function createPropertyOp(xref, bindingKind, name, expression) {
|
|
10098
|
-
return {
|
|
10099
|
-
kind: OpKind.Property,
|
|
10100
|
-
target: xref,
|
|
10101
|
-
bindingKind,
|
|
10102
|
-
name,
|
|
10103
|
-
expression,
|
|
10104
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10105
|
-
...TRAIT_CONSUMES_VARS,
|
|
10106
|
-
...NEW_OP,
|
|
10107
|
-
};
|
|
10108
|
-
}
|
|
10109
|
-
/** Create a `StylePropOp`. */
|
|
10110
|
-
function createStylePropOp(xref, name, expression, unit) {
|
|
10111
|
-
return {
|
|
10112
|
-
kind: OpKind.StyleProp,
|
|
10113
|
-
target: xref,
|
|
10114
|
-
name,
|
|
10115
|
-
expression,
|
|
10116
|
-
unit,
|
|
10117
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10118
|
-
...TRAIT_CONSUMES_VARS,
|
|
10119
|
-
...NEW_OP,
|
|
10120
|
-
};
|
|
10121
|
-
}
|
|
10122
|
-
/**
|
|
10123
|
-
* Create a `ClassPropOp`.
|
|
10124
|
-
*/
|
|
10125
|
-
function createClassPropOp(xref, name, expression) {
|
|
10126
|
-
return {
|
|
10127
|
-
kind: OpKind.ClassProp,
|
|
10128
|
-
target: xref,
|
|
10319
|
+
kind: OpKind.Listener,
|
|
10320
|
+
target,
|
|
10321
|
+
tag,
|
|
10129
10322
|
name,
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
}
|
|
10136
|
-
/** Create a `StyleMapOp`. */
|
|
10137
|
-
function createStyleMapOp(xref, expression) {
|
|
10138
|
-
return {
|
|
10139
|
-
kind: OpKind.StyleMap,
|
|
10140
|
-
target: xref,
|
|
10141
|
-
expression,
|
|
10142
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10143
|
-
...TRAIT_CONSUMES_VARS,
|
|
10144
|
-
...NEW_OP,
|
|
10145
|
-
};
|
|
10146
|
-
}
|
|
10147
|
-
/**
|
|
10148
|
-
* Create a `ClassMapOp`.
|
|
10149
|
-
*/
|
|
10150
|
-
function createClassMapOp(xref, expression) {
|
|
10151
|
-
return {
|
|
10152
|
-
kind: OpKind.ClassMap,
|
|
10153
|
-
target: xref,
|
|
10154
|
-
expression,
|
|
10155
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10156
|
-
...TRAIT_CONSUMES_VARS,
|
|
10323
|
+
handlerOps: new OpList(),
|
|
10324
|
+
handlerFnName: null,
|
|
10325
|
+
consumesDollarEvent: false,
|
|
10326
|
+
isAnimationListener: true,
|
|
10327
|
+
animationPhase,
|
|
10157
10328
|
...NEW_OP,
|
|
10329
|
+
...TRAIT_USES_SLOT_INDEX,
|
|
10158
10330
|
};
|
|
10159
10331
|
}
|
|
10160
|
-
|
|
10161
|
-
* Create an `AttributeOp`.
|
|
10162
|
-
*/
|
|
10163
|
-
function createAttributeOp(target, attributeKind, name, value) {
|
|
10332
|
+
function createPipeOp(xref, name) {
|
|
10164
10333
|
return {
|
|
10165
|
-
kind: OpKind.
|
|
10166
|
-
|
|
10167
|
-
attributeKind,
|
|
10334
|
+
kind: OpKind.Pipe,
|
|
10335
|
+
xref,
|
|
10168
10336
|
name,
|
|
10169
|
-
value,
|
|
10170
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10171
|
-
...TRAIT_CONSUMES_VARS,
|
|
10172
10337
|
...NEW_OP,
|
|
10338
|
+
...TRAIT_CONSUMES_SLOT,
|
|
10173
10339
|
};
|
|
10174
10340
|
}
|
|
10175
10341
|
/**
|
|
10176
|
-
*
|
|
10342
|
+
* Whether the active namespace is HTML, MathML, or SVG mode.
|
|
10177
10343
|
*/
|
|
10178
|
-
|
|
10344
|
+
var Namespace;
|
|
10345
|
+
(function (Namespace) {
|
|
10346
|
+
Namespace[Namespace["HTML"] = 0] = "HTML";
|
|
10347
|
+
Namespace[Namespace["SVG"] = 1] = "SVG";
|
|
10348
|
+
Namespace[Namespace["Math"] = 2] = "Math";
|
|
10349
|
+
})(Namespace || (Namespace = {}));
|
|
10350
|
+
function createNamespaceOp(namespace) {
|
|
10179
10351
|
return {
|
|
10180
|
-
kind: OpKind.
|
|
10181
|
-
|
|
10182
|
-
bindingKind,
|
|
10183
|
-
name,
|
|
10184
|
-
strings,
|
|
10185
|
-
expressions,
|
|
10186
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10187
|
-
...TRAIT_CONSUMES_VARS,
|
|
10352
|
+
kind: OpKind.Namespace,
|
|
10353
|
+
active: namespace,
|
|
10188
10354
|
...NEW_OP,
|
|
10189
10355
|
};
|
|
10190
10356
|
}
|
|
10191
|
-
|
|
10357
|
+
|
|
10358
|
+
function createHostPropertyOp(name, expression, sourceSpan) {
|
|
10192
10359
|
return {
|
|
10193
|
-
kind: OpKind.
|
|
10194
|
-
target: target,
|
|
10195
|
-
attributeKind,
|
|
10360
|
+
kind: OpKind.HostProperty,
|
|
10196
10361
|
name,
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10362
|
+
expression,
|
|
10363
|
+
sourceSpan,
|
|
10200
10364
|
...TRAIT_CONSUMES_VARS,
|
|
10201
10365
|
...NEW_OP,
|
|
10202
10366
|
};
|
|
10203
10367
|
}
|
|
10368
|
+
|
|
10204
10369
|
/**
|
|
10205
|
-
*
|
|
10370
|
+
* A compilation unit is compiled into a template function.
|
|
10371
|
+
* Some example units are views and host bindings.
|
|
10206
10372
|
*/
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10373
|
+
class CompilationUnit {
|
|
10374
|
+
constructor(xref) {
|
|
10375
|
+
this.xref = xref;
|
|
10376
|
+
/**
|
|
10377
|
+
* List of creation operations for this view.
|
|
10378
|
+
*
|
|
10379
|
+
* Creation operations may internally contain other operations, including update operations.
|
|
10380
|
+
*/
|
|
10381
|
+
this.create = new OpList();
|
|
10382
|
+
/**
|
|
10383
|
+
* List of update operations for this view.
|
|
10384
|
+
*/
|
|
10385
|
+
this.update = new OpList();
|
|
10386
|
+
/**
|
|
10387
|
+
* Name of the function which will be generated for this unit.
|
|
10388
|
+
*
|
|
10389
|
+
* May be `null` if not yet determined.
|
|
10390
|
+
*/
|
|
10391
|
+
this.fnName = null;
|
|
10392
|
+
/**
|
|
10393
|
+
* Number of variable slots used within this view, or `null` if variables have not yet been
|
|
10394
|
+
* counted.
|
|
10395
|
+
*/
|
|
10396
|
+
this.vars = null;
|
|
10397
|
+
}
|
|
10398
|
+
/**
|
|
10399
|
+
* Iterate over all `ir.Op`s within this view.
|
|
10400
|
+
*
|
|
10401
|
+
* Some operations may have child operations, which this iterator will visit.
|
|
10402
|
+
*/
|
|
10403
|
+
*ops() {
|
|
10404
|
+
for (const op of this.create) {
|
|
10405
|
+
yield op;
|
|
10406
|
+
if (op.kind === OpKind.Listener) {
|
|
10407
|
+
for (const listenerOp of op.handlerOps) {
|
|
10408
|
+
yield listenerOp;
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10411
|
+
}
|
|
10412
|
+
for (const op of this.update) {
|
|
10413
|
+
yield op;
|
|
10414
|
+
}
|
|
10415
|
+
}
|
|
10219
10416
|
}
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10417
|
+
class HostBindingCompilationJob extends CompilationUnit {
|
|
10418
|
+
// TODO: Perhaps we should accept a reference to the enclosing component, and get the name from
|
|
10419
|
+
// there?
|
|
10420
|
+
constructor(componentName, pool, compatibility) {
|
|
10421
|
+
super(0);
|
|
10422
|
+
this.componentName = componentName;
|
|
10423
|
+
this.pool = pool;
|
|
10424
|
+
this.compatibility = compatibility;
|
|
10425
|
+
this.fnSuffix = 'HostBindings';
|
|
10426
|
+
this.units = [this];
|
|
10427
|
+
this.nextXrefId = 1;
|
|
10428
|
+
}
|
|
10429
|
+
get job() {
|
|
10430
|
+
return this;
|
|
10431
|
+
}
|
|
10432
|
+
get root() {
|
|
10433
|
+
return this;
|
|
10434
|
+
}
|
|
10435
|
+
allocateXrefId() {
|
|
10436
|
+
return this.nextXrefId++;
|
|
10437
|
+
}
|
|
10233
10438
|
}
|
|
10234
10439
|
/**
|
|
10235
|
-
*
|
|
10440
|
+
* Compilation-in-progress of a whole component's template, including the main template and any
|
|
10441
|
+
* embedded views or host bindings.
|
|
10236
10442
|
*/
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10443
|
+
class ComponentCompilationJob {
|
|
10444
|
+
get units() {
|
|
10445
|
+
return this.views.values();
|
|
10446
|
+
}
|
|
10447
|
+
constructor(componentName, pool, compatibility) {
|
|
10448
|
+
this.componentName = componentName;
|
|
10449
|
+
this.pool = pool;
|
|
10450
|
+
this.compatibility = compatibility;
|
|
10451
|
+
this.fnSuffix = 'Template';
|
|
10452
|
+
/**
|
|
10453
|
+
* Tracks the next `ir.XrefId` which can be assigned as template structures are ingested.
|
|
10454
|
+
*/
|
|
10455
|
+
this.nextXrefId = 0;
|
|
10456
|
+
/**
|
|
10457
|
+
* Map of view IDs to `ViewCompilation`s.
|
|
10458
|
+
*/
|
|
10459
|
+
this.views = new Map();
|
|
10460
|
+
/**
|
|
10461
|
+
* Constant expressions used by operations within this component's compilation.
|
|
10462
|
+
*
|
|
10463
|
+
* This will eventually become the `consts` array in the component definition.
|
|
10464
|
+
*/
|
|
10465
|
+
this.consts = [];
|
|
10466
|
+
// Allocate the root view.
|
|
10467
|
+
const root = new ViewCompilationUnit(this, this.allocateXrefId(), null);
|
|
10468
|
+
this.views.set(root.xref, root);
|
|
10469
|
+
this.root = root;
|
|
10470
|
+
}
|
|
10471
|
+
/**
|
|
10472
|
+
* Add a `ViewCompilation` for a new embedded view to this compilation.
|
|
10473
|
+
*/
|
|
10474
|
+
allocateView(parent) {
|
|
10475
|
+
const view = new ViewCompilationUnit(this, this.allocateXrefId(), parent);
|
|
10476
|
+
this.views.set(view.xref, view);
|
|
10477
|
+
return view;
|
|
10478
|
+
}
|
|
10479
|
+
/**
|
|
10480
|
+
* Generate a new unique `ir.XrefId` in this job.
|
|
10481
|
+
*/
|
|
10482
|
+
allocateXrefId() {
|
|
10483
|
+
return this.nextXrefId++;
|
|
10484
|
+
}
|
|
10485
|
+
/**
|
|
10486
|
+
* Add a constant `o.Expression` to the compilation and return its index in the `consts` array.
|
|
10487
|
+
*/
|
|
10488
|
+
addConst(newConst) {
|
|
10489
|
+
for (let idx = 0; idx < this.consts.length; idx++) {
|
|
10490
|
+
if (this.consts[idx].isEquivalent(newConst)) {
|
|
10491
|
+
return idx;
|
|
10492
|
+
}
|
|
10493
|
+
}
|
|
10494
|
+
const idx = this.consts.length;
|
|
10495
|
+
this.consts.push(newConst);
|
|
10496
|
+
return idx;
|
|
10497
|
+
}
|
|
10247
10498
|
}
|
|
10248
10499
|
/**
|
|
10249
|
-
*
|
|
10500
|
+
* Compilation-in-progress of an individual view within a template.
|
|
10250
10501
|
*/
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10502
|
+
class ViewCompilationUnit extends CompilationUnit {
|
|
10503
|
+
constructor(job, xref, parent) {
|
|
10504
|
+
super(xref);
|
|
10505
|
+
this.job = job;
|
|
10506
|
+
this.parent = parent;
|
|
10507
|
+
/**
|
|
10508
|
+
* Map of declared variables available within this view to the property on the context object
|
|
10509
|
+
* which they alias.
|
|
10510
|
+
*/
|
|
10511
|
+
this.contextVariables = new Map();
|
|
10512
|
+
/**
|
|
10513
|
+
* Number of declaration slots used within this view, or `null` if slots have not yet been
|
|
10514
|
+
* allocated.
|
|
10515
|
+
*/
|
|
10516
|
+
this.decls = null;
|
|
10517
|
+
}
|
|
10518
|
+
get compatibility() {
|
|
10519
|
+
return this.job.compatibility;
|
|
10520
|
+
}
|
|
10257
10521
|
}
|
|
10258
10522
|
|
|
10259
10523
|
/**
|
|
10260
10524
|
* Counts the number of variable slots used within each view, and stores that on the view itself, as
|
|
10261
10525
|
* well as propagates it to the `ir.TemplateOp` for embedded views.
|
|
10262
10526
|
*/
|
|
10263
|
-
function phaseVarCounting(
|
|
10527
|
+
function phaseVarCounting(job) {
|
|
10264
10528
|
// First, count the vars used in each view, and update the view-level counter.
|
|
10265
|
-
for (const
|
|
10529
|
+
for (const unit of job.units) {
|
|
10266
10530
|
let varCount = 0;
|
|
10267
|
-
for (const op of
|
|
10531
|
+
for (const op of unit.ops()) {
|
|
10268
10532
|
if (hasConsumesVarsTrait(op)) {
|
|
10269
10533
|
varCount += varsUsedByOp(op);
|
|
10270
10534
|
}
|
|
@@ -10281,17 +10545,19 @@ function phaseVarCounting(cpl) {
|
|
|
10281
10545
|
}
|
|
10282
10546
|
});
|
|
10283
10547
|
}
|
|
10284
|
-
|
|
10548
|
+
unit.vars = varCount;
|
|
10285
10549
|
}
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
for (const
|
|
10290
|
-
|
|
10291
|
-
|
|
10550
|
+
if (job instanceof ComponentCompilationJob) {
|
|
10551
|
+
// Add var counts for each view to the `ir.TemplateOp` which declares that view (if the view is
|
|
10552
|
+
// an embedded view).
|
|
10553
|
+
for (const view of job.views.values()) {
|
|
10554
|
+
for (const op of view.create) {
|
|
10555
|
+
if (op.kind !== OpKind.Template) {
|
|
10556
|
+
continue;
|
|
10557
|
+
}
|
|
10558
|
+
const childView = job.views.get(op.xref);
|
|
10559
|
+
op.vars = childView.vars;
|
|
10292
10560
|
}
|
|
10293
|
-
const childView = cpl.views.get(op.xref);
|
|
10294
|
-
op.vars = childView.vars;
|
|
10295
10561
|
}
|
|
10296
10562
|
}
|
|
10297
10563
|
}
|
|
@@ -10300,32 +10566,32 @@ function phaseVarCounting(cpl) {
|
|
|
10300
10566
|
* count the variables used by any particular `op`.
|
|
10301
10567
|
*/
|
|
10302
10568
|
function varsUsedByOp(op) {
|
|
10569
|
+
let slots;
|
|
10303
10570
|
switch (op.kind) {
|
|
10304
10571
|
case OpKind.Property:
|
|
10572
|
+
case OpKind.HostProperty:
|
|
10305
10573
|
case OpKind.Attribute:
|
|
10306
|
-
//
|
|
10307
|
-
|
|
10574
|
+
// All of these bindings use 1 variable slot, plus 1 slot for every interpolated expression,
|
|
10575
|
+
// if any.
|
|
10576
|
+
slots = 1;
|
|
10577
|
+
if (op.expression instanceof Interpolation) {
|
|
10578
|
+
slots += op.expression.expressions.length;
|
|
10579
|
+
}
|
|
10580
|
+
return slots;
|
|
10308
10581
|
case OpKind.StyleProp:
|
|
10309
10582
|
case OpKind.ClassProp:
|
|
10310
10583
|
case OpKind.StyleMap:
|
|
10311
10584
|
case OpKind.ClassMap:
|
|
10312
|
-
// Style & class bindings use 2 variable slots
|
|
10313
|
-
|
|
10585
|
+
// Style & class bindings use 2 variable slots, plus 1 slot for every interpolated expression,
|
|
10586
|
+
// if any.
|
|
10587
|
+
slots = 2;
|
|
10588
|
+
if (op.expression instanceof Interpolation) {
|
|
10589
|
+
slots += op.expression.expressions.length;
|
|
10590
|
+
}
|
|
10591
|
+
return slots;
|
|
10314
10592
|
case OpKind.InterpolateText:
|
|
10315
10593
|
// `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
|
|
10316
|
-
return op.expressions.length;
|
|
10317
|
-
case OpKind.InterpolateProperty:
|
|
10318
|
-
// `ir.InterpolatePropertyOp`s use a variable slot for each dynamic expression, plus one for
|
|
10319
|
-
// the result.
|
|
10320
|
-
return 1 + op.expressions.length;
|
|
10321
|
-
case OpKind.InterpolateAttribute:
|
|
10322
|
-
// One variable slot for each dynamic expression, plus one for the result.
|
|
10323
|
-
return 1 + op.expressions.length;
|
|
10324
|
-
case OpKind.InterpolateStyleProp:
|
|
10325
|
-
case OpKind.InterpolateStyleMap:
|
|
10326
|
-
case OpKind.InterpolateClassMap:
|
|
10327
|
-
// One variable slot for each dynamic expression, plus two for binding the result.
|
|
10328
|
-
return 2 + op.expressions.length;
|
|
10594
|
+
return op.interpolation.expressions.length;
|
|
10329
10595
|
default:
|
|
10330
10596
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
10331
10597
|
}
|
|
@@ -10376,39 +10642,109 @@ function phaseAlignPipeVariadicVarOffset(cpl) {
|
|
|
10376
10642
|
}
|
|
10377
10643
|
|
|
10378
10644
|
/**
|
|
10379
|
-
* Find
|
|
10380
|
-
* In cases where no instruction needs to be generated for the attribute or binding, it is removed.
|
|
10645
|
+
* Find any function calls to `$any`, excluding `this.$any`, and delete them.
|
|
10381
10646
|
*/
|
|
10382
|
-
function
|
|
10647
|
+
function phaseFindAnyCasts(cpl) {
|
|
10383
10648
|
for (const [_, view] of cpl.views) {
|
|
10384
|
-
|
|
10649
|
+
for (const op of view.ops()) {
|
|
10650
|
+
transformExpressionsInOp(op, removeAnys, VisitorContextFlag.None);
|
|
10651
|
+
}
|
|
10385
10652
|
}
|
|
10386
10653
|
}
|
|
10387
|
-
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10654
|
+
function removeAnys(e) {
|
|
10655
|
+
if (e instanceof InvokeFunctionExpr && e.fn instanceof LexicalReadExpr &&
|
|
10656
|
+
e.fn.name === '$any') {
|
|
10657
|
+
if (e.args.length !== 1) {
|
|
10658
|
+
throw new Error('The $any builtin function expects exactly one argument.');
|
|
10659
|
+
}
|
|
10660
|
+
return e.args[0];
|
|
10394
10661
|
}
|
|
10395
|
-
return
|
|
10662
|
+
return e;
|
|
10396
10663
|
}
|
|
10664
|
+
|
|
10397
10665
|
/**
|
|
10398
|
-
*
|
|
10666
|
+
* Parses string representation of a style and converts it into object literal.
|
|
10667
|
+
*
|
|
10668
|
+
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
10669
|
+
* Example: `color: red; height: auto`.
|
|
10670
|
+
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
10671
|
+
* 'auto']`
|
|
10399
10672
|
*/
|
|
10400
|
-
function
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10673
|
+
function parse(value) {
|
|
10674
|
+
// we use a string array here instead of a string map
|
|
10675
|
+
// because a string-map is not guaranteed to retain the
|
|
10676
|
+
// order of the entries whereas a string array can be
|
|
10677
|
+
// constructed in a [key, value, key, value] format.
|
|
10678
|
+
const styles = [];
|
|
10679
|
+
let i = 0;
|
|
10680
|
+
let parenDepth = 0;
|
|
10681
|
+
let quote = 0 /* Char.QuoteNone */;
|
|
10682
|
+
let valueStart = 0;
|
|
10683
|
+
let propStart = 0;
|
|
10684
|
+
let currentProp = null;
|
|
10685
|
+
while (i < value.length) {
|
|
10686
|
+
const token = value.charCodeAt(i++);
|
|
10687
|
+
switch (token) {
|
|
10688
|
+
case 40 /* Char.OpenParen */:
|
|
10689
|
+
parenDepth++;
|
|
10690
|
+
break;
|
|
10691
|
+
case 41 /* Char.CloseParen */:
|
|
10692
|
+
parenDepth--;
|
|
10693
|
+
break;
|
|
10694
|
+
case 39 /* Char.QuoteSingle */:
|
|
10695
|
+
// valueStart needs to be there since prop values don't
|
|
10696
|
+
// have quotes in CSS
|
|
10697
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
10698
|
+
quote = 39 /* Char.QuoteSingle */;
|
|
10699
|
+
}
|
|
10700
|
+
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
10701
|
+
quote = 0 /* Char.QuoteNone */;
|
|
10702
|
+
}
|
|
10703
|
+
break;
|
|
10704
|
+
case 34 /* Char.QuoteDouble */:
|
|
10705
|
+
// same logic as above
|
|
10706
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
10707
|
+
quote = 34 /* Char.QuoteDouble */;
|
|
10708
|
+
}
|
|
10709
|
+
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
10710
|
+
quote = 0 /* Char.QuoteNone */;
|
|
10711
|
+
}
|
|
10712
|
+
break;
|
|
10713
|
+
case 58 /* Char.Colon */:
|
|
10714
|
+
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
10715
|
+
currentProp = hyphenate$1(value.substring(propStart, i - 1).trim());
|
|
10716
|
+
valueStart = i;
|
|
10717
|
+
}
|
|
10718
|
+
break;
|
|
10719
|
+
case 59 /* Char.Semicolon */:
|
|
10720
|
+
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
10721
|
+
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
10722
|
+
styles.push(currentProp, styleVal);
|
|
10723
|
+
propStart = i;
|
|
10724
|
+
valueStart = 0;
|
|
10725
|
+
currentProp = null;
|
|
10726
|
+
}
|
|
10727
|
+
break;
|
|
10728
|
+
}
|
|
10404
10729
|
}
|
|
10405
|
-
|
|
10730
|
+
if (currentProp && valueStart) {
|
|
10731
|
+
const styleVal = value.slice(valueStart).trim();
|
|
10732
|
+
styles.push(currentProp, styleVal);
|
|
10733
|
+
}
|
|
10734
|
+
return styles;
|
|
10406
10735
|
}
|
|
10736
|
+
function hyphenate$1(value) {
|
|
10737
|
+
return value
|
|
10738
|
+
.replace(/[a-z][A-Z]/g, v => {
|
|
10739
|
+
return v.charAt(0) + '-' + v.charAt(1);
|
|
10740
|
+
})
|
|
10741
|
+
.toLowerCase();
|
|
10742
|
+
}
|
|
10743
|
+
|
|
10407
10744
|
/**
|
|
10408
|
-
*
|
|
10409
|
-
* not need further processing.
|
|
10745
|
+
* Gets a map of all elements in the given view by their xref id.
|
|
10410
10746
|
*/
|
|
10411
|
-
function
|
|
10747
|
+
function getElementsByXrefId(view) {
|
|
10412
10748
|
const elements = new Map();
|
|
10413
10749
|
for (const op of view.create) {
|
|
10414
10750
|
if (!isElementOrContainerOp(op)) {
|
|
@@ -10416,61 +10752,170 @@ function populateElementAttributes(view, compatibility) {
|
|
|
10416
10752
|
}
|
|
10417
10753
|
elements.set(op.xref, op);
|
|
10418
10754
|
}
|
|
10755
|
+
return elements;
|
|
10756
|
+
}
|
|
10757
|
+
|
|
10758
|
+
/**
|
|
10759
|
+
* Find all attribute and binding ops, and collect them into the ElementAttribute structures.
|
|
10760
|
+
* In cases where no instruction needs to be generated for the attribute or binding, it is removed.
|
|
10761
|
+
*/
|
|
10762
|
+
function phaseAttributeExtraction(cpl) {
|
|
10763
|
+
for (const [_, view] of cpl.views) {
|
|
10764
|
+
populateElementAttributes(view);
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
/**
|
|
10768
|
+
* Looks up an element in the given map by xref ID.
|
|
10769
|
+
*/
|
|
10770
|
+
function lookupElement$2(elements, xref) {
|
|
10771
|
+
const el = elements.get(xref);
|
|
10772
|
+
if (el === undefined) {
|
|
10773
|
+
throw new Error('All attributes should have an element-like target.');
|
|
10774
|
+
}
|
|
10775
|
+
return el;
|
|
10776
|
+
}
|
|
10777
|
+
/**
|
|
10778
|
+
* Populates the ElementAttributes map for the given view, and removes ops for any bindings that do
|
|
10779
|
+
* not need further processing.
|
|
10780
|
+
*/
|
|
10781
|
+
function populateElementAttributes(view) {
|
|
10782
|
+
const elements = getElementsByXrefId(view);
|
|
10419
10783
|
for (const op of view.ops()) {
|
|
10420
10784
|
let ownerOp;
|
|
10421
10785
|
switch (op.kind) {
|
|
10422
10786
|
case OpKind.Attribute:
|
|
10423
|
-
|
|
10424
|
-
assertIsElementAttributes(ownerOp.attributes);
|
|
10425
|
-
// The old compiler only extracted string constants, so we emulate that behavior in
|
|
10426
|
-
// compaitiblity mode, otherwise we optimize more aggressively.
|
|
10427
|
-
let extractable = compatibility ?
|
|
10428
|
-
(op.value instanceof LiteralExpr && typeof op.value.value === 'string') :
|
|
10429
|
-
(op.value.isConstant());
|
|
10430
|
-
// We don't need to generate instructions for attributes that can be extracted as consts.
|
|
10431
|
-
if (extractable) {
|
|
10432
|
-
ownerOp.attributes.add(op.attributeKind, op.name, op.value);
|
|
10433
|
-
OpList.remove(op);
|
|
10434
|
-
}
|
|
10787
|
+
extractAttributeOp(view, op, elements);
|
|
10435
10788
|
break;
|
|
10436
10789
|
case OpKind.Property:
|
|
10437
|
-
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
ownerOp
|
|
10441
|
-
break;
|
|
10442
|
-
case OpKind.InterpolateProperty:
|
|
10443
|
-
ownerOp = lookupElement(elements, op.target);
|
|
10790
|
+
if (op.isAnimationTrigger) {
|
|
10791
|
+
continue; // Don't extract animation properties.
|
|
10792
|
+
}
|
|
10793
|
+
ownerOp = lookupElement$2(elements, op.target);
|
|
10444
10794
|
assertIsElementAttributes(ownerOp.attributes);
|
|
10445
|
-
ownerOp.attributes.add(op.
|
|
10795
|
+
ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null);
|
|
10446
10796
|
break;
|
|
10447
10797
|
case OpKind.StyleProp:
|
|
10448
10798
|
case OpKind.ClassProp:
|
|
10449
|
-
ownerOp = lookupElement(elements, op.target);
|
|
10799
|
+
ownerOp = lookupElement$2(elements, op.target);
|
|
10450
10800
|
assertIsElementAttributes(ownerOp.attributes);
|
|
10451
|
-
//
|
|
10452
|
-
//
|
|
10453
|
-
if (
|
|
10454
|
-
|
|
10801
|
+
// Empty StyleProperty and ClassName expressions are treated differently depending on
|
|
10802
|
+
// compatibility mode.
|
|
10803
|
+
if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
10804
|
+
op.expression instanceof EmptyExpr) {
|
|
10805
|
+
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
10806
|
+
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
10807
|
+
// mode.
|
|
10808
|
+
ownerOp.attributes.add(BindingKind.Property, op.name, null);
|
|
10455
10809
|
}
|
|
10456
10810
|
break;
|
|
10457
10811
|
case OpKind.Listener:
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
ownerOp.attributes.add(ElementAttributeKind.Binding, op.name, null);
|
|
10461
|
-
// We don't need to generate instructions for listeners on templates.
|
|
10462
|
-
if (ownerOp.kind === OpKind.Template) {
|
|
10463
|
-
OpList.remove(op);
|
|
10812
|
+
if (op.isAnimationListener) {
|
|
10813
|
+
continue; // Don't extract animation listeners.
|
|
10464
10814
|
}
|
|
10815
|
+
ownerOp = lookupElement$2(elements, op.target);
|
|
10816
|
+
assertIsElementAttributes(ownerOp.attributes);
|
|
10817
|
+
ownerOp.attributes.add(BindingKind.Property, op.name, null);
|
|
10465
10818
|
break;
|
|
10466
10819
|
}
|
|
10467
10820
|
}
|
|
10468
10821
|
}
|
|
10822
|
+
function isStringLiteral(expr) {
|
|
10823
|
+
return expr instanceof LiteralExpr && typeof expr.value === 'string';
|
|
10824
|
+
}
|
|
10825
|
+
function extractAttributeOp(view, op, elements) {
|
|
10826
|
+
if (op.expression instanceof Interpolation) {
|
|
10827
|
+
return;
|
|
10828
|
+
}
|
|
10829
|
+
const ownerOp = lookupElement$2(elements, op.target);
|
|
10830
|
+
assertIsElementAttributes(ownerOp.attributes);
|
|
10831
|
+
if (op.name === 'style' && isStringLiteral(op.expression)) {
|
|
10832
|
+
// TemplateDefinitionBuilder did not extract style attributes that had a security context.
|
|
10833
|
+
if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
10834
|
+
op.securityContext !== SecurityContext.NONE) {
|
|
10835
|
+
return;
|
|
10836
|
+
}
|
|
10837
|
+
// Extract style attributes.
|
|
10838
|
+
const parsedStyles = parse(op.expression.value);
|
|
10839
|
+
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
10840
|
+
ownerOp.attributes.add(BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]));
|
|
10841
|
+
}
|
|
10842
|
+
OpList.remove(op);
|
|
10843
|
+
}
|
|
10844
|
+
else {
|
|
10845
|
+
// The old compiler only extracted string constants, so we emulate that behavior in
|
|
10846
|
+
// compaitiblity mode, otherwise we optimize more aggressively.
|
|
10847
|
+
let extractable = view.compatibility === CompatibilityMode.TemplateDefinitionBuilder ?
|
|
10848
|
+
(op.expression instanceof LiteralExpr && typeof op.expression.value === 'string') :
|
|
10849
|
+
op.expression.isConstant();
|
|
10850
|
+
// We don't need to generate instructions for attributes that can be extracted as consts.
|
|
10851
|
+
if (extractable) {
|
|
10852
|
+
ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression);
|
|
10853
|
+
OpList.remove(op);
|
|
10854
|
+
}
|
|
10855
|
+
}
|
|
10856
|
+
}
|
|
10857
|
+
|
|
10858
|
+
/**
|
|
10859
|
+
* Looks up an element in the given map by xref ID.
|
|
10860
|
+
*/
|
|
10861
|
+
function lookupElement$1(elements, xref) {
|
|
10862
|
+
const el = elements.get(xref);
|
|
10863
|
+
if (el === undefined) {
|
|
10864
|
+
throw new Error('All attributes should have an element-like target.');
|
|
10865
|
+
}
|
|
10866
|
+
return el;
|
|
10867
|
+
}
|
|
10868
|
+
function phaseBindingSpecialization(job) {
|
|
10869
|
+
const elements = new Map();
|
|
10870
|
+
for (const unit of job.units) {
|
|
10871
|
+
for (const op of unit.create) {
|
|
10872
|
+
if (!isElementOrContainerOp(op)) {
|
|
10873
|
+
continue;
|
|
10874
|
+
}
|
|
10875
|
+
elements.set(op.xref, op);
|
|
10876
|
+
}
|
|
10877
|
+
}
|
|
10878
|
+
for (const unit of job.units) {
|
|
10879
|
+
for (const op of unit.ops()) {
|
|
10880
|
+
if (op.kind !== OpKind.Binding) {
|
|
10881
|
+
continue;
|
|
10882
|
+
}
|
|
10883
|
+
switch (op.bindingKind) {
|
|
10884
|
+
case BindingKind.Attribute:
|
|
10885
|
+
if (op.name === 'ngNonBindable') {
|
|
10886
|
+
OpList.remove(op);
|
|
10887
|
+
const target = lookupElement$1(elements, op.target);
|
|
10888
|
+
target.nonBindable = true;
|
|
10889
|
+
}
|
|
10890
|
+
else {
|
|
10891
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTemplate, op.sourceSpan));
|
|
10892
|
+
}
|
|
10893
|
+
break;
|
|
10894
|
+
case BindingKind.Property:
|
|
10895
|
+
case BindingKind.Animation:
|
|
10896
|
+
if (job instanceof HostBindingCompilationJob) {
|
|
10897
|
+
// TODO: host property animations
|
|
10898
|
+
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.sourceSpan));
|
|
10899
|
+
}
|
|
10900
|
+
else {
|
|
10901
|
+
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isTemplate, op.sourceSpan));
|
|
10902
|
+
}
|
|
10903
|
+
break;
|
|
10904
|
+
case BindingKind.I18n:
|
|
10905
|
+
case BindingKind.ClassName:
|
|
10906
|
+
case BindingKind.StyleProperty:
|
|
10907
|
+
throw new Error(`Unhandled binding of kind ${BindingKind[op.bindingKind]}`);
|
|
10908
|
+
}
|
|
10909
|
+
}
|
|
10910
|
+
}
|
|
10911
|
+
}
|
|
10469
10912
|
|
|
10470
10913
|
const CHAINABLE = new Set([
|
|
10471
10914
|
Identifiers.elementStart,
|
|
10472
10915
|
Identifiers.elementEnd,
|
|
10916
|
+
Identifiers.element,
|
|
10473
10917
|
Identifiers.property,
|
|
10918
|
+
Identifiers.hostProperty,
|
|
10474
10919
|
Identifiers.styleProp,
|
|
10475
10920
|
Identifiers.attribute,
|
|
10476
10921
|
Identifiers.stylePropInterpolate1,
|
|
@@ -10483,9 +10928,11 @@ const CHAINABLE = new Set([
|
|
|
10483
10928
|
Identifiers.stylePropInterpolate8,
|
|
10484
10929
|
Identifiers.stylePropInterpolateV,
|
|
10485
10930
|
Identifiers.classProp,
|
|
10931
|
+
Identifiers.listener,
|
|
10486
10932
|
Identifiers.elementContainerStart,
|
|
10487
10933
|
Identifiers.elementContainerEnd,
|
|
10488
10934
|
Identifiers.elementContainer,
|
|
10935
|
+
Identifiers.listener,
|
|
10489
10936
|
]);
|
|
10490
10937
|
/**
|
|
10491
10938
|
* Post-process a reified view compilation and convert sequential calls to chainable instructions
|
|
@@ -10504,10 +10951,10 @@ const CHAINABLE = new Set([
|
|
|
10504
10951
|
* elementStart(0, 'div')(1, 'span');
|
|
10505
10952
|
* ```
|
|
10506
10953
|
*/
|
|
10507
|
-
function phaseChaining(
|
|
10508
|
-
for (const
|
|
10509
|
-
chainOperationsInList(
|
|
10510
|
-
chainOperationsInList(
|
|
10954
|
+
function phaseChaining(job) {
|
|
10955
|
+
for (const unit of job.units) {
|
|
10956
|
+
chainOperationsInList(unit.create);
|
|
10957
|
+
chainOperationsInList(unit.update);
|
|
10511
10958
|
}
|
|
10512
10959
|
}
|
|
10513
10960
|
function chainOperationsInList(opList) {
|
|
@@ -10628,10 +11075,10 @@ function phaseEmptyElements(cpl) {
|
|
|
10628
11075
|
* Finds all unresolved safe read expressions, and converts them into the appropriate output AST
|
|
10629
11076
|
* reads, guarded by null checks.
|
|
10630
11077
|
*/
|
|
10631
|
-
function phaseExpandSafeReads(
|
|
10632
|
-
for (const
|
|
10633
|
-
for (const op of
|
|
10634
|
-
transformExpressionsInOp(op, e => safeTransform(e, {
|
|
11078
|
+
function phaseExpandSafeReads(job) {
|
|
11079
|
+
for (const unit of job.units) {
|
|
11080
|
+
for (const op of unit.ops()) {
|
|
11081
|
+
transformExpressionsInOp(op, e => safeTransform(e, { job }), VisitorContextFlag.None);
|
|
10635
11082
|
transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
|
|
10636
11083
|
}
|
|
10637
11084
|
}
|
|
@@ -10696,7 +11143,9 @@ function eliminateTemporaryAssignments(e, tmps, ctx) {
|
|
|
10696
11143
|
// temporary variables to themselves. This happens because some subexpression that the
|
|
10697
11144
|
// temporary refers to, possibly through nested temporaries, has a function call. We copy that
|
|
10698
11145
|
// behavior here.
|
|
10699
|
-
return ctx.compatibility
|
|
11146
|
+
return ctx.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder ?
|
|
11147
|
+
new AssignTemporaryExpr(read, read.xref) :
|
|
11148
|
+
read;
|
|
10700
11149
|
}
|
|
10701
11150
|
return e;
|
|
10702
11151
|
}, VisitorContextFlag.None);
|
|
@@ -10710,7 +11159,7 @@ function eliminateTemporaryAssignments(e, tmps, ctx) {
|
|
|
10710
11159
|
function safeTernaryWithTemporary(guard, body, ctx) {
|
|
10711
11160
|
let result;
|
|
10712
11161
|
if (needsTemporaryInSafeAccess(guard)) {
|
|
10713
|
-
const xref = ctx.
|
|
11162
|
+
const xref = ctx.job.allocateXrefId();
|
|
10714
11163
|
result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
|
|
10715
11164
|
}
|
|
10716
11165
|
else {
|
|
@@ -10724,7 +11173,8 @@ function safeTernaryWithTemporary(guard, body, ctx) {
|
|
|
10724
11173
|
return new SafeTernaryExpr(result[0], body(result[1]));
|
|
10725
11174
|
}
|
|
10726
11175
|
function isSafeAccessExpression(e) {
|
|
10727
|
-
return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr
|
|
11176
|
+
return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr ||
|
|
11177
|
+
e instanceof SafeInvokeFunctionExpr;
|
|
10728
11178
|
}
|
|
10729
11179
|
function isUnsafeAccessExpression(e) {
|
|
10730
11180
|
return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
|
|
@@ -10746,10 +11196,6 @@ function deepestSafeTernary(e) {
|
|
|
10746
11196
|
// TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
|
|
10747
11197
|
// instead to save some code size.
|
|
10748
11198
|
function safeTransform(e, ctx) {
|
|
10749
|
-
if (e instanceof SafeInvokeFunctionExpr) {
|
|
10750
|
-
// TODO: Implement safe function calls in a subsequent commit.
|
|
10751
|
-
return new InvokeFunctionExpr(e.receiver, e.args);
|
|
10752
|
-
}
|
|
10753
11199
|
if (!isAccessExpression(e)) {
|
|
10754
11200
|
return e;
|
|
10755
11201
|
}
|
|
@@ -10767,6 +11213,10 @@ function safeTransform(e, ctx) {
|
|
|
10767
11213
|
dst.expr = dst.expr.key(e.index);
|
|
10768
11214
|
return e.receiver;
|
|
10769
11215
|
}
|
|
11216
|
+
if (e instanceof SafeInvokeFunctionExpr) {
|
|
11217
|
+
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.callFn(e.args), ctx);
|
|
11218
|
+
return e.receiver;
|
|
11219
|
+
}
|
|
10770
11220
|
if (e instanceof SafePropertyReadExpr) {
|
|
10771
11221
|
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
|
|
10772
11222
|
return e.receiver;
|
|
@@ -10777,6 +11227,9 @@ function safeTransform(e, ctx) {
|
|
|
10777
11227
|
}
|
|
10778
11228
|
}
|
|
10779
11229
|
else {
|
|
11230
|
+
if (e instanceof SafeInvokeFunctionExpr) {
|
|
11231
|
+
return safeTernaryWithTemporary(e.receiver, (r) => r.callFn(e.args), ctx);
|
|
11232
|
+
}
|
|
10780
11233
|
if (e instanceof SafePropertyReadExpr) {
|
|
10781
11234
|
return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
|
|
10782
11235
|
}
|
|
@@ -10834,7 +11287,7 @@ function phaseGenerateAdvance(cpl) {
|
|
|
10834
11287
|
if (delta < 0) {
|
|
10835
11288
|
throw new Error(`AssertionError: slot counter should never need to move backwards`);
|
|
10836
11289
|
}
|
|
10837
|
-
OpList.insertBefore(createAdvanceOp(delta), op);
|
|
11290
|
+
OpList.insertBefore(createAdvanceOp(delta, op.sourceSpan), op);
|
|
10838
11291
|
slotContext = slot;
|
|
10839
11292
|
}
|
|
10840
11293
|
}
|
|
@@ -10872,7 +11325,7 @@ function recursivelyProcessView(view, parentScope) {
|
|
|
10872
11325
|
switch (op.kind) {
|
|
10873
11326
|
case OpKind.Template:
|
|
10874
11327
|
// Descend into child embedded views.
|
|
10875
|
-
recursivelyProcessView(view.
|
|
11328
|
+
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
10876
11329
|
break;
|
|
10877
11330
|
case OpKind.Listener:
|
|
10878
11331
|
// Prepend variables to listener handler functions.
|
|
@@ -10945,15 +11398,15 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
10945
11398
|
// Before generating variables for a parent view, we need to switch to the context of the parent
|
|
10946
11399
|
// view with a `nextContext` expression. This context switching operation itself declares a
|
|
10947
11400
|
// variable, because the context of the view may be referenced directly.
|
|
10948
|
-
newOps.push(createVariableOp(view.
|
|
11401
|
+
newOps.push(createVariableOp(view.job.allocateXrefId(), scope.viewContextVariable, new NextContextExpr()));
|
|
10949
11402
|
}
|
|
10950
11403
|
// Add variables for all context variables available in this scope's view.
|
|
10951
|
-
for (const [name, value] of view.
|
|
10952
|
-
newOps.push(createVariableOp(view.
|
|
11404
|
+
for (const [name, value] of view.job.views.get(scope.view).contextVariables) {
|
|
11405
|
+
newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), new ReadPropExpr(new ContextExpr(scope.view), value)));
|
|
10953
11406
|
}
|
|
10954
11407
|
// Add variables for all local references declared for elements in this scope.
|
|
10955
11408
|
for (const ref of scope.references) {
|
|
10956
|
-
newOps.push(createVariableOp(view.
|
|
11409
|
+
newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.offset)));
|
|
10957
11410
|
}
|
|
10958
11411
|
if (scope.parent !== null) {
|
|
10959
11412
|
// Recursively add variables from the parent scope.
|
|
@@ -10962,6 +11415,62 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
10962
11415
|
return newOps;
|
|
10963
11416
|
}
|
|
10964
11417
|
|
|
11418
|
+
const STYLE_DOT = 'style.';
|
|
11419
|
+
const CLASS_DOT = 'class.';
|
|
11420
|
+
function phaseHostStylePropertyParsing(job) {
|
|
11421
|
+
for (const op of job.update) {
|
|
11422
|
+
if (op.kind !== OpKind.Binding) {
|
|
11423
|
+
continue;
|
|
11424
|
+
}
|
|
11425
|
+
if (op.name.startsWith(STYLE_DOT)) {
|
|
11426
|
+
op.bindingKind = BindingKind.StyleProperty;
|
|
11427
|
+
op.name = op.name.substring(STYLE_DOT.length);
|
|
11428
|
+
if (isCssCustomProperty$1(op.name)) {
|
|
11429
|
+
op.name = hyphenate(op.name);
|
|
11430
|
+
}
|
|
11431
|
+
const { property, suffix } = parseProperty$1(op.name);
|
|
11432
|
+
op.name = property;
|
|
11433
|
+
op.unit = suffix;
|
|
11434
|
+
}
|
|
11435
|
+
else if (op.name.startsWith('style!')) {
|
|
11436
|
+
// TODO: do we only transform !important?
|
|
11437
|
+
op.name = 'style';
|
|
11438
|
+
}
|
|
11439
|
+
else if (op.name.startsWith(CLASS_DOT)) {
|
|
11440
|
+
op.bindingKind = BindingKind.ClassName;
|
|
11441
|
+
op.name = parseProperty$1(op.name.substring(CLASS_DOT.length)).property;
|
|
11442
|
+
}
|
|
11443
|
+
}
|
|
11444
|
+
}
|
|
11445
|
+
/**
|
|
11446
|
+
* Checks whether property name is a custom CSS property.
|
|
11447
|
+
* See: https://www.w3.org/TR/css-variables-1
|
|
11448
|
+
*/
|
|
11449
|
+
function isCssCustomProperty$1(name) {
|
|
11450
|
+
return name.startsWith('--');
|
|
11451
|
+
}
|
|
11452
|
+
function hyphenate(value) {
|
|
11453
|
+
return value
|
|
11454
|
+
.replace(/[a-z][A-Z]/g, v => {
|
|
11455
|
+
return v.charAt(0) + '-' + v.charAt(1);
|
|
11456
|
+
})
|
|
11457
|
+
.toLowerCase();
|
|
11458
|
+
}
|
|
11459
|
+
function parseProperty$1(name) {
|
|
11460
|
+
const overrideIndex = name.indexOf('!important');
|
|
11461
|
+
if (overrideIndex !== -1) {
|
|
11462
|
+
name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
|
|
11463
|
+
}
|
|
11464
|
+
let suffix = null;
|
|
11465
|
+
let property = name;
|
|
11466
|
+
const unitIndex = name.lastIndexOf('.');
|
|
11467
|
+
if (unitIndex > 0) {
|
|
11468
|
+
suffix = name.slice(unitIndex + 1);
|
|
11469
|
+
property = name.substring(0, unitIndex);
|
|
11470
|
+
}
|
|
11471
|
+
return { property, suffix };
|
|
11472
|
+
}
|
|
11473
|
+
|
|
10965
11474
|
/**
|
|
10966
11475
|
* Lifts local reference declarations on element-like structures within each view into an entry in
|
|
10967
11476
|
* the `consts` array for the whole component.
|
|
@@ -10998,82 +11507,62 @@ function serializeLocalRefs(refs) {
|
|
|
10998
11507
|
}
|
|
10999
11508
|
|
|
11000
11509
|
/**
|
|
11001
|
-
*
|
|
11002
|
-
*
|
|
11003
|
-
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
11004
|
-
* Example: `color: red; height: auto`.
|
|
11005
|
-
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
11006
|
-
* 'auto']`
|
|
11510
|
+
* Change namespaces between HTML, SVG and MathML, depending on the next element.
|
|
11007
11511
|
*/
|
|
11008
|
-
function
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
let currentProp = null;
|
|
11020
|
-
while (i < value.length) {
|
|
11021
|
-
const token = value.charCodeAt(i++);
|
|
11022
|
-
switch (token) {
|
|
11023
|
-
case 40 /* Char.OpenParen */:
|
|
11024
|
-
parenDepth++;
|
|
11025
|
-
break;
|
|
11026
|
-
case 41 /* Char.CloseParen */:
|
|
11027
|
-
parenDepth--;
|
|
11028
|
-
break;
|
|
11029
|
-
case 39 /* Char.QuoteSingle */:
|
|
11030
|
-
// valueStart needs to be there since prop values don't
|
|
11031
|
-
// have quotes in CSS
|
|
11032
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
11033
|
-
quote = 39 /* Char.QuoteSingle */;
|
|
11034
|
-
}
|
|
11035
|
-
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11036
|
-
quote = 0 /* Char.QuoteNone */;
|
|
11037
|
-
}
|
|
11038
|
-
break;
|
|
11039
|
-
case 34 /* Char.QuoteDouble */:
|
|
11040
|
-
// same logic as above
|
|
11041
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
11042
|
-
quote = 34 /* Char.QuoteDouble */;
|
|
11043
|
-
}
|
|
11044
|
-
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11045
|
-
quote = 0 /* Char.QuoteNone */;
|
|
11046
|
-
}
|
|
11047
|
-
break;
|
|
11048
|
-
case 58 /* Char.Colon */:
|
|
11049
|
-
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11050
|
-
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
11051
|
-
valueStart = i;
|
|
11052
|
-
}
|
|
11053
|
-
break;
|
|
11054
|
-
case 59 /* Char.Semicolon */:
|
|
11055
|
-
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11056
|
-
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
11057
|
-
styles.push(currentProp, styleVal);
|
|
11058
|
-
propStart = i;
|
|
11059
|
-
valueStart = 0;
|
|
11060
|
-
currentProp = null;
|
|
11061
|
-
}
|
|
11062
|
-
break;
|
|
11512
|
+
function phaseNamespace(job) {
|
|
11513
|
+
for (const [_, view] of job.views) {
|
|
11514
|
+
let activeNamespace = Namespace.HTML;
|
|
11515
|
+
for (const op of view.create) {
|
|
11516
|
+
if (op.kind !== OpKind.Element && op.kind !== OpKind.ElementStart) {
|
|
11517
|
+
continue;
|
|
11518
|
+
}
|
|
11519
|
+
if (op.namespace !== activeNamespace) {
|
|
11520
|
+
OpList.insertBefore(createNamespaceOp(op.namespace), op);
|
|
11521
|
+
activeNamespace = op.namespace;
|
|
11522
|
+
}
|
|
11063
11523
|
}
|
|
11064
11524
|
}
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11525
|
+
}
|
|
11526
|
+
|
|
11527
|
+
const BINARY_OPERATORS = new Map([
|
|
11528
|
+
['&&', BinaryOperator.And],
|
|
11529
|
+
['>', BinaryOperator.Bigger],
|
|
11530
|
+
['>=', BinaryOperator.BiggerEquals],
|
|
11531
|
+
['&', BinaryOperator.BitwiseAnd],
|
|
11532
|
+
['/', BinaryOperator.Divide],
|
|
11533
|
+
['==', BinaryOperator.Equals],
|
|
11534
|
+
['===', BinaryOperator.Identical],
|
|
11535
|
+
['<', BinaryOperator.Lower],
|
|
11536
|
+
['<=', BinaryOperator.LowerEquals],
|
|
11537
|
+
['-', BinaryOperator.Minus],
|
|
11538
|
+
['%', BinaryOperator.Modulo],
|
|
11539
|
+
['*', BinaryOperator.Multiply],
|
|
11540
|
+
['!=', BinaryOperator.NotEquals],
|
|
11541
|
+
['!==', BinaryOperator.NotIdentical],
|
|
11542
|
+
['??', BinaryOperator.NullishCoalesce],
|
|
11543
|
+
['||', BinaryOperator.Or],
|
|
11544
|
+
['+', BinaryOperator.Plus],
|
|
11545
|
+
]);
|
|
11546
|
+
const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
|
|
11547
|
+
function namespaceForKey(namespacePrefixKey) {
|
|
11548
|
+
if (namespacePrefixKey === null) {
|
|
11549
|
+
return Namespace.HTML;
|
|
11068
11550
|
}
|
|
11069
|
-
return
|
|
11551
|
+
return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
|
|
11070
11552
|
}
|
|
11071
|
-
function
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11553
|
+
function keyForNamespace(namespace) {
|
|
11554
|
+
for (const [k, n] of NAMESPACES.entries()) {
|
|
11555
|
+
if (n === namespace) {
|
|
11556
|
+
return k;
|
|
11557
|
+
}
|
|
11558
|
+
}
|
|
11559
|
+
return null; // No namespace prefix for HTML
|
|
11560
|
+
}
|
|
11561
|
+
function prefixWithNamespace(strippedTag, namespace) {
|
|
11562
|
+
if (namespace === Namespace.HTML) {
|
|
11563
|
+
return strippedTag;
|
|
11564
|
+
}
|
|
11565
|
+
return `:${keyForNamespace(namespace)}:${strippedTag}`;
|
|
11077
11566
|
}
|
|
11078
11567
|
|
|
11079
11568
|
/**
|
|
@@ -11082,41 +11571,53 @@ function hyphenate(value) {
|
|
|
11082
11571
|
* This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
|
|
11083
11572
|
* the reads can be emitted correctly.
|
|
11084
11573
|
*/
|
|
11085
|
-
function phaseNaming(cpl
|
|
11086
|
-
addNamesToView(cpl.root, cpl.componentName, { index: 0 }, compatibility);
|
|
11574
|
+
function phaseNaming(cpl) {
|
|
11575
|
+
addNamesToView(cpl.root, cpl.componentName, { index: 0 }, cpl.compatibility === CompatibilityMode.TemplateDefinitionBuilder);
|
|
11087
11576
|
}
|
|
11088
|
-
function addNamesToView(
|
|
11089
|
-
if (
|
|
11090
|
-
|
|
11577
|
+
function addNamesToView(unit, baseName, state, compatibility) {
|
|
11578
|
+
if (unit.fnName === null) {
|
|
11579
|
+
unit.fnName = sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`);
|
|
11091
11580
|
}
|
|
11092
11581
|
// Keep track of the names we assign to variables in the view. We'll need to propagate these
|
|
11093
11582
|
// into reads of those variables afterwards.
|
|
11094
11583
|
const varNames = new Map();
|
|
11095
|
-
for (const op of
|
|
11584
|
+
for (const op of unit.ops()) {
|
|
11096
11585
|
switch (op.kind) {
|
|
11586
|
+
case OpKind.Property:
|
|
11587
|
+
if (op.isAnimationTrigger) {
|
|
11588
|
+
op.name = '@' + op.name;
|
|
11589
|
+
}
|
|
11590
|
+
break;
|
|
11097
11591
|
case OpKind.Listener:
|
|
11098
11592
|
if (op.handlerFnName === null) {
|
|
11099
|
-
// TODO(alxhub): convert this temporary name to match how the
|
|
11100
|
-
// `TemplateDefinitionBuilder` names listener functions.
|
|
11101
11593
|
if (op.slot === null) {
|
|
11102
11594
|
throw new Error(`Expected a slot to be assigned`);
|
|
11103
11595
|
}
|
|
11104
|
-
op.
|
|
11105
|
-
|
|
11596
|
+
const safeTagName = op.tag.replace('-', '_');
|
|
11597
|
+
if (op.isAnimationListener) {
|
|
11598
|
+
op.handlerFnName = sanitizeIdentifier(`${unit.fnName}_${safeTagName}_animation_${op.name}_${op.animationPhase}_${op.slot}_listener`);
|
|
11599
|
+
op.name = `@${op.name}.${op.animationPhase}`;
|
|
11600
|
+
}
|
|
11601
|
+
else {
|
|
11602
|
+
op.handlerFnName =
|
|
11603
|
+
sanitizeIdentifier(`${unit.fnName}_${safeTagName}_${op.name}_${op.slot}_listener`);
|
|
11604
|
+
}
|
|
11106
11605
|
}
|
|
11107
11606
|
break;
|
|
11108
11607
|
case OpKind.Variable:
|
|
11109
11608
|
varNames.set(op.xref, getVariableName(op.variable, state));
|
|
11110
11609
|
break;
|
|
11111
11610
|
case OpKind.Template:
|
|
11112
|
-
|
|
11611
|
+
if (!(unit instanceof ViewCompilationUnit)) {
|
|
11612
|
+
throw new Error(`AssertionError: must be compiling a component`);
|
|
11613
|
+
}
|
|
11614
|
+
const childView = unit.job.views.get(op.xref);
|
|
11113
11615
|
if (op.slot === null) {
|
|
11114
11616
|
throw new Error(`Expected slot to be assigned`);
|
|
11115
11617
|
}
|
|
11116
|
-
addNamesToView(childView, `${baseName}_${op.tag}_${op.slot}`, state, compatibility);
|
|
11618
|
+
addNamesToView(childView, `${baseName}_${prefixWithNamespace(op.tag, op.namespace)}_${op.slot}`, state, compatibility);
|
|
11117
11619
|
break;
|
|
11118
11620
|
case OpKind.StyleProp:
|
|
11119
|
-
case OpKind.InterpolateStyleProp:
|
|
11120
11621
|
op.name = normalizeStylePropName(op.name);
|
|
11121
11622
|
if (compatibility) {
|
|
11122
11623
|
op.name = stripImportant(op.name);
|
|
@@ -11131,7 +11632,7 @@ function addNamesToView(view, baseName, state, compatibility) {
|
|
|
11131
11632
|
}
|
|
11132
11633
|
// Having named all variables declared in the view, now we can push those names into the
|
|
11133
11634
|
// `ir.ReadVariableExpr` expressions which represent reads of those variables.
|
|
11134
|
-
for (const op of
|
|
11635
|
+
for (const op of unit.ops()) {
|
|
11135
11636
|
visitExpressionsInOp(op, expr => {
|
|
11136
11637
|
if (!(expr instanceof ReadVariableExpr) || expr.name !== null) {
|
|
11137
11638
|
return;
|
|
@@ -11146,6 +11647,9 @@ function addNamesToView(view, baseName, state, compatibility) {
|
|
|
11146
11647
|
function getVariableName(variable, state) {
|
|
11147
11648
|
if (variable.name === null) {
|
|
11148
11649
|
switch (variable.kind) {
|
|
11650
|
+
case SemanticVariableKind.Context:
|
|
11651
|
+
variable.name = `ctx_r${state.index++}`;
|
|
11652
|
+
break;
|
|
11149
11653
|
case SemanticVariableKind.Identifier:
|
|
11150
11654
|
variable.name = `${variable.identifier}_${state.index++}`;
|
|
11151
11655
|
break;
|
|
@@ -11160,7 +11664,7 @@ function getVariableName(variable, state) {
|
|
|
11160
11664
|
* Normalizes a style prop name by hyphenating it (unless its a CSS variable).
|
|
11161
11665
|
*/
|
|
11162
11666
|
function normalizeStylePropName(name) {
|
|
11163
|
-
return name.startsWith('--') ? name : hyphenate(name);
|
|
11667
|
+
return name.startsWith('--') ? name : hyphenate$1(name);
|
|
11164
11668
|
}
|
|
11165
11669
|
/**
|
|
11166
11670
|
* Strips `!important` out of the given style or class name.
|
|
@@ -11257,15 +11761,82 @@ function phaseNgContainer(cpl) {
|
|
|
11257
11761
|
}
|
|
11258
11762
|
}
|
|
11259
11763
|
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11764
|
+
/**
|
|
11765
|
+
* Transforms special-case bindings with 'style' or 'class' in their names. Must run before the
|
|
11766
|
+
* main binding specialization pass.
|
|
11767
|
+
*/
|
|
11768
|
+
function phaseNoListenersOnTemplates(job) {
|
|
11769
|
+
for (const unit of job.units) {
|
|
11770
|
+
let inTemplate = false;
|
|
11771
|
+
for (const op of unit.create) {
|
|
11772
|
+
switch (op.kind) {
|
|
11773
|
+
case OpKind.Template:
|
|
11774
|
+
inTemplate = true;
|
|
11775
|
+
break;
|
|
11776
|
+
case OpKind.ElementStart:
|
|
11777
|
+
case OpKind.Element:
|
|
11778
|
+
case OpKind.ContainerStart:
|
|
11779
|
+
case OpKind.Container:
|
|
11780
|
+
inTemplate = false;
|
|
11781
|
+
break;
|
|
11782
|
+
case OpKind.Listener:
|
|
11783
|
+
if (inTemplate) {
|
|
11784
|
+
OpList.remove(op);
|
|
11785
|
+
}
|
|
11786
|
+
break;
|
|
11787
|
+
}
|
|
11788
|
+
}
|
|
11789
|
+
}
|
|
11790
|
+
}
|
|
11791
|
+
|
|
11792
|
+
/**
|
|
11793
|
+
* Looks up an element in the given map by xref ID.
|
|
11794
|
+
*/
|
|
11795
|
+
function lookupElement(elements, xref) {
|
|
11796
|
+
const el = elements.get(xref);
|
|
11797
|
+
if (el === undefined) {
|
|
11798
|
+
throw new Error('All attributes should have an element-like target.');
|
|
11799
|
+
}
|
|
11800
|
+
return el;
|
|
11801
|
+
}
|
|
11802
|
+
/**
|
|
11803
|
+
* When a container is marked with `ngNonBindable`, the non-bindable characteristic also applies to
|
|
11804
|
+
* all descendants of that container. Therefore, we must emit `disableBindings` and `enableBindings`
|
|
11805
|
+
* instructions for every such container.
|
|
11806
|
+
*/
|
|
11807
|
+
function phaseNonbindable(job) {
|
|
11808
|
+
const elements = new Map();
|
|
11809
|
+
for (const view of job.units) {
|
|
11810
|
+
for (const op of view.create) {
|
|
11811
|
+
if (!isElementOrContainerOp(op)) {
|
|
11812
|
+
continue;
|
|
11813
|
+
}
|
|
11814
|
+
elements.set(op.xref, op);
|
|
11815
|
+
}
|
|
11816
|
+
}
|
|
11817
|
+
for (const [_, view] of job.views) {
|
|
11818
|
+
for (const op of view.create) {
|
|
11819
|
+
if ((op.kind === OpKind.ElementStart || op.kind === OpKind.ContainerStart) &&
|
|
11820
|
+
op.nonBindable) {
|
|
11821
|
+
OpList.insertAfter(createDisableBindingsOp(op.xref), op);
|
|
11822
|
+
}
|
|
11823
|
+
if ((op.kind === OpKind.ElementEnd || op.kind === OpKind.ContainerEnd) &&
|
|
11824
|
+
lookupElement(elements, op.xref).nonBindable) {
|
|
11825
|
+
OpList.insertBefore(createEnableBindingsOp(op.xref), op);
|
|
11826
|
+
}
|
|
11827
|
+
}
|
|
11828
|
+
}
|
|
11829
|
+
}
|
|
11830
|
+
|
|
11831
|
+
function phaseNullishCoalescing(job) {
|
|
11832
|
+
for (const unit of job.units) {
|
|
11833
|
+
for (const op of unit.ops()) {
|
|
11263
11834
|
transformExpressionsInOp(op, expr => {
|
|
11264
11835
|
if (!(expr instanceof BinaryOperatorExpr) ||
|
|
11265
11836
|
expr.operator !== BinaryOperator.NullishCoalesce) {
|
|
11266
11837
|
return expr;
|
|
11267
11838
|
}
|
|
11268
|
-
const assignment = new AssignTemporaryExpr(expr.lhs.clone(),
|
|
11839
|
+
const assignment = new AssignTemporaryExpr(expr.lhs.clone(), job.allocateXrefId());
|
|
11269
11840
|
const read = new ReadTemporaryExpr(assignment.xref);
|
|
11270
11841
|
// TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
|
|
11271
11842
|
// `t != null` instead of including an undefined check as well.
|
|
@@ -11341,23 +11912,40 @@ function phasePipeVariadic(cpl) {
|
|
|
11341
11912
|
}
|
|
11342
11913
|
}
|
|
11343
11914
|
|
|
11915
|
+
function kindTest(kind) {
|
|
11916
|
+
return (op) => op.kind === kind;
|
|
11917
|
+
}
|
|
11344
11918
|
/**
|
|
11345
11919
|
* Defines the groups based on `OpKind` that ops will be divided into. Ops will be collected into
|
|
11346
11920
|
* groups, then optionally transformed, before recombining the groups in the order defined here.
|
|
11347
11921
|
*/
|
|
11348
11922
|
const ORDERING = [
|
|
11349
|
-
{
|
|
11350
|
-
{
|
|
11351
|
-
{
|
|
11352
|
-
{
|
|
11353
|
-
{
|
|
11354
|
-
|
|
11355
|
-
|
|
11923
|
+
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
11924
|
+
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
11925
|
+
{ test: kindTest(OpKind.StyleProp) },
|
|
11926
|
+
{ test: kindTest(OpKind.ClassProp) },
|
|
11927
|
+
{
|
|
11928
|
+
test: (op) => (op.kind === OpKind.Property || op.kind === OpKind.HostProperty) &&
|
|
11929
|
+
op.expression instanceof Interpolation
|
|
11930
|
+
},
|
|
11931
|
+
{
|
|
11932
|
+
test: (op) => (op.kind === OpKind.Property || op.kind === OpKind.HostProperty) &&
|
|
11933
|
+
!(op.expression instanceof Interpolation)
|
|
11934
|
+
},
|
|
11935
|
+
{ test: kindTest(OpKind.Attribute) },
|
|
11356
11936
|
];
|
|
11357
11937
|
/**
|
|
11358
11938
|
* The set of all op kinds we handle in the reordering phase.
|
|
11359
11939
|
*/
|
|
11360
|
-
const handledOpKinds = new Set(
|
|
11940
|
+
const handledOpKinds = new Set([
|
|
11941
|
+
OpKind.StyleMap,
|
|
11942
|
+
OpKind.ClassMap,
|
|
11943
|
+
OpKind.StyleProp,
|
|
11944
|
+
OpKind.ClassProp,
|
|
11945
|
+
OpKind.Property,
|
|
11946
|
+
OpKind.HostProperty,
|
|
11947
|
+
OpKind.Attribute,
|
|
11948
|
+
]);
|
|
11361
11949
|
/**
|
|
11362
11950
|
* Reorders property and attribute ops according to the following ordering:
|
|
11363
11951
|
* 1. styleMap & styleMapInterpolate (drops all but the last op in the group)
|
|
@@ -11369,9 +11957,9 @@ const handledOpKinds = new Set(ORDERING.flatMap(group => [...group.kinds]));
|
|
|
11369
11957
|
* 7. attribute & attributeInterpolate (ordering preserve within group)
|
|
11370
11958
|
*/
|
|
11371
11959
|
function phasePropertyOrdering(cpl) {
|
|
11372
|
-
for (const
|
|
11960
|
+
for (const unit of cpl.units) {
|
|
11373
11961
|
let opsToOrder = [];
|
|
11374
|
-
for (const op of
|
|
11962
|
+
for (const op of unit.update) {
|
|
11375
11963
|
if (handledOpKinds.has(op.kind)) {
|
|
11376
11964
|
// Pull out ops that need o be ordered.
|
|
11377
11965
|
opsToOrder.push(op);
|
|
@@ -11388,7 +11976,7 @@ function phasePropertyOrdering(cpl) {
|
|
|
11388
11976
|
}
|
|
11389
11977
|
// If we still have ops pulled at the end, put them back in the correct order.
|
|
11390
11978
|
for (const orderedOp of reorder(opsToOrder)) {
|
|
11391
|
-
|
|
11979
|
+
unit.update.push(orderedOp);
|
|
11392
11980
|
}
|
|
11393
11981
|
}
|
|
11394
11982
|
}
|
|
@@ -11399,7 +11987,7 @@ function reorder(ops) {
|
|
|
11399
11987
|
// Break the ops list into groups based on OpKind.
|
|
11400
11988
|
const groups = Array.from(ORDERING, () => new Array());
|
|
11401
11989
|
for (const op of ops) {
|
|
11402
|
-
const groupIndex = ORDERING.findIndex(o => o.
|
|
11990
|
+
const groupIndex = ORDERING.findIndex(o => o.test(op));
|
|
11403
11991
|
groups[groupIndex].push(op);
|
|
11404
11992
|
}
|
|
11405
11993
|
// Reassemble the groups into a single list, in the correct order.
|
|
@@ -11415,15 +12003,15 @@ function keepLast(ops) {
|
|
|
11415
12003
|
return ops.slice(ops.length - 1);
|
|
11416
12004
|
}
|
|
11417
12005
|
|
|
11418
|
-
function phasePureFunctionExtraction(
|
|
11419
|
-
for (const view of
|
|
12006
|
+
function phasePureFunctionExtraction(job) {
|
|
12007
|
+
for (const view of job.units) {
|
|
11420
12008
|
for (const op of view.ops()) {
|
|
11421
12009
|
visitExpressionsInOp(op, expr => {
|
|
11422
12010
|
if (!(expr instanceof PureFunctionExpr) || expr.body === null) {
|
|
11423
12011
|
return;
|
|
11424
12012
|
}
|
|
11425
12013
|
const constantDef = new PureFunctionConstant(expr.args.length);
|
|
11426
|
-
expr.fn =
|
|
12014
|
+
expr.fn = job.pool.getSharedConstant(constantDef, expr.body);
|
|
11427
12015
|
expr.body = null;
|
|
11428
12016
|
});
|
|
11429
12017
|
}
|
|
@@ -11459,8 +12047,8 @@ class PureFunctionConstant extends GenericKeyFn {
|
|
|
11459
12047
|
}
|
|
11460
12048
|
}
|
|
11461
12049
|
|
|
11462
|
-
function phasePureLiteralStructures(
|
|
11463
|
-
for (const view of
|
|
12050
|
+
function phasePureLiteralStructures(job) {
|
|
12051
|
+
for (const view of job.units) {
|
|
11464
12052
|
for (const op of view.update) {
|
|
11465
12053
|
transformExpressionsInOp(op, (expr, flags) => {
|
|
11466
12054
|
if (flags & VisitorContextFlag.InChildOperation) {
|
|
@@ -11511,13 +12099,13 @@ function transformLiteralMap(expr) {
|
|
|
11511
12099
|
// This file contains helpers for generating calls to Ivy instructions. In particular, each
|
|
11512
12100
|
// instruction type is represented as a function, which may select a specific instruction variant
|
|
11513
12101
|
// depending on the exact arguments.
|
|
11514
|
-
function element(slot, tag, constIndex, localRefIndex) {
|
|
11515
|
-
return elementOrContainerBase(Identifiers.element, slot, tag, constIndex, localRefIndex);
|
|
12102
|
+
function element(slot, tag, constIndex, localRefIndex, sourceSpan) {
|
|
12103
|
+
return elementOrContainerBase(Identifiers.element, slot, tag, constIndex, localRefIndex, sourceSpan);
|
|
11516
12104
|
}
|
|
11517
|
-
function elementStart(slot, tag, constIndex, localRefIndex) {
|
|
11518
|
-
return elementOrContainerBase(Identifiers.elementStart, slot, tag, constIndex, localRefIndex);
|
|
12105
|
+
function elementStart(slot, tag, constIndex, localRefIndex, sourceSpan) {
|
|
12106
|
+
return elementOrContainerBase(Identifiers.elementStart, slot, tag, constIndex, localRefIndex, sourceSpan);
|
|
11519
12107
|
}
|
|
11520
|
-
function elementOrContainerBase(instruction, slot, tag, constIndex, localRefIndex) {
|
|
12108
|
+
function elementOrContainerBase(instruction, slot, tag, constIndex, localRefIndex, sourceSpan) {
|
|
11521
12109
|
const args = [literal(slot)];
|
|
11522
12110
|
if (tag !== null) {
|
|
11523
12111
|
args.push(literal(tag));
|
|
@@ -11529,21 +12117,21 @@ function elementOrContainerBase(instruction, slot, tag, constIndex, localRefInde
|
|
|
11529
12117
|
else if (constIndex !== null) {
|
|
11530
12118
|
args.push(literal(constIndex));
|
|
11531
12119
|
}
|
|
11532
|
-
return call(instruction, args);
|
|
12120
|
+
return call(instruction, args, sourceSpan);
|
|
11533
12121
|
}
|
|
11534
|
-
function elementEnd() {
|
|
11535
|
-
return call(Identifiers.elementEnd, []);
|
|
12122
|
+
function elementEnd(sourceSpan) {
|
|
12123
|
+
return call(Identifiers.elementEnd, [], sourceSpan);
|
|
11536
12124
|
}
|
|
11537
|
-
function elementContainerStart(slot, constIndex, localRefIndex) {
|
|
11538
|
-
return elementOrContainerBase(Identifiers.elementContainerStart, slot, /* tag */ null, constIndex, localRefIndex);
|
|
12125
|
+
function elementContainerStart(slot, constIndex, localRefIndex, sourceSpan) {
|
|
12126
|
+
return elementOrContainerBase(Identifiers.elementContainerStart, slot, /* tag */ null, constIndex, localRefIndex, sourceSpan);
|
|
11539
12127
|
}
|
|
11540
|
-
function elementContainer(slot, constIndex, localRefIndex) {
|
|
11541
|
-
return elementOrContainerBase(Identifiers.elementContainer, slot, /* tag */ null, constIndex, localRefIndex);
|
|
12128
|
+
function elementContainer(slot, constIndex, localRefIndex, sourceSpan) {
|
|
12129
|
+
return elementOrContainerBase(Identifiers.elementContainer, slot, /* tag */ null, constIndex, localRefIndex, sourceSpan);
|
|
11542
12130
|
}
|
|
11543
12131
|
function elementContainerEnd() {
|
|
11544
|
-
return call(Identifiers.elementContainerEnd, []);
|
|
12132
|
+
return call(Identifiers.elementContainerEnd, [], null);
|
|
11545
12133
|
}
|
|
11546
|
-
function template(slot, templateFnRef, decls, vars, tag, constIndex) {
|
|
12134
|
+
function template(slot, templateFnRef, decls, vars, tag, constIndex, sourceSpan) {
|
|
11547
12135
|
return call(Identifiers.templateCreate, [
|
|
11548
12136
|
literal(slot),
|
|
11549
12137
|
templateFnRef,
|
|
@@ -11551,24 +12139,39 @@ function template(slot, templateFnRef, decls, vars, tag, constIndex) {
|
|
|
11551
12139
|
literal(vars),
|
|
11552
12140
|
literal(tag),
|
|
11553
12141
|
literal(constIndex),
|
|
11554
|
-
]);
|
|
12142
|
+
], sourceSpan);
|
|
12143
|
+
}
|
|
12144
|
+
function disableBindings() {
|
|
12145
|
+
return call(Identifiers.disableBindings, [], null);
|
|
12146
|
+
}
|
|
12147
|
+
function enableBindings() {
|
|
12148
|
+
return call(Identifiers.enableBindings, [], null);
|
|
11555
12149
|
}
|
|
11556
12150
|
function listener(name, handlerFn) {
|
|
11557
12151
|
return call(Identifiers.listener, [
|
|
11558
12152
|
literal(name),
|
|
11559
12153
|
handlerFn,
|
|
11560
|
-
]);
|
|
12154
|
+
], null);
|
|
11561
12155
|
}
|
|
11562
12156
|
function pipe(slot, name) {
|
|
11563
12157
|
return call(Identifiers.pipe, [
|
|
11564
12158
|
literal(slot),
|
|
11565
12159
|
literal(name),
|
|
11566
|
-
]);
|
|
12160
|
+
], null);
|
|
12161
|
+
}
|
|
12162
|
+
function namespaceHTML() {
|
|
12163
|
+
return call(Identifiers.namespaceHTML, [], null);
|
|
12164
|
+
}
|
|
12165
|
+
function namespaceSVG() {
|
|
12166
|
+
return call(Identifiers.namespaceSVG, [], null);
|
|
11567
12167
|
}
|
|
11568
|
-
function
|
|
12168
|
+
function namespaceMath() {
|
|
12169
|
+
return call(Identifiers.namespaceMathML, [], null);
|
|
12170
|
+
}
|
|
12171
|
+
function advance(delta, sourceSpan) {
|
|
11569
12172
|
return call(Identifiers.advance, [
|
|
11570
12173
|
literal(delta),
|
|
11571
|
-
]);
|
|
12174
|
+
], sourceSpan);
|
|
11572
12175
|
}
|
|
11573
12176
|
function reference(slot) {
|
|
11574
12177
|
return importExpr(Identifiers.reference).callFn([
|
|
@@ -11591,37 +12194,42 @@ function resetView(returnValue) {
|
|
|
11591
12194
|
returnValue,
|
|
11592
12195
|
]);
|
|
11593
12196
|
}
|
|
11594
|
-
function text(slot, initialValue) {
|
|
11595
|
-
const args = [literal(slot)];
|
|
12197
|
+
function text(slot, initialValue, sourceSpan) {
|
|
12198
|
+
const args = [literal(slot, null)];
|
|
11596
12199
|
if (initialValue !== '') {
|
|
11597
12200
|
args.push(literal(initialValue));
|
|
11598
12201
|
}
|
|
11599
|
-
return call(Identifiers.text, args);
|
|
12202
|
+
return call(Identifiers.text, args, sourceSpan);
|
|
11600
12203
|
}
|
|
11601
|
-
function property(name, expression) {
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
12204
|
+
function property(name, expression, sanitizer, sourceSpan) {
|
|
12205
|
+
const args = [literal(name), expression];
|
|
12206
|
+
if (sanitizer !== null) {
|
|
12207
|
+
args.push(sanitizer);
|
|
12208
|
+
}
|
|
12209
|
+
return call(Identifiers.property, args, sourceSpan);
|
|
11606
12210
|
}
|
|
11607
|
-
function attribute(name, expression) {
|
|
11608
|
-
|
|
12211
|
+
function attribute(name, expression, sanitizer) {
|
|
12212
|
+
const args = [literal(name), expression];
|
|
12213
|
+
if (sanitizer !== null) {
|
|
12214
|
+
args.push(sanitizer);
|
|
12215
|
+
}
|
|
12216
|
+
return call(Identifiers.attribute, args, null);
|
|
11609
12217
|
}
|
|
11610
12218
|
function styleProp(name, expression, unit) {
|
|
11611
12219
|
const args = [literal(name), expression];
|
|
11612
12220
|
if (unit !== null) {
|
|
11613
12221
|
args.push(literal(unit));
|
|
11614
12222
|
}
|
|
11615
|
-
return call(Identifiers.styleProp, args);
|
|
12223
|
+
return call(Identifiers.styleProp, args, null);
|
|
11616
12224
|
}
|
|
11617
12225
|
function classProp(name, expression) {
|
|
11618
|
-
return call(Identifiers.classProp, [literal(name), expression]);
|
|
12226
|
+
return call(Identifiers.classProp, [literal(name), expression], null);
|
|
11619
12227
|
}
|
|
11620
12228
|
function styleMap(expression) {
|
|
11621
|
-
return call(Identifiers.styleMap, [expression]);
|
|
12229
|
+
return call(Identifiers.styleMap, [expression], null);
|
|
11622
12230
|
}
|
|
11623
12231
|
function classMap(expression) {
|
|
11624
|
-
return call(Identifiers.classMap, [expression]);
|
|
12232
|
+
return call(Identifiers.classMap, [expression], null);
|
|
11625
12233
|
}
|
|
11626
12234
|
const PIPE_BINDINGS = [
|
|
11627
12235
|
Identifiers.pipeBind1,
|
|
@@ -11647,7 +12255,7 @@ function pipeBindV(slot, varOffset, args) {
|
|
|
11647
12255
|
args,
|
|
11648
12256
|
]);
|
|
11649
12257
|
}
|
|
11650
|
-
function textInterpolate(strings, expressions) {
|
|
12258
|
+
function textInterpolate(strings, expressions, sourceSpan) {
|
|
11651
12259
|
if (strings.length < 1 || expressions.length !== strings.length - 1) {
|
|
11652
12260
|
throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
|
|
11653
12261
|
}
|
|
@@ -11663,15 +12271,23 @@ function textInterpolate(strings, expressions) {
|
|
|
11663
12271
|
// idx points at the last string.
|
|
11664
12272
|
interpolationArgs.push(literal(strings[idx]));
|
|
11665
12273
|
}
|
|
11666
|
-
return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
12274
|
+
return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
|
|
11667
12275
|
}
|
|
11668
|
-
function propertyInterpolate(name, strings, expressions) {
|
|
12276
|
+
function propertyInterpolate(name, strings, expressions, sanitizer, sourceSpan) {
|
|
11669
12277
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11670
|
-
|
|
12278
|
+
const extraArgs = [];
|
|
12279
|
+
if (sanitizer !== null) {
|
|
12280
|
+
extraArgs.push(sanitizer);
|
|
12281
|
+
}
|
|
12282
|
+
return callVariadicInstruction(PROPERTY_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, sourceSpan);
|
|
11671
12283
|
}
|
|
11672
|
-
function attributeInterpolate(name, strings, expressions) {
|
|
12284
|
+
function attributeInterpolate(name, strings, expressions, sanitizer) {
|
|
11673
12285
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11674
|
-
|
|
12286
|
+
const extraArgs = [];
|
|
12287
|
+
if (sanitizer !== null) {
|
|
12288
|
+
extraArgs.push(sanitizer);
|
|
12289
|
+
}
|
|
12290
|
+
return callVariadicInstruction(ATTRIBUTE_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, null);
|
|
11675
12291
|
}
|
|
11676
12292
|
function stylePropInterpolate(name, strings, expressions, unit) {
|
|
11677
12293
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
@@ -11679,21 +12295,24 @@ function stylePropInterpolate(name, strings, expressions, unit) {
|
|
|
11679
12295
|
if (unit !== null) {
|
|
11680
12296
|
extraArgs.push(literal(unit));
|
|
11681
12297
|
}
|
|
11682
|
-
return callVariadicInstruction(STYLE_PROP_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs);
|
|
12298
|
+
return callVariadicInstruction(STYLE_PROP_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, null);
|
|
11683
12299
|
}
|
|
11684
12300
|
function styleMapInterpolate(strings, expressions) {
|
|
11685
12301
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11686
|
-
return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
12302
|
+
return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], null);
|
|
11687
12303
|
}
|
|
11688
12304
|
function classMapInterpolate(strings, expressions) {
|
|
11689
12305
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11690
|
-
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
12306
|
+
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], null);
|
|
12307
|
+
}
|
|
12308
|
+
function hostProperty(name, expression) {
|
|
12309
|
+
return call(Identifiers.hostProperty, [literal(name), expression], null);
|
|
11691
12310
|
}
|
|
11692
12311
|
function pureFunction(varOffset, fn, args) {
|
|
11693
12312
|
return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
|
|
11694
12313
|
literal(varOffset),
|
|
11695
12314
|
fn,
|
|
11696
|
-
], args);
|
|
12315
|
+
], args, [], null);
|
|
11697
12316
|
}
|
|
11698
12317
|
/**
|
|
11699
12318
|
* Collates the string an expression arguments for an interpolation instruction.
|
|
@@ -11716,8 +12335,9 @@ function collateInterpolationArgs(strings, expressions) {
|
|
|
11716
12335
|
}
|
|
11717
12336
|
return interpolationArgs;
|
|
11718
12337
|
}
|
|
11719
|
-
function call(instruction, args) {
|
|
11720
|
-
|
|
12338
|
+
function call(instruction, args, sourceSpan) {
|
|
12339
|
+
const expr = importExpr(instruction).callFn(args, sourceSpan);
|
|
12340
|
+
return createStatementOp(new ExpressionStatement(expr, sourceSpan));
|
|
11721
12341
|
}
|
|
11722
12342
|
/**
|
|
11723
12343
|
* `InterpolationConfig` for the `textInterpolate` instruction.
|
|
@@ -11872,28 +12492,37 @@ const PURE_FUNCTION_CONFIG = {
|
|
|
11872
12492
|
variable: Identifiers.pureFunctionV,
|
|
11873
12493
|
mapping: n => n,
|
|
11874
12494
|
};
|
|
11875
|
-
function callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs
|
|
12495
|
+
function callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan) {
|
|
11876
12496
|
const n = config.mapping(interpolationArgs.length);
|
|
11877
12497
|
if (n < config.constant.length) {
|
|
11878
12498
|
// Constant calling pattern.
|
|
11879
|
-
return importExpr(config.constant[n])
|
|
11880
|
-
...baseArgs, ...interpolationArgs, ...extraArgs
|
|
11881
|
-
]);
|
|
12499
|
+
return importExpr(config.constant[n])
|
|
12500
|
+
.callFn([...baseArgs, ...interpolationArgs, ...extraArgs], sourceSpan);
|
|
11882
12501
|
}
|
|
11883
12502
|
else if (config.variable !== null) {
|
|
11884
12503
|
// Variable calling pattern.
|
|
11885
|
-
return importExpr(config.variable)
|
|
11886
|
-
...baseArgs, literalArr(interpolationArgs), ...extraArgs
|
|
11887
|
-
]);
|
|
12504
|
+
return importExpr(config.variable)
|
|
12505
|
+
.callFn([...baseArgs, literalArr(interpolationArgs), ...extraArgs], sourceSpan);
|
|
11888
12506
|
}
|
|
11889
12507
|
else {
|
|
11890
12508
|
throw new Error(`AssertionError: unable to call variadic function`);
|
|
11891
12509
|
}
|
|
11892
12510
|
}
|
|
11893
|
-
function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs
|
|
11894
|
-
return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs)
|
|
12511
|
+
function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs, sourceSpan) {
|
|
12512
|
+
return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan)
|
|
12513
|
+
.toStmt());
|
|
11895
12514
|
}
|
|
11896
12515
|
|
|
12516
|
+
/**
|
|
12517
|
+
* Map of sanitizers to their identifier.
|
|
12518
|
+
*/
|
|
12519
|
+
const sanitizerIdentifierMap = new Map([
|
|
12520
|
+
[SanitizerFn.Html, Identifiers.sanitizeHtml],
|
|
12521
|
+
[SanitizerFn.IframeAttribute, Identifiers.validateIframeAttribute],
|
|
12522
|
+
[SanitizerFn.ResourceUrl, Identifiers.sanitizeResourceUrl],
|
|
12523
|
+
[SanitizerFn.Script, Identifiers.sanitizeScript],
|
|
12524
|
+
[SanitizerFn.Style, Identifiers.sanitizeStyle], [SanitizerFn.Url, Identifiers.sanitizeUrl]
|
|
12525
|
+
]);
|
|
11897
12526
|
/**
|
|
11898
12527
|
* Compiles semantic operations across all views and generates output `o.Statement`s with actual
|
|
11899
12528
|
* runtime calls in their place.
|
|
@@ -11903,45 +12532,54 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs
|
|
|
11903
12532
|
* `ir.StatementOp`s (which wrap generated `o.Statement`s).
|
|
11904
12533
|
*/
|
|
11905
12534
|
function phaseReify(cpl) {
|
|
11906
|
-
for (const
|
|
11907
|
-
reifyCreateOperations(
|
|
11908
|
-
reifyUpdateOperations(
|
|
12535
|
+
for (const unit of cpl.units) {
|
|
12536
|
+
reifyCreateOperations(unit, unit.create);
|
|
12537
|
+
reifyUpdateOperations(unit, unit.update);
|
|
11909
12538
|
}
|
|
11910
12539
|
}
|
|
11911
|
-
function reifyCreateOperations(
|
|
12540
|
+
function reifyCreateOperations(unit, ops) {
|
|
11912
12541
|
for (const op of ops) {
|
|
11913
12542
|
transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
|
|
11914
12543
|
switch (op.kind) {
|
|
11915
12544
|
case OpKind.Text:
|
|
11916
|
-
OpList.replace(op, text(op.slot, op.initialValue));
|
|
12545
|
+
OpList.replace(op, text(op.slot, op.initialValue, op.sourceSpan));
|
|
11917
12546
|
break;
|
|
11918
12547
|
case OpKind.ElementStart:
|
|
11919
|
-
OpList.replace(op, elementStart(op.slot, op.tag, op.attributes, op.localRefs));
|
|
12548
|
+
OpList.replace(op, elementStart(op.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
11920
12549
|
break;
|
|
11921
12550
|
case OpKind.Element:
|
|
11922
|
-
OpList.replace(op, element(op.slot, op.tag, op.attributes, op.localRefs));
|
|
12551
|
+
OpList.replace(op, element(op.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
11923
12552
|
break;
|
|
11924
12553
|
case OpKind.ElementEnd:
|
|
11925
|
-
OpList.replace(op, elementEnd());
|
|
12554
|
+
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
11926
12555
|
break;
|
|
11927
12556
|
case OpKind.ContainerStart:
|
|
11928
|
-
OpList.replace(op, elementContainerStart(op.slot, op.attributes, op.localRefs));
|
|
12557
|
+
OpList.replace(op, elementContainerStart(op.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
11929
12558
|
break;
|
|
11930
12559
|
case OpKind.Container:
|
|
11931
|
-
OpList.replace(op, elementContainer(op.slot, op.attributes, op.localRefs));
|
|
12560
|
+
OpList.replace(op, elementContainer(op.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
11932
12561
|
break;
|
|
11933
12562
|
case OpKind.ContainerEnd:
|
|
11934
12563
|
OpList.replace(op, elementContainerEnd());
|
|
11935
12564
|
break;
|
|
11936
12565
|
case OpKind.Template:
|
|
11937
|
-
|
|
11938
|
-
|
|
12566
|
+
if (!(unit instanceof ViewCompilationUnit)) {
|
|
12567
|
+
throw new Error(`AssertionError: must be compiling a component`);
|
|
12568
|
+
}
|
|
12569
|
+
const childView = unit.job.views.get(op.xref);
|
|
12570
|
+
OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.sourceSpan));
|
|
12571
|
+
break;
|
|
12572
|
+
case OpKind.DisableBindings:
|
|
12573
|
+
OpList.replace(op, disableBindings());
|
|
12574
|
+
break;
|
|
12575
|
+
case OpKind.EnableBindings:
|
|
12576
|
+
OpList.replace(op, enableBindings());
|
|
11939
12577
|
break;
|
|
11940
12578
|
case OpKind.Pipe:
|
|
11941
12579
|
OpList.replace(op, pipe(op.slot, op.name));
|
|
11942
12580
|
break;
|
|
11943
12581
|
case OpKind.Listener:
|
|
11944
|
-
const listenerFn = reifyListenerHandler(
|
|
12582
|
+
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
11945
12583
|
OpList.replace(op, listener(op.name, listenerFn));
|
|
11946
12584
|
break;
|
|
11947
12585
|
case OpKind.Variable:
|
|
@@ -11950,6 +12588,19 @@ function reifyCreateOperations(view, ops) {
|
|
|
11950
12588
|
}
|
|
11951
12589
|
OpList.replace(op, createStatementOp(new DeclareVarStmt(op.variable.name, op.initializer, undefined, StmtModifier.Final)));
|
|
11952
12590
|
break;
|
|
12591
|
+
case OpKind.Namespace:
|
|
12592
|
+
switch (op.active) {
|
|
12593
|
+
case Namespace.HTML:
|
|
12594
|
+
OpList.replace(op, namespaceHTML());
|
|
12595
|
+
break;
|
|
12596
|
+
case Namespace.SVG:
|
|
12597
|
+
OpList.replace(op, namespaceSVG());
|
|
12598
|
+
break;
|
|
12599
|
+
case Namespace.Math:
|
|
12600
|
+
OpList.replace(op, namespaceMath());
|
|
12601
|
+
break;
|
|
12602
|
+
}
|
|
12603
|
+
break;
|
|
11953
12604
|
case OpKind.Statement:
|
|
11954
12605
|
// Pass statement operations directly through.
|
|
11955
12606
|
break;
|
|
@@ -11958,48 +12609,66 @@ function reifyCreateOperations(view, ops) {
|
|
|
11958
12609
|
}
|
|
11959
12610
|
}
|
|
11960
12611
|
}
|
|
11961
|
-
function reifyUpdateOperations(
|
|
12612
|
+
function reifyUpdateOperations(_unit, ops) {
|
|
11962
12613
|
for (const op of ops) {
|
|
11963
12614
|
transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
|
|
11964
12615
|
switch (op.kind) {
|
|
11965
12616
|
case OpKind.Advance:
|
|
11966
|
-
OpList.replace(op, advance(op.delta));
|
|
12617
|
+
OpList.replace(op, advance(op.delta, op.sourceSpan));
|
|
11967
12618
|
break;
|
|
11968
12619
|
case OpKind.Property:
|
|
11969
|
-
|
|
12620
|
+
if (op.expression instanceof Interpolation) {
|
|
12621
|
+
OpList.replace(op, propertyInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer, op.sourceSpan));
|
|
12622
|
+
}
|
|
12623
|
+
else {
|
|
12624
|
+
OpList.replace(op, property(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
12625
|
+
}
|
|
11970
12626
|
break;
|
|
11971
12627
|
case OpKind.StyleProp:
|
|
11972
|
-
|
|
12628
|
+
if (op.expression instanceof Interpolation) {
|
|
12629
|
+
OpList.replace(op, stylePropInterpolate(op.name, op.expression.strings, op.expression.expressions, op.unit));
|
|
12630
|
+
}
|
|
12631
|
+
else {
|
|
12632
|
+
OpList.replace(op, styleProp(op.name, op.expression, op.unit));
|
|
12633
|
+
}
|
|
11973
12634
|
break;
|
|
11974
12635
|
case OpKind.ClassProp:
|
|
11975
12636
|
OpList.replace(op, classProp(op.name, op.expression));
|
|
11976
12637
|
break;
|
|
11977
12638
|
case OpKind.StyleMap:
|
|
11978
|
-
|
|
12639
|
+
if (op.expression instanceof Interpolation) {
|
|
12640
|
+
OpList.replace(op, styleMapInterpolate(op.expression.strings, op.expression.expressions));
|
|
12641
|
+
}
|
|
12642
|
+
else {
|
|
12643
|
+
OpList.replace(op, styleMap(op.expression));
|
|
12644
|
+
}
|
|
11979
12645
|
break;
|
|
11980
12646
|
case OpKind.ClassMap:
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
OpList.replace(op, stylePropInterpolate(op.name, op.strings, op.expressions, op.unit));
|
|
11988
|
-
break;
|
|
11989
|
-
case OpKind.InterpolateStyleMap:
|
|
11990
|
-
OpList.replace(op, styleMapInterpolate(op.strings, op.expressions));
|
|
11991
|
-
break;
|
|
11992
|
-
case OpKind.InterpolateClassMap:
|
|
11993
|
-
OpList.replace(op, classMapInterpolate(op.strings, op.expressions));
|
|
12647
|
+
if (op.expression instanceof Interpolation) {
|
|
12648
|
+
OpList.replace(op, classMapInterpolate(op.expression.strings, op.expression.expressions));
|
|
12649
|
+
}
|
|
12650
|
+
else {
|
|
12651
|
+
OpList.replace(op, classMap(op.expression));
|
|
12652
|
+
}
|
|
11994
12653
|
break;
|
|
11995
12654
|
case OpKind.InterpolateText:
|
|
11996
|
-
OpList.replace(op, textInterpolate(op.strings, op.expressions));
|
|
12655
|
+
OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
|
|
11997
12656
|
break;
|
|
11998
12657
|
case OpKind.Attribute:
|
|
11999
|
-
|
|
12658
|
+
if (op.expression instanceof Interpolation) {
|
|
12659
|
+
OpList.replace(op, attributeInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer));
|
|
12660
|
+
}
|
|
12661
|
+
else {
|
|
12662
|
+
OpList.replace(op, attribute(op.name, op.expression, op.sanitizer));
|
|
12663
|
+
}
|
|
12000
12664
|
break;
|
|
12001
|
-
case OpKind.
|
|
12002
|
-
|
|
12665
|
+
case OpKind.HostProperty:
|
|
12666
|
+
if (op.expression instanceof Interpolation) {
|
|
12667
|
+
throw new Error('not yet handled');
|
|
12668
|
+
}
|
|
12669
|
+
else {
|
|
12670
|
+
OpList.replace(op, hostProperty(op.name, op.expression));
|
|
12671
|
+
}
|
|
12003
12672
|
break;
|
|
12004
12673
|
case OpKind.Variable:
|
|
12005
12674
|
if (op.variable.name === null) {
|
|
@@ -12061,6 +12730,8 @@ function reifyIrExpression(expr) {
|
|
|
12061
12730
|
return pipeBind(expr.slot, expr.varOffset, expr.args);
|
|
12062
12731
|
case ExpressionKind.PipeBindingVariadic:
|
|
12063
12732
|
return pipeBindV(expr.slot, expr.varOffset, expr.args);
|
|
12733
|
+
case ExpressionKind.SanitizerExpr:
|
|
12734
|
+
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
12064
12735
|
default:
|
|
12065
12736
|
throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
|
|
12066
12737
|
}
|
|
@@ -12069,10 +12740,9 @@ function reifyIrExpression(expr) {
|
|
|
12069
12740
|
* Listeners get turned into a function expression, which may or may not have the `$event`
|
|
12070
12741
|
* parameter defined.
|
|
12071
12742
|
*/
|
|
12072
|
-
function reifyListenerHandler(
|
|
12073
|
-
const lookForEvent = new LookForEventVisitor();
|
|
12743
|
+
function reifyListenerHandler(unit, name, handlerOps, consumesDollarEvent) {
|
|
12074
12744
|
// First, reify all instruction calls within `handlerOps`.
|
|
12075
|
-
reifyUpdateOperations(
|
|
12745
|
+
reifyUpdateOperations(unit, handlerOps);
|
|
12076
12746
|
// Next, extract all the `o.Statement`s from the reified operations. We can expect that at this
|
|
12077
12747
|
// point, all operations have been converted to statements.
|
|
12078
12748
|
const handlerStmts = [];
|
|
@@ -12082,27 +12752,31 @@ function reifyListenerHandler(view, name, handlerOps) {
|
|
|
12082
12752
|
}
|
|
12083
12753
|
handlerStmts.push(op.statement);
|
|
12084
12754
|
}
|
|
12085
|
-
//
|
|
12086
|
-
// parameter.
|
|
12087
|
-
lookForEvent.visitAllStatements(handlerStmts, null);
|
|
12755
|
+
// If `$event` is referenced, we need to generate it as a parameter.
|
|
12088
12756
|
const params = [];
|
|
12089
|
-
if (
|
|
12757
|
+
if (consumesDollarEvent) {
|
|
12090
12758
|
// We need the `$event` parameter.
|
|
12091
12759
|
params.push(new FnParam('$event'));
|
|
12092
12760
|
}
|
|
12093
12761
|
return fn(params, handlerStmts, undefined, undefined, name);
|
|
12094
12762
|
}
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12763
|
+
|
|
12764
|
+
function phaseRemoveEmptyBindings(job) {
|
|
12765
|
+
for (const unit of job.units) {
|
|
12766
|
+
for (const op of unit.update) {
|
|
12767
|
+
switch (op.kind) {
|
|
12768
|
+
case OpKind.Attribute:
|
|
12769
|
+
case OpKind.Binding:
|
|
12770
|
+
case OpKind.ClassProp:
|
|
12771
|
+
case OpKind.ClassMap:
|
|
12772
|
+
case OpKind.Property:
|
|
12773
|
+
case OpKind.StyleProp:
|
|
12774
|
+
case OpKind.StyleMap:
|
|
12775
|
+
if (op.expression instanceof EmptyExpr) {
|
|
12776
|
+
OpList.remove(op);
|
|
12777
|
+
}
|
|
12778
|
+
break;
|
|
12779
|
+
}
|
|
12106
12780
|
}
|
|
12107
12781
|
}
|
|
12108
12782
|
}
|
|
@@ -12113,9 +12787,9 @@ class LookForEventVisitor extends RecursiveAstVisitor$1 {
|
|
|
12113
12787
|
* that store those contexts (for contexts accessed via the `nextContext()` instruction).
|
|
12114
12788
|
*/
|
|
12115
12789
|
function phaseResolveContexts(cpl) {
|
|
12116
|
-
for (const
|
|
12117
|
-
processLexicalScope$1(
|
|
12118
|
-
processLexicalScope$1(
|
|
12790
|
+
for (const unit of cpl.units) {
|
|
12791
|
+
processLexicalScope$1(unit, unit.create);
|
|
12792
|
+
processLexicalScope$1(unit, unit.update);
|
|
12119
12793
|
}
|
|
12120
12794
|
}
|
|
12121
12795
|
function processLexicalScope$1(view, ops) {
|
|
@@ -12153,6 +12827,30 @@ function processLexicalScope$1(view, ops) {
|
|
|
12153
12827
|
}
|
|
12154
12828
|
}
|
|
12155
12829
|
|
|
12830
|
+
/**
|
|
12831
|
+
* Any variable inside a listener with the name `$event` will be transformed into a output lexical
|
|
12832
|
+
* read immediately, and does not participate in any of the normal logic for handling variables.
|
|
12833
|
+
*/
|
|
12834
|
+
function phaseResolveDollarEvent(cpl) {
|
|
12835
|
+
for (const [_, view] of cpl.views) {
|
|
12836
|
+
resolveDollarEvent(view, view.create);
|
|
12837
|
+
resolveDollarEvent(view, view.update);
|
|
12838
|
+
}
|
|
12839
|
+
}
|
|
12840
|
+
function resolveDollarEvent(view, ops) {
|
|
12841
|
+
for (const op of ops) {
|
|
12842
|
+
if (op.kind === OpKind.Listener) {
|
|
12843
|
+
transformExpressionsInOp(op, (expr) => {
|
|
12844
|
+
if (expr instanceof LexicalReadExpr && expr.name === '$event') {
|
|
12845
|
+
op.consumesDollarEvent = true;
|
|
12846
|
+
return new ReadVarExpr(expr.name);
|
|
12847
|
+
}
|
|
12848
|
+
return expr;
|
|
12849
|
+
}, VisitorContextFlag.InChildOperation);
|
|
12850
|
+
}
|
|
12851
|
+
}
|
|
12852
|
+
}
|
|
12853
|
+
|
|
12156
12854
|
/**
|
|
12157
12855
|
* Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
|
|
12158
12856
|
* property reads on the top-level component context.
|
|
@@ -12161,12 +12859,12 @@ function processLexicalScope$1(view, ops) {
|
|
|
12161
12859
|
* views.
|
|
12162
12860
|
*/
|
|
12163
12861
|
function phaseResolveNames(cpl) {
|
|
12164
|
-
for (const
|
|
12165
|
-
processLexicalScope(
|
|
12166
|
-
processLexicalScope(
|
|
12862
|
+
for (const unit of cpl.units) {
|
|
12863
|
+
processLexicalScope(unit, unit.create, null);
|
|
12864
|
+
processLexicalScope(unit, unit.update, null);
|
|
12167
12865
|
}
|
|
12168
12866
|
}
|
|
12169
|
-
function processLexicalScope(
|
|
12867
|
+
function processLexicalScope(unit, ops, savedView) {
|
|
12170
12868
|
// Maps names defined in the lexical scope of this template to the `ir.XrefId`s of the variable
|
|
12171
12869
|
// declarations which represent those values.
|
|
12172
12870
|
//
|
|
@@ -12200,7 +12898,7 @@ function processLexicalScope(view, ops, savedView) {
|
|
|
12200
12898
|
case OpKind.Listener:
|
|
12201
12899
|
// Listener functions have separate variable declarations, so process them as a separate
|
|
12202
12900
|
// lexical scope.
|
|
12203
|
-
processLexicalScope(
|
|
12901
|
+
processLexicalScope(unit, op.handlerOps, savedView);
|
|
12204
12902
|
break;
|
|
12205
12903
|
}
|
|
12206
12904
|
}
|
|
@@ -12208,7 +12906,11 @@ function processLexicalScope(view, ops, savedView) {
|
|
|
12208
12906
|
// scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
|
|
12209
12907
|
// variable.
|
|
12210
12908
|
for (const op of ops) {
|
|
12211
|
-
|
|
12909
|
+
if (op.kind == OpKind.Listener) {
|
|
12910
|
+
// Listeners were already processed above with their own scopes.
|
|
12911
|
+
continue;
|
|
12912
|
+
}
|
|
12913
|
+
transformExpressionsInOp(op, (expr, flags) => {
|
|
12212
12914
|
if (expr instanceof LexicalReadExpr) {
|
|
12213
12915
|
// `expr` is a read of a name within the lexical scope of this view.
|
|
12214
12916
|
// Either that name is defined within the current view, or it represents a property from the
|
|
@@ -12219,7 +12921,7 @@ function processLexicalScope(view, ops, savedView) {
|
|
|
12219
12921
|
}
|
|
12220
12922
|
else {
|
|
12221
12923
|
// Reading from the component context.
|
|
12222
|
-
return new ReadPropExpr(new ContextExpr(
|
|
12924
|
+
return new ReadPropExpr(new ContextExpr(unit.job.root.xref), expr.name);
|
|
12223
12925
|
}
|
|
12224
12926
|
}
|
|
12225
12927
|
else if (expr instanceof RestoreViewExpr && typeof expr.view === 'number') {
|
|
@@ -12227,7 +12929,7 @@ function processLexicalScope(view, ops, savedView) {
|
|
|
12227
12929
|
// parent creation list. We expect to find that we captured the `savedView` previously, and
|
|
12228
12930
|
// that it matches the expected view to be restored.
|
|
12229
12931
|
if (savedView === null || savedView.view !== expr.view) {
|
|
12230
|
-
throw new Error(`AssertionError: no saved view ${expr.view} from view ${
|
|
12932
|
+
throw new Error(`AssertionError: no saved view ${expr.view} from view ${unit.xref}`);
|
|
12231
12933
|
}
|
|
12232
12934
|
expr.view = new ReadVariableExpr(savedView.variable);
|
|
12233
12935
|
return expr;
|
|
@@ -12242,14 +12944,61 @@ function processLexicalScope(view, ops, savedView) {
|
|
|
12242
12944
|
if (expr instanceof LexicalReadExpr) {
|
|
12243
12945
|
throw new Error(`AssertionError: no lexical reads should remain, but found read of ${expr.name}`);
|
|
12244
12946
|
}
|
|
12245
|
-
});
|
|
12947
|
+
});
|
|
12948
|
+
}
|
|
12949
|
+
}
|
|
12950
|
+
|
|
12951
|
+
/**
|
|
12952
|
+
* Mapping of security contexts to sanitizer function for that context.
|
|
12953
|
+
*/
|
|
12954
|
+
const sanitizers = new Map([
|
|
12955
|
+
[SecurityContext.HTML, SanitizerFn.Html], [SecurityContext.SCRIPT, SanitizerFn.Script],
|
|
12956
|
+
[SecurityContext.STYLE, SanitizerFn.Style], [SecurityContext.URL, SanitizerFn.Url],
|
|
12957
|
+
[SecurityContext.RESOURCE_URL, SanitizerFn.ResourceUrl]
|
|
12958
|
+
]);
|
|
12959
|
+
/**
|
|
12960
|
+
* Resolves sanitization functions for ops that need them.
|
|
12961
|
+
*/
|
|
12962
|
+
function phaseResolveSanitizers(cpl) {
|
|
12963
|
+
for (const [_, view] of cpl.views) {
|
|
12964
|
+
const elements = getElementsByXrefId(view);
|
|
12965
|
+
let sanitizerFn;
|
|
12966
|
+
for (const op of view.update) {
|
|
12967
|
+
switch (op.kind) {
|
|
12968
|
+
case OpKind.Property:
|
|
12969
|
+
case OpKind.Attribute:
|
|
12970
|
+
sanitizerFn = sanitizers.get(op.securityContext) || null;
|
|
12971
|
+
op.sanitizer = sanitizerFn ? new SanitizerExpr(sanitizerFn) : null;
|
|
12972
|
+
// If there was no sanitization function found based on the security context of an
|
|
12973
|
+
// attribute/property, check whether this attribute/property is one of the
|
|
12974
|
+
// security-sensitive <iframe> attributes (and that the current element is actually an
|
|
12975
|
+
// <iframe>).
|
|
12976
|
+
if (op.sanitizer === null) {
|
|
12977
|
+
const ownerOp = elements.get(op.target);
|
|
12978
|
+
if (ownerOp === undefined) {
|
|
12979
|
+
throw Error('Property should have an element-like owner');
|
|
12980
|
+
}
|
|
12981
|
+
if (isIframeElement$1(ownerOp) && isIframeSecuritySensitiveAttr(op.name)) {
|
|
12982
|
+
op.sanitizer = new SanitizerExpr(SanitizerFn.IframeAttribute);
|
|
12983
|
+
}
|
|
12984
|
+
}
|
|
12985
|
+
break;
|
|
12986
|
+
}
|
|
12987
|
+
}
|
|
12246
12988
|
}
|
|
12247
12989
|
}
|
|
12990
|
+
/**
|
|
12991
|
+
* Checks whether the given op represents an iframe element.
|
|
12992
|
+
*/
|
|
12993
|
+
function isIframeElement$1(op) {
|
|
12994
|
+
return (op.kind === OpKind.Element || op.kind === OpKind.ElementStart) &&
|
|
12995
|
+
op.tag.toLowerCase() === 'iframe';
|
|
12996
|
+
}
|
|
12248
12997
|
|
|
12249
12998
|
function phaseSaveRestoreView(cpl) {
|
|
12250
12999
|
for (const view of cpl.views.values()) {
|
|
12251
13000
|
view.create.prepend([
|
|
12252
|
-
createVariableOp(view.
|
|
13001
|
+
createVariableOp(view.job.allocateXrefId(), {
|
|
12253
13002
|
kind: SemanticVariableKind.SavedView,
|
|
12254
13003
|
name: null,
|
|
12255
13004
|
view: view.xref,
|
|
@@ -12279,7 +13028,7 @@ function phaseSaveRestoreView(cpl) {
|
|
|
12279
13028
|
}
|
|
12280
13029
|
function addSaveRestoreViewOperationToListener(view, op) {
|
|
12281
13030
|
op.handlerOps.prepend([
|
|
12282
|
-
createVariableOp(view.
|
|
13031
|
+
createVariableOp(view.job.allocateXrefId(), {
|
|
12283
13032
|
kind: SemanticVariableKind.Context,
|
|
12284
13033
|
name: null,
|
|
12285
13034
|
view: view.xref,
|
|
@@ -12373,6 +13122,40 @@ function phaseSlotAllocation(cpl) {
|
|
|
12373
13122
|
}
|
|
12374
13123
|
}
|
|
12375
13124
|
|
|
13125
|
+
/**
|
|
13126
|
+
* Transforms special-case bindings with 'style' or 'class' in their names. Must run before the
|
|
13127
|
+
* main binding specialization pass.
|
|
13128
|
+
*/
|
|
13129
|
+
function phaseStyleBindingSpecialization(cpl) {
|
|
13130
|
+
for (const unit of cpl.units) {
|
|
13131
|
+
for (const op of unit.update) {
|
|
13132
|
+
if (op.kind !== OpKind.Binding) {
|
|
13133
|
+
continue;
|
|
13134
|
+
}
|
|
13135
|
+
switch (op.bindingKind) {
|
|
13136
|
+
case BindingKind.ClassName:
|
|
13137
|
+
if (op.expression instanceof Interpolation) {
|
|
13138
|
+
throw new Error(`Unexpected interpolation in ClassName binding`);
|
|
13139
|
+
}
|
|
13140
|
+
OpList.replace(op, createClassPropOp(op.target, op.name, op.expression, op.sourceSpan));
|
|
13141
|
+
break;
|
|
13142
|
+
case BindingKind.StyleProperty:
|
|
13143
|
+
OpList.replace(op, createStylePropOp(op.target, op.name, op.expression, op.unit, op.sourceSpan));
|
|
13144
|
+
break;
|
|
13145
|
+
case BindingKind.Property:
|
|
13146
|
+
case BindingKind.Template:
|
|
13147
|
+
if (op.name === 'style') {
|
|
13148
|
+
OpList.replace(op, createStyleMapOp(op.target, op.expression, op.sourceSpan));
|
|
13149
|
+
}
|
|
13150
|
+
else if (op.name === 'class') {
|
|
13151
|
+
OpList.replace(op, createClassMapOp(op.target, op.expression, op.sourceSpan));
|
|
13152
|
+
}
|
|
13153
|
+
break;
|
|
13154
|
+
}
|
|
13155
|
+
}
|
|
13156
|
+
}
|
|
13157
|
+
}
|
|
13158
|
+
|
|
12376
13159
|
/**
|
|
12377
13160
|
* Find all assignments and usages of temporary variables, which are linked to each other with cross
|
|
12378
13161
|
* references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
|
|
@@ -12383,38 +13166,58 @@ function phaseSlotAllocation(cpl) {
|
|
|
12383
13166
|
* Implement an algorithm for reuse.
|
|
12384
13167
|
*/
|
|
12385
13168
|
function phaseTemporaryVariables(cpl) {
|
|
12386
|
-
for (const
|
|
13169
|
+
for (const unit of cpl.units) {
|
|
12387
13170
|
let opCount = 0;
|
|
12388
13171
|
let generatedStatements = [];
|
|
12389
|
-
for (const op of
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
let defs = new Map();
|
|
13172
|
+
for (const op of unit.ops()) {
|
|
13173
|
+
// Identify the final time each temp var is read.
|
|
13174
|
+
const finalReads = new Map();
|
|
12393
13175
|
visitExpressionsInOp(op, expr => {
|
|
12394
|
-
if (expr instanceof ReadTemporaryExpr
|
|
12395
|
-
|
|
13176
|
+
if (expr instanceof ReadTemporaryExpr) {
|
|
13177
|
+
finalReads.set(expr.xref, expr);
|
|
12396
13178
|
}
|
|
12397
13179
|
});
|
|
12398
|
-
for
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
13180
|
+
// Name the temp vars, accounting for the fact that a name can be reused after it has been
|
|
13181
|
+
// read for the final time.
|
|
13182
|
+
let count = 0;
|
|
13183
|
+
const assigned = new Set();
|
|
13184
|
+
const released = new Set();
|
|
13185
|
+
const defs = new Map();
|
|
12403
13186
|
visitExpressionsInOp(op, expr => {
|
|
12404
|
-
if (expr instanceof
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
13187
|
+
if (expr instanceof AssignTemporaryExpr) {
|
|
13188
|
+
if (!assigned.has(expr.xref)) {
|
|
13189
|
+
assigned.add(expr.xref);
|
|
13190
|
+
// TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
|
|
13191
|
+
// It seems to rely on an expression index instead of an op index.
|
|
13192
|
+
defs.set(expr.xref, `tmp_${opCount}_${count++}`);
|
|
13193
|
+
}
|
|
13194
|
+
assignName(defs, expr);
|
|
13195
|
+
}
|
|
13196
|
+
else if (expr instanceof ReadTemporaryExpr) {
|
|
13197
|
+
if (finalReads.get(expr.xref) === expr) {
|
|
13198
|
+
released.add(expr.xref);
|
|
13199
|
+
count--;
|
|
12408
13200
|
}
|
|
12409
|
-
expr
|
|
13201
|
+
assignName(defs, expr);
|
|
12410
13202
|
}
|
|
12411
13203
|
});
|
|
12412
|
-
|
|
13204
|
+
// Add declarations for the temp vars.
|
|
13205
|
+
generatedStatements.push(...Array.from(new Set(defs.values()))
|
|
12413
13206
|
.map(name => createStatementOp(new DeclareVarStmt(name))));
|
|
12414
13207
|
opCount++;
|
|
12415
13208
|
}
|
|
12416
|
-
|
|
13209
|
+
unit.update.prepend(generatedStatements);
|
|
13210
|
+
}
|
|
13211
|
+
}
|
|
13212
|
+
/**
|
|
13213
|
+
* Assigns a name to the temporary variable in the given temporary variable expression.
|
|
13214
|
+
*/
|
|
13215
|
+
function assignName(names, expr) {
|
|
13216
|
+
const name = names.get(expr.xref);
|
|
13217
|
+
if (name === undefined) {
|
|
13218
|
+
throw new Error(`Found xref with unassigned name: ${expr.xref}`);
|
|
12417
13219
|
}
|
|
13220
|
+
expr.name = name;
|
|
12418
13221
|
}
|
|
12419
13222
|
|
|
12420
13223
|
/**
|
|
@@ -12435,13 +13238,13 @@ function phaseTemporaryVariables(cpl) {
|
|
|
12435
13238
|
* To guarantee correctness, analysis of "fences" in the instruction lists is used to determine
|
|
12436
13239
|
* which optimizations are safe to perform.
|
|
12437
13240
|
*/
|
|
12438
|
-
function phaseVariableOptimization(
|
|
12439
|
-
for (const
|
|
12440
|
-
optimizeVariablesInOpList(
|
|
12441
|
-
optimizeVariablesInOpList(
|
|
12442
|
-
for (const op of
|
|
13241
|
+
function phaseVariableOptimization(job) {
|
|
13242
|
+
for (const unit of job.units) {
|
|
13243
|
+
optimizeVariablesInOpList(unit.create, job.compatibility);
|
|
13244
|
+
optimizeVariablesInOpList(unit.update, job.compatibility);
|
|
13245
|
+
for (const op of unit.create) {
|
|
12443
13246
|
if (op.kind === OpKind.Listener) {
|
|
12444
|
-
optimizeVariablesInOpList(op.handlerOps,
|
|
13247
|
+
optimizeVariablesInOpList(op.handlerOps, job.compatibility);
|
|
12445
13248
|
}
|
|
12446
13249
|
}
|
|
12447
13250
|
}
|
|
@@ -12482,7 +13285,7 @@ var Fence;
|
|
|
12482
13285
|
/**
|
|
12483
13286
|
* Process a list of operations and optimize variables within that list.
|
|
12484
13287
|
*/
|
|
12485
|
-
function optimizeVariablesInOpList(ops,
|
|
13288
|
+
function optimizeVariablesInOpList(ops, compatibility) {
|
|
12486
13289
|
const varDecls = new Map();
|
|
12487
13290
|
const varUsages = new Map();
|
|
12488
13291
|
// Track variables that are used outside of the immediate operation list. For example, within
|
|
@@ -12573,7 +13376,8 @@ function optimizeVariablesInOpList(ops, options) {
|
|
|
12573
13376
|
const opInfo = opMap.get(targetOp);
|
|
12574
13377
|
// Is the variable used in this operation?
|
|
12575
13378
|
if (opInfo.variablesUsed.has(candidate)) {
|
|
12576
|
-
if (
|
|
13379
|
+
if (compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
13380
|
+
!allowConservativeInlining(decl, targetOp)) {
|
|
12577
13381
|
// We're in conservative mode, and this variable is not eligible for inlining into the
|
|
12578
13382
|
// target operation in this mode.
|
|
12579
13383
|
break;
|
|
@@ -12782,35 +13586,68 @@ function allowConservativeInlining(decl, target) {
|
|
|
12782
13586
|
|
|
12783
13587
|
/**
|
|
12784
13588
|
* Run all transformation phases in the correct order against a `ComponentCompilation`. After this
|
|
12785
|
-
* processing, the compilation should be in a state where it can be emitted
|
|
12786
|
-
*/
|
|
12787
|
-
function transformTemplate(
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12812
|
-
|
|
12813
|
-
|
|
13589
|
+
* processing, the compilation should be in a state where it can be emitted.
|
|
13590
|
+
*/
|
|
13591
|
+
function transformTemplate(job) {
|
|
13592
|
+
phaseNamespace(job);
|
|
13593
|
+
phaseStyleBindingSpecialization(job);
|
|
13594
|
+
phaseBindingSpecialization(job);
|
|
13595
|
+
phaseAttributeExtraction(job);
|
|
13596
|
+
phaseRemoveEmptyBindings(job);
|
|
13597
|
+
phaseNoListenersOnTemplates(job);
|
|
13598
|
+
phasePipeCreation(job);
|
|
13599
|
+
phasePipeVariadic(job);
|
|
13600
|
+
phasePureLiteralStructures(job);
|
|
13601
|
+
phaseGenerateVariables(job);
|
|
13602
|
+
phaseSaveRestoreView(job);
|
|
13603
|
+
phaseFindAnyCasts(job);
|
|
13604
|
+
phaseResolveDollarEvent(job);
|
|
13605
|
+
phaseResolveNames(job);
|
|
13606
|
+
phaseResolveContexts(job);
|
|
13607
|
+
phaseResolveSanitizers(job);
|
|
13608
|
+
phaseLocalRefs(job);
|
|
13609
|
+
phaseConstCollection(job);
|
|
13610
|
+
phaseNullishCoalescing(job);
|
|
13611
|
+
phaseExpandSafeReads(job);
|
|
13612
|
+
phaseTemporaryVariables(job);
|
|
13613
|
+
phaseSlotAllocation(job);
|
|
13614
|
+
phaseVarCounting(job);
|
|
13615
|
+
phaseGenerateAdvance(job);
|
|
13616
|
+
phaseVariableOptimization(job);
|
|
13617
|
+
phaseNaming(job);
|
|
13618
|
+
phaseMergeNextContext(job);
|
|
13619
|
+
phaseNgContainer(job);
|
|
13620
|
+
phaseEmptyElements(job);
|
|
13621
|
+
phaseNonbindable(job);
|
|
13622
|
+
phasePureFunctionExtraction(job);
|
|
13623
|
+
phaseAlignPipeVariadicVarOffset(job);
|
|
13624
|
+
phasePropertyOrdering(job);
|
|
13625
|
+
phaseReify(job);
|
|
13626
|
+
phaseChaining(job);
|
|
13627
|
+
}
|
|
13628
|
+
/**
|
|
13629
|
+
* Run all transformation phases in the correct order against a `HostBindingCompilationJob`. After
|
|
13630
|
+
* this processing, the compilation should be in a state where it can be emitted.
|
|
13631
|
+
*/
|
|
13632
|
+
function transformHostBinding(job) {
|
|
13633
|
+
phaseHostStylePropertyParsing(job);
|
|
13634
|
+
phaseStyleBindingSpecialization(job);
|
|
13635
|
+
phaseBindingSpecialization(job);
|
|
13636
|
+
phasePureLiteralStructures(job);
|
|
13637
|
+
phaseNullishCoalescing(job);
|
|
13638
|
+
phaseExpandSafeReads(job);
|
|
13639
|
+
phaseTemporaryVariables(job);
|
|
13640
|
+
phaseVarCounting(job);
|
|
13641
|
+
phaseVariableOptimization(job);
|
|
13642
|
+
phaseResolveNames(job);
|
|
13643
|
+
phaseResolveContexts(job);
|
|
13644
|
+
// TODO: Figure out how to make this work for host bindings.
|
|
13645
|
+
// phaseResolveSanitizers(job);
|
|
13646
|
+
phaseNaming(job);
|
|
13647
|
+
phasePureFunctionExtraction(job);
|
|
13648
|
+
phasePropertyOrdering(job);
|
|
13649
|
+
phaseReify(job);
|
|
13650
|
+
phaseChaining(job);
|
|
12814
13651
|
}
|
|
12815
13652
|
/**
|
|
12816
13653
|
* Compile all views in the given `ComponentCompilation` into the final template function, which may
|
|
@@ -12822,7 +13659,7 @@ function emitTemplateFn(tpl, pool) {
|
|
|
12822
13659
|
return rootFn;
|
|
12823
13660
|
}
|
|
12824
13661
|
function emitChildViews(parent, pool) {
|
|
12825
|
-
for (const view of parent.
|
|
13662
|
+
for (const view of parent.job.views.values()) {
|
|
12826
13663
|
if (view.parent !== parent.xref) {
|
|
12827
13664
|
continue;
|
|
12828
13665
|
}
|
|
@@ -12873,151 +13710,85 @@ function maybeGenerateRfBlock(flag, statements) {
|
|
|
12873
13710
|
ifStmt(new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, variable('rf'), literal(flag)), statements),
|
|
12874
13711
|
];
|
|
12875
13712
|
}
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
* embedded views or host bindings.
|
|
12880
|
-
*/
|
|
12881
|
-
class ComponentCompilation {
|
|
12882
|
-
constructor(componentName, pool) {
|
|
12883
|
-
this.componentName = componentName;
|
|
12884
|
-
this.pool = pool;
|
|
12885
|
-
/**
|
|
12886
|
-
* Tracks the next `ir.XrefId` which can be assigned as template structures are ingested.
|
|
12887
|
-
*/
|
|
12888
|
-
this.nextXrefId = 0;
|
|
12889
|
-
/**
|
|
12890
|
-
* Map of view IDs to `ViewCompilation`s.
|
|
12891
|
-
*/
|
|
12892
|
-
this.views = new Map();
|
|
12893
|
-
/**
|
|
12894
|
-
* Constant expressions used by operations within this component's compilation.
|
|
12895
|
-
*
|
|
12896
|
-
* This will eventually become the `consts` array in the component definition.
|
|
12897
|
-
*/
|
|
12898
|
-
this.consts = [];
|
|
12899
|
-
// Allocate the root view.
|
|
12900
|
-
const root = new ViewCompilation(this, this.allocateXrefId(), null);
|
|
12901
|
-
this.views.set(root.xref, root);
|
|
12902
|
-
this.root = root;
|
|
12903
|
-
}
|
|
12904
|
-
/**
|
|
12905
|
-
* Add a `ViewCompilation` for a new embedded view to this compilation.
|
|
12906
|
-
*/
|
|
12907
|
-
allocateView(parent) {
|
|
12908
|
-
const view = new ViewCompilation(this, this.allocateXrefId(), parent);
|
|
12909
|
-
this.views.set(view.xref, view);
|
|
12910
|
-
return view;
|
|
12911
|
-
}
|
|
12912
|
-
/**
|
|
12913
|
-
* Generate a new unique `ir.XrefId`.
|
|
12914
|
-
*/
|
|
12915
|
-
allocateXrefId() {
|
|
12916
|
-
return this.nextXrefId++;
|
|
13713
|
+
function emitHostBindingFunction(job) {
|
|
13714
|
+
if (job.fnName === null) {
|
|
13715
|
+
throw new Error(`AssertionError: host binding function is unnamed`);
|
|
12917
13716
|
}
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
for (let idx = 0; idx < this.consts.length; idx++) {
|
|
12923
|
-
if (this.consts[idx].isEquivalent(newConst)) {
|
|
12924
|
-
return idx;
|
|
12925
|
-
}
|
|
13717
|
+
const createStatements = [];
|
|
13718
|
+
for (const op of job.create) {
|
|
13719
|
+
if (op.kind !== OpKind.Statement) {
|
|
13720
|
+
throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
|
|
12926
13721
|
}
|
|
12927
|
-
|
|
12928
|
-
this.consts.push(newConst);
|
|
12929
|
-
return idx;
|
|
12930
|
-
}
|
|
12931
|
-
}
|
|
12932
|
-
/**
|
|
12933
|
-
* Compilation-in-progress of an individual view within a template.
|
|
12934
|
-
*/
|
|
12935
|
-
class ViewCompilation {
|
|
12936
|
-
constructor(tpl, xref, parent) {
|
|
12937
|
-
this.tpl = tpl;
|
|
12938
|
-
this.xref = xref;
|
|
12939
|
-
this.parent = parent;
|
|
12940
|
-
/**
|
|
12941
|
-
* Name of the function which will be generated for this view.
|
|
12942
|
-
*
|
|
12943
|
-
* May be `null` if not yet determined.
|
|
12944
|
-
*/
|
|
12945
|
-
this.fnName = null;
|
|
12946
|
-
/**
|
|
12947
|
-
* List of creation operations for this view.
|
|
12948
|
-
*
|
|
12949
|
-
* Creation operations may internally contain other operations, including update operations.
|
|
12950
|
-
*/
|
|
12951
|
-
this.create = new OpList();
|
|
12952
|
-
/**
|
|
12953
|
-
* List of update operations for this view.
|
|
12954
|
-
*/
|
|
12955
|
-
this.update = new OpList();
|
|
12956
|
-
/**
|
|
12957
|
-
* Map of declared variables available within this view to the property on the context object
|
|
12958
|
-
* which they alias.
|
|
12959
|
-
*/
|
|
12960
|
-
this.contextVariables = new Map();
|
|
12961
|
-
/**
|
|
12962
|
-
* Number of declaration slots used within this view, or `null` if slots have not yet been
|
|
12963
|
-
* allocated.
|
|
12964
|
-
*/
|
|
12965
|
-
this.decls = null;
|
|
12966
|
-
/**
|
|
12967
|
-
* Number of variable slots used within this view, or `null` if variables have not yet been
|
|
12968
|
-
* counted.
|
|
12969
|
-
*/
|
|
12970
|
-
this.vars = null;
|
|
13722
|
+
createStatements.push(op.statement);
|
|
12971
13723
|
}
|
|
12972
|
-
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
*/
|
|
12977
|
-
*ops() {
|
|
12978
|
-
for (const op of this.create) {
|
|
12979
|
-
yield op;
|
|
12980
|
-
if (op.kind === OpKind.Listener) {
|
|
12981
|
-
for (const listenerOp of op.handlerOps) {
|
|
12982
|
-
yield listenerOp;
|
|
12983
|
-
}
|
|
12984
|
-
}
|
|
12985
|
-
}
|
|
12986
|
-
for (const op of this.update) {
|
|
12987
|
-
yield op;
|
|
13724
|
+
const updateStatements = [];
|
|
13725
|
+
for (const op of job.update) {
|
|
13726
|
+
if (op.kind !== OpKind.Statement) {
|
|
13727
|
+
throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
|
|
12988
13728
|
}
|
|
13729
|
+
updateStatements.push(op.statement);
|
|
13730
|
+
}
|
|
13731
|
+
if (createStatements.length === 0 && updateStatements.length === 0) {
|
|
13732
|
+
return null;
|
|
12989
13733
|
}
|
|
13734
|
+
const createCond = maybeGenerateRfBlock(1, createStatements);
|
|
13735
|
+
const updateCond = maybeGenerateRfBlock(2, updateStatements);
|
|
13736
|
+
return fn([
|
|
13737
|
+
new FnParam('rf'),
|
|
13738
|
+
new FnParam('ctx'),
|
|
13739
|
+
], [
|
|
13740
|
+
...createCond,
|
|
13741
|
+
...updateCond,
|
|
13742
|
+
],
|
|
13743
|
+
/* type */ undefined, /* sourceSpan */ undefined, job.fnName);
|
|
12990
13744
|
}
|
|
12991
13745
|
|
|
12992
|
-
const
|
|
12993
|
-
['&&', BinaryOperator.And],
|
|
12994
|
-
['>', BinaryOperator.Bigger],
|
|
12995
|
-
['>=', BinaryOperator.BiggerEquals],
|
|
12996
|
-
['&', BinaryOperator.BitwiseAnd],
|
|
12997
|
-
['/', BinaryOperator.Divide],
|
|
12998
|
-
['==', BinaryOperator.Equals],
|
|
12999
|
-
['===', BinaryOperator.Identical],
|
|
13000
|
-
['<', BinaryOperator.Lower],
|
|
13001
|
-
['<=', BinaryOperator.LowerEquals],
|
|
13002
|
-
['-', BinaryOperator.Minus],
|
|
13003
|
-
['%', BinaryOperator.Modulo],
|
|
13004
|
-
['*', BinaryOperator.Multiply],
|
|
13005
|
-
['!=', BinaryOperator.NotEquals],
|
|
13006
|
-
['!==', BinaryOperator.NotIdentical],
|
|
13007
|
-
['??', BinaryOperator.NullishCoalesce],
|
|
13008
|
-
['||', BinaryOperator.Or],
|
|
13009
|
-
['+', BinaryOperator.Plus],
|
|
13010
|
-
]);
|
|
13011
|
-
|
|
13746
|
+
const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
|
|
13012
13747
|
/**
|
|
13013
13748
|
* Process a template AST and convert it into a `ComponentCompilation` in the intermediate
|
|
13014
13749
|
* representation.
|
|
13015
13750
|
*/
|
|
13016
|
-
function
|
|
13017
|
-
const cpl = new
|
|
13751
|
+
function ingestComponent(componentName, template, constantPool) {
|
|
13752
|
+
const cpl = new ComponentCompilationJob(componentName, constantPool, compatibilityMode);
|
|
13018
13753
|
ingestNodes(cpl.root, template);
|
|
13019
13754
|
return cpl;
|
|
13020
13755
|
}
|
|
13756
|
+
/**
|
|
13757
|
+
* Process a host binding AST and convert it into a `HostBindingCompilationJob` in the intermediate
|
|
13758
|
+
* representation.
|
|
13759
|
+
*/
|
|
13760
|
+
function ingestHostBinding(input, bindingParser, constantPool) {
|
|
13761
|
+
const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
|
|
13762
|
+
for (const property of input.properties ?? []) {
|
|
13763
|
+
ingestHostProperty(job, property);
|
|
13764
|
+
}
|
|
13765
|
+
for (const event of input.events ?? []) {
|
|
13766
|
+
ingestHostEvent(job, event);
|
|
13767
|
+
}
|
|
13768
|
+
return job;
|
|
13769
|
+
}
|
|
13770
|
+
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
13771
|
+
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
13772
|
+
function ingestHostProperty(job, property) {
|
|
13773
|
+
let expression;
|
|
13774
|
+
const ast = property.expression.ast;
|
|
13775
|
+
if (ast instanceof Interpolation$1) {
|
|
13776
|
+
expression =
|
|
13777
|
+
new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job)));
|
|
13778
|
+
}
|
|
13779
|
+
else {
|
|
13780
|
+
expression = convertAst(ast, job);
|
|
13781
|
+
}
|
|
13782
|
+
let bindingKind = BindingKind.Property;
|
|
13783
|
+
// TODO: this should really be handled in the parser.
|
|
13784
|
+
if (property.name.startsWith('attr.')) {
|
|
13785
|
+
property.name = property.name.substring('attr.'.length);
|
|
13786
|
+
bindingKind = BindingKind.Attribute;
|
|
13787
|
+
}
|
|
13788
|
+
job.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
|
|
13789
|
+
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, false, property.sourceSpan));
|
|
13790
|
+
}
|
|
13791
|
+
function ingestHostEvent(job, event) { }
|
|
13021
13792
|
/**
|
|
13022
13793
|
* Ingest the nodes of a template AST into the given `ViewCompilation`.
|
|
13023
13794
|
*/
|
|
@@ -13048,21 +13819,27 @@ function ingestElement(view, element) {
|
|
|
13048
13819
|
for (const attr of element.attributes) {
|
|
13049
13820
|
staticAttributes[attr.name] = attr.value;
|
|
13050
13821
|
}
|
|
13051
|
-
const id = view.
|
|
13052
|
-
const
|
|
13822
|
+
const id = view.job.allocateXrefId();
|
|
13823
|
+
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
13824
|
+
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.startSourceSpan);
|
|
13053
13825
|
view.create.push(startOp);
|
|
13054
13826
|
ingestBindings(view, startOp, element);
|
|
13055
13827
|
ingestReferences(startOp, element);
|
|
13056
13828
|
ingestNodes(view, element.children);
|
|
13057
|
-
view.create.push(createElementEndOp(id));
|
|
13829
|
+
view.create.push(createElementEndOp(id, element.endSourceSpan));
|
|
13058
13830
|
}
|
|
13059
13831
|
/**
|
|
13060
13832
|
* Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
|
|
13061
13833
|
*/
|
|
13062
13834
|
function ingestTemplate(view, tmpl) {
|
|
13063
|
-
const childView = view.
|
|
13835
|
+
const childView = view.job.allocateView(view.xref);
|
|
13836
|
+
let tagNameWithoutNamespace = tmpl.tagName;
|
|
13837
|
+
let namespacePrefix = '';
|
|
13838
|
+
if (tmpl.tagName) {
|
|
13839
|
+
[namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
|
|
13840
|
+
}
|
|
13064
13841
|
// TODO: validate the fallback tag name here.
|
|
13065
|
-
const tplOp = createTemplateOp(childView.xref,
|
|
13842
|
+
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), tmpl.startSourceSpan);
|
|
13066
13843
|
view.create.push(tplOp);
|
|
13067
13844
|
ingestBindings(view, tplOp, tmpl);
|
|
13068
13845
|
ingestReferences(tplOp, tmpl);
|
|
@@ -13075,7 +13852,7 @@ function ingestTemplate(view, tmpl) {
|
|
|
13075
13852
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
13076
13853
|
*/
|
|
13077
13854
|
function ingestText(view, text) {
|
|
13078
|
-
view.create.push(createTextOp(view.
|
|
13855
|
+
view.create.push(createTextOp(view.job.allocateXrefId(), text.value, text.sourceSpan));
|
|
13079
13856
|
}
|
|
13080
13857
|
/**
|
|
13081
13858
|
* Ingest an interpolated text node from the AST into the given `ViewCompilation`.
|
|
@@ -13085,12 +13862,12 @@ function ingestBoundText(view, text) {
|
|
|
13085
13862
|
if (value instanceof ASTWithSource) {
|
|
13086
13863
|
value = value.ast;
|
|
13087
13864
|
}
|
|
13088
|
-
if (!(value instanceof Interpolation)) {
|
|
13865
|
+
if (!(value instanceof Interpolation$1)) {
|
|
13089
13866
|
throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
|
|
13090
13867
|
}
|
|
13091
|
-
const textXref = view.
|
|
13092
|
-
view.create.push(createTextOp(textXref, ''));
|
|
13093
|
-
view.update.push(createInterpolateTextOp(textXref, value.strings, value.expressions.map(expr => convertAst(expr, view.
|
|
13868
|
+
const textXref = view.job.allocateXrefId();
|
|
13869
|
+
view.create.push(createTextOp(textXref, '', text.sourceSpan));
|
|
13870
|
+
view.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, view.job))), text.sourceSpan));
|
|
13094
13871
|
}
|
|
13095
13872
|
/**
|
|
13096
13873
|
* Convert a template AST expression into an output AST expression.
|
|
@@ -13100,7 +13877,7 @@ function convertAst(ast, cpl) {
|
|
|
13100
13877
|
return convertAst(ast.ast, cpl);
|
|
13101
13878
|
}
|
|
13102
13879
|
else if (ast instanceof PropertyRead) {
|
|
13103
|
-
if (ast.receiver instanceof ImplicitReceiver) {
|
|
13880
|
+
if (ast.receiver instanceof ImplicitReceiver && !(ast.receiver instanceof ThisReceiver)) {
|
|
13104
13881
|
return new LexicalReadExpr(ast.name);
|
|
13105
13882
|
}
|
|
13106
13883
|
else {
|
|
@@ -13187,24 +13964,33 @@ function ingestBindings(view, op, element) {
|
|
|
13187
13964
|
if (element instanceof Template) {
|
|
13188
13965
|
for (const attr of element.templateAttrs) {
|
|
13189
13966
|
if (attr instanceof TextAttribute) {
|
|
13190
|
-
view
|
|
13967
|
+
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true);
|
|
13191
13968
|
}
|
|
13192
13969
|
else {
|
|
13193
|
-
|
|
13970
|
+
ingestBinding(view, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, true);
|
|
13194
13971
|
}
|
|
13195
13972
|
}
|
|
13196
13973
|
}
|
|
13197
13974
|
for (const attr of element.attributes) {
|
|
13198
|
-
// This is only attribute TextLiteral bindings, such as `attr.foo="bar
|
|
13975
|
+
// This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
|
|
13199
13976
|
// `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
|
|
13200
13977
|
// `BindingType.Attribute`.
|
|
13201
|
-
view
|
|
13978
|
+
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, false);
|
|
13202
13979
|
}
|
|
13203
13980
|
for (const input of element.inputs) {
|
|
13204
|
-
|
|
13981
|
+
ingestBinding(view, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false);
|
|
13205
13982
|
}
|
|
13206
13983
|
for (const output of element.outputs) {
|
|
13207
|
-
|
|
13984
|
+
let listenerOp;
|
|
13985
|
+
if (output.type === 1 /* e.ParsedEventType.Animation */) {
|
|
13986
|
+
if (output.phase === null) {
|
|
13987
|
+
throw Error('Animation listener should have a phase');
|
|
13988
|
+
}
|
|
13989
|
+
listenerOp = createListenerOpForAnimation(op.xref, output.name, output.phase, op.tag);
|
|
13990
|
+
}
|
|
13991
|
+
else {
|
|
13992
|
+
listenerOp = createListenerOp(op.xref, output.name, op.tag);
|
|
13993
|
+
}
|
|
13208
13994
|
// if output.handler is a chain, then push each statement from the chain separately, and
|
|
13209
13995
|
// return the last one?
|
|
13210
13996
|
let inputExprs;
|
|
@@ -13221,7 +14007,7 @@ function ingestBindings(view, op, element) {
|
|
|
13221
14007
|
if (inputExprs.length === 0) {
|
|
13222
14008
|
throw new Error('Expected listener to have non-empty expression list.');
|
|
13223
14009
|
}
|
|
13224
|
-
const expressions = inputExprs.map(expr => convertAst(expr, view.
|
|
14010
|
+
const expressions = inputExprs.map(expr => convertAst(expr, view.job));
|
|
13225
14011
|
const returnExpr = expressions.pop();
|
|
13226
14012
|
for (const expr of expressions) {
|
|
13227
14013
|
const stmtOp = createStatementOp(new ExpressionStatement(expr));
|
|
@@ -13231,95 +14017,29 @@ function ingestBindings(view, op, element) {
|
|
|
13231
14017
|
view.create.push(listenerOp);
|
|
13232
14018
|
}
|
|
13233
14019
|
}
|
|
13234
|
-
|
|
14020
|
+
const BINDING_KINDS = new Map([
|
|
14021
|
+
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
14022
|
+
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
14023
|
+
[2 /* e.BindingType.Class */, BindingKind.ClassName],
|
|
14024
|
+
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
14025
|
+
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
14026
|
+
]);
|
|
14027
|
+
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTemplateBinding) {
|
|
13235
14028
|
if (value instanceof ASTWithSource) {
|
|
13236
14029
|
value = value.ast;
|
|
13237
14030
|
}
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
}
|
|
13245
|
-
view.update.push(createInterpolateStyleMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
13246
|
-
}
|
|
13247
|
-
else if (name === 'class') {
|
|
13248
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13249
|
-
throw Error('Unexpected class binding on ng-template');
|
|
13250
|
-
}
|
|
13251
|
-
view.update.push(createInterpolateClassMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
13252
|
-
}
|
|
13253
|
-
else {
|
|
13254
|
-
view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
13255
|
-
}
|
|
13256
|
-
break;
|
|
13257
|
-
case 3 /* e.BindingType.Style */:
|
|
13258
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13259
|
-
throw Error('Unexpected style binding on ng-template');
|
|
13260
|
-
}
|
|
13261
|
-
view.update.push(createInterpolateStylePropOp(xref, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)), unit));
|
|
13262
|
-
break;
|
|
13263
|
-
case 1 /* e.BindingType.Attribute */:
|
|
13264
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13265
|
-
throw new Error('Attribute bindings on templates are not expected to be valid');
|
|
13266
|
-
}
|
|
13267
|
-
const attributeInterpolate = createInterpolateAttributeOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)));
|
|
13268
|
-
view.update.push(attributeInterpolate);
|
|
13269
|
-
break;
|
|
13270
|
-
case 2 /* e.BindingType.Class */:
|
|
13271
|
-
throw Error('Unexpected interpolation in class property binding');
|
|
13272
|
-
// TODO: implement remaining binding types.
|
|
13273
|
-
case 4 /* e.BindingType.Animation */:
|
|
13274
|
-
default:
|
|
13275
|
-
throw Error(`Interpolated property binding type not handled: ${type}`);
|
|
13276
|
-
}
|
|
14031
|
+
let expression;
|
|
14032
|
+
if (value instanceof Interpolation$1) {
|
|
14033
|
+
expression = new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, view.job)));
|
|
14034
|
+
}
|
|
14035
|
+
else if (value instanceof AST) {
|
|
14036
|
+
expression = convertAst(value, view.job);
|
|
13277
14037
|
}
|
|
13278
14038
|
else {
|
|
13279
|
-
|
|
13280
|
-
case 0 /* e.BindingType.Property */:
|
|
13281
|
-
// Bindings to [style] are mapped to their own special instruction.
|
|
13282
|
-
if (name === 'style') {
|
|
13283
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13284
|
-
throw Error('Unexpected style binding on ng-template');
|
|
13285
|
-
}
|
|
13286
|
-
view.update.push(createStyleMapOp(xref, convertAst(value, view.tpl)));
|
|
13287
|
-
}
|
|
13288
|
-
else if (name === 'class') {
|
|
13289
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13290
|
-
throw Error('Unexpected class binding on ng-template');
|
|
13291
|
-
}
|
|
13292
|
-
view.update.push(createClassMapOp(xref, convertAst(value, view.tpl)));
|
|
13293
|
-
}
|
|
13294
|
-
else {
|
|
13295
|
-
view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
|
|
13296
|
-
}
|
|
13297
|
-
break;
|
|
13298
|
-
case 3 /* e.BindingType.Style */:
|
|
13299
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13300
|
-
throw Error('Unexpected style binding on ng-template');
|
|
13301
|
-
}
|
|
13302
|
-
view.update.push(createStylePropOp(xref, name, convertAst(value, view.tpl), unit));
|
|
13303
|
-
break;
|
|
13304
|
-
case 1 /* e.BindingType.Attribute */:
|
|
13305
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13306
|
-
throw new Error('Attribute bindings on templates are not expected to be valid');
|
|
13307
|
-
}
|
|
13308
|
-
const attrOp = createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
|
|
13309
|
-
view.update.push(attrOp);
|
|
13310
|
-
break;
|
|
13311
|
-
case 2 /* e.BindingType.Class */:
|
|
13312
|
-
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13313
|
-
throw Error('Unexpected class binding on ng-template');
|
|
13314
|
-
}
|
|
13315
|
-
view.update.push(createClassPropOp(xref, name, convertAst(value, view.tpl)));
|
|
13316
|
-
break;
|
|
13317
|
-
// TODO: implement remaining binding types.
|
|
13318
|
-
case 4 /* e.BindingType.Animation */:
|
|
13319
|
-
default:
|
|
13320
|
-
throw Error(`Property binding type not handled: ${type}`);
|
|
13321
|
-
}
|
|
14039
|
+
expression = value;
|
|
13322
14040
|
}
|
|
14041
|
+
const kind = BINDING_KINDS.get(type);
|
|
14042
|
+
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTemplateBinding, sourceSpan));
|
|
13323
14043
|
}
|
|
13324
14044
|
/**
|
|
13325
14045
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -13514,7 +14234,7 @@ class StylingBuilder {
|
|
|
13514
14234
|
// CSS custom properties are case-sensitive so we shouldn't normalize them.
|
|
13515
14235
|
// See: https://www.w3.org/TR/css-variables-1/#defining-variables
|
|
13516
14236
|
if (!isCssCustomProperty(name)) {
|
|
13517
|
-
name = hyphenate(name);
|
|
14237
|
+
name = hyphenate$1(name);
|
|
13518
14238
|
}
|
|
13519
14239
|
const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
|
|
13520
14240
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
|
@@ -13644,7 +14364,7 @@ class StylingBuilder {
|
|
|
13644
14364
|
// pipes can be picked up in time before the template is built
|
|
13645
14365
|
const mapValue = stylingInput.value.visit(valueConverter);
|
|
13646
14366
|
let reference;
|
|
13647
|
-
if (mapValue instanceof Interpolation) {
|
|
14367
|
+
if (mapValue instanceof Interpolation$1) {
|
|
13648
14368
|
totalBindingSlotsRequired += mapValue.expressions.length;
|
|
13649
14369
|
reference = isClassBased ? getClassMapInterpolationExpression(mapValue) :
|
|
13650
14370
|
getStyleMapInterpolationExpression(mapValue);
|
|
@@ -13679,7 +14399,7 @@ class StylingBuilder {
|
|
|
13679
14399
|
// We need to store the intermediate value so that we don't allocate
|
|
13680
14400
|
// the strings on each CD.
|
|
13681
14401
|
let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
|
|
13682
|
-
if (value instanceof Interpolation) {
|
|
14402
|
+
if (value instanceof Interpolation$1) {
|
|
13683
14403
|
totalBindingSlotsRequired += value.expressions.length;
|
|
13684
14404
|
if (getInterpolationExpressionFn) {
|
|
13685
14405
|
referenceForCall = getInterpolationExpressionFn(value);
|
|
@@ -14323,6 +15043,7 @@ class Parser$1 {
|
|
|
14323
15043
|
ast.visit(checker);
|
|
14324
15044
|
return checker.errors;
|
|
14325
15045
|
}
|
|
15046
|
+
// Host bindings parsed here
|
|
14326
15047
|
parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
|
|
14327
15048
|
const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
|
|
14328
15049
|
const errors = this.checkSimpleExpression(ast);
|
|
@@ -14405,7 +15126,7 @@ class Parser$1 {
|
|
|
14405
15126
|
}
|
|
14406
15127
|
createInterpolationAst(strings, expressions, input, location, absoluteOffset) {
|
|
14407
15128
|
const span = new ParseSpan(0, input.length);
|
|
14408
|
-
const interpolation = new Interpolation(span, span.toAbsolute(absoluteOffset), strings, expressions);
|
|
15129
|
+
const interpolation = new Interpolation$1(span, span.toAbsolute(absoluteOffset), strings, expressions);
|
|
14409
15130
|
return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors);
|
|
14410
15131
|
}
|
|
14411
15132
|
/**
|
|
@@ -19532,9 +20253,12 @@ class _TreeBuilder {
|
|
|
19532
20253
|
}
|
|
19533
20254
|
_consumeComment(token) {
|
|
19534
20255
|
const text = this._advanceIf(7 /* TokenType.RAW_TEXT */);
|
|
19535
|
-
this._advanceIf(11 /* TokenType.COMMENT_END */);
|
|
20256
|
+
const endToken = this._advanceIf(11 /* TokenType.COMMENT_END */);
|
|
19536
20257
|
const value = text != null ? text.parts[0].trim() : null;
|
|
19537
|
-
|
|
20258
|
+
const sourceSpan = endToken == null ?
|
|
20259
|
+
token.sourceSpan :
|
|
20260
|
+
new ParseSourceSpan(token.sourceSpan.start, endToken.sourceSpan.end, token.sourceSpan.fullStart);
|
|
20261
|
+
this._addToParent(new Comment(value, sourceSpan));
|
|
19538
20262
|
}
|
|
19539
20263
|
_consumeExpansion(token) {
|
|
19540
20264
|
const switchValue = this._advance();
|
|
@@ -22525,7 +23249,7 @@ function createComponentDefConsts() {
|
|
|
22525
23249
|
};
|
|
22526
23250
|
}
|
|
22527
23251
|
class TemplateDefinitionBuilder {
|
|
22528
|
-
constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, _namespace, relativeContextFilePath, i18nUseExternalIds, _constants = createComponentDefConsts()) {
|
|
23252
|
+
constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, _namespace, relativeContextFilePath, i18nUseExternalIds, deferBlocks, _constants = createComponentDefConsts()) {
|
|
22529
23253
|
this.constantPool = constantPool;
|
|
22530
23254
|
this.level = level;
|
|
22531
23255
|
this.contextName = contextName;
|
|
@@ -22534,6 +23258,7 @@ class TemplateDefinitionBuilder {
|
|
|
22534
23258
|
this.templateName = templateName;
|
|
22535
23259
|
this._namespace = _namespace;
|
|
22536
23260
|
this.i18nUseExternalIds = i18nUseExternalIds;
|
|
23261
|
+
this.deferBlocks = deferBlocks;
|
|
22537
23262
|
this._constants = _constants;
|
|
22538
23263
|
this._dataIndex = 0;
|
|
22539
23264
|
this._bindingContext = 0;
|
|
@@ -22736,7 +23461,7 @@ class TemplateDefinitionBuilder {
|
|
|
22736
23461
|
else {
|
|
22737
23462
|
const value = prop.value.visit(this._valueConverter);
|
|
22738
23463
|
this.allocateBindingSlots(value);
|
|
22739
|
-
if (value instanceof Interpolation) {
|
|
23464
|
+
if (value instanceof Interpolation$1) {
|
|
22740
23465
|
const { strings, expressions } = value;
|
|
22741
23466
|
const { id, bindings } = this.i18n;
|
|
22742
23467
|
const label = assembleI18nBoundString(strings, bindings.size, id);
|
|
@@ -22856,7 +23581,7 @@ class TemplateDefinitionBuilder {
|
|
|
22856
23581
|
const message = attr.i18n;
|
|
22857
23582
|
const converted = attr.value.visit(this._valueConverter);
|
|
22858
23583
|
this.allocateBindingSlots(converted);
|
|
22859
|
-
if (converted instanceof Interpolation) {
|
|
23584
|
+
if (converted instanceof Interpolation$1) {
|
|
22860
23585
|
const placeholders = assembleBoundTextPlaceholders(message);
|
|
22861
23586
|
const params = placeholdersToParams(placeholders);
|
|
22862
23587
|
i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params));
|
|
@@ -23076,7 +23801,7 @@ class TemplateDefinitionBuilder {
|
|
|
23076
23801
|
}
|
|
23077
23802
|
this.allocateBindingSlots(value);
|
|
23078
23803
|
if (inputType === 0 /* BindingType.Property */) {
|
|
23079
|
-
if (value instanceof Interpolation) {
|
|
23804
|
+
if (value instanceof Interpolation$1) {
|
|
23080
23805
|
// prop="{{value}}" and friends
|
|
23081
23806
|
this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
|
|
23082
23807
|
}
|
|
@@ -23090,12 +23815,12 @@ class TemplateDefinitionBuilder {
|
|
|
23090
23815
|
}
|
|
23091
23816
|
}
|
|
23092
23817
|
else if (inputType === 1 /* BindingType.Attribute */) {
|
|
23093
|
-
if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
|
|
23818
|
+
if (value instanceof Interpolation$1 && getInterpolationArgsLength(value) > 1) {
|
|
23094
23819
|
// attr.name="text{{value}}" and friends
|
|
23095
23820
|
this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params);
|
|
23096
23821
|
}
|
|
23097
23822
|
else {
|
|
23098
|
-
const boundValue = value instanceof Interpolation ? value.expressions[0] : value;
|
|
23823
|
+
const boundValue = value instanceof Interpolation$1 ? value.expressions[0] : value;
|
|
23099
23824
|
// [attr.name]="value" or attr.name="{{value}}"
|
|
23100
23825
|
// Collect the attribute bindings so that they can be chained at the end.
|
|
23101
23826
|
attributeBindings.push({
|
|
@@ -23165,7 +23890,7 @@ class TemplateDefinitionBuilder {
|
|
|
23165
23890
|
parameters.push(importExpr(Identifiers.templateRefExtractor));
|
|
23166
23891
|
}
|
|
23167
23892
|
// Create the template function
|
|
23168
|
-
const templateVisitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this._constants);
|
|
23893
|
+
const templateVisitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this.deferBlocks, this._constants);
|
|
23169
23894
|
// Nested templates must not be visited until after their parent templates have completed
|
|
23170
23895
|
// processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
|
|
23171
23896
|
// be able to support bindings in nested templates to local refs that occur after the
|
|
@@ -23208,7 +23933,7 @@ class TemplateDefinitionBuilder {
|
|
|
23208
23933
|
if (this.i18n) {
|
|
23209
23934
|
const value = text.value.visit(this._valueConverter);
|
|
23210
23935
|
this.allocateBindingSlots(value);
|
|
23211
|
-
if (value instanceof Interpolation) {
|
|
23936
|
+
if (value instanceof Interpolation$1) {
|
|
23212
23937
|
this.i18n.appendBoundText(text.i18n);
|
|
23213
23938
|
this.i18nAppendBindings(value.expressions);
|
|
23214
23939
|
}
|
|
@@ -23218,7 +23943,7 @@ class TemplateDefinitionBuilder {
|
|
|
23218
23943
|
this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(nodeIndex)]);
|
|
23219
23944
|
const value = text.value.visit(this._valueConverter);
|
|
23220
23945
|
this.allocateBindingSlots(value);
|
|
23221
|
-
if (value instanceof Interpolation) {
|
|
23946
|
+
if (value instanceof Interpolation$1) {
|
|
23222
23947
|
this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value));
|
|
23223
23948
|
}
|
|
23224
23949
|
else {
|
|
@@ -23275,8 +24000,43 @@ class TemplateDefinitionBuilder {
|
|
|
23275
24000
|
}
|
|
23276
24001
|
return null;
|
|
23277
24002
|
}
|
|
23278
|
-
|
|
23279
|
-
|
|
24003
|
+
visitDeferredBlock(deferred) {
|
|
24004
|
+
const templateIndex = this.allocateDataSlot();
|
|
24005
|
+
const deferredDeps = this.deferBlocks.get(deferred);
|
|
24006
|
+
const contextName = `${this.contextName}_Defer_${templateIndex}`;
|
|
24007
|
+
const depsFnName = `${contextName}_DepsFn`;
|
|
24008
|
+
const parameters = [
|
|
24009
|
+
literal(templateIndex),
|
|
24010
|
+
deferredDeps ? variable(depsFnName) : TYPED_NULL_EXPR,
|
|
24011
|
+
];
|
|
24012
|
+
if (deferredDeps) {
|
|
24013
|
+
// This defer block has deps for which we need to generate dynamic imports.
|
|
24014
|
+
const dependencyExp = [];
|
|
24015
|
+
for (const deferredDep of deferredDeps) {
|
|
24016
|
+
if (deferredDep.isDeferrable) {
|
|
24017
|
+
// Callback function, e.g. `function(m) { return m.MyCmp; }`.
|
|
24018
|
+
const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(deferredDep.symbolName))]);
|
|
24019
|
+
const fileName = deferredDep.importPath;
|
|
24020
|
+
// Dynamic import, e.g. `import('./a').then(...)`.
|
|
24021
|
+
const importExpr = (new DynamicImportExpr(fileName)).prop('then').callFn([innerFn]);
|
|
24022
|
+
dependencyExp.push(importExpr);
|
|
24023
|
+
}
|
|
24024
|
+
else {
|
|
24025
|
+
// Non-deferrable symbol, just use a reference to the type.
|
|
24026
|
+
dependencyExp.push(deferredDep.type);
|
|
24027
|
+
}
|
|
24028
|
+
}
|
|
24029
|
+
const depsFnBody = [];
|
|
24030
|
+
depsFnBody.push(new ReturnStatement(literalArr(dependencyExp)));
|
|
24031
|
+
const depsFnExpr = fn([] /* args */, depsFnBody, INFERRED_TYPE, null, depsFnName);
|
|
24032
|
+
this.constantPool.statements.push(depsFnExpr.toDeclStmt(depsFnName));
|
|
24033
|
+
}
|
|
24034
|
+
// e.g. `defer(1, MyComp_Defer_1_DepsFn, ...)`
|
|
24035
|
+
this.creationInstruction(deferred.sourceSpan, Identifiers.defer, () => {
|
|
24036
|
+
return trimTrailingNulls(parameters);
|
|
24037
|
+
});
|
|
24038
|
+
}
|
|
24039
|
+
// TODO: implement nested deferred block instructions.
|
|
23280
24040
|
visitDeferredTrigger(trigger) { }
|
|
23281
24041
|
visitDeferredBlockPlaceholder(block) { }
|
|
23282
24042
|
visitDeferredBlockError(block) { }
|
|
@@ -23312,7 +24072,7 @@ class TemplateDefinitionBuilder {
|
|
|
23312
24072
|
continue;
|
|
23313
24073
|
}
|
|
23314
24074
|
this.allocateBindingSlots(value);
|
|
23315
|
-
if (value instanceof Interpolation) {
|
|
24075
|
+
if (value instanceof Interpolation$1) {
|
|
23316
24076
|
// Params typically contain attribute namespace and value sanitizer, which is applicable
|
|
23317
24077
|
// for regular HTML elements, but not applicable for <ng-template> (since props act as
|
|
23318
24078
|
// inputs to directives), so keep params array empty.
|
|
@@ -23344,7 +24104,7 @@ class TemplateDefinitionBuilder {
|
|
|
23344
24104
|
if (instruction) {
|
|
23345
24105
|
for (const call of instruction.calls) {
|
|
23346
24106
|
allocateBindingSlots += call.allocateBindingSlots;
|
|
23347
|
-
this.updateInstructionWithAdvance(elementIndex, call.sourceSpan, instruction.reference, () => call.params(value => (call.supportsInterpolation && value instanceof Interpolation) ?
|
|
24107
|
+
this.updateInstructionWithAdvance(elementIndex, call.sourceSpan, instruction.reference, () => call.params(value => (call.supportsInterpolation && value instanceof Interpolation$1) ?
|
|
23348
24108
|
this.getUpdateInstructionArguments(value) :
|
|
23349
24109
|
this.convertPropertyBinding(value)));
|
|
23350
24110
|
}
|
|
@@ -23377,7 +24137,7 @@ class TemplateDefinitionBuilder {
|
|
|
23377
24137
|
return originalSlots;
|
|
23378
24138
|
}
|
|
23379
24139
|
allocateBindingSlots(value) {
|
|
23380
|
-
this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1;
|
|
24140
|
+
this._bindingSlots += value instanceof Interpolation$1 ? value.expressions.length : 1;
|
|
23381
24141
|
}
|
|
23382
24142
|
/**
|
|
23383
24143
|
* Gets an expression that refers to the implicit receiver. The implicit
|
|
@@ -24330,7 +25090,7 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
24330
25090
|
// This is the main path currently used in compilation, which compiles the template with the
|
|
24331
25091
|
// legacy `TemplateDefinitionBuilder`.
|
|
24332
25092
|
const template = meta.template;
|
|
24333
|
-
const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
|
|
25093
|
+
const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks);
|
|
24334
25094
|
const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
|
|
24335
25095
|
// We need to provide this so that dynamically generated components know what
|
|
24336
25096
|
// projected content blocks to pass through to the component when it is
|
|
@@ -24365,7 +25125,7 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
24365
25125
|
else {
|
|
24366
25126
|
// This path compiles the template using the prototype template pipeline. First the template is
|
|
24367
25127
|
// ingested into IR:
|
|
24368
|
-
const tpl =
|
|
25128
|
+
const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool);
|
|
24369
25129
|
// Then the IR is transformed to prepare it for cod egeneration.
|
|
24370
25130
|
transformTemplate(tpl);
|
|
24371
25131
|
// Finally we emit the template function:
|
|
@@ -24594,6 +25354,25 @@ function createViewQueriesFunction(viewQueries, constantPool, name) {
|
|
|
24594
25354
|
}
|
|
24595
25355
|
// Return a host binding function or null if one is not necessary.
|
|
24596
25356
|
function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) {
|
|
25357
|
+
const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, typeSourceSpan);
|
|
25358
|
+
// Calculate host event bindings
|
|
25359
|
+
const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, typeSourceSpan);
|
|
25360
|
+
if (USE_TEMPLATE_PIPELINE) {
|
|
25361
|
+
// TODO: host binding metadata is not yet parsed in the template pipeline, so we need to extract
|
|
25362
|
+
// that code from below. Then, we will ingest a `HostBindingJob`, and run the template pipeline
|
|
25363
|
+
// phases.
|
|
25364
|
+
const hostJob = ingestHostBinding({
|
|
25365
|
+
componentName: name,
|
|
25366
|
+
properties: bindings,
|
|
25367
|
+
events: eventBindings,
|
|
25368
|
+
}, bindingParser, constantPool);
|
|
25369
|
+
transformHostBinding(hostJob);
|
|
25370
|
+
const varCount = hostJob.root.vars;
|
|
25371
|
+
if (varCount !== null && varCount > 0) {
|
|
25372
|
+
definitionMap.set('hostVars', literal(varCount));
|
|
25373
|
+
}
|
|
25374
|
+
return emitHostBindingFunction(hostJob);
|
|
25375
|
+
}
|
|
24597
25376
|
const bindingContext = variable(CONTEXT_NAME);
|
|
24598
25377
|
const styleBuilder = new StylingBuilder(bindingContext);
|
|
24599
25378
|
const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
|
|
@@ -24607,13 +25386,10 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
24607
25386
|
const updateInstructions = [];
|
|
24608
25387
|
const updateVariables = [];
|
|
24609
25388
|
const hostBindingSourceSpan = typeSourceSpan;
|
|
24610
|
-
// Calculate host event bindings
|
|
24611
|
-
const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, hostBindingSourceSpan);
|
|
24612
25389
|
if (eventBindings && eventBindings.length) {
|
|
24613
25390
|
createInstructions.push(...createHostListeners(eventBindings, name));
|
|
24614
25391
|
}
|
|
24615
25392
|
// Calculate the host property bindings
|
|
24616
|
-
const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, hostBindingSourceSpan);
|
|
24617
25393
|
const allOtherBindings = [];
|
|
24618
25394
|
// We need to calculate the total amount of binding slots required by
|
|
24619
25395
|
// all the instructions together before any value conversions happen.
|
|
@@ -24956,6 +25732,11 @@ function createHostDirectivesMappingArray(mapping) {
|
|
|
24956
25732
|
class ResourceLoader {
|
|
24957
25733
|
}
|
|
24958
25734
|
|
|
25735
|
+
let enabledBlockTypes;
|
|
25736
|
+
/** Temporary utility that enables specific block types in JIT compilations. */
|
|
25737
|
+
function ɵsetEnabledBlockTypes(types) {
|
|
25738
|
+
enabledBlockTypes = types.length > 0 ? new Set(types) : undefined;
|
|
25739
|
+
}
|
|
24959
25740
|
class CompilerFacadeImpl {
|
|
24960
25741
|
constructor(jitEvaluator = new JitEvaluator()) {
|
|
24961
25742
|
this.jitEvaluator = jitEvaluator;
|
|
@@ -25076,6 +25857,10 @@ class CompilerFacadeImpl {
|
|
|
25076
25857
|
template,
|
|
25077
25858
|
declarations: facade.declarations.map(convertDeclarationFacadeToMetadata),
|
|
25078
25859
|
declarationListEmitMode: 0 /* DeclarationListEmitMode.Direct */,
|
|
25860
|
+
// TODO: leaving empty in JIT mode for now,
|
|
25861
|
+
// to be implemented as one of the next steps.
|
|
25862
|
+
deferBlocks: new Map(),
|
|
25863
|
+
deferrableDeclToImportDecl: new Map(),
|
|
25079
25864
|
styles: [...facade.styles, ...template.styles],
|
|
25080
25865
|
encapsulation: facade.encapsulation,
|
|
25081
25866
|
interpolation,
|
|
@@ -25306,6 +26091,10 @@ function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMap
|
|
|
25306
26091
|
viewProviders: decl.viewProviders !== undefined ? new WrappedNodeExpr(decl.viewProviders) :
|
|
25307
26092
|
null,
|
|
25308
26093
|
animations: decl.animations !== undefined ? new WrappedNodeExpr(decl.animations) : null,
|
|
26094
|
+
// TODO: leaving empty in JIT mode for now,
|
|
26095
|
+
// to be implemented as one of the next steps.
|
|
26096
|
+
deferBlocks: new Map(),
|
|
26097
|
+
deferrableDeclToImportDecl: new Map(),
|
|
25309
26098
|
changeDetection: decl.changeDetection ?? ChangeDetectionStrategy.Default,
|
|
25310
26099
|
encapsulation: decl.encapsulation ?? ViewEncapsulation.Emulated,
|
|
25311
26100
|
interpolation,
|
|
@@ -25353,11 +26142,7 @@ function convertPipeDeclarationToMetadata(pipe) {
|
|
|
25353
26142
|
function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
|
|
25354
26143
|
const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
|
|
25355
26144
|
// Parse the template and check for errors.
|
|
25356
|
-
const parsed = parseTemplate(template, sourceMapUrl, {
|
|
25357
|
-
preserveWhitespaces,
|
|
25358
|
-
interpolationConfig,
|
|
25359
|
-
enabledBlockTypes: new Set(), // TODO: enable deferred blocks when testing in JIT mode.
|
|
25360
|
-
});
|
|
26145
|
+
const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig, enabledBlockTypes });
|
|
25361
26146
|
if (parsed.errors !== null) {
|
|
25362
26147
|
const errors = parsed.errors.map(err => err.toString()).join(', ');
|
|
25363
26148
|
throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
|
|
@@ -25546,7 +26331,7 @@ function publishFacade(global) {
|
|
|
25546
26331
|
* @description
|
|
25547
26332
|
* Entry point for all public APIs of the compiler package.
|
|
25548
26333
|
*/
|
|
25549
|
-
const VERSION = new Version('16.2.0-
|
|
26334
|
+
const VERSION = new Version('16.2.0-rc.0');
|
|
25550
26335
|
|
|
25551
26336
|
class CompilerConfig {
|
|
25552
26337
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -27014,11 +27799,11 @@ class R3TargetBinder {
|
|
|
27014
27799
|
// - bindings: Map of inputs, outputs, and attributes to the directive/element that claims
|
|
27015
27800
|
// them. TODO(alxhub): handle multiple directives claiming an input/output/etc.
|
|
27016
27801
|
// - references: Map of #references to their targets.
|
|
27017
|
-
const { directives, bindings, references } = DirectiveBinder.apply(target.template, this.directiveMatcher);
|
|
27802
|
+
const { directives, eagerDirectives, bindings, references } = DirectiveBinder.apply(target.template, this.directiveMatcher);
|
|
27018
27803
|
// Finally, run the TemplateBinder to bind references, variables, and other entities within the
|
|
27019
27804
|
// template. This extracts all the metadata that doesn't depend on directive matching.
|
|
27020
|
-
const { expressions, symbols, nestingLevel, usedPipes } = TemplateBinder.applyWithScope(target.template, scope);
|
|
27021
|
-
return new R3BoundTarget(target, directives, bindings, references, expressions, symbols, nestingLevel, templateEntities, usedPipes);
|
|
27805
|
+
const { expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks } = TemplateBinder.applyWithScope(target.template, scope);
|
|
27806
|
+
return new R3BoundTarget(target, directives, eagerDirectives, bindings, references, expressions, symbols, nestingLevel, templateEntities, usedPipes, eagerPipes, deferBlocks);
|
|
27022
27807
|
}
|
|
27023
27808
|
}
|
|
27024
27809
|
/**
|
|
@@ -27159,11 +27944,14 @@ class Scope {
|
|
|
27159
27944
|
* Usually used via the static `apply()` method.
|
|
27160
27945
|
*/
|
|
27161
27946
|
class DirectiveBinder {
|
|
27162
|
-
constructor(matcher, directives, bindings, references) {
|
|
27947
|
+
constructor(matcher, directives, eagerDirectives, bindings, references) {
|
|
27163
27948
|
this.matcher = matcher;
|
|
27164
27949
|
this.directives = directives;
|
|
27950
|
+
this.eagerDirectives = eagerDirectives;
|
|
27165
27951
|
this.bindings = bindings;
|
|
27166
27952
|
this.references = references;
|
|
27953
|
+
// Indicates whether we are visiting elements within a {#defer} block
|
|
27954
|
+
this.isInDeferBlock = false;
|
|
27167
27955
|
}
|
|
27168
27956
|
/**
|
|
27169
27957
|
* Process a template (list of `Node`s) and perform directive matching against each node.
|
|
@@ -27181,9 +27969,10 @@ class DirectiveBinder {
|
|
|
27181
27969
|
const directives = new Map();
|
|
27182
27970
|
const bindings = new Map();
|
|
27183
27971
|
const references = new Map();
|
|
27184
|
-
const
|
|
27972
|
+
const eagerDirectives = [];
|
|
27973
|
+
const matcher = new DirectiveBinder(selectorMatcher, directives, eagerDirectives, bindings, references);
|
|
27185
27974
|
matcher.ingest(template);
|
|
27186
|
-
return { directives, bindings, references };
|
|
27975
|
+
return { directives, eagerDirectives, bindings, references };
|
|
27187
27976
|
}
|
|
27188
27977
|
ingest(template) {
|
|
27189
27978
|
template.forEach(node => node.visit(this));
|
|
@@ -27203,6 +27992,9 @@ class DirectiveBinder {
|
|
|
27203
27992
|
this.matcher.match(cssSelector, (_selector, results) => directives.push(...results));
|
|
27204
27993
|
if (directives.length > 0) {
|
|
27205
27994
|
this.directives.set(node, directives);
|
|
27995
|
+
if (!this.isInDeferBlock) {
|
|
27996
|
+
this.eagerDirectives.push(...directives);
|
|
27997
|
+
}
|
|
27206
27998
|
}
|
|
27207
27999
|
// Resolve any references that are created on this node.
|
|
27208
28000
|
node.references.forEach(ref => {
|
|
@@ -27253,7 +28045,9 @@ class DirectiveBinder {
|
|
|
27253
28045
|
node.children.forEach(child => child.visit(this));
|
|
27254
28046
|
}
|
|
27255
28047
|
visitDeferredBlock(deferred) {
|
|
28048
|
+
this.isInDeferBlock = true;
|
|
27256
28049
|
deferred.children.forEach(child => child.visit(this));
|
|
28050
|
+
this.isInDeferBlock = false;
|
|
27257
28051
|
deferred.placeholder?.visit(this);
|
|
27258
28052
|
deferred.loading?.visit(this);
|
|
27259
28053
|
deferred.error?.visit(this);
|
|
@@ -27290,15 +28084,19 @@ class DirectiveBinder {
|
|
|
27290
28084
|
* by overridden methods from that visitor.
|
|
27291
28085
|
*/
|
|
27292
28086
|
class TemplateBinder extends RecursiveAstVisitor {
|
|
27293
|
-
constructor(bindings, symbols, usedPipes, nestingLevel, scope, template, level) {
|
|
28087
|
+
constructor(bindings, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, level) {
|
|
27294
28088
|
super();
|
|
27295
28089
|
this.bindings = bindings;
|
|
27296
28090
|
this.symbols = symbols;
|
|
27297
28091
|
this.usedPipes = usedPipes;
|
|
28092
|
+
this.eagerPipes = eagerPipes;
|
|
28093
|
+
this.deferBlocks = deferBlocks;
|
|
27298
28094
|
this.nestingLevel = nestingLevel;
|
|
27299
28095
|
this.scope = scope;
|
|
27300
28096
|
this.template = template;
|
|
27301
28097
|
this.level = level;
|
|
28098
|
+
// Indicates whether we are visiting elements within a {#defer} block
|
|
28099
|
+
this.isInDeferBlock = false;
|
|
27302
28100
|
// Save a bit of processing time by constructing this closure in advance.
|
|
27303
28101
|
this.visitNode = (node) => node.visit(this);
|
|
27304
28102
|
}
|
|
@@ -27330,11 +28128,13 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
27330
28128
|
const symbols = new Map();
|
|
27331
28129
|
const nestingLevel = new Map();
|
|
27332
28130
|
const usedPipes = new Set();
|
|
28131
|
+
const eagerPipes = new Set();
|
|
27333
28132
|
const template = nodes instanceof Template ? nodes : null;
|
|
28133
|
+
const deferBlocks = new Set();
|
|
27334
28134
|
// The top-level template has nesting level 0.
|
|
27335
|
-
const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template, 0);
|
|
28135
|
+
const binder = new TemplateBinder(expressions, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, 0);
|
|
27336
28136
|
binder.ingest(nodes);
|
|
27337
|
-
return { expressions, symbols, nestingLevel, usedPipes };
|
|
28137
|
+
return { expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks };
|
|
27338
28138
|
}
|
|
27339
28139
|
ingest(template) {
|
|
27340
28140
|
if (template instanceof Template) {
|
|
@@ -27365,7 +28165,7 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
27365
28165
|
template.references.forEach(this.visitNode);
|
|
27366
28166
|
// Next, recurse into the template using its scope, and bumping the nesting level up by one.
|
|
27367
28167
|
const childScope = this.scope.getChildScope(template);
|
|
27368
|
-
const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.nestingLevel, childScope, template, this.level + 1);
|
|
28168
|
+
const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.eagerPipes, this.deferBlocks, this.nestingLevel, childScope, template, this.level + 1);
|
|
27369
28169
|
binder.ingest(template);
|
|
27370
28170
|
}
|
|
27371
28171
|
visitVariable(variable) {
|
|
@@ -27396,9 +28196,12 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
27396
28196
|
event.handler.visit(this);
|
|
27397
28197
|
}
|
|
27398
28198
|
visitDeferredBlock(deferred) {
|
|
28199
|
+
this.deferBlocks.add(deferred);
|
|
28200
|
+
this.isInDeferBlock = true;
|
|
28201
|
+
deferred.children.forEach(this.visitNode);
|
|
28202
|
+
this.isInDeferBlock = false;
|
|
27399
28203
|
deferred.triggers.forEach(this.visitNode);
|
|
27400
28204
|
deferred.prefetchTriggers.forEach(this.visitNode);
|
|
27401
|
-
deferred.children.forEach(this.visitNode);
|
|
27402
28205
|
deferred.placeholder && this.visitNode(deferred.placeholder);
|
|
27403
28206
|
deferred.loading && this.visitNode(deferred.loading);
|
|
27404
28207
|
deferred.error && this.visitNode(deferred.error);
|
|
@@ -27422,6 +28225,9 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
27422
28225
|
}
|
|
27423
28226
|
visitPipe(ast, context) {
|
|
27424
28227
|
this.usedPipes.add(ast.name);
|
|
28228
|
+
if (!this.isInDeferBlock) {
|
|
28229
|
+
this.eagerPipes.add(ast.name);
|
|
28230
|
+
}
|
|
27425
28231
|
return super.visitPipe(ast, context);
|
|
27426
28232
|
}
|
|
27427
28233
|
// These five types of AST expressions can refer to expression roots, which could be variables
|
|
@@ -27458,9 +28264,10 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
27458
28264
|
* See `BoundTarget` for documentation on the individual methods.
|
|
27459
28265
|
*/
|
|
27460
28266
|
class R3BoundTarget {
|
|
27461
|
-
constructor(target, directives, bindings, references, exprTargets, symbols, nestingLevel, templateEntities, usedPipes) {
|
|
28267
|
+
constructor(target, directives, eagerDirectives, bindings, references, exprTargets, symbols, nestingLevel, templateEntities, usedPipes, eagerPipes, deferredBlocks) {
|
|
27462
28268
|
this.target = target;
|
|
27463
28269
|
this.directives = directives;
|
|
28270
|
+
this.eagerDirectives = eagerDirectives;
|
|
27464
28271
|
this.bindings = bindings;
|
|
27465
28272
|
this.references = references;
|
|
27466
28273
|
this.exprTargets = exprTargets;
|
|
@@ -27468,6 +28275,8 @@ class R3BoundTarget {
|
|
|
27468
28275
|
this.nestingLevel = nestingLevel;
|
|
27469
28276
|
this.templateEntities = templateEntities;
|
|
27470
28277
|
this.usedPipes = usedPipes;
|
|
28278
|
+
this.eagerPipes = eagerPipes;
|
|
28279
|
+
this.deferredBlocks = deferredBlocks;
|
|
27471
28280
|
}
|
|
27472
28281
|
getEntitiesInTemplateScope(template) {
|
|
27473
28282
|
return this.templateEntities.get(template) ?? new Set();
|
|
@@ -27495,9 +28304,19 @@ class R3BoundTarget {
|
|
|
27495
28304
|
this.directives.forEach(dirs => dirs.forEach(dir => set.add(dir)));
|
|
27496
28305
|
return Array.from(set.values());
|
|
27497
28306
|
}
|
|
28307
|
+
getEagerlyUsedDirectives() {
|
|
28308
|
+
const set = new Set(this.eagerDirectives);
|
|
28309
|
+
return Array.from(set.values());
|
|
28310
|
+
}
|
|
27498
28311
|
getUsedPipes() {
|
|
27499
28312
|
return Array.from(this.usedPipes);
|
|
27500
28313
|
}
|
|
28314
|
+
getEagerlyUsedPipes() {
|
|
28315
|
+
return Array.from(this.eagerPipes);
|
|
28316
|
+
}
|
|
28317
|
+
getDeferBlocks() {
|
|
28318
|
+
return Array.from(this.deferredBlocks);
|
|
28319
|
+
}
|
|
27501
28320
|
}
|
|
27502
28321
|
function extractTemplateEntities(rootScope) {
|
|
27503
28322
|
const entityMap = new Map();
|
|
@@ -27555,7 +28374,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
27555
28374
|
function compileDeclareClassMetadata(metadata) {
|
|
27556
28375
|
const definitionMap = new DefinitionMap();
|
|
27557
28376
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
27558
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28377
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
27559
28378
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27560
28379
|
definitionMap.set('type', metadata.type);
|
|
27561
28380
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -27658,7 +28477,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
27658
28477
|
function createDirectiveDefinitionMap(meta) {
|
|
27659
28478
|
const definitionMap = new DefinitionMap();
|
|
27660
28479
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
27661
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28480
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
27662
28481
|
// e.g. `type: MyDirective`
|
|
27663
28482
|
definitionMap.set('type', meta.type.value);
|
|
27664
28483
|
if (meta.isStandalone) {
|
|
@@ -27886,7 +28705,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
27886
28705
|
function compileDeclareFactoryFunction(meta) {
|
|
27887
28706
|
const definitionMap = new DefinitionMap();
|
|
27888
28707
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
27889
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28708
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
27890
28709
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27891
28710
|
definitionMap.set('type', meta.type.value);
|
|
27892
28711
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -27921,7 +28740,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
27921
28740
|
function createInjectableDefinitionMap(meta) {
|
|
27922
28741
|
const definitionMap = new DefinitionMap();
|
|
27923
28742
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
27924
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28743
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
27925
28744
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27926
28745
|
definitionMap.set('type', meta.type.value);
|
|
27927
28746
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -27972,7 +28791,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
27972
28791
|
function createInjectorDefinitionMap(meta) {
|
|
27973
28792
|
const definitionMap = new DefinitionMap();
|
|
27974
28793
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
27975
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28794
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
27976
28795
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27977
28796
|
definitionMap.set('type', meta.type.value);
|
|
27978
28797
|
definitionMap.set('providers', meta.providers);
|
|
@@ -28005,7 +28824,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
28005
28824
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
28006
28825
|
}
|
|
28007
28826
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
28008
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28827
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
28009
28828
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28010
28829
|
definitionMap.set('type', meta.type.value);
|
|
28011
28830
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -28056,7 +28875,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
28056
28875
|
function createPipeDefinitionMap(meta) {
|
|
28057
28876
|
const definitionMap = new DefinitionMap();
|
|
28058
28877
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
28059
|
-
definitionMap.set('version', literal('16.2.0-
|
|
28878
|
+
definitionMap.set('version', literal('16.2.0-rc.0'));
|
|
28060
28879
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28061
28880
|
// e.g. `type: MyPipe`
|
|
28062
28881
|
definitionMap.set('type', meta.type.value);
|
|
@@ -28089,5 +28908,5 @@ publishFacade(_global);
|
|
|
28089
28908
|
|
|
28090
28909
|
// This file is not used to build this module. It is only used during editing
|
|
28091
28910
|
|
|
28092
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
28911
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
28093
28912
|
//# sourceMappingURL=compiler.mjs.map
|