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