@angular/compiler 16.2.0-next.2 → 16.2.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler.mjs +3 -3
- package/esm2022/src/jit_compiler_facade.mjs +6 -2
- package/esm2022/src/output/abstract_emitter.mjs +4 -1
- package/esm2022/src/output/output_ast.mjs +22 -1
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_ast.mjs +109 -1
- package/esm2022/src/render3/r3_deferred_blocks.mjs +156 -0
- package/esm2022/src/render3/r3_deferred_triggers.mjs +275 -0
- package/esm2022/src/render3/r3_template_transform.mjs +40 -12
- package/esm2022/src/render3/view/t2_binder.mjs +61 -6
- package/esm2022/src/render3/view/template.mjs +17 -3
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +21 -9
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +4 -1
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +42 -1
- package/esm2022/src/template/pipeline/src/emit.mjs +8 -6
- package/esm2022/src/template/pipeline/src/ingest.mjs +25 -3
- package/esm2022/src/template/pipeline/src/instruction.mjs +35 -8
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +2 -1
- package/esm2022/src/template/pipeline/src/phases/chaining.mjs +11 -1
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +38 -9
- package/esm2022/src/template/pipeline/src/phases/property_ordering.mjs +82 -0
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +10 -1
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +13 -8
- package/esm2022/src/template_parser/binding_parser.mjs +4 -4
- package/esm2022/src/util.mjs +2 -8
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1322 -454
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +120 -2
- package/package.json +2 -2
- package/testing/index.d.ts +1 -1
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v16.2.0-next.
|
|
2
|
+
* @license Angular v16.2.0-next.3
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -1621,6 +1621,24 @@ class ConditionalExpr extends Expression {
|
|
|
1621
1621
|
return new ConditionalExpr(this.condition.clone(), this.trueCase.clone(), this.falseCase?.clone(), this.type, this.sourceSpan);
|
|
1622
1622
|
}
|
|
1623
1623
|
}
|
|
1624
|
+
class DynamicImportExpr extends Expression {
|
|
1625
|
+
constructor(url, sourceSpan) {
|
|
1626
|
+
super(null, sourceSpan);
|
|
1627
|
+
this.url = url;
|
|
1628
|
+
}
|
|
1629
|
+
isEquivalent(e) {
|
|
1630
|
+
return e instanceof DynamicImportExpr && this.url === e.url;
|
|
1631
|
+
}
|
|
1632
|
+
isConstant() {
|
|
1633
|
+
return false;
|
|
1634
|
+
}
|
|
1635
|
+
visitExpression(visitor, context) {
|
|
1636
|
+
return visitor.visitDynamicImportExpr(this, context);
|
|
1637
|
+
}
|
|
1638
|
+
clone() {
|
|
1639
|
+
return new DynamicImportExpr(this.url, this.sourceSpan);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1624
1642
|
class NotExpr extends Expression {
|
|
1625
1643
|
constructor(condition, sourceSpan) {
|
|
1626
1644
|
super(BOOL_TYPE, sourceSpan);
|
|
@@ -2009,6 +2027,9 @@ class RecursiveAstVisitor$1 {
|
|
|
2009
2027
|
ast.value.visitExpression(this, context);
|
|
2010
2028
|
return this.visitExpression(ast, context);
|
|
2011
2029
|
}
|
|
2030
|
+
visitDynamicImportExpr(ast, context) {
|
|
2031
|
+
return this.visitExpression(ast, context);
|
|
2032
|
+
}
|
|
2012
2033
|
visitInvokeFunctionExpr(ast, context) {
|
|
2013
2034
|
ast.fn.visitExpression(this, context);
|
|
2014
2035
|
this.visitAllExpressions(ast.args, context);
|
|
@@ -2247,6 +2268,7 @@ var output_ast = /*#__PURE__*/Object.freeze({
|
|
|
2247
2268
|
ExternalExpr: ExternalExpr,
|
|
2248
2269
|
ExternalReference: ExternalReference,
|
|
2249
2270
|
ConditionalExpr: ConditionalExpr,
|
|
2271
|
+
DynamicImportExpr: DynamicImportExpr,
|
|
2250
2272
|
NotExpr: NotExpr,
|
|
2251
2273
|
FnParam: FnParam,
|
|
2252
2274
|
FunctionExpr: FunctionExpr,
|
|
@@ -2825,13 +2847,7 @@ class Version {
|
|
|
2825
2847
|
this.patch = splits.slice(2).join('.');
|
|
2826
2848
|
}
|
|
2827
2849
|
}
|
|
2828
|
-
|
|
2829
|
-
// `_global` variable should point to the NodeJS `global` in that case. Note: Typeof/Instanceof
|
|
2830
|
-
// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
|
|
2831
|
-
// https://github.com/terser/terser/issues/250.
|
|
2832
|
-
const _global = ( /* @__PURE__ */(() => (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
|
|
2833
|
-
(typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
|
|
2834
|
-
self instanceof WorkerGlobalScope && self))());
|
|
2850
|
+
const _global = globalThis;
|
|
2835
2851
|
function newArray(size, value) {
|
|
2836
2852
|
const list = [];
|
|
2837
2853
|
for (let i = 0; i < size; i++) {
|
|
@@ -3313,6 +3329,9 @@ class AbstractEmitterVisitor {
|
|
|
3313
3329
|
ctx.print(ast, `)`);
|
|
3314
3330
|
return null;
|
|
3315
3331
|
}
|
|
3332
|
+
visitDynamicImportExpr(ast, ctx) {
|
|
3333
|
+
ctx.print(ast, `import(${ast.url})`);
|
|
3334
|
+
}
|
|
3316
3335
|
visitNotExpr(ast, ctx) {
|
|
3317
3336
|
ctx.print(ast, '!');
|
|
3318
3337
|
ast.condition.visitExpression(this, ctx);
|
|
@@ -3886,6 +3905,96 @@ class Element$1 {
|
|
|
3886
3905
|
return visitor.visitElement(this);
|
|
3887
3906
|
}
|
|
3888
3907
|
}
|
|
3908
|
+
class DeferredTrigger {
|
|
3909
|
+
constructor(sourceSpan) {
|
|
3910
|
+
this.sourceSpan = sourceSpan;
|
|
3911
|
+
}
|
|
3912
|
+
visit(visitor) {
|
|
3913
|
+
return visitor.visitDeferredTrigger(this);
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
class BoundDeferredTrigger extends DeferredTrigger {
|
|
3917
|
+
constructor(value, sourceSpan) {
|
|
3918
|
+
super(sourceSpan);
|
|
3919
|
+
this.value = value;
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
class IdleDeferredTrigger extends DeferredTrigger {
|
|
3923
|
+
}
|
|
3924
|
+
class ImmediateDeferredTrigger extends DeferredTrigger {
|
|
3925
|
+
}
|
|
3926
|
+
class HoverDeferredTrigger extends DeferredTrigger {
|
|
3927
|
+
}
|
|
3928
|
+
class TimerDeferredTrigger extends DeferredTrigger {
|
|
3929
|
+
constructor(delay, sourceSpan) {
|
|
3930
|
+
super(sourceSpan);
|
|
3931
|
+
this.delay = delay;
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
class InteractionDeferredTrigger extends DeferredTrigger {
|
|
3935
|
+
constructor(reference, sourceSpan) {
|
|
3936
|
+
super(sourceSpan);
|
|
3937
|
+
this.reference = reference;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
class ViewportDeferredTrigger extends DeferredTrigger {
|
|
3941
|
+
constructor(reference, sourceSpan) {
|
|
3942
|
+
super(sourceSpan);
|
|
3943
|
+
this.reference = reference;
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
class DeferredBlockPlaceholder {
|
|
3947
|
+
constructor(children, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3948
|
+
this.children = children;
|
|
3949
|
+
this.minimumTime = minimumTime;
|
|
3950
|
+
this.sourceSpan = sourceSpan;
|
|
3951
|
+
this.startSourceSpan = startSourceSpan;
|
|
3952
|
+
this.endSourceSpan = endSourceSpan;
|
|
3953
|
+
}
|
|
3954
|
+
visit(visitor) {
|
|
3955
|
+
return visitor.visitDeferredBlockPlaceholder(this);
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
class DeferredBlockLoading {
|
|
3959
|
+
constructor(children, afterTime, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3960
|
+
this.children = children;
|
|
3961
|
+
this.afterTime = afterTime;
|
|
3962
|
+
this.minimumTime = minimumTime;
|
|
3963
|
+
this.sourceSpan = sourceSpan;
|
|
3964
|
+
this.startSourceSpan = startSourceSpan;
|
|
3965
|
+
this.endSourceSpan = endSourceSpan;
|
|
3966
|
+
}
|
|
3967
|
+
visit(visitor) {
|
|
3968
|
+
return visitor.visitDeferredBlockLoading(this);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
class DeferredBlockError {
|
|
3972
|
+
constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3973
|
+
this.children = children;
|
|
3974
|
+
this.sourceSpan = sourceSpan;
|
|
3975
|
+
this.startSourceSpan = startSourceSpan;
|
|
3976
|
+
this.endSourceSpan = endSourceSpan;
|
|
3977
|
+
}
|
|
3978
|
+
visit(visitor) {
|
|
3979
|
+
return visitor.visitDeferredBlockError(this);
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
class DeferredBlock {
|
|
3983
|
+
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3984
|
+
this.children = children;
|
|
3985
|
+
this.triggers = triggers;
|
|
3986
|
+
this.prefetchTriggers = prefetchTriggers;
|
|
3987
|
+
this.placeholder = placeholder;
|
|
3988
|
+
this.loading = loading;
|
|
3989
|
+
this.error = error;
|
|
3990
|
+
this.sourceSpan = sourceSpan;
|
|
3991
|
+
this.startSourceSpan = startSourceSpan;
|
|
3992
|
+
this.endSourceSpan = endSourceSpan;
|
|
3993
|
+
}
|
|
3994
|
+
visit(visitor) {
|
|
3995
|
+
return visitor.visitDeferredBlock(this);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3889
3998
|
class Template {
|
|
3890
3999
|
constructor(
|
|
3891
4000
|
// tagName is the name of the container element, if applicable.
|
|
@@ -3973,6 +4082,23 @@ class RecursiveVisitor$1 {
|
|
|
3973
4082
|
visitAll$1(this, template.references);
|
|
3974
4083
|
visitAll$1(this, template.variables);
|
|
3975
4084
|
}
|
|
4085
|
+
visitDeferredBlock(deferred) {
|
|
4086
|
+
visitAll$1(this, deferred.triggers);
|
|
4087
|
+
visitAll$1(this, deferred.prefetchTriggers);
|
|
4088
|
+
visitAll$1(this, deferred.children);
|
|
4089
|
+
deferred.placeholder?.visit(this);
|
|
4090
|
+
deferred.loading?.visit(this);
|
|
4091
|
+
deferred.error?.visit(this);
|
|
4092
|
+
}
|
|
4093
|
+
visitDeferredBlockPlaceholder(block) {
|
|
4094
|
+
visitAll$1(this, block.children);
|
|
4095
|
+
}
|
|
4096
|
+
visitDeferredBlockError(block) {
|
|
4097
|
+
visitAll$1(this, block.children);
|
|
4098
|
+
}
|
|
4099
|
+
visitDeferredBlockLoading(block) {
|
|
4100
|
+
visitAll$1(this, block.children);
|
|
4101
|
+
}
|
|
3976
4102
|
visitContent(content) { }
|
|
3977
4103
|
visitVariable(variable) { }
|
|
3978
4104
|
visitReference(reference) { }
|
|
@@ -3982,6 +4108,7 @@ class RecursiveVisitor$1 {
|
|
|
3982
4108
|
visitText(text) { }
|
|
3983
4109
|
visitBoundText(text) { }
|
|
3984
4110
|
visitIcu(icu) { }
|
|
4111
|
+
visitDeferredTrigger(trigger) { }
|
|
3985
4112
|
}
|
|
3986
4113
|
function visitAll$1(visitor, nodes) {
|
|
3987
4114
|
const result = [];
|
|
@@ -8685,38 +8812,50 @@ var OpKind;
|
|
|
8685
8812
|
* An operation to bind an expression to a style property of an element.
|
|
8686
8813
|
*/
|
|
8687
8814
|
OpKind[OpKind["StyleProp"] = 14] = "StyleProp";
|
|
8815
|
+
/**
|
|
8816
|
+
* An operation to bind an expression to a class property of an element.
|
|
8817
|
+
*/
|
|
8818
|
+
OpKind[OpKind["ClassProp"] = 15] = "ClassProp";
|
|
8688
8819
|
/**
|
|
8689
8820
|
* An operation to bind an expression to the styles of an element.
|
|
8690
8821
|
*/
|
|
8691
|
-
OpKind[OpKind["StyleMap"] =
|
|
8822
|
+
OpKind[OpKind["StyleMap"] = 16] = "StyleMap";
|
|
8823
|
+
/**
|
|
8824
|
+
* An operation to bind an expression to the classes of an element.
|
|
8825
|
+
*/
|
|
8826
|
+
OpKind[OpKind["ClassMap"] = 17] = "ClassMap";
|
|
8692
8827
|
/**
|
|
8693
8828
|
* An operation to interpolate text into a property binding.
|
|
8694
8829
|
*/
|
|
8695
|
-
OpKind[OpKind["InterpolateProperty"] =
|
|
8830
|
+
OpKind[OpKind["InterpolateProperty"] = 18] = "InterpolateProperty";
|
|
8696
8831
|
/**
|
|
8697
8832
|
* An operation to interpolate text into a style property binding.
|
|
8698
8833
|
*/
|
|
8699
|
-
OpKind[OpKind["InterpolateStyleProp"] =
|
|
8834
|
+
OpKind[OpKind["InterpolateStyleProp"] = 19] = "InterpolateStyleProp";
|
|
8700
8835
|
/**
|
|
8701
8836
|
* An operation to interpolate text into a style mapping.
|
|
8702
8837
|
*/
|
|
8703
|
-
OpKind[OpKind["InterpolateStyleMap"] =
|
|
8838
|
+
OpKind[OpKind["InterpolateStyleMap"] = 20] = "InterpolateStyleMap";
|
|
8839
|
+
/**
|
|
8840
|
+
* An operation to interpolate text into a class mapping.
|
|
8841
|
+
*/
|
|
8842
|
+
OpKind[OpKind["InterpolateClassMap"] = 21] = "InterpolateClassMap";
|
|
8704
8843
|
/**
|
|
8705
8844
|
* An operation to advance the runtime's implicit slot context during the update phase of a view.
|
|
8706
8845
|
*/
|
|
8707
|
-
OpKind[OpKind["Advance"] =
|
|
8846
|
+
OpKind[OpKind["Advance"] = 22] = "Advance";
|
|
8708
8847
|
/**
|
|
8709
8848
|
* An operation to instantiate a pipe.
|
|
8710
8849
|
*/
|
|
8711
|
-
OpKind[OpKind["Pipe"] =
|
|
8850
|
+
OpKind[OpKind["Pipe"] = 23] = "Pipe";
|
|
8712
8851
|
/**
|
|
8713
8852
|
* An operation to associate an attribute with an element.
|
|
8714
8853
|
*/
|
|
8715
|
-
OpKind[OpKind["Attribute"] =
|
|
8854
|
+
OpKind[OpKind["Attribute"] = 24] = "Attribute";
|
|
8716
8855
|
/**
|
|
8717
8856
|
* An operation to interpolate text into an attribute binding.
|
|
8718
8857
|
*/
|
|
8719
|
-
OpKind[OpKind["InterpolateAttribute"] =
|
|
8858
|
+
OpKind[OpKind["InterpolateAttribute"] = 25] = "InterpolateAttribute";
|
|
8720
8859
|
})(OpKind || (OpKind = {}));
|
|
8721
8860
|
/**
|
|
8722
8861
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9454,11 +9593,14 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9454
9593
|
case OpKind.Property:
|
|
9455
9594
|
case OpKind.StyleProp:
|
|
9456
9595
|
case OpKind.StyleMap:
|
|
9596
|
+
case OpKind.ClassProp:
|
|
9597
|
+
case OpKind.ClassMap:
|
|
9457
9598
|
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
9458
9599
|
break;
|
|
9459
9600
|
case OpKind.InterpolateProperty:
|
|
9460
9601
|
case OpKind.InterpolateStyleProp:
|
|
9461
9602
|
case OpKind.InterpolateStyleMap:
|
|
9603
|
+
case OpKind.InterpolateClassMap:
|
|
9462
9604
|
case OpKind.InterpolateText:
|
|
9463
9605
|
for (let i = 0; i < op.expressions.length; i++) {
|
|
9464
9606
|
op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
|
|
@@ -9977,6 +10119,20 @@ function createStylePropOp(xref, name, expression, unit) {
|
|
|
9977
10119
|
...NEW_OP,
|
|
9978
10120
|
};
|
|
9979
10121
|
}
|
|
10122
|
+
/**
|
|
10123
|
+
* Create a `ClassPropOp`.
|
|
10124
|
+
*/
|
|
10125
|
+
function createClassPropOp(xref, name, expression) {
|
|
10126
|
+
return {
|
|
10127
|
+
kind: OpKind.ClassProp,
|
|
10128
|
+
target: xref,
|
|
10129
|
+
name,
|
|
10130
|
+
expression,
|
|
10131
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10132
|
+
...TRAIT_CONSUMES_VARS,
|
|
10133
|
+
...NEW_OP,
|
|
10134
|
+
};
|
|
10135
|
+
}
|
|
9980
10136
|
/** Create a `StyleMapOp`. */
|
|
9981
10137
|
function createStyleMapOp(xref, expression) {
|
|
9982
10138
|
return {
|
|
@@ -9988,6 +10144,19 @@ function createStyleMapOp(xref, expression) {
|
|
|
9988
10144
|
...NEW_OP,
|
|
9989
10145
|
};
|
|
9990
10146
|
}
|
|
10147
|
+
/**
|
|
10148
|
+
* Create a `ClassMapOp`.
|
|
10149
|
+
*/
|
|
10150
|
+
function createClassMapOp(xref, expression) {
|
|
10151
|
+
return {
|
|
10152
|
+
kind: OpKind.ClassMap,
|
|
10153
|
+
target: xref,
|
|
10154
|
+
expression,
|
|
10155
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10156
|
+
...TRAIT_CONSUMES_VARS,
|
|
10157
|
+
...NEW_OP,
|
|
10158
|
+
};
|
|
10159
|
+
}
|
|
9991
10160
|
/**
|
|
9992
10161
|
* Create an `AttributeOp`.
|
|
9993
10162
|
*/
|
|
@@ -10062,6 +10231,20 @@ function createInterpolateStyleMapOp(xref, strings, expressions) {
|
|
|
10062
10231
|
...NEW_OP,
|
|
10063
10232
|
};
|
|
10064
10233
|
}
|
|
10234
|
+
/**
|
|
10235
|
+
* Create a `InterpolateStyleMap`.
|
|
10236
|
+
*/
|
|
10237
|
+
function createInterpolateClassMapOp(xref, strings, expressions) {
|
|
10238
|
+
return {
|
|
10239
|
+
kind: OpKind.InterpolateClassMap,
|
|
10240
|
+
target: xref,
|
|
10241
|
+
strings,
|
|
10242
|
+
expressions,
|
|
10243
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
10244
|
+
...TRAIT_CONSUMES_VARS,
|
|
10245
|
+
...NEW_OP,
|
|
10246
|
+
};
|
|
10247
|
+
}
|
|
10065
10248
|
/**
|
|
10066
10249
|
* Create an `AdvanceOp`.
|
|
10067
10250
|
*/
|
|
@@ -10119,25 +10302,30 @@ function phaseVarCounting(cpl) {
|
|
|
10119
10302
|
function varsUsedByOp(op) {
|
|
10120
10303
|
switch (op.kind) {
|
|
10121
10304
|
case OpKind.Property:
|
|
10122
|
-
case OpKind.StyleProp:
|
|
10123
|
-
case OpKind.StyleMap:
|
|
10124
|
-
// Property bindings use 1 variable slot.
|
|
10125
|
-
return 1;
|
|
10126
10305
|
case OpKind.Attribute:
|
|
10127
|
-
//
|
|
10306
|
+
// Property & attribute bindings use 1 variable slot.
|
|
10128
10307
|
return 1;
|
|
10308
|
+
case OpKind.StyleProp:
|
|
10309
|
+
case OpKind.ClassProp:
|
|
10310
|
+
case OpKind.StyleMap:
|
|
10311
|
+
case OpKind.ClassMap:
|
|
10312
|
+
// Style & class bindings use 2 variable slots.
|
|
10313
|
+
return 2;
|
|
10129
10314
|
case OpKind.InterpolateText:
|
|
10130
10315
|
// `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
|
|
10131
10316
|
return op.expressions.length;
|
|
10132
10317
|
case OpKind.InterpolateProperty:
|
|
10133
|
-
case OpKind.InterpolateStyleProp:
|
|
10134
|
-
case OpKind.InterpolateStyleMap:
|
|
10135
10318
|
// `ir.InterpolatePropertyOp`s use a variable slot for each dynamic expression, plus one for
|
|
10136
10319
|
// the result.
|
|
10137
10320
|
return 1 + op.expressions.length;
|
|
10138
10321
|
case OpKind.InterpolateAttribute:
|
|
10139
10322
|
// One variable slot for each dynamic expression, plus one for the result.
|
|
10140
10323
|
return 1 + op.expressions.length;
|
|
10324
|
+
case OpKind.InterpolateStyleProp:
|
|
10325
|
+
case OpKind.InterpolateStyleMap:
|
|
10326
|
+
case OpKind.InterpolateClassMap:
|
|
10327
|
+
// One variable slot for each dynamic expression, plus two for binding the result.
|
|
10328
|
+
return 2 + op.expressions.length;
|
|
10141
10329
|
default:
|
|
10142
10330
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
10143
10331
|
}
|
|
@@ -10257,6 +10445,7 @@ function populateElementAttributes(view, compatibility) {
|
|
|
10257
10445
|
ownerOp.attributes.add(op.bindingKind, op.name, null);
|
|
10258
10446
|
break;
|
|
10259
10447
|
case OpKind.StyleProp:
|
|
10448
|
+
case OpKind.ClassProp:
|
|
10260
10449
|
ownerOp = lookupElement(elements, op.target);
|
|
10261
10450
|
assertIsElementAttributes(ownerOp.attributes);
|
|
10262
10451
|
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
@@ -10284,6 +10473,16 @@ const CHAINABLE = new Set([
|
|
|
10284
10473
|
Identifiers.property,
|
|
10285
10474
|
Identifiers.styleProp,
|
|
10286
10475
|
Identifiers.attribute,
|
|
10476
|
+
Identifiers.stylePropInterpolate1,
|
|
10477
|
+
Identifiers.stylePropInterpolate2,
|
|
10478
|
+
Identifiers.stylePropInterpolate3,
|
|
10479
|
+
Identifiers.stylePropInterpolate4,
|
|
10480
|
+
Identifiers.stylePropInterpolate5,
|
|
10481
|
+
Identifiers.stylePropInterpolate6,
|
|
10482
|
+
Identifiers.stylePropInterpolate7,
|
|
10483
|
+
Identifiers.stylePropInterpolate8,
|
|
10484
|
+
Identifiers.stylePropInterpolateV,
|
|
10485
|
+
Identifiers.classProp,
|
|
10287
10486
|
Identifiers.elementContainerStart,
|
|
10288
10487
|
Identifiers.elementContainerEnd,
|
|
10289
10488
|
Identifiers.elementContainer,
|
|
@@ -10426,87 +10625,238 @@ function phaseEmptyElements(cpl) {
|
|
|
10426
10625
|
}
|
|
10427
10626
|
|
|
10428
10627
|
/**
|
|
10429
|
-
*
|
|
10430
|
-
*
|
|
10628
|
+
* Finds all unresolved safe read expressions, and converts them into the appropriate output AST
|
|
10629
|
+
* reads, guarded by null checks.
|
|
10431
10630
|
*/
|
|
10432
|
-
function
|
|
10631
|
+
function phaseExpandSafeReads(cpl, compatibility) {
|
|
10433
10632
|
for (const [_, view] of cpl.views) {
|
|
10434
|
-
|
|
10435
|
-
|
|
10436
|
-
|
|
10437
|
-
if (!hasConsumesSlotTrait(op)) {
|
|
10438
|
-
continue;
|
|
10439
|
-
}
|
|
10440
|
-
else if (op.slot === null) {
|
|
10441
|
-
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
10442
|
-
}
|
|
10443
|
-
slotMap.set(op.xref, op.slot);
|
|
10444
|
-
}
|
|
10445
|
-
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
10446
|
-
// the runtime's implicit slot counter will be set to the correct slot before executing each
|
|
10447
|
-
// update operation which depends on it.
|
|
10448
|
-
//
|
|
10449
|
-
// To do that, we track what the runtime's slot counter will be through the update operations.
|
|
10450
|
-
let slotContext = 0;
|
|
10451
|
-
for (const op of view.update) {
|
|
10452
|
-
if (!hasDependsOnSlotContextTrait(op)) {
|
|
10453
|
-
// `op` doesn't depend on the slot counter, so it can be skipped.
|
|
10454
|
-
continue;
|
|
10455
|
-
}
|
|
10456
|
-
else if (!slotMap.has(op.target)) {
|
|
10457
|
-
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
10458
|
-
// the `slotMap`.
|
|
10459
|
-
throw new Error(`AssertionError: reference to unknown slot for var ${op.target}`);
|
|
10460
|
-
}
|
|
10461
|
-
const slot = slotMap.get(op.target);
|
|
10462
|
-
// Does the slot counter need to be adjusted?
|
|
10463
|
-
if (slotContext !== slot) {
|
|
10464
|
-
// If so, generate an `ir.AdvanceOp` to advance the counter.
|
|
10465
|
-
const delta = slot - slotContext;
|
|
10466
|
-
if (delta < 0) {
|
|
10467
|
-
throw new Error(`AssertionError: slot counter should never need to move backwards`);
|
|
10468
|
-
}
|
|
10469
|
-
OpList.insertBefore(createAdvanceOp(delta), op);
|
|
10470
|
-
slotContext = slot;
|
|
10471
|
-
}
|
|
10633
|
+
for (const op of view.ops()) {
|
|
10634
|
+
transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
|
|
10635
|
+
transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
|
|
10472
10636
|
}
|
|
10473
10637
|
}
|
|
10474
10638
|
}
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10639
|
+
// A lookup set of all the expression kinds that require a temporary variable to be generated.
|
|
10640
|
+
const requiresTemporary = [
|
|
10641
|
+
InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr,
|
|
10642
|
+
PipeBindingExpr
|
|
10643
|
+
].map(e => e.constructor.name);
|
|
10644
|
+
function needsTemporaryInSafeAccess(e) {
|
|
10645
|
+
// TODO: We probably want to use an expression visitor to recursively visit all descendents.
|
|
10646
|
+
// However, that would potentially do a lot of extra work (because it cannot short circuit), so we
|
|
10647
|
+
// implement the logic ourselves for now.
|
|
10648
|
+
if (e instanceof UnaryOperatorExpr) {
|
|
10649
|
+
return needsTemporaryInSafeAccess(e.expr);
|
|
10650
|
+
}
|
|
10651
|
+
else if (e instanceof BinaryOperatorExpr) {
|
|
10652
|
+
return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
|
|
10653
|
+
}
|
|
10654
|
+
else if (e instanceof ConditionalExpr) {
|
|
10655
|
+
if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase))
|
|
10656
|
+
return true;
|
|
10657
|
+
return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
|
|
10658
|
+
}
|
|
10659
|
+
else if (e instanceof NotExpr) {
|
|
10660
|
+
return needsTemporaryInSafeAccess(e.condition);
|
|
10661
|
+
}
|
|
10662
|
+
else if (e instanceof AssignTemporaryExpr) {
|
|
10663
|
+
return needsTemporaryInSafeAccess(e.expr);
|
|
10664
|
+
}
|
|
10665
|
+
else if (e instanceof ReadPropExpr) {
|
|
10666
|
+
return needsTemporaryInSafeAccess(e.receiver);
|
|
10491
10667
|
}
|
|
10668
|
+
else if (e instanceof ReadKeyExpr) {
|
|
10669
|
+
return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
|
|
10670
|
+
}
|
|
10671
|
+
// TODO: Switch to a method which is exhaustive of newly added expression subtypes.
|
|
10672
|
+
return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr ||
|
|
10673
|
+
e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr ||
|
|
10674
|
+
e instanceof PipeBindingExpr;
|
|
10492
10675
|
}
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10676
|
+
function temporariesIn(e) {
|
|
10677
|
+
const temporaries = new Set();
|
|
10678
|
+
// TODO: Although it's not currently supported by the transform helper, we should be able to
|
|
10679
|
+
// short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
|
|
10680
|
+
// into the subexpressions of temporary assignments.
|
|
10681
|
+
transformExpressionsInExpression(e, e => {
|
|
10682
|
+
if (e instanceof AssignTemporaryExpr) {
|
|
10683
|
+
temporaries.add(e.xref);
|
|
10684
|
+
}
|
|
10685
|
+
return e;
|
|
10686
|
+
}, VisitorContextFlag.None);
|
|
10687
|
+
return temporaries;
|
|
10688
|
+
}
|
|
10689
|
+
function eliminateTemporaryAssignments(e, tmps, ctx) {
|
|
10690
|
+
// TODO: We can be more efficient than the transform helper here. We don't need to visit any
|
|
10691
|
+
// descendents of temporary assignments.
|
|
10692
|
+
transformExpressionsInExpression(e, e => {
|
|
10693
|
+
if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
|
|
10694
|
+
const read = new ReadTemporaryExpr(e.xref);
|
|
10695
|
+
// `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
|
|
10696
|
+
// temporary variables to themselves. This happens because some subexpression that the
|
|
10697
|
+
// temporary refers to, possibly through nested temporaries, has a function call. We copy that
|
|
10698
|
+
// behavior here.
|
|
10699
|
+
return ctx.compatibility ? new AssignTemporaryExpr(read, read.xref) : read;
|
|
10700
|
+
}
|
|
10701
|
+
return e;
|
|
10702
|
+
}, VisitorContextFlag.None);
|
|
10703
|
+
return e;
|
|
10704
|
+
}
|
|
10705
|
+
/**
|
|
10706
|
+
* Creates a safe ternary guarded by the input expression, and with a body generated by the provided
|
|
10707
|
+
* callback on the input expression. Generates a temporary variable assignment if needed, and
|
|
10708
|
+
* deduplicates nested temporary assignments if needed.
|
|
10709
|
+
*/
|
|
10710
|
+
function safeTernaryWithTemporary(guard, body, ctx) {
|
|
10711
|
+
let result;
|
|
10712
|
+
if (needsTemporaryInSafeAccess(guard)) {
|
|
10713
|
+
const xref = ctx.cpl.allocateXrefId();
|
|
10714
|
+
result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
|
|
10715
|
+
}
|
|
10716
|
+
else {
|
|
10717
|
+
result = [guard, guard.clone()];
|
|
10718
|
+
// Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
|
|
10719
|
+
// introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
|
|
10720
|
+
// assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
|
|
10721
|
+
// by transforming it from an assignment into a read on the expression side.
|
|
10722
|
+
eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
|
|
10723
|
+
}
|
|
10724
|
+
return new SafeTernaryExpr(result[0], body(result[1]));
|
|
10725
|
+
}
|
|
10726
|
+
function isSafeAccessExpression(e) {
|
|
10727
|
+
return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
|
|
10728
|
+
}
|
|
10729
|
+
function isUnsafeAccessExpression(e) {
|
|
10730
|
+
return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
|
|
10731
|
+
e instanceof InvokeFunctionExpr;
|
|
10732
|
+
}
|
|
10733
|
+
function isAccessExpression(e) {
|
|
10734
|
+
return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
|
|
10735
|
+
}
|
|
10736
|
+
function deepestSafeTernary(e) {
|
|
10737
|
+
if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
|
|
10738
|
+
let st = e.receiver;
|
|
10739
|
+
while (st.expr instanceof SafeTernaryExpr) {
|
|
10740
|
+
st = st.expr;
|
|
10741
|
+
}
|
|
10742
|
+
return st;
|
|
10743
|
+
}
|
|
10744
|
+
return null;
|
|
10745
|
+
}
|
|
10746
|
+
// TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
|
|
10747
|
+
// instead to save some code size.
|
|
10748
|
+
function safeTransform(e, ctx) {
|
|
10749
|
+
if (e instanceof SafeInvokeFunctionExpr) {
|
|
10750
|
+
// TODO: Implement safe function calls in a subsequent commit.
|
|
10751
|
+
return new InvokeFunctionExpr(e.receiver, e.args);
|
|
10752
|
+
}
|
|
10753
|
+
if (!isAccessExpression(e)) {
|
|
10754
|
+
return e;
|
|
10755
|
+
}
|
|
10756
|
+
const dst = deepestSafeTernary(e);
|
|
10757
|
+
if (dst) {
|
|
10758
|
+
if (e instanceof InvokeFunctionExpr) {
|
|
10759
|
+
dst.expr = dst.expr.callFn(e.args);
|
|
10760
|
+
return e.receiver;
|
|
10761
|
+
}
|
|
10762
|
+
if (e instanceof ReadPropExpr) {
|
|
10763
|
+
dst.expr = dst.expr.prop(e.name);
|
|
10764
|
+
return e.receiver;
|
|
10765
|
+
}
|
|
10766
|
+
if (e instanceof ReadKeyExpr) {
|
|
10767
|
+
dst.expr = dst.expr.key(e.index);
|
|
10768
|
+
return e.receiver;
|
|
10769
|
+
}
|
|
10770
|
+
if (e instanceof SafePropertyReadExpr) {
|
|
10771
|
+
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
|
|
10772
|
+
return e.receiver;
|
|
10773
|
+
}
|
|
10774
|
+
if (e instanceof SafeKeyedReadExpr) {
|
|
10775
|
+
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
|
|
10776
|
+
return e.receiver;
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10779
|
+
else {
|
|
10780
|
+
if (e instanceof SafePropertyReadExpr) {
|
|
10781
|
+
return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
|
|
10782
|
+
}
|
|
10783
|
+
if (e instanceof SafeKeyedReadExpr) {
|
|
10784
|
+
return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
return e;
|
|
10788
|
+
}
|
|
10789
|
+
function ternaryTransform(e) {
|
|
10790
|
+
if (!(e instanceof SafeTernaryExpr)) {
|
|
10791
|
+
return e;
|
|
10792
|
+
}
|
|
10793
|
+
return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
|
|
10794
|
+
}
|
|
10795
|
+
|
|
10796
|
+
/**
|
|
10797
|
+
* Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
|
|
10798
|
+
* context will be advanced correctly.
|
|
10799
|
+
*/
|
|
10800
|
+
function phaseGenerateAdvance(cpl) {
|
|
10801
|
+
for (const [_, view] of cpl.views) {
|
|
10802
|
+
// First build a map of all of the declarations in the view that have assigned slots.
|
|
10803
|
+
const slotMap = new Map();
|
|
10804
|
+
for (const op of view.create) {
|
|
10805
|
+
if (!hasConsumesSlotTrait(op)) {
|
|
10806
|
+
continue;
|
|
10807
|
+
}
|
|
10808
|
+
else if (op.slot === null) {
|
|
10809
|
+
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
10810
|
+
}
|
|
10811
|
+
slotMap.set(op.xref, op.slot);
|
|
10812
|
+
}
|
|
10813
|
+
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
10814
|
+
// the runtime's implicit slot counter will be set to the correct slot before executing each
|
|
10815
|
+
// update operation which depends on it.
|
|
10816
|
+
//
|
|
10817
|
+
// To do that, we track what the runtime's slot counter will be through the update operations.
|
|
10818
|
+
let slotContext = 0;
|
|
10819
|
+
for (const op of view.update) {
|
|
10820
|
+
if (!hasDependsOnSlotContextTrait(op)) {
|
|
10821
|
+
// `op` doesn't depend on the slot counter, so it can be skipped.
|
|
10822
|
+
continue;
|
|
10823
|
+
}
|
|
10824
|
+
else if (!slotMap.has(op.target)) {
|
|
10825
|
+
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
10826
|
+
// the `slotMap`.
|
|
10827
|
+
throw new Error(`AssertionError: reference to unknown slot for var ${op.target}`);
|
|
10828
|
+
}
|
|
10829
|
+
const slot = slotMap.get(op.target);
|
|
10830
|
+
// Does the slot counter need to be adjusted?
|
|
10831
|
+
if (slotContext !== slot) {
|
|
10832
|
+
// If so, generate an `ir.AdvanceOp` to advance the counter.
|
|
10833
|
+
const delta = slot - slotContext;
|
|
10834
|
+
if (delta < 0) {
|
|
10835
|
+
throw new Error(`AssertionError: slot counter should never need to move backwards`);
|
|
10836
|
+
}
|
|
10837
|
+
OpList.insertBefore(createAdvanceOp(delta), op);
|
|
10838
|
+
slotContext = slot;
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10841
|
+
}
|
|
10842
|
+
}
|
|
10843
|
+
|
|
10844
|
+
/**
|
|
10845
|
+
* Generate a preamble sequence for each view creation block and listener function which declares
|
|
10846
|
+
* any variables that be referenced in other operations in the block.
|
|
10847
|
+
*
|
|
10848
|
+
* Variables generated include:
|
|
10849
|
+
* * a saved view context to be used to restore the current view in event listeners.
|
|
10850
|
+
* * the context of the restored view within event listener handlers.
|
|
10851
|
+
* * context variables from the current view as well as all parent views (including the root
|
|
10852
|
+
* context if needed).
|
|
10853
|
+
* * local references from elements within the current view and any lexical parents.
|
|
10854
|
+
*
|
|
10855
|
+
* Variables are generated here unconditionally, and may optimized away in future operations if it
|
|
10856
|
+
* turns out their values (and any side effects) are unused.
|
|
10857
|
+
*/
|
|
10858
|
+
function phaseGenerateVariables(cpl) {
|
|
10859
|
+
recursivelyProcessView(cpl.root, /* there is no parent scope for the root view */ null);
|
|
10510
10860
|
}
|
|
10511
10861
|
/**
|
|
10512
10862
|
* Process the given `ViewCompilation` and generate preambles for it and any listeners that it
|
|
@@ -10647,18 +10997,97 @@ function serializeLocalRefs(refs) {
|
|
|
10647
10997
|
return literalArr(constRefs);
|
|
10648
10998
|
}
|
|
10649
10999
|
|
|
11000
|
+
/**
|
|
11001
|
+
* Parses string representation of a style and converts it into object literal.
|
|
11002
|
+
*
|
|
11003
|
+
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
11004
|
+
* Example: `color: red; height: auto`.
|
|
11005
|
+
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
11006
|
+
* 'auto']`
|
|
11007
|
+
*/
|
|
11008
|
+
function parse(value) {
|
|
11009
|
+
// we use a string array here instead of a string map
|
|
11010
|
+
// because a string-map is not guaranteed to retain the
|
|
11011
|
+
// order of the entries whereas a string array can be
|
|
11012
|
+
// constructed in a [key, value, key, value] format.
|
|
11013
|
+
const styles = [];
|
|
11014
|
+
let i = 0;
|
|
11015
|
+
let parenDepth = 0;
|
|
11016
|
+
let quote = 0 /* Char.QuoteNone */;
|
|
11017
|
+
let valueStart = 0;
|
|
11018
|
+
let propStart = 0;
|
|
11019
|
+
let currentProp = null;
|
|
11020
|
+
while (i < value.length) {
|
|
11021
|
+
const token = value.charCodeAt(i++);
|
|
11022
|
+
switch (token) {
|
|
11023
|
+
case 40 /* Char.OpenParen */:
|
|
11024
|
+
parenDepth++;
|
|
11025
|
+
break;
|
|
11026
|
+
case 41 /* Char.CloseParen */:
|
|
11027
|
+
parenDepth--;
|
|
11028
|
+
break;
|
|
11029
|
+
case 39 /* Char.QuoteSingle */:
|
|
11030
|
+
// valueStart needs to be there since prop values don't
|
|
11031
|
+
// have quotes in CSS
|
|
11032
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
11033
|
+
quote = 39 /* Char.QuoteSingle */;
|
|
11034
|
+
}
|
|
11035
|
+
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11036
|
+
quote = 0 /* Char.QuoteNone */;
|
|
11037
|
+
}
|
|
11038
|
+
break;
|
|
11039
|
+
case 34 /* Char.QuoteDouble */:
|
|
11040
|
+
// same logic as above
|
|
11041
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
11042
|
+
quote = 34 /* Char.QuoteDouble */;
|
|
11043
|
+
}
|
|
11044
|
+
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11045
|
+
quote = 0 /* Char.QuoteNone */;
|
|
11046
|
+
}
|
|
11047
|
+
break;
|
|
11048
|
+
case 58 /* Char.Colon */:
|
|
11049
|
+
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11050
|
+
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
11051
|
+
valueStart = i;
|
|
11052
|
+
}
|
|
11053
|
+
break;
|
|
11054
|
+
case 59 /* Char.Semicolon */:
|
|
11055
|
+
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11056
|
+
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
11057
|
+
styles.push(currentProp, styleVal);
|
|
11058
|
+
propStart = i;
|
|
11059
|
+
valueStart = 0;
|
|
11060
|
+
currentProp = null;
|
|
11061
|
+
}
|
|
11062
|
+
break;
|
|
11063
|
+
}
|
|
11064
|
+
}
|
|
11065
|
+
if (currentProp && valueStart) {
|
|
11066
|
+
const styleVal = value.slice(valueStart).trim();
|
|
11067
|
+
styles.push(currentProp, styleVal);
|
|
11068
|
+
}
|
|
11069
|
+
return styles;
|
|
11070
|
+
}
|
|
11071
|
+
function hyphenate(value) {
|
|
11072
|
+
return value
|
|
11073
|
+
.replace(/[a-z][A-Z]/g, v => {
|
|
11074
|
+
return v.charAt(0) + '-' + v.charAt(1);
|
|
11075
|
+
})
|
|
11076
|
+
.toLowerCase();
|
|
11077
|
+
}
|
|
11078
|
+
|
|
10650
11079
|
/**
|
|
10651
11080
|
* Generate names for functions and variables across all views.
|
|
10652
11081
|
*
|
|
10653
11082
|
* This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
|
|
10654
11083
|
* the reads can be emitted correctly.
|
|
10655
11084
|
*/
|
|
10656
|
-
function phaseNaming(cpl) {
|
|
10657
|
-
addNamesToView(cpl.root, cpl.componentName, { index: 0 });
|
|
11085
|
+
function phaseNaming(cpl, compatibility) {
|
|
11086
|
+
addNamesToView(cpl.root, cpl.componentName, { index: 0 }, compatibility);
|
|
10658
11087
|
}
|
|
10659
|
-
function addNamesToView(view, baseName, state) {
|
|
11088
|
+
function addNamesToView(view, baseName, state, compatibility) {
|
|
10660
11089
|
if (view.fnName === null) {
|
|
10661
|
-
view.fnName = `${baseName}_Template
|
|
11090
|
+
view.fnName = sanitizeIdentifier(`${baseName}_Template`);
|
|
10662
11091
|
}
|
|
10663
11092
|
// Keep track of the names we assign to variables in the view. We'll need to propagate these
|
|
10664
11093
|
// into reads of those variables afterwards.
|
|
@@ -10672,7 +11101,8 @@ function addNamesToView(view, baseName, state) {
|
|
|
10672
11101
|
if (op.slot === null) {
|
|
10673
11102
|
throw new Error(`Expected a slot to be assigned`);
|
|
10674
11103
|
}
|
|
10675
|
-
op.handlerFnName =
|
|
11104
|
+
op.handlerFnName =
|
|
11105
|
+
sanitizeIdentifier(`${view.fnName}_${op.tag}_${op.name}_${op.slot}_listener`);
|
|
10676
11106
|
}
|
|
10677
11107
|
break;
|
|
10678
11108
|
case OpKind.Variable:
|
|
@@ -10683,9 +11113,19 @@ function addNamesToView(view, baseName, state) {
|
|
|
10683
11113
|
if (op.slot === null) {
|
|
10684
11114
|
throw new Error(`Expected slot to be assigned`);
|
|
10685
11115
|
}
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
11116
|
+
addNamesToView(childView, `${baseName}_${op.tag}_${op.slot}`, state, compatibility);
|
|
11117
|
+
break;
|
|
11118
|
+
case OpKind.StyleProp:
|
|
11119
|
+
case OpKind.InterpolateStyleProp:
|
|
11120
|
+
op.name = normalizeStylePropName(op.name);
|
|
11121
|
+
if (compatibility) {
|
|
11122
|
+
op.name = stripImportant(op.name);
|
|
11123
|
+
}
|
|
11124
|
+
break;
|
|
11125
|
+
case OpKind.ClassProp:
|
|
11126
|
+
if (compatibility) {
|
|
11127
|
+
op.name = stripImportant(op.name);
|
|
11128
|
+
}
|
|
10689
11129
|
break;
|
|
10690
11130
|
}
|
|
10691
11131
|
}
|
|
@@ -10716,6 +11156,22 @@ function getVariableName(variable, state) {
|
|
|
10716
11156
|
}
|
|
10717
11157
|
return variable.name;
|
|
10718
11158
|
}
|
|
11159
|
+
/**
|
|
11160
|
+
* Normalizes a style prop name by hyphenating it (unless its a CSS variable).
|
|
11161
|
+
*/
|
|
11162
|
+
function normalizeStylePropName(name) {
|
|
11163
|
+
return name.startsWith('--') ? name : hyphenate(name);
|
|
11164
|
+
}
|
|
11165
|
+
/**
|
|
11166
|
+
* Strips `!important` out of the given style or class name.
|
|
11167
|
+
*/
|
|
11168
|
+
function stripImportant(name) {
|
|
11169
|
+
const importantIndex = name.indexOf('!important');
|
|
11170
|
+
if (importantIndex > -1) {
|
|
11171
|
+
return name.substring(0, importantIndex);
|
|
11172
|
+
}
|
|
11173
|
+
return name;
|
|
11174
|
+
}
|
|
10719
11175
|
|
|
10720
11176
|
/**
|
|
10721
11177
|
* Merges logically sequential `NextContextExpr` operations.
|
|
@@ -10801,6 +11257,24 @@ function phaseNgContainer(cpl) {
|
|
|
10801
11257
|
}
|
|
10802
11258
|
}
|
|
10803
11259
|
|
|
11260
|
+
function phaseNullishCoalescing(cpl) {
|
|
11261
|
+
for (const view of cpl.views.values()) {
|
|
11262
|
+
for (const op of view.ops()) {
|
|
11263
|
+
transformExpressionsInOp(op, expr => {
|
|
11264
|
+
if (!(expr instanceof BinaryOperatorExpr) ||
|
|
11265
|
+
expr.operator !== BinaryOperator.NullishCoalesce) {
|
|
11266
|
+
return expr;
|
|
11267
|
+
}
|
|
11268
|
+
const assignment = new AssignTemporaryExpr(expr.lhs.clone(), cpl.allocateXrefId());
|
|
11269
|
+
const read = new ReadTemporaryExpr(assignment.xref);
|
|
11270
|
+
// TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
|
|
11271
|
+
// `t != null` instead of including an undefined check as well.
|
|
11272
|
+
return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
|
|
11273
|
+
}, VisitorContextFlag.None);
|
|
11274
|
+
}
|
|
11275
|
+
}
|
|
11276
|
+
}
|
|
11277
|
+
|
|
10804
11278
|
function phasePipeCreation(cpl) {
|
|
10805
11279
|
for (const view of cpl.views.values()) {
|
|
10806
11280
|
processPipeBindingsInView(view);
|
|
@@ -10867,6 +11341,80 @@ function phasePipeVariadic(cpl) {
|
|
|
10867
11341
|
}
|
|
10868
11342
|
}
|
|
10869
11343
|
|
|
11344
|
+
/**
|
|
11345
|
+
* Defines the groups based on `OpKind` that ops will be divided into. Ops will be collected into
|
|
11346
|
+
* groups, then optionally transformed, before recombining the groups in the order defined here.
|
|
11347
|
+
*/
|
|
11348
|
+
const ORDERING = [
|
|
11349
|
+
{ kinds: new Set([OpKind.StyleMap, OpKind.InterpolateStyleMap]), transform: keepLast },
|
|
11350
|
+
{ kinds: new Set([OpKind.ClassMap, OpKind.InterpolateClassMap]), transform: keepLast },
|
|
11351
|
+
{ kinds: new Set([OpKind.StyleProp, OpKind.InterpolateStyleProp]) },
|
|
11352
|
+
{ kinds: new Set([OpKind.ClassProp]) },
|
|
11353
|
+
{ kinds: new Set([OpKind.InterpolateProperty]) },
|
|
11354
|
+
{ kinds: new Set([OpKind.Property]) },
|
|
11355
|
+
{ kinds: new Set([OpKind.Attribute, OpKind.InterpolateAttribute]) },
|
|
11356
|
+
];
|
|
11357
|
+
/**
|
|
11358
|
+
* The set of all op kinds we handle in the reordering phase.
|
|
11359
|
+
*/
|
|
11360
|
+
const handledOpKinds = new Set(ORDERING.flatMap(group => [...group.kinds]));
|
|
11361
|
+
/**
|
|
11362
|
+
* Reorders property and attribute ops according to the following ordering:
|
|
11363
|
+
* 1. styleMap & styleMapInterpolate (drops all but the last op in the group)
|
|
11364
|
+
* 2. classMap & classMapInterpolate (drops all but the last op in the group)
|
|
11365
|
+
* 3. styleProp & stylePropInterpolate (ordering preserved within group)
|
|
11366
|
+
* 4. classProp (ordering preserved within group)
|
|
11367
|
+
* 5. propertyInterpolate (ordering preserved within group)
|
|
11368
|
+
* 6. property (ordering preserved within group)
|
|
11369
|
+
* 7. attribute & attributeInterpolate (ordering preserve within group)
|
|
11370
|
+
*/
|
|
11371
|
+
function phasePropertyOrdering(cpl) {
|
|
11372
|
+
for (const [_, view] of cpl.views) {
|
|
11373
|
+
let opsToOrder = [];
|
|
11374
|
+
for (const op of view.update) {
|
|
11375
|
+
if (handledOpKinds.has(op.kind)) {
|
|
11376
|
+
// Pull out ops that need o be ordered.
|
|
11377
|
+
opsToOrder.push(op);
|
|
11378
|
+
OpList.remove(op);
|
|
11379
|
+
}
|
|
11380
|
+
else {
|
|
11381
|
+
// When we encounter an op that shouldn't be reordered, put the ones we've pulled so far
|
|
11382
|
+
// back in the correct order.
|
|
11383
|
+
for (const orderedOp of reorder(opsToOrder)) {
|
|
11384
|
+
OpList.insertBefore(orderedOp, op);
|
|
11385
|
+
}
|
|
11386
|
+
opsToOrder = [];
|
|
11387
|
+
}
|
|
11388
|
+
}
|
|
11389
|
+
// If we still have ops pulled at the end, put them back in the correct order.
|
|
11390
|
+
for (const orderedOp of reorder(opsToOrder)) {
|
|
11391
|
+
view.update.push(orderedOp);
|
|
11392
|
+
}
|
|
11393
|
+
}
|
|
11394
|
+
}
|
|
11395
|
+
/**
|
|
11396
|
+
* Reorders the given list of ops according to the ordering defined by `ORDERING`.
|
|
11397
|
+
*/
|
|
11398
|
+
function reorder(ops) {
|
|
11399
|
+
// Break the ops list into groups based on OpKind.
|
|
11400
|
+
const groups = Array.from(ORDERING, () => new Array());
|
|
11401
|
+
for (const op of ops) {
|
|
11402
|
+
const groupIndex = ORDERING.findIndex(o => o.kinds.has(op.kind));
|
|
11403
|
+
groups[groupIndex].push(op);
|
|
11404
|
+
}
|
|
11405
|
+
// Reassemble the groups into a single list, in the correct order.
|
|
11406
|
+
return groups.flatMap((group, i) => {
|
|
11407
|
+
const transform = ORDERING[i].transform;
|
|
11408
|
+
return transform ? transform(group) : group;
|
|
11409
|
+
});
|
|
11410
|
+
}
|
|
11411
|
+
/**
|
|
11412
|
+
* Keeps only the last op in a list of ops.
|
|
11413
|
+
*/
|
|
11414
|
+
function keepLast(ops) {
|
|
11415
|
+
return ops.slice(ops.length - 1);
|
|
11416
|
+
}
|
|
11417
|
+
|
|
10870
11418
|
function phasePureFunctionExtraction(cpl) {
|
|
10871
11419
|
for (const view of cpl.views.values()) {
|
|
10872
11420
|
for (const op of view.ops()) {
|
|
@@ -11066,9 +11614,15 @@ function styleProp(name, expression, unit) {
|
|
|
11066
11614
|
}
|
|
11067
11615
|
return call(Identifiers.styleProp, args);
|
|
11068
11616
|
}
|
|
11617
|
+
function classProp(name, expression) {
|
|
11618
|
+
return call(Identifiers.classProp, [literal(name), expression]);
|
|
11619
|
+
}
|
|
11069
11620
|
function styleMap(expression) {
|
|
11070
11621
|
return call(Identifiers.styleMap, [expression]);
|
|
11071
11622
|
}
|
|
11623
|
+
function classMap(expression) {
|
|
11624
|
+
return call(Identifiers.classMap, [expression]);
|
|
11625
|
+
}
|
|
11072
11626
|
const PIPE_BINDINGS = [
|
|
11073
11627
|
Identifiers.pipeBind1,
|
|
11074
11628
|
Identifiers.pipeBind2,
|
|
@@ -11131,6 +11685,10 @@ function styleMapInterpolate(strings, expressions) {
|
|
|
11131
11685
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11132
11686
|
return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
11133
11687
|
}
|
|
11688
|
+
function classMapInterpolate(strings, expressions) {
|
|
11689
|
+
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
11690
|
+
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
11691
|
+
}
|
|
11134
11692
|
function pureFunction(varOffset, fn, args) {
|
|
11135
11693
|
return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
|
|
11136
11694
|
literal(varOffset),
|
|
@@ -11212,7 +11770,7 @@ const PROPERTY_INTERPOLATE_CONFIG = {
|
|
|
11212
11770
|
*/
|
|
11213
11771
|
const STYLE_PROP_INTERPOLATE_CONFIG = {
|
|
11214
11772
|
constant: [
|
|
11215
|
-
|
|
11773
|
+
Identifiers.styleProp,
|
|
11216
11774
|
Identifiers.stylePropInterpolate1,
|
|
11217
11775
|
Identifiers.stylePropInterpolate2,
|
|
11218
11776
|
Identifiers.stylePropInterpolate3,
|
|
@@ -11227,9 +11785,6 @@ const STYLE_PROP_INTERPOLATE_CONFIG = {
|
|
|
11227
11785
|
if (n % 2 === 0) {
|
|
11228
11786
|
throw new Error(`Expected odd number of arguments`);
|
|
11229
11787
|
}
|
|
11230
|
-
if (n < 3) {
|
|
11231
|
-
throw new Error(`Expected at least 3 arguments`);
|
|
11232
|
-
}
|
|
11233
11788
|
return (n - 1) / 2;
|
|
11234
11789
|
},
|
|
11235
11790
|
};
|
|
@@ -11261,7 +11816,7 @@ const ATTRIBUTE_INTERPOLATE_CONFIG = {
|
|
|
11261
11816
|
*/
|
|
11262
11817
|
const STYLE_MAP_INTERPOLATE_CONFIG = {
|
|
11263
11818
|
constant: [
|
|
11264
|
-
|
|
11819
|
+
Identifiers.styleMap,
|
|
11265
11820
|
Identifiers.styleMapInterpolate1,
|
|
11266
11821
|
Identifiers.styleMapInterpolate2,
|
|
11267
11822
|
Identifiers.styleMapInterpolate3,
|
|
@@ -11276,8 +11831,28 @@ const STYLE_MAP_INTERPOLATE_CONFIG = {
|
|
|
11276
11831
|
if (n % 2 === 0) {
|
|
11277
11832
|
throw new Error(`Expected odd number of arguments`);
|
|
11278
11833
|
}
|
|
11279
|
-
|
|
11280
|
-
|
|
11834
|
+
return (n - 1) / 2;
|
|
11835
|
+
},
|
|
11836
|
+
};
|
|
11837
|
+
/**
|
|
11838
|
+
* `InterpolationConfig` for the `classMapInterpolate` instruction.
|
|
11839
|
+
*/
|
|
11840
|
+
const CLASS_MAP_INTERPOLATE_CONFIG = {
|
|
11841
|
+
constant: [
|
|
11842
|
+
Identifiers.classMap,
|
|
11843
|
+
Identifiers.classMapInterpolate1,
|
|
11844
|
+
Identifiers.classMapInterpolate2,
|
|
11845
|
+
Identifiers.classMapInterpolate3,
|
|
11846
|
+
Identifiers.classMapInterpolate4,
|
|
11847
|
+
Identifiers.classMapInterpolate5,
|
|
11848
|
+
Identifiers.classMapInterpolate6,
|
|
11849
|
+
Identifiers.classMapInterpolate7,
|
|
11850
|
+
Identifiers.classMapInterpolate8,
|
|
11851
|
+
],
|
|
11852
|
+
variable: Identifiers.classMapInterpolateV,
|
|
11853
|
+
mapping: n => {
|
|
11854
|
+
if (n % 2 === 0) {
|
|
11855
|
+
throw new Error(`Expected odd number of arguments`);
|
|
11281
11856
|
}
|
|
11282
11857
|
return (n - 1) / 2;
|
|
11283
11858
|
},
|
|
@@ -11396,9 +11971,15 @@ function reifyUpdateOperations(_view, ops) {
|
|
|
11396
11971
|
case OpKind.StyleProp:
|
|
11397
11972
|
OpList.replace(op, styleProp(op.name, op.expression, op.unit));
|
|
11398
11973
|
break;
|
|
11974
|
+
case OpKind.ClassProp:
|
|
11975
|
+
OpList.replace(op, classProp(op.name, op.expression));
|
|
11976
|
+
break;
|
|
11399
11977
|
case OpKind.StyleMap:
|
|
11400
11978
|
OpList.replace(op, styleMap(op.expression));
|
|
11401
11979
|
break;
|
|
11980
|
+
case OpKind.ClassMap:
|
|
11981
|
+
OpList.replace(op, classMap(op.expression));
|
|
11982
|
+
break;
|
|
11402
11983
|
case OpKind.InterpolateProperty:
|
|
11403
11984
|
OpList.replace(op, propertyInterpolate(op.name, op.strings, op.expressions));
|
|
11404
11985
|
break;
|
|
@@ -11408,6 +11989,9 @@ function reifyUpdateOperations(_view, ops) {
|
|
|
11408
11989
|
case OpKind.InterpolateStyleMap:
|
|
11409
11990
|
OpList.replace(op, styleMapInterpolate(op.strings, op.expressions));
|
|
11410
11991
|
break;
|
|
11992
|
+
case OpKind.InterpolateClassMap:
|
|
11993
|
+
OpList.replace(op, classMapInterpolate(op.strings, op.expressions));
|
|
11994
|
+
break;
|
|
11411
11995
|
case OpKind.InterpolateText:
|
|
11412
11996
|
OpList.replace(op, textInterpolate(op.strings, op.expressions));
|
|
11413
11997
|
break;
|
|
@@ -11765,27 +12349,71 @@ function phaseSlotAllocation(cpl) {
|
|
|
11765
12349
|
// We do expect to find a slot allocated for everything which might be referenced.
|
|
11766
12350
|
throw new Error(`AssertionError: no slot allocated for ${OpKind[op.kind]} target ${op.target}`);
|
|
11767
12351
|
}
|
|
11768
|
-
op.slot = slotMap.get(op.target);
|
|
12352
|
+
op.slot = slotMap.get(op.target);
|
|
12353
|
+
}
|
|
12354
|
+
// Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
|
|
12355
|
+
visitExpressionsInOp(op, expr => {
|
|
12356
|
+
if (!isIrExpression(expr)) {
|
|
12357
|
+
return;
|
|
12358
|
+
}
|
|
12359
|
+
if (!hasUsesSlotIndexTrait(expr) || expr.slot !== null) {
|
|
12360
|
+
return;
|
|
12361
|
+
}
|
|
12362
|
+
// The `UsesSlotIndexExprTrait` indicates that this expression references something declared
|
|
12363
|
+
// in this component template by its slot index. Use the `target` `ir.XrefId` to find the
|
|
12364
|
+
// allocated slot for that declaration in `slotMap`.
|
|
12365
|
+
if (!slotMap.has(expr.target)) {
|
|
12366
|
+
// We do expect to find a slot allocated for everything which might be referenced.
|
|
12367
|
+
throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
|
|
12368
|
+
}
|
|
12369
|
+
// Record the allocated slot on the expression.
|
|
12370
|
+
expr.slot = slotMap.get(expr.target);
|
|
12371
|
+
});
|
|
12372
|
+
}
|
|
12373
|
+
}
|
|
12374
|
+
}
|
|
12375
|
+
|
|
12376
|
+
/**
|
|
12377
|
+
* Find all assignments and usages of temporary variables, which are linked to each other with cross
|
|
12378
|
+
* references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
|
|
12379
|
+
* them at the beginning of the update block.
|
|
12380
|
+
*
|
|
12381
|
+
* TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
|
|
12382
|
+
* in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
|
|
12383
|
+
* Implement an algorithm for reuse.
|
|
12384
|
+
*/
|
|
12385
|
+
function phaseTemporaryVariables(cpl) {
|
|
12386
|
+
for (const view of cpl.views.values()) {
|
|
12387
|
+
let opCount = 0;
|
|
12388
|
+
let generatedStatements = [];
|
|
12389
|
+
for (const op of view.ops()) {
|
|
12390
|
+
let count = 0;
|
|
12391
|
+
let xrefs = new Set();
|
|
12392
|
+
let defs = new Map();
|
|
12393
|
+
visitExpressionsInOp(op, expr => {
|
|
12394
|
+
if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
|
|
12395
|
+
xrefs.add(expr.xref);
|
|
12396
|
+
}
|
|
12397
|
+
});
|
|
12398
|
+
for (const xref of xrefs) {
|
|
12399
|
+
// TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`. It seems
|
|
12400
|
+
// to rely on an expression index instead of an op index.
|
|
12401
|
+
defs.set(xref, `tmp_${opCount}_${count++}`);
|
|
11769
12402
|
}
|
|
11770
|
-
// Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
|
|
11771
12403
|
visitExpressionsInOp(op, expr => {
|
|
11772
|
-
if (
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
// The `UsesSlotIndexExprTrait` indicates that this expression references something declared
|
|
11779
|
-
// in this component template by its slot index. Use the `target` `ir.XrefId` to find the
|
|
11780
|
-
// allocated slot for that declaration in `slotMap`.
|
|
11781
|
-
if (!slotMap.has(expr.target)) {
|
|
11782
|
-
// We do expect to find a slot allocated for everything which might be referenced.
|
|
11783
|
-
throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
|
|
12404
|
+
if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
|
|
12405
|
+
const name = defs.get(expr.xref);
|
|
12406
|
+
if (name === undefined) {
|
|
12407
|
+
throw new Error('Found xref with unassigned name');
|
|
12408
|
+
}
|
|
12409
|
+
expr.name = name;
|
|
11784
12410
|
}
|
|
11785
|
-
// Record the allocated slot on the expression.
|
|
11786
|
-
expr.slot = slotMap.get(expr.target);
|
|
11787
12411
|
});
|
|
12412
|
+
generatedStatements.push(...Array.from(defs.values())
|
|
12413
|
+
.map(name => createStatementOp(new DeclareVarStmt(name))));
|
|
12414
|
+
opCount++;
|
|
11788
12415
|
}
|
|
12416
|
+
view.update.prepend(generatedStatements);
|
|
11789
12417
|
}
|
|
11790
12418
|
}
|
|
11791
12419
|
|
|
@@ -12152,225 +12780,12 @@ function allowConservativeInlining(decl, target) {
|
|
|
12152
12780
|
}
|
|
12153
12781
|
}
|
|
12154
12782
|
|
|
12155
|
-
/**
|
|
12156
|
-
* Finds all unresolved safe read expressions, and converts them into the appropriate output AST
|
|
12157
|
-
* reads, guarded by null checks.
|
|
12158
|
-
*/
|
|
12159
|
-
function phaseExpandSafeReads(cpl, compatibility) {
|
|
12160
|
-
for (const [_, view] of cpl.views) {
|
|
12161
|
-
for (const op of view.ops()) {
|
|
12162
|
-
transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
|
|
12163
|
-
transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
|
|
12164
|
-
}
|
|
12165
|
-
}
|
|
12166
|
-
}
|
|
12167
|
-
// A lookup set of all the expression kinds that require a temporary variable to be generated.
|
|
12168
|
-
const requiresTemporary = [
|
|
12169
|
-
InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr,
|
|
12170
|
-
PipeBindingExpr
|
|
12171
|
-
].map(e => e.constructor.name);
|
|
12172
|
-
function needsTemporaryInSafeAccess(e) {
|
|
12173
|
-
// TODO: We probably want to use an expression visitor to recursively visit all descendents.
|
|
12174
|
-
// However, that would potentially do a lot of extra work (because it cannot short circuit), so we
|
|
12175
|
-
// implement the logic ourselves for now.
|
|
12176
|
-
if (e instanceof UnaryOperatorExpr) {
|
|
12177
|
-
return needsTemporaryInSafeAccess(e.expr);
|
|
12178
|
-
}
|
|
12179
|
-
else if (e instanceof BinaryOperatorExpr) {
|
|
12180
|
-
return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
|
|
12181
|
-
}
|
|
12182
|
-
else if (e instanceof ConditionalExpr) {
|
|
12183
|
-
if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase))
|
|
12184
|
-
return true;
|
|
12185
|
-
return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
|
|
12186
|
-
}
|
|
12187
|
-
else if (e instanceof NotExpr) {
|
|
12188
|
-
return needsTemporaryInSafeAccess(e.condition);
|
|
12189
|
-
}
|
|
12190
|
-
else if (e instanceof AssignTemporaryExpr) {
|
|
12191
|
-
return needsTemporaryInSafeAccess(e.expr);
|
|
12192
|
-
}
|
|
12193
|
-
else if (e instanceof ReadPropExpr) {
|
|
12194
|
-
return needsTemporaryInSafeAccess(e.receiver);
|
|
12195
|
-
}
|
|
12196
|
-
else if (e instanceof ReadKeyExpr) {
|
|
12197
|
-
return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
|
|
12198
|
-
}
|
|
12199
|
-
// TODO: Switch to a method which is exhaustive of newly added expression subtypes.
|
|
12200
|
-
return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr ||
|
|
12201
|
-
e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr ||
|
|
12202
|
-
e instanceof PipeBindingExpr;
|
|
12203
|
-
}
|
|
12204
|
-
function temporariesIn(e) {
|
|
12205
|
-
const temporaries = new Set();
|
|
12206
|
-
// TODO: Although it's not currently supported by the transform helper, we should be able to
|
|
12207
|
-
// short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
|
|
12208
|
-
// into the subexpressions of temporary assignments.
|
|
12209
|
-
transformExpressionsInExpression(e, e => {
|
|
12210
|
-
if (e instanceof AssignTemporaryExpr) {
|
|
12211
|
-
temporaries.add(e.xref);
|
|
12212
|
-
}
|
|
12213
|
-
return e;
|
|
12214
|
-
}, VisitorContextFlag.None);
|
|
12215
|
-
return temporaries;
|
|
12216
|
-
}
|
|
12217
|
-
function eliminateTemporaryAssignments(e, tmps, ctx) {
|
|
12218
|
-
// TODO: We can be more efficient than the transform helper here. We don't need to visit any
|
|
12219
|
-
// descendents of temporary assignments.
|
|
12220
|
-
transformExpressionsInExpression(e, e => {
|
|
12221
|
-
if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
|
|
12222
|
-
const read = new ReadTemporaryExpr(e.xref);
|
|
12223
|
-
// `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
|
|
12224
|
-
// temporary variables to themselves. This happens because some subexpression that the
|
|
12225
|
-
// temporary refers to, possibly through nested temporaries, has a function call. We copy that
|
|
12226
|
-
// behavior here.
|
|
12227
|
-
return ctx.compatibility ? new AssignTemporaryExpr(read, read.xref) : read;
|
|
12228
|
-
}
|
|
12229
|
-
return e;
|
|
12230
|
-
}, VisitorContextFlag.None);
|
|
12231
|
-
return e;
|
|
12232
|
-
}
|
|
12233
|
-
/**
|
|
12234
|
-
* Creates a safe ternary guarded by the input expression, and with a body generated by the provided
|
|
12235
|
-
* callback on the input expression. Generates a temporary variable assignment if needed, and
|
|
12236
|
-
* deduplicates nested temporary assignments if needed.
|
|
12237
|
-
*/
|
|
12238
|
-
function safeTernaryWithTemporary(guard, body, ctx) {
|
|
12239
|
-
let result;
|
|
12240
|
-
if (needsTemporaryInSafeAccess(guard)) {
|
|
12241
|
-
const xref = ctx.cpl.allocateXrefId();
|
|
12242
|
-
result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
|
|
12243
|
-
}
|
|
12244
|
-
else {
|
|
12245
|
-
result = [guard, guard.clone()];
|
|
12246
|
-
// Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
|
|
12247
|
-
// introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
|
|
12248
|
-
// assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
|
|
12249
|
-
// by transforming it from an assignment into a read on the expression side.
|
|
12250
|
-
eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
|
|
12251
|
-
}
|
|
12252
|
-
return new SafeTernaryExpr(result[0], body(result[1]));
|
|
12253
|
-
}
|
|
12254
|
-
function isSafeAccessExpression(e) {
|
|
12255
|
-
return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
|
|
12256
|
-
}
|
|
12257
|
-
function isUnsafeAccessExpression(e) {
|
|
12258
|
-
return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
|
|
12259
|
-
e instanceof InvokeFunctionExpr;
|
|
12260
|
-
}
|
|
12261
|
-
function isAccessExpression(e) {
|
|
12262
|
-
return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
|
|
12263
|
-
}
|
|
12264
|
-
function deepestSafeTernary(e) {
|
|
12265
|
-
if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
|
|
12266
|
-
let st = e.receiver;
|
|
12267
|
-
while (st.expr instanceof SafeTernaryExpr) {
|
|
12268
|
-
st = st.expr;
|
|
12269
|
-
}
|
|
12270
|
-
return st;
|
|
12271
|
-
}
|
|
12272
|
-
return null;
|
|
12273
|
-
}
|
|
12274
|
-
// TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
|
|
12275
|
-
// instead to save some code size.
|
|
12276
|
-
function safeTransform(e, ctx) {
|
|
12277
|
-
if (e instanceof SafeInvokeFunctionExpr) {
|
|
12278
|
-
// TODO: Implement safe function calls in a subsequent commit.
|
|
12279
|
-
return new InvokeFunctionExpr(e.receiver, e.args);
|
|
12280
|
-
}
|
|
12281
|
-
if (!isAccessExpression(e)) {
|
|
12282
|
-
return e;
|
|
12283
|
-
}
|
|
12284
|
-
const dst = deepestSafeTernary(e);
|
|
12285
|
-
if (dst) {
|
|
12286
|
-
if (e instanceof InvokeFunctionExpr) {
|
|
12287
|
-
dst.expr = dst.expr.callFn(e.args);
|
|
12288
|
-
return e.receiver;
|
|
12289
|
-
}
|
|
12290
|
-
if (e instanceof ReadPropExpr) {
|
|
12291
|
-
dst.expr = dst.expr.prop(e.name);
|
|
12292
|
-
return e.receiver;
|
|
12293
|
-
}
|
|
12294
|
-
if (e instanceof ReadKeyExpr) {
|
|
12295
|
-
dst.expr = dst.expr.key(e.index);
|
|
12296
|
-
return e.receiver;
|
|
12297
|
-
}
|
|
12298
|
-
if (e instanceof SafePropertyReadExpr) {
|
|
12299
|
-
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
|
|
12300
|
-
return e.receiver;
|
|
12301
|
-
}
|
|
12302
|
-
if (e instanceof SafeKeyedReadExpr) {
|
|
12303
|
-
dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
|
|
12304
|
-
return e.receiver;
|
|
12305
|
-
}
|
|
12306
|
-
}
|
|
12307
|
-
else {
|
|
12308
|
-
if (e instanceof SafePropertyReadExpr) {
|
|
12309
|
-
return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
|
|
12310
|
-
}
|
|
12311
|
-
if (e instanceof SafeKeyedReadExpr) {
|
|
12312
|
-
return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
|
|
12313
|
-
}
|
|
12314
|
-
}
|
|
12315
|
-
return e;
|
|
12316
|
-
}
|
|
12317
|
-
function ternaryTransform(e) {
|
|
12318
|
-
if (!(e instanceof SafeTernaryExpr)) {
|
|
12319
|
-
return e;
|
|
12320
|
-
}
|
|
12321
|
-
return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
|
|
12322
|
-
}
|
|
12323
|
-
|
|
12324
|
-
/**
|
|
12325
|
-
* Find all assignments and usages of temporary variables, which are linked to each other with cross
|
|
12326
|
-
* references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
|
|
12327
|
-
* them at the beginning of the update block.
|
|
12328
|
-
*
|
|
12329
|
-
* TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
|
|
12330
|
-
* in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
|
|
12331
|
-
* Implement an algorithm for reuse.
|
|
12332
|
-
*/
|
|
12333
|
-
function phaseTemporaryVariables(cpl) {
|
|
12334
|
-
for (const view of cpl.views.values()) {
|
|
12335
|
-
let opCount = 0;
|
|
12336
|
-
let generatedStatements = [];
|
|
12337
|
-
for (const op of view.ops()) {
|
|
12338
|
-
let count = 0;
|
|
12339
|
-
let xrefs = new Set();
|
|
12340
|
-
let defs = new Map();
|
|
12341
|
-
visitExpressionsInOp(op, expr => {
|
|
12342
|
-
if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
|
|
12343
|
-
xrefs.add(expr.xref);
|
|
12344
|
-
}
|
|
12345
|
-
});
|
|
12346
|
-
for (const xref of xrefs) {
|
|
12347
|
-
// TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`. It seems
|
|
12348
|
-
// to rely on an expression index instead of an op index.
|
|
12349
|
-
defs.set(xref, `tmp_${opCount}_${count++}`);
|
|
12350
|
-
}
|
|
12351
|
-
visitExpressionsInOp(op, expr => {
|
|
12352
|
-
if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
|
|
12353
|
-
const name = defs.get(expr.xref);
|
|
12354
|
-
if (name === undefined) {
|
|
12355
|
-
throw new Error('Found xref with unassigned name');
|
|
12356
|
-
}
|
|
12357
|
-
expr.name = name;
|
|
12358
|
-
}
|
|
12359
|
-
});
|
|
12360
|
-
generatedStatements.push(...Array.from(defs.values())
|
|
12361
|
-
.map(name => createStatementOp(new DeclareVarStmt(name))));
|
|
12362
|
-
opCount++;
|
|
12363
|
-
}
|
|
12364
|
-
view.update.prepend(generatedStatements);
|
|
12365
|
-
}
|
|
12366
|
-
}
|
|
12367
|
-
|
|
12368
12783
|
/**
|
|
12369
12784
|
* Run all transformation phases in the correct order against a `ComponentCompilation`. After this
|
|
12370
12785
|
* processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
|
|
12371
12786
|
*/
|
|
12372
12787
|
function transformTemplate(cpl) {
|
|
12373
|
-
phaseAttributeExtraction(cpl, true);
|
|
12788
|
+
phaseAttributeExtraction(cpl, /* compatibility */ true);
|
|
12374
12789
|
phasePipeCreation(cpl);
|
|
12375
12790
|
phasePipeVariadic(cpl);
|
|
12376
12791
|
phasePureLiteralStructures(cpl);
|
|
@@ -12386,13 +12801,14 @@ function transformTemplate(cpl) {
|
|
|
12386
12801
|
phaseSlotAllocation(cpl);
|
|
12387
12802
|
phaseVarCounting(cpl);
|
|
12388
12803
|
phaseGenerateAdvance(cpl);
|
|
12389
|
-
phaseNaming(cpl);
|
|
12804
|
+
phaseNaming(cpl, /* compatibility */ true);
|
|
12390
12805
|
phaseVariableOptimization(cpl, { conservative: true });
|
|
12391
12806
|
phaseMergeNextContext(cpl);
|
|
12392
12807
|
phaseNgContainer(cpl);
|
|
12393
12808
|
phaseEmptyElements(cpl);
|
|
12394
12809
|
phasePureFunctionExtraction(cpl);
|
|
12395
12810
|
phaseAlignPipeVariadicVarOffset(cpl);
|
|
12811
|
+
phasePropertyOrdering(cpl);
|
|
12396
12812
|
phaseReify(cpl);
|
|
12397
12813
|
phaseChaining(cpl);
|
|
12398
12814
|
}
|
|
@@ -12828,6 +13244,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
|
|
|
12828
13244
|
}
|
|
12829
13245
|
view.update.push(createInterpolateStyleMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
12830
13246
|
}
|
|
13247
|
+
else if (name === 'class') {
|
|
13248
|
+
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13249
|
+
throw Error('Unexpected class binding on ng-template');
|
|
13250
|
+
}
|
|
13251
|
+
view.update.push(createInterpolateClassMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
13252
|
+
}
|
|
12831
13253
|
else {
|
|
12832
13254
|
view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
|
|
12833
13255
|
}
|
|
@@ -12845,8 +13267,11 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
|
|
|
12845
13267
|
const attributeInterpolate = createInterpolateAttributeOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)));
|
|
12846
13268
|
view.update.push(attributeInterpolate);
|
|
12847
13269
|
break;
|
|
13270
|
+
case 2 /* e.BindingType.Class */:
|
|
13271
|
+
throw Error('Unexpected interpolation in class property binding');
|
|
13272
|
+
// TODO: implement remaining binding types.
|
|
13273
|
+
case 4 /* e.BindingType.Animation */:
|
|
12848
13274
|
default:
|
|
12849
|
-
// TODO: implement remaining binding types.
|
|
12850
13275
|
throw Error(`Interpolated property binding type not handled: ${type}`);
|
|
12851
13276
|
}
|
|
12852
13277
|
}
|
|
@@ -12860,6 +13285,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
|
|
|
12860
13285
|
}
|
|
12861
13286
|
view.update.push(createStyleMapOp(xref, convertAst(value, view.tpl)));
|
|
12862
13287
|
}
|
|
13288
|
+
else if (name === 'class') {
|
|
13289
|
+
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13290
|
+
throw Error('Unexpected class binding on ng-template');
|
|
13291
|
+
}
|
|
13292
|
+
view.update.push(createClassMapOp(xref, convertAst(value, view.tpl)));
|
|
13293
|
+
}
|
|
12863
13294
|
else {
|
|
12864
13295
|
view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
|
|
12865
13296
|
}
|
|
@@ -12877,8 +13308,15 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
|
|
|
12877
13308
|
const attrOp = createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
|
|
12878
13309
|
view.update.push(attrOp);
|
|
12879
13310
|
break;
|
|
13311
|
+
case 2 /* e.BindingType.Class */:
|
|
13312
|
+
if (bindingKind !== ElementAttributeKind.Binding) {
|
|
13313
|
+
throw Error('Unexpected class binding on ng-template');
|
|
13314
|
+
}
|
|
13315
|
+
view.update.push(createClassPropOp(xref, name, convertAst(value, view.tpl)));
|
|
13316
|
+
break;
|
|
13317
|
+
// TODO: implement remaining binding types.
|
|
13318
|
+
case 4 /* e.BindingType.Animation */:
|
|
12880
13319
|
default:
|
|
12881
|
-
// TODO: implement remaining binding types.
|
|
12882
13320
|
throw Error(`Property binding type not handled: ${type}`);
|
|
12883
13321
|
}
|
|
12884
13322
|
}
|
|
@@ -12907,85 +13345,6 @@ function assertIsArray(value) {
|
|
|
12907
13345
|
|
|
12908
13346
|
const USE_TEMPLATE_PIPELINE = false;
|
|
12909
13347
|
|
|
12910
|
-
/**
|
|
12911
|
-
* Parses string representation of a style and converts it into object literal.
|
|
12912
|
-
*
|
|
12913
|
-
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
12914
|
-
* Example: `color: red; height: auto`.
|
|
12915
|
-
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
12916
|
-
* 'auto']`
|
|
12917
|
-
*/
|
|
12918
|
-
function parse(value) {
|
|
12919
|
-
// we use a string array here instead of a string map
|
|
12920
|
-
// because a string-map is not guaranteed to retain the
|
|
12921
|
-
// order of the entries whereas a string array can be
|
|
12922
|
-
// constructed in a [key, value, key, value] format.
|
|
12923
|
-
const styles = [];
|
|
12924
|
-
let i = 0;
|
|
12925
|
-
let parenDepth = 0;
|
|
12926
|
-
let quote = 0 /* Char.QuoteNone */;
|
|
12927
|
-
let valueStart = 0;
|
|
12928
|
-
let propStart = 0;
|
|
12929
|
-
let currentProp = null;
|
|
12930
|
-
while (i < value.length) {
|
|
12931
|
-
const token = value.charCodeAt(i++);
|
|
12932
|
-
switch (token) {
|
|
12933
|
-
case 40 /* Char.OpenParen */:
|
|
12934
|
-
parenDepth++;
|
|
12935
|
-
break;
|
|
12936
|
-
case 41 /* Char.CloseParen */:
|
|
12937
|
-
parenDepth--;
|
|
12938
|
-
break;
|
|
12939
|
-
case 39 /* Char.QuoteSingle */:
|
|
12940
|
-
// valueStart needs to be there since prop values don't
|
|
12941
|
-
// have quotes in CSS
|
|
12942
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
12943
|
-
quote = 39 /* Char.QuoteSingle */;
|
|
12944
|
-
}
|
|
12945
|
-
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
12946
|
-
quote = 0 /* Char.QuoteNone */;
|
|
12947
|
-
}
|
|
12948
|
-
break;
|
|
12949
|
-
case 34 /* Char.QuoteDouble */:
|
|
12950
|
-
// same logic as above
|
|
12951
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
12952
|
-
quote = 34 /* Char.QuoteDouble */;
|
|
12953
|
-
}
|
|
12954
|
-
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
12955
|
-
quote = 0 /* Char.QuoteNone */;
|
|
12956
|
-
}
|
|
12957
|
-
break;
|
|
12958
|
-
case 58 /* Char.Colon */:
|
|
12959
|
-
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
12960
|
-
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
12961
|
-
valueStart = i;
|
|
12962
|
-
}
|
|
12963
|
-
break;
|
|
12964
|
-
case 59 /* Char.Semicolon */:
|
|
12965
|
-
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
12966
|
-
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
12967
|
-
styles.push(currentProp, styleVal);
|
|
12968
|
-
propStart = i;
|
|
12969
|
-
valueStart = 0;
|
|
12970
|
-
currentProp = null;
|
|
12971
|
-
}
|
|
12972
|
-
break;
|
|
12973
|
-
}
|
|
12974
|
-
}
|
|
12975
|
-
if (currentProp && valueStart) {
|
|
12976
|
-
const styleVal = value.slice(valueStart).trim();
|
|
12977
|
-
styles.push(currentProp, styleVal);
|
|
12978
|
-
}
|
|
12979
|
-
return styles;
|
|
12980
|
-
}
|
|
12981
|
-
function hyphenate(value) {
|
|
12982
|
-
return value
|
|
12983
|
-
.replace(/[a-z][A-Z]/g, v => {
|
|
12984
|
-
return v.charAt(0) + '-' + v.charAt(1);
|
|
12985
|
-
})
|
|
12986
|
-
.toLowerCase();
|
|
12987
|
-
}
|
|
12988
|
-
|
|
12989
13348
|
const IMPORTANT_FLAG = '!important';
|
|
12990
13349
|
/**
|
|
12991
13350
|
* Minimum amount of binding slots required in the runtime for style/class bindings.
|
|
@@ -19904,7 +20263,7 @@ class BindingParser {
|
|
|
19904
20263
|
this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
19905
20264
|
}
|
|
19906
20265
|
else {
|
|
19907
|
-
this._parsePropertyAst(name, this.
|
|
20266
|
+
this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
19908
20267
|
}
|
|
19909
20268
|
}
|
|
19910
20269
|
parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
|
|
@@ -19926,11 +20285,11 @@ class BindingParser {
|
|
|
19926
20285
|
// This will occur when a @trigger is not paired with an expression.
|
|
19927
20286
|
// For animations it is valid to not have an expression since */void
|
|
19928
20287
|
// states will be applied by angular when the element is attached/detached
|
|
19929
|
-
const ast = this.
|
|
20288
|
+
const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
|
|
19930
20289
|
targetMatchableAttrs.push([name, ast.source]);
|
|
19931
20290
|
targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
|
|
19932
20291
|
}
|
|
19933
|
-
|
|
20292
|
+
parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
|
|
19934
20293
|
const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
|
|
19935
20294
|
try {
|
|
19936
20295
|
const ast = isHostBinding ?
|
|
@@ -20207,6 +20566,415 @@ function normalizeNgContentSelect(selectAttr) {
|
|
|
20207
20566
|
return selectAttr;
|
|
20208
20567
|
}
|
|
20209
20568
|
|
|
20569
|
+
/** Pattern for a timing value in a trigger. */
|
|
20570
|
+
const TIME_PATTERN = /^\d+(ms|s)?$/;
|
|
20571
|
+
/** Pattern for a separator between keywords in a trigger expression. */
|
|
20572
|
+
const SEPARATOR_PATTERN = /^\s$/;
|
|
20573
|
+
/** Pairs of characters that form syntax that is comma-delimited. */
|
|
20574
|
+
const COMMA_DELIMITED_SYNTAX = new Map([
|
|
20575
|
+
[$LBRACE, $RBRACE],
|
|
20576
|
+
[$LBRACKET, $RBRACKET],
|
|
20577
|
+
[$LPAREN, $RPAREN], // Function calls
|
|
20578
|
+
]);
|
|
20579
|
+
/** Possible types of `on` triggers. */
|
|
20580
|
+
var OnTriggerType;
|
|
20581
|
+
(function (OnTriggerType) {
|
|
20582
|
+
OnTriggerType["IDLE"] = "idle";
|
|
20583
|
+
OnTriggerType["TIMER"] = "timer";
|
|
20584
|
+
OnTriggerType["INTERACTION"] = "interaction";
|
|
20585
|
+
OnTriggerType["IMMEDIATE"] = "immediate";
|
|
20586
|
+
OnTriggerType["HOVER"] = "hover";
|
|
20587
|
+
OnTriggerType["VIEWPORT"] = "viewport";
|
|
20588
|
+
})(OnTriggerType || (OnTriggerType = {}));
|
|
20589
|
+
/** Parses a `when` deferred trigger. */
|
|
20590
|
+
function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
|
|
20591
|
+
const whenIndex = expression.indexOf('when');
|
|
20592
|
+
// This is here just to be safe, we shouldn't enter this function
|
|
20593
|
+
// in the first place if a block doesn't have the "when" keyword.
|
|
20594
|
+
if (whenIndex === -1) {
|
|
20595
|
+
errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
|
|
20596
|
+
return null;
|
|
20597
|
+
}
|
|
20598
|
+
const start = getTriggerParametersStart(expression, whenIndex + 1);
|
|
20599
|
+
const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
|
|
20600
|
+
return new BoundDeferredTrigger(parsed, sourceSpan);
|
|
20601
|
+
}
|
|
20602
|
+
/** Parses an `on` trigger */
|
|
20603
|
+
function parseOnTrigger({ expression, sourceSpan }, errors) {
|
|
20604
|
+
const onIndex = expression.indexOf('on');
|
|
20605
|
+
// This is here just to be safe, we shouldn't enter this function
|
|
20606
|
+
// in the first place if a block doesn't have the "on" keyword.
|
|
20607
|
+
if (onIndex === -1) {
|
|
20608
|
+
errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
|
|
20609
|
+
return [];
|
|
20610
|
+
}
|
|
20611
|
+
const start = getTriggerParametersStart(expression, onIndex + 1);
|
|
20612
|
+
return new OnTriggerParser(expression, start, sourceSpan, errors).parse();
|
|
20613
|
+
}
|
|
20614
|
+
class OnTriggerParser {
|
|
20615
|
+
constructor(expression, start, span, errors) {
|
|
20616
|
+
this.expression = expression;
|
|
20617
|
+
this.start = start;
|
|
20618
|
+
this.span = span;
|
|
20619
|
+
this.errors = errors;
|
|
20620
|
+
this.index = 0;
|
|
20621
|
+
this.triggers = [];
|
|
20622
|
+
this.tokens = new Lexer().tokenize(expression.slice(start));
|
|
20623
|
+
}
|
|
20624
|
+
parse() {
|
|
20625
|
+
while (this.tokens.length > 0 && this.index < this.tokens.length) {
|
|
20626
|
+
const token = this.token();
|
|
20627
|
+
if (!token.isIdentifier()) {
|
|
20628
|
+
this.unexpectedToken(token);
|
|
20629
|
+
break;
|
|
20630
|
+
}
|
|
20631
|
+
// An identifier immediately followed by a comma or the end of
|
|
20632
|
+
// the expression cannot have parameters so we can exit early.
|
|
20633
|
+
if (this.isFollowedByOrLast($COMMA)) {
|
|
20634
|
+
this.consumeTrigger(token, []);
|
|
20635
|
+
this.advance();
|
|
20636
|
+
}
|
|
20637
|
+
else if (this.isFollowedByOrLast($LPAREN)) {
|
|
20638
|
+
this.advance(); // Advance to the opening paren.
|
|
20639
|
+
const prevErrors = this.errors.length;
|
|
20640
|
+
const parameters = this.consumeParameters();
|
|
20641
|
+
if (this.errors.length !== prevErrors) {
|
|
20642
|
+
break;
|
|
20643
|
+
}
|
|
20644
|
+
this.consumeTrigger(token, parameters);
|
|
20645
|
+
this.advance(); // Advance past the closing paren.
|
|
20646
|
+
}
|
|
20647
|
+
else if (this.index < this.tokens.length - 1) {
|
|
20648
|
+
this.unexpectedToken(this.tokens[this.index + 1]);
|
|
20649
|
+
}
|
|
20650
|
+
this.advance();
|
|
20651
|
+
}
|
|
20652
|
+
return this.triggers;
|
|
20653
|
+
}
|
|
20654
|
+
advance() {
|
|
20655
|
+
this.index++;
|
|
20656
|
+
}
|
|
20657
|
+
isFollowedByOrLast(char) {
|
|
20658
|
+
if (this.index === this.tokens.length - 1) {
|
|
20659
|
+
return true;
|
|
20660
|
+
}
|
|
20661
|
+
return this.tokens[this.index + 1].isCharacter(char);
|
|
20662
|
+
}
|
|
20663
|
+
token() {
|
|
20664
|
+
return this.tokens[Math.min(this.index, this.tokens.length - 1)];
|
|
20665
|
+
}
|
|
20666
|
+
consumeTrigger(identifier, parameters) {
|
|
20667
|
+
const startSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
|
|
20668
|
+
const endSpan = startSpan.moveBy(this.token().end - identifier.index);
|
|
20669
|
+
const sourceSpan = new ParseSourceSpan(startSpan, endSpan);
|
|
20670
|
+
try {
|
|
20671
|
+
switch (identifier.toString()) {
|
|
20672
|
+
case OnTriggerType.IDLE:
|
|
20673
|
+
this.triggers.push(createIdleTrigger(parameters, sourceSpan));
|
|
20674
|
+
break;
|
|
20675
|
+
case OnTriggerType.TIMER:
|
|
20676
|
+
this.triggers.push(createTimerTrigger(parameters, sourceSpan));
|
|
20677
|
+
break;
|
|
20678
|
+
case OnTriggerType.INTERACTION:
|
|
20679
|
+
this.triggers.push(createInteractionTrigger(parameters, sourceSpan));
|
|
20680
|
+
break;
|
|
20681
|
+
case OnTriggerType.IMMEDIATE:
|
|
20682
|
+
this.triggers.push(createImmediateTrigger(parameters, sourceSpan));
|
|
20683
|
+
break;
|
|
20684
|
+
case OnTriggerType.HOVER:
|
|
20685
|
+
this.triggers.push(createHoverTrigger(parameters, sourceSpan));
|
|
20686
|
+
break;
|
|
20687
|
+
case OnTriggerType.VIEWPORT:
|
|
20688
|
+
this.triggers.push(createViewportTrigger(parameters, sourceSpan));
|
|
20689
|
+
break;
|
|
20690
|
+
default:
|
|
20691
|
+
throw new Error(`Unrecognized trigger type "${identifier}"`);
|
|
20692
|
+
}
|
|
20693
|
+
}
|
|
20694
|
+
catch (e) {
|
|
20695
|
+
this.error(identifier, e.message);
|
|
20696
|
+
}
|
|
20697
|
+
}
|
|
20698
|
+
consumeParameters() {
|
|
20699
|
+
const parameters = [];
|
|
20700
|
+
if (!this.token().isCharacter($LPAREN)) {
|
|
20701
|
+
this.unexpectedToken(this.token());
|
|
20702
|
+
return parameters;
|
|
20703
|
+
}
|
|
20704
|
+
this.advance();
|
|
20705
|
+
const commaDelimStack = [];
|
|
20706
|
+
let current = '';
|
|
20707
|
+
while (this.index < this.tokens.length) {
|
|
20708
|
+
const token = this.token();
|
|
20709
|
+
// Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
|
|
20710
|
+
// Note that we don't need to account for strings here since the lexer already parsed them
|
|
20711
|
+
// into string tokens.
|
|
20712
|
+
if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
|
|
20713
|
+
if (current.length) {
|
|
20714
|
+
parameters.push(current);
|
|
20715
|
+
}
|
|
20716
|
+
break;
|
|
20717
|
+
}
|
|
20718
|
+
// In the `on` microsyntax "top-level" commas (e.g. ones outside of an parameters) separate
|
|
20719
|
+
// the different triggers (e.g. `on idle,timer(500)`). This is problematic, because the
|
|
20720
|
+
// function-like syntax also implies that multiple parameters can be passed into the
|
|
20721
|
+
// individual trigger (e.g. `on foo(a, b)`). To avoid tripping up the parser with commas that
|
|
20722
|
+
// are part of other sorts of syntax (object literals, arrays), we treat anything inside
|
|
20723
|
+
// a comma-delimited syntax block as plain text.
|
|
20724
|
+
if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
|
|
20725
|
+
commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
|
|
20726
|
+
}
|
|
20727
|
+
if (commaDelimStack.length > 0 &&
|
|
20728
|
+
token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
|
|
20729
|
+
commaDelimStack.pop();
|
|
20730
|
+
}
|
|
20731
|
+
// If we hit a comma outside of a comma-delimited syntax, it means
|
|
20732
|
+
// that we're at the top level and we're starting a new parameter.
|
|
20733
|
+
if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
|
|
20734
|
+
parameters.push(current);
|
|
20735
|
+
current = '';
|
|
20736
|
+
this.advance();
|
|
20737
|
+
continue;
|
|
20738
|
+
}
|
|
20739
|
+
// Otherwise treat the token as a plain text character in the current parameter.
|
|
20740
|
+
current += this.tokenText();
|
|
20741
|
+
this.advance();
|
|
20742
|
+
}
|
|
20743
|
+
if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
|
|
20744
|
+
this.error(this.token(), 'Unexpected end of expression');
|
|
20745
|
+
}
|
|
20746
|
+
if (this.index < this.tokens.length - 1 &&
|
|
20747
|
+
!this.tokens[this.index + 1].isCharacter($COMMA)) {
|
|
20748
|
+
this.unexpectedToken(this.tokens[this.index + 1]);
|
|
20749
|
+
}
|
|
20750
|
+
return parameters;
|
|
20751
|
+
}
|
|
20752
|
+
tokenText() {
|
|
20753
|
+
// Tokens have a toString already which we could use, but for string tokens it omits the quotes.
|
|
20754
|
+
// Eventually we could expose this information on the token directly.
|
|
20755
|
+
return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
|
|
20756
|
+
}
|
|
20757
|
+
error(token, message) {
|
|
20758
|
+
const newStart = this.span.start.moveBy(this.start + token.index);
|
|
20759
|
+
const newEnd = newStart.moveBy(token.end - token.index);
|
|
20760
|
+
this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
|
|
20761
|
+
}
|
|
20762
|
+
unexpectedToken(token) {
|
|
20763
|
+
this.error(token, `Unexpected token "${token}"`);
|
|
20764
|
+
}
|
|
20765
|
+
}
|
|
20766
|
+
function createIdleTrigger(parameters, sourceSpan) {
|
|
20767
|
+
if (parameters.length > 0) {
|
|
20768
|
+
throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
|
|
20769
|
+
}
|
|
20770
|
+
return new IdleDeferredTrigger(sourceSpan);
|
|
20771
|
+
}
|
|
20772
|
+
function createTimerTrigger(parameters, sourceSpan) {
|
|
20773
|
+
if (parameters.length !== 1) {
|
|
20774
|
+
throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
|
|
20775
|
+
}
|
|
20776
|
+
const delay = parseDeferredTime(parameters[0]);
|
|
20777
|
+
if (delay === null) {
|
|
20778
|
+
throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
|
|
20779
|
+
}
|
|
20780
|
+
return new TimerDeferredTrigger(delay, sourceSpan);
|
|
20781
|
+
}
|
|
20782
|
+
function createInteractionTrigger(parameters, sourceSpan) {
|
|
20783
|
+
if (parameters.length > 1) {
|
|
20784
|
+
throw new Error(`"${OnTriggerType.INTERACTION}" trigger can only have zero or one parameters`);
|
|
20785
|
+
}
|
|
20786
|
+
return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
|
|
20787
|
+
}
|
|
20788
|
+
function createImmediateTrigger(parameters, sourceSpan) {
|
|
20789
|
+
if (parameters.length > 0) {
|
|
20790
|
+
throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
|
|
20791
|
+
}
|
|
20792
|
+
return new ImmediateDeferredTrigger(sourceSpan);
|
|
20793
|
+
}
|
|
20794
|
+
function createHoverTrigger(parameters, sourceSpan) {
|
|
20795
|
+
if (parameters.length > 0) {
|
|
20796
|
+
throw new Error(`"${OnTriggerType.HOVER}" trigger cannot have parameters`);
|
|
20797
|
+
}
|
|
20798
|
+
return new HoverDeferredTrigger(sourceSpan);
|
|
20799
|
+
}
|
|
20800
|
+
function createViewportTrigger(parameters, sourceSpan) {
|
|
20801
|
+
// TODO: the RFC has some more potential parameters for `viewport`.
|
|
20802
|
+
if (parameters.length > 1) {
|
|
20803
|
+
throw new Error(`"${OnTriggerType.VIEWPORT}" trigger can only have zero or one parameters`);
|
|
20804
|
+
}
|
|
20805
|
+
return new ViewportDeferredTrigger(parameters[0] ?? null, sourceSpan);
|
|
20806
|
+
}
|
|
20807
|
+
/** Gets the index within an expression at which the trigger parameters start. */
|
|
20808
|
+
function getTriggerParametersStart(value, startPosition = 0) {
|
|
20809
|
+
let hasFoundSeparator = false;
|
|
20810
|
+
for (let i = startPosition; i < value.length; i++) {
|
|
20811
|
+
if (SEPARATOR_PATTERN.test(value[i])) {
|
|
20812
|
+
hasFoundSeparator = true;
|
|
20813
|
+
}
|
|
20814
|
+
else if (hasFoundSeparator) {
|
|
20815
|
+
return i;
|
|
20816
|
+
}
|
|
20817
|
+
}
|
|
20818
|
+
return -1;
|
|
20819
|
+
}
|
|
20820
|
+
/**
|
|
20821
|
+
* Parses a time expression from a deferred trigger to
|
|
20822
|
+
* milliseconds. Returns null if it cannot be parsed.
|
|
20823
|
+
*/
|
|
20824
|
+
function parseDeferredTime(value) {
|
|
20825
|
+
const match = value.match(TIME_PATTERN);
|
|
20826
|
+
if (!match) {
|
|
20827
|
+
return null;
|
|
20828
|
+
}
|
|
20829
|
+
const [time, units] = match;
|
|
20830
|
+
return parseInt(time) * (units === 's' ? 1000 : 1);
|
|
20831
|
+
}
|
|
20832
|
+
|
|
20833
|
+
/** Pattern to identify a `prefetch when` trigger. */
|
|
20834
|
+
const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
|
|
20835
|
+
/** Pattern to identify a `prefetch on` trigger. */
|
|
20836
|
+
const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
|
|
20837
|
+
/** Pattern to identify a `minimum` parameter in a block. */
|
|
20838
|
+
const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
|
|
20839
|
+
/** Pattern to identify a `after` parameter in a block. */
|
|
20840
|
+
const AFTER_PARAMETER_PATTERN = /^after\s/;
|
|
20841
|
+
/** Pattern to identify a `when` parameter in a block. */
|
|
20842
|
+
const WHEN_PARAMETER_PATTERN = /^when\s/;
|
|
20843
|
+
/** Pattern to identify a `on` parameter in a block. */
|
|
20844
|
+
const ON_PARAMETER_PATTERN = /^on\s/;
|
|
20845
|
+
/** Possible types of secondary deferred blocks. */
|
|
20846
|
+
var SecondaryDeferredBlockType;
|
|
20847
|
+
(function (SecondaryDeferredBlockType) {
|
|
20848
|
+
SecondaryDeferredBlockType["PLACEHOLDER"] = "placeholder";
|
|
20849
|
+
SecondaryDeferredBlockType["LOADING"] = "loading";
|
|
20850
|
+
SecondaryDeferredBlockType["ERROR"] = "error";
|
|
20851
|
+
})(SecondaryDeferredBlockType || (SecondaryDeferredBlockType = {}));
|
|
20852
|
+
/** Creates a deferred block from an HTML AST node. */
|
|
20853
|
+
function createDeferredBlock(ast, visitor, bindingParser) {
|
|
20854
|
+
const errors = [];
|
|
20855
|
+
const [primaryBlock, ...secondaryBlocks] = ast.blocks;
|
|
20856
|
+
const { triggers, prefetchTriggers } = parsePrimaryTriggers(primaryBlock.parameters, bindingParser, errors);
|
|
20857
|
+
const { placeholder, loading, error } = parseSecondaryBlocks(secondaryBlocks, errors, visitor);
|
|
20858
|
+
return {
|
|
20859
|
+
node: new DeferredBlock(visitAll(visitor, primaryBlock.children), triggers, prefetchTriggers, placeholder, loading, error, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
20860
|
+
errors,
|
|
20861
|
+
};
|
|
20862
|
+
}
|
|
20863
|
+
function parseSecondaryBlocks(blocks, errors, visitor) {
|
|
20864
|
+
let placeholder = null;
|
|
20865
|
+
let loading = null;
|
|
20866
|
+
let error = null;
|
|
20867
|
+
for (const block of blocks) {
|
|
20868
|
+
try {
|
|
20869
|
+
switch (block.name) {
|
|
20870
|
+
case SecondaryDeferredBlockType.PLACEHOLDER:
|
|
20871
|
+
if (placeholder !== null) {
|
|
20872
|
+
errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.PLACEHOLDER}" block`));
|
|
20873
|
+
}
|
|
20874
|
+
else {
|
|
20875
|
+
placeholder = parsePlaceholderBlock(block, visitor);
|
|
20876
|
+
}
|
|
20877
|
+
break;
|
|
20878
|
+
case SecondaryDeferredBlockType.LOADING:
|
|
20879
|
+
if (loading !== null) {
|
|
20880
|
+
errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.LOADING}" block`));
|
|
20881
|
+
}
|
|
20882
|
+
else {
|
|
20883
|
+
loading = parseLoadingBlock(block, visitor);
|
|
20884
|
+
}
|
|
20885
|
+
break;
|
|
20886
|
+
case SecondaryDeferredBlockType.ERROR:
|
|
20887
|
+
if (error !== null) {
|
|
20888
|
+
errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.ERROR}" block`));
|
|
20889
|
+
}
|
|
20890
|
+
else {
|
|
20891
|
+
error = parseErrorBlock(block, visitor);
|
|
20892
|
+
}
|
|
20893
|
+
break;
|
|
20894
|
+
default:
|
|
20895
|
+
errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "${block.name}"`));
|
|
20896
|
+
break;
|
|
20897
|
+
}
|
|
20898
|
+
}
|
|
20899
|
+
catch (e) {
|
|
20900
|
+
errors.push(new ParseError(block.startSourceSpan, e.message));
|
|
20901
|
+
}
|
|
20902
|
+
}
|
|
20903
|
+
return { placeholder, loading, error };
|
|
20904
|
+
}
|
|
20905
|
+
function parsePlaceholderBlock(ast, visitor) {
|
|
20906
|
+
let minimumTime = null;
|
|
20907
|
+
for (const param of ast.parameters) {
|
|
20908
|
+
if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
|
|
20909
|
+
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
20910
|
+
if (parsedTime === null) {
|
|
20911
|
+
throw new Error(`Could not parse time value of parameter "minimum"`);
|
|
20912
|
+
}
|
|
20913
|
+
minimumTime = parsedTime;
|
|
20914
|
+
}
|
|
20915
|
+
else {
|
|
20916
|
+
throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.PLACEHOLDER}" block: "${param.expression}"`);
|
|
20917
|
+
}
|
|
20918
|
+
}
|
|
20919
|
+
return new DeferredBlockPlaceholder(visitAll(visitor, ast.children), minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
20920
|
+
}
|
|
20921
|
+
function parseLoadingBlock(ast, visitor) {
|
|
20922
|
+
let afterTime = null;
|
|
20923
|
+
let minimumTime = null;
|
|
20924
|
+
for (const param of ast.parameters) {
|
|
20925
|
+
if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
|
|
20926
|
+
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
20927
|
+
if (parsedTime === null) {
|
|
20928
|
+
throw new Error(`Could not parse time value of parameter "after"`);
|
|
20929
|
+
}
|
|
20930
|
+
afterTime = parsedTime;
|
|
20931
|
+
}
|
|
20932
|
+
else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
|
|
20933
|
+
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
20934
|
+
if (parsedTime === null) {
|
|
20935
|
+
throw new Error(`Could not parse time value of parameter "minimum"`);
|
|
20936
|
+
}
|
|
20937
|
+
minimumTime = parsedTime;
|
|
20938
|
+
}
|
|
20939
|
+
else {
|
|
20940
|
+
throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.LOADING}" block: "${param.expression}"`);
|
|
20941
|
+
}
|
|
20942
|
+
}
|
|
20943
|
+
return new DeferredBlockLoading(visitAll(visitor, ast.children), afterTime, minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
20944
|
+
}
|
|
20945
|
+
function parseErrorBlock(ast, visitor) {
|
|
20946
|
+
if (ast.parameters.length > 0) {
|
|
20947
|
+
throw new Error(`"${SecondaryDeferredBlockType.ERROR}" block cannot have parameters`);
|
|
20948
|
+
}
|
|
20949
|
+
return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
20950
|
+
}
|
|
20951
|
+
function parsePrimaryTriggers(params, bindingParser, errors) {
|
|
20952
|
+
const triggers = [];
|
|
20953
|
+
const prefetchTriggers = [];
|
|
20954
|
+
for (const param of params) {
|
|
20955
|
+
// The lexer ignores the leading spaces so we can assume
|
|
20956
|
+
// that the expression starts with a keyword.
|
|
20957
|
+
if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
|
|
20958
|
+
const result = parseWhenTrigger(param, bindingParser, errors);
|
|
20959
|
+
result !== null && triggers.push(result);
|
|
20960
|
+
}
|
|
20961
|
+
else if (ON_PARAMETER_PATTERN.test(param.expression)) {
|
|
20962
|
+
triggers.push(...parseOnTrigger(param, errors));
|
|
20963
|
+
}
|
|
20964
|
+
else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
|
|
20965
|
+
const result = parseWhenTrigger(param, bindingParser, errors);
|
|
20966
|
+
result !== null && prefetchTriggers.push(result);
|
|
20967
|
+
}
|
|
20968
|
+
else if (PREFETCH_ON_PATTERN.test(param.expression)) {
|
|
20969
|
+
prefetchTriggers.push(...parseOnTrigger(param, errors));
|
|
20970
|
+
}
|
|
20971
|
+
else {
|
|
20972
|
+
errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
|
|
20973
|
+
}
|
|
20974
|
+
}
|
|
20975
|
+
return { triggers, prefetchTriggers };
|
|
20976
|
+
}
|
|
20977
|
+
|
|
20210
20978
|
const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
|
|
20211
20979
|
// Group 1 = "bind-"
|
|
20212
20980
|
const KW_BIND_IDX = 1;
|
|
@@ -20330,7 +21098,16 @@ class HtmlAstToIvyAst {
|
|
|
20330
21098
|
attributes.push(this.visitAttribute(attribute));
|
|
20331
21099
|
}
|
|
20332
21100
|
}
|
|
20333
|
-
|
|
21101
|
+
let children;
|
|
21102
|
+
if (preparsedElement.nonBindable) {
|
|
21103
|
+
// The `NonBindableVisitor` may need to return an array of nodes for block groups so we need
|
|
21104
|
+
// to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
|
|
21105
|
+
// a new array.
|
|
21106
|
+
children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
|
|
21107
|
+
}
|
|
21108
|
+
else {
|
|
21109
|
+
children = visitAll(this, element.children);
|
|
21110
|
+
}
|
|
20334
21111
|
let parsedElement;
|
|
20335
21112
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
|
20336
21113
|
// `<ng-content>`
|
|
@@ -20429,14 +21206,22 @@ class HtmlAstToIvyAst {
|
|
|
20429
21206
|
return null;
|
|
20430
21207
|
}
|
|
20431
21208
|
visitBlockGroup(group, context) {
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
|
|
20438
|
-
|
|
21209
|
+
const primaryBlock = group.blocks[0];
|
|
21210
|
+
// The HTML parser ensures that we don't hit this case, but we have an assertion just in case.
|
|
21211
|
+
if (!primaryBlock) {
|
|
21212
|
+
this.reportError('Block group must have at least one block.', group.sourceSpan);
|
|
21213
|
+
return null;
|
|
21214
|
+
}
|
|
21215
|
+
if (primaryBlock.name === 'defer' && this.options.enabledBlockTypes.has(primaryBlock.name)) {
|
|
21216
|
+
const { node, errors } = createDeferredBlock(group, this, this.bindingParser);
|
|
21217
|
+
this.errors.push(...errors);
|
|
21218
|
+
return node;
|
|
21219
|
+
}
|
|
21220
|
+
this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
|
|
21221
|
+
return null;
|
|
20439
21222
|
}
|
|
21223
|
+
visitBlock(block, context) { }
|
|
21224
|
+
visitBlockParameter(parameter, context) { }
|
|
20440
21225
|
// convert view engine `ParsedProperty` to a format suitable for IVY
|
|
20441
21226
|
extractAttributes(elementName, properties, i18nPropsMeta) {
|
|
20442
21227
|
const bound = [];
|
|
@@ -20615,13 +21400,23 @@ class NonBindableVisitor {
|
|
|
20615
21400
|
return null;
|
|
20616
21401
|
}
|
|
20617
21402
|
visitBlockGroup(group, context) {
|
|
20618
|
-
|
|
21403
|
+
const nodes = visitAll(this, group.blocks);
|
|
21404
|
+
// We only need to do the end tag since the start will be added as a part of the primary block.
|
|
21405
|
+
if (group.endSourceSpan !== null) {
|
|
21406
|
+
nodes.push(new Text$3(group.endSourceSpan.toString(), group.endSourceSpan));
|
|
21407
|
+
}
|
|
21408
|
+
return nodes;
|
|
20619
21409
|
}
|
|
20620
21410
|
visitBlock(block, context) {
|
|
20621
|
-
|
|
21411
|
+
return [
|
|
21412
|
+
// In an ngNonBindable context we treat the opening/closing tags of block as plain text.
|
|
21413
|
+
// This is the as if the `tokenizeBlocks` option was disabled.
|
|
21414
|
+
new Text$3(block.startSourceSpan.toString(), block.startSourceSpan),
|
|
21415
|
+
...visitAll(this, block.children)
|
|
21416
|
+
];
|
|
20622
21417
|
}
|
|
20623
21418
|
visitBlockParameter(parameter, context) {
|
|
20624
|
-
|
|
21419
|
+
return null;
|
|
20625
21420
|
}
|
|
20626
21421
|
}
|
|
20627
21422
|
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
|
@@ -22469,6 +23264,12 @@ class TemplateDefinitionBuilder {
|
|
|
22469
23264
|
}
|
|
22470
23265
|
return null;
|
|
22471
23266
|
}
|
|
23267
|
+
// TODO: implement deferred block instructions.
|
|
23268
|
+
visitDeferredBlock(deferred) { }
|
|
23269
|
+
visitDeferredTrigger(trigger) { }
|
|
23270
|
+
visitDeferredBlockPlaceholder(block) { }
|
|
23271
|
+
visitDeferredBlockError(block) { }
|
|
23272
|
+
visitDeferredBlockLoading(block) { }
|
|
22472
23273
|
allocateDataSlot() {
|
|
22473
23274
|
return this._dataIndex++;
|
|
22474
23275
|
}
|
|
@@ -23205,7 +24006,12 @@ function parseTemplate(template, templateUrl, options = {}) {
|
|
|
23205
24006
|
const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
|
|
23206
24007
|
const bindingParser = makeBindingParser(interpolationConfig);
|
|
23207
24008
|
const htmlParser = new HtmlParser();
|
|
23208
|
-
const parseResult = htmlParser.parse(template, templateUrl, {
|
|
24009
|
+
const parseResult = htmlParser.parse(template, templateUrl, {
|
|
24010
|
+
leadingTriviaChars: LEADING_TRIVIA_CHARS,
|
|
24011
|
+
...options,
|
|
24012
|
+
tokenizeExpansionForms: true,
|
|
24013
|
+
tokenizeBlocks: options.enabledBlockTypes != null && options.enabledBlockTypes.size > 0,
|
|
24014
|
+
});
|
|
23209
24015
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
23210
24016
|
parseResult.errors.length > 0) {
|
|
23211
24017
|
const parsedTemplate = {
|
|
@@ -23256,7 +24062,10 @@ function parseTemplate(template, templateUrl, options = {}) {
|
|
|
23256
24062
|
rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
|
23257
24063
|
}
|
|
23258
24064
|
}
|
|
23259
|
-
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
|
|
24065
|
+
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
|
|
24066
|
+
collectCommentNodes: !!options.collectCommentNodes,
|
|
24067
|
+
enabledBlockTypes: options.enabledBlockTypes || new Set(),
|
|
24068
|
+
});
|
|
23260
24069
|
errors.push(...parseResult.errors, ...i18nMetaResult.errors);
|
|
23261
24070
|
const parsedTemplate = {
|
|
23262
24071
|
interpolationConfig,
|
|
@@ -24533,7 +25342,11 @@ function convertPipeDeclarationToMetadata(pipe) {
|
|
|
24533
25342
|
function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
|
|
24534
25343
|
const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
|
|
24535
25344
|
// Parse the template and check for errors.
|
|
24536
|
-
const parsed = parseTemplate(template, sourceMapUrl, {
|
|
25345
|
+
const parsed = parseTemplate(template, sourceMapUrl, {
|
|
25346
|
+
preserveWhitespaces,
|
|
25347
|
+
interpolationConfig,
|
|
25348
|
+
enabledBlockTypes: new Set(), // TODO: enable deferred blocks when testing in JIT mode.
|
|
25349
|
+
});
|
|
24537
25350
|
if (parsed.errors !== null) {
|
|
24538
25351
|
const errors = parsed.errors.map(err => err.toString()).join(', ');
|
|
24539
25352
|
throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
|
|
@@ -24722,7 +25535,7 @@ function publishFacade(global) {
|
|
|
24722
25535
|
* @description
|
|
24723
25536
|
* Entry point for all public APIs of the compiler package.
|
|
24724
25537
|
*/
|
|
24725
|
-
const VERSION = new Version('16.2.0-next.
|
|
25538
|
+
const VERSION = new Version('16.2.0-next.3');
|
|
24726
25539
|
|
|
24727
25540
|
class CompilerConfig {
|
|
24728
25541
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -26267,6 +27080,21 @@ class Scope {
|
|
|
26267
27080
|
// Declare the variable if it's not already.
|
|
26268
27081
|
this.maybeDeclare(reference);
|
|
26269
27082
|
}
|
|
27083
|
+
visitDeferredBlock(deferred) {
|
|
27084
|
+
deferred.children.forEach(node => node.visit(this));
|
|
27085
|
+
deferred.placeholder?.visit(this);
|
|
27086
|
+
deferred.loading?.visit(this);
|
|
27087
|
+
deferred.error?.visit(this);
|
|
27088
|
+
}
|
|
27089
|
+
visitDeferredBlockPlaceholder(block) {
|
|
27090
|
+
block.children.forEach(node => node.visit(this));
|
|
27091
|
+
}
|
|
27092
|
+
visitDeferredBlockError(block) {
|
|
27093
|
+
block.children.forEach(node => node.visit(this));
|
|
27094
|
+
}
|
|
27095
|
+
visitDeferredBlockLoading(block) {
|
|
27096
|
+
block.children.forEach(node => node.visit(this));
|
|
27097
|
+
}
|
|
26270
27098
|
// Unused visitors.
|
|
26271
27099
|
visitContent(content) { }
|
|
26272
27100
|
visitBoundAttribute(attr) { }
|
|
@@ -26275,6 +27103,7 @@ class Scope {
|
|
|
26275
27103
|
visitText(text) { }
|
|
26276
27104
|
visitTextAttribute(attr) { }
|
|
26277
27105
|
visitIcu(icu) { }
|
|
27106
|
+
visitDeferredTrigger(trigger) { }
|
|
26278
27107
|
maybeDeclare(thing) {
|
|
26279
27108
|
// Declare something with a name, as long as that name isn't taken.
|
|
26280
27109
|
if (!this.namedEntities.has(thing.name)) {
|
|
@@ -26412,6 +27241,21 @@ class DirectiveBinder {
|
|
|
26412
27241
|
// Recurse into the node's children.
|
|
26413
27242
|
node.children.forEach(child => child.visit(this));
|
|
26414
27243
|
}
|
|
27244
|
+
visitDeferredBlock(deferred) {
|
|
27245
|
+
deferred.children.forEach(child => child.visit(this));
|
|
27246
|
+
deferred.placeholder?.visit(this);
|
|
27247
|
+
deferred.loading?.visit(this);
|
|
27248
|
+
deferred.error?.visit(this);
|
|
27249
|
+
}
|
|
27250
|
+
visitDeferredBlockPlaceholder(block) {
|
|
27251
|
+
block.children.forEach(child => child.visit(this));
|
|
27252
|
+
}
|
|
27253
|
+
visitDeferredBlockError(block) {
|
|
27254
|
+
block.children.forEach(child => child.visit(this));
|
|
27255
|
+
}
|
|
27256
|
+
visitDeferredBlockLoading(block) {
|
|
27257
|
+
block.children.forEach(child => child.visit(this));
|
|
27258
|
+
}
|
|
26415
27259
|
// Unused visitors.
|
|
26416
27260
|
visitContent(content) { }
|
|
26417
27261
|
visitVariable(variable) { }
|
|
@@ -26423,6 +27267,7 @@ class DirectiveBinder {
|
|
|
26423
27267
|
visitText(text) { }
|
|
26424
27268
|
visitBoundText(text) { }
|
|
26425
27269
|
visitIcu(icu) { }
|
|
27270
|
+
visitDeferredTrigger(trigger) { }
|
|
26426
27271
|
}
|
|
26427
27272
|
/**
|
|
26428
27273
|
* Processes a template and extract metadata about expressions and symbols within.
|
|
@@ -26460,7 +27305,7 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
26460
27305
|
/**
|
|
26461
27306
|
* Process a template and extract metadata about expressions and symbols within.
|
|
26462
27307
|
*
|
|
26463
|
-
* @param
|
|
27308
|
+
* @param nodes the nodes of the template to process
|
|
26464
27309
|
* @param scope the `Scope` of the template being processed.
|
|
26465
27310
|
* @returns three maps which contain metadata about the template: `expressions` which interprets
|
|
26466
27311
|
* special `AST` nodes in expressions as pointing to references or variables declared within the
|
|
@@ -26469,14 +27314,15 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
26469
27314
|
* nesting level (how many levels deep within the template structure the `Template` is), starting
|
|
26470
27315
|
* at 1.
|
|
26471
27316
|
*/
|
|
26472
|
-
static applyWithScope(
|
|
27317
|
+
static applyWithScope(nodes, scope) {
|
|
26473
27318
|
const expressions = new Map();
|
|
26474
27319
|
const symbols = new Map();
|
|
26475
27320
|
const nestingLevel = new Map();
|
|
26476
27321
|
const usedPipes = new Set();
|
|
27322
|
+
const template = nodes instanceof Template ? nodes : null;
|
|
26477
27323
|
// The top-level template has nesting level 0.
|
|
26478
|
-
const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template
|
|
26479
|
-
binder.ingest(
|
|
27324
|
+
const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template, 0);
|
|
27325
|
+
binder.ingest(nodes);
|
|
26480
27326
|
return { expressions, symbols, nestingLevel, usedPipes };
|
|
26481
27327
|
}
|
|
26482
27328
|
ingest(template) {
|
|
@@ -26538,6 +27384,28 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
26538
27384
|
visitBoundEvent(event) {
|
|
26539
27385
|
event.handler.visit(this);
|
|
26540
27386
|
}
|
|
27387
|
+
visitDeferredBlock(deferred) {
|
|
27388
|
+
deferred.triggers.forEach(this.visitNode);
|
|
27389
|
+
deferred.prefetchTriggers.forEach(this.visitNode);
|
|
27390
|
+
deferred.children.forEach(this.visitNode);
|
|
27391
|
+
deferred.placeholder && this.visitNode(deferred.placeholder);
|
|
27392
|
+
deferred.loading && this.visitNode(deferred.loading);
|
|
27393
|
+
deferred.error && this.visitNode(deferred.error);
|
|
27394
|
+
}
|
|
27395
|
+
visitDeferredTrigger(trigger) {
|
|
27396
|
+
if (trigger instanceof BoundDeferredTrigger) {
|
|
27397
|
+
trigger.value.visit(this);
|
|
27398
|
+
}
|
|
27399
|
+
}
|
|
27400
|
+
visitDeferredBlockPlaceholder(block) {
|
|
27401
|
+
block.children.forEach(this.visitNode);
|
|
27402
|
+
}
|
|
27403
|
+
visitDeferredBlockError(block) {
|
|
27404
|
+
block.children.forEach(this.visitNode);
|
|
27405
|
+
}
|
|
27406
|
+
visitDeferredBlockLoading(block) {
|
|
27407
|
+
block.children.forEach(this.visitNode);
|
|
27408
|
+
}
|
|
26541
27409
|
visitBoundText(text) {
|
|
26542
27410
|
text.value.visit(this);
|
|
26543
27411
|
}
|
|
@@ -26676,7 +27544,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
26676
27544
|
function compileDeclareClassMetadata(metadata) {
|
|
26677
27545
|
const definitionMap = new DefinitionMap();
|
|
26678
27546
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
26679
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27547
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
26680
27548
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
26681
27549
|
definitionMap.set('type', metadata.type);
|
|
26682
27550
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -26779,7 +27647,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
26779
27647
|
function createDirectiveDefinitionMap(meta) {
|
|
26780
27648
|
const definitionMap = new DefinitionMap();
|
|
26781
27649
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
26782
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27650
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
26783
27651
|
// e.g. `type: MyDirective`
|
|
26784
27652
|
definitionMap.set('type', meta.type.value);
|
|
26785
27653
|
if (meta.isStandalone) {
|
|
@@ -27007,7 +27875,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
27007
27875
|
function compileDeclareFactoryFunction(meta) {
|
|
27008
27876
|
const definitionMap = new DefinitionMap();
|
|
27009
27877
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
27010
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27878
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
27011
27879
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27012
27880
|
definitionMap.set('type', meta.type.value);
|
|
27013
27881
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -27042,7 +27910,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
27042
27910
|
function createInjectableDefinitionMap(meta) {
|
|
27043
27911
|
const definitionMap = new DefinitionMap();
|
|
27044
27912
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
27045
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27913
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
27046
27914
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27047
27915
|
definitionMap.set('type', meta.type.value);
|
|
27048
27916
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -27093,7 +27961,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
27093
27961
|
function createInjectorDefinitionMap(meta) {
|
|
27094
27962
|
const definitionMap = new DefinitionMap();
|
|
27095
27963
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
27096
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27964
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
27097
27965
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27098
27966
|
definitionMap.set('type', meta.type.value);
|
|
27099
27967
|
definitionMap.set('providers', meta.providers);
|
|
@@ -27126,7 +27994,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
27126
27994
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
27127
27995
|
}
|
|
27128
27996
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
27129
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
27997
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
27130
27998
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27131
27999
|
definitionMap.set('type', meta.type.value);
|
|
27132
28000
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -27177,7 +28045,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
27177
28045
|
function createPipeDefinitionMap(meta) {
|
|
27178
28046
|
const definitionMap = new DefinitionMap();
|
|
27179
28047
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
27180
|
-
definitionMap.set('version', literal('16.2.0-next.
|
|
28048
|
+
definitionMap.set('version', literal('16.2.0-next.3'));
|
|
27181
28049
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
27182
28050
|
// e.g. `type: MyPipe`
|
|
27183
28051
|
definitionMap.set('type', meta.type.value);
|
|
@@ -27210,5 +28078,5 @@ publishFacade(_global);
|
|
|
27210
28078
|
|
|
27211
28079
|
// This file is not used to build this module. It is only used during editing
|
|
27212
28080
|
|
|
27213
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element$1 as TmplAstElement, Icu$1 as TmplAstIcu, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
28081
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
27214
28082
|
//# sourceMappingURL=compiler.mjs.map
|