@angular/compiler 16.2.2 → 17.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler.mjs +3 -3
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/component.mjs +4 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_ast.mjs +112 -9
- package/esm2022/src/render3/r3_class_metadata_compiler.mjs +55 -1
- package/esm2022/src/render3/r3_control_flow.mjs +332 -0
- package/esm2022/src/render3/r3_deferred_blocks.mjs +16 -9
- package/esm2022/src/render3/r3_deferred_triggers.mjs +33 -19
- package/esm2022/src/render3/r3_identifiers.mjs +18 -1
- package/esm2022/src/render3/r3_template_transform.mjs +28 -7
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +12 -2
- package/esm2022/src/render3/view/t2_binder.mjs +66 -5
- package/esm2022/src/render3/view/template.mjs +282 -59
- package/esm2022/src/render3/view/util.mjs +4 -2
- package/esm2022/src/template/pipeline/ir/index.mjs +2 -3
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +41 -3
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +11 -1
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +16 -4
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +5 -3
- package/esm2022/src/template/pipeline/src/emit.mjs +3 -1
- package/esm2022/src/template/pipeline/src/ingest.mjs +10 -10
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +43 -75
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +90 -13
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +38 -0
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1307 -430
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +153 -5
- package/package.json +2 -2
- package/testing/index.d.ts +1 -1
- package/esm2022/src/template/pipeline/ir/src/element.mjs +0 -108
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular
|
|
2
|
+
* @license Angular v17.0.0-next.1
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2614,6 +2614,21 @@ class Identifiers {
|
|
|
2614
2614
|
static { this.resetView = { name: 'ɵɵresetView', moduleName: CORE }; }
|
|
2615
2615
|
static { this.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE }; }
|
|
2616
2616
|
static { this.defer = { name: 'ɵɵdefer', moduleName: CORE }; }
|
|
2617
|
+
static { this.deferWhen = { name: 'ɵɵdeferWhen', moduleName: CORE }; }
|
|
2618
|
+
static { this.deferOnIdle = { name: 'ɵɵdeferOnIdle', moduleName: CORE }; }
|
|
2619
|
+
static { this.deferOnImmediate = { name: 'ɵɵdeferOnImmediate', moduleName: CORE }; }
|
|
2620
|
+
static { this.deferOnTimer = { name: 'ɵɵdeferOnTimer', moduleName: CORE }; }
|
|
2621
|
+
static { this.deferOnHover = { name: 'ɵɵdeferOnHover', moduleName: CORE }; }
|
|
2622
|
+
static { this.deferOnInteraction = { name: 'ɵɵdeferOnInteraction', moduleName: CORE }; }
|
|
2623
|
+
static { this.deferOnViewport = { name: 'ɵɵdeferOnViewport', moduleName: CORE }; }
|
|
2624
|
+
static { this.deferPrefetchWhen = { name: 'ɵɵdeferPrefetchWhen', moduleName: CORE }; }
|
|
2625
|
+
static { this.deferPrefetchOnIdle = { name: 'ɵɵdeferPrefetchOnIdle', moduleName: CORE }; }
|
|
2626
|
+
static { this.deferPrefetchOnImmediate = { name: 'ɵɵdeferPrefetchOnImmediate', moduleName: CORE }; }
|
|
2627
|
+
static { this.deferPrefetchOnTimer = { name: 'ɵɵdeferPrefetchOnTimer', moduleName: CORE }; }
|
|
2628
|
+
static { this.deferPrefetchOnHover = { name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE }; }
|
|
2629
|
+
static { this.deferPrefetchOnInteraction = { name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE }; }
|
|
2630
|
+
static { this.deferPrefetchOnViewport = { name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE }; }
|
|
2631
|
+
static { this.conditional = { name: 'ɵɵconditional', moduleName: CORE }; }
|
|
2617
2632
|
static { this.text = { name: 'ɵɵtext', moduleName: CORE }; }
|
|
2618
2633
|
static { this.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; }
|
|
2619
2634
|
static { this.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; }
|
|
@@ -2681,6 +2696,7 @@ class Identifiers {
|
|
|
2681
2696
|
static { this.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE }; }
|
|
2682
2697
|
static { this.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE }; }
|
|
2683
2698
|
static { this.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE }; }
|
|
2699
|
+
static { this.getComponentDepsFactory = { name: 'ɵɵgetComponentDepsFactory', moduleName: CORE }; }
|
|
2684
2700
|
static { this.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE }; }
|
|
2685
2701
|
static { this.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE }; }
|
|
2686
2702
|
static { this.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE }; }
|
|
@@ -2729,6 +2745,7 @@ class Identifiers {
|
|
|
2729
2745
|
static { this.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE }; }
|
|
2730
2746
|
static { this.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; }
|
|
2731
2747
|
static { this.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; }
|
|
2748
|
+
static { this.setClassMetadataAsync = { name: 'ɵsetClassMetadataAsync', moduleName: CORE }; }
|
|
2732
2749
|
static { this.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; }
|
|
2733
2750
|
static { this.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; }
|
|
2734
2751
|
static { this.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; }
|
|
@@ -3983,18 +4000,107 @@ class DeferredBlockError {
|
|
|
3983
4000
|
class DeferredBlock {
|
|
3984
4001
|
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3985
4002
|
this.children = children;
|
|
3986
|
-
this.triggers = triggers;
|
|
3987
|
-
this.prefetchTriggers = prefetchTriggers;
|
|
3988
4003
|
this.placeholder = placeholder;
|
|
3989
4004
|
this.loading = loading;
|
|
3990
4005
|
this.error = error;
|
|
3991
4006
|
this.sourceSpan = sourceSpan;
|
|
3992
4007
|
this.startSourceSpan = startSourceSpan;
|
|
3993
4008
|
this.endSourceSpan = endSourceSpan;
|
|
4009
|
+
this.triggers = triggers;
|
|
4010
|
+
this.prefetchTriggers = prefetchTriggers;
|
|
4011
|
+
// We cache the keys since we know that they won't change and we
|
|
4012
|
+
// don't want to enumarate them every time we're traversing the AST.
|
|
4013
|
+
this.definedTriggers = Object.keys(triggers);
|
|
4014
|
+
this.definedPrefetchTriggers = Object.keys(prefetchTriggers);
|
|
3994
4015
|
}
|
|
3995
4016
|
visit(visitor) {
|
|
3996
4017
|
return visitor.visitDeferredBlock(this);
|
|
3997
4018
|
}
|
|
4019
|
+
visitAll(visitor) {
|
|
4020
|
+
this.visitTriggers(this.definedTriggers, this.triggers, visitor);
|
|
4021
|
+
this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
|
|
4022
|
+
visitAll$1(visitor, this.children);
|
|
4023
|
+
this.placeholder && visitor.visitDeferredBlockPlaceholder(this.placeholder);
|
|
4024
|
+
this.loading && visitor.visitDeferredBlockLoading(this.loading);
|
|
4025
|
+
this.error && visitor.visitDeferredBlockError(this.error);
|
|
4026
|
+
}
|
|
4027
|
+
visitTriggers(keys, triggers, visitor) {
|
|
4028
|
+
for (const key of keys) {
|
|
4029
|
+
visitor.visitDeferredTrigger(triggers[key]);
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
class SwitchBlock {
|
|
4034
|
+
constructor(expression, cases, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4035
|
+
this.expression = expression;
|
|
4036
|
+
this.cases = cases;
|
|
4037
|
+
this.sourceSpan = sourceSpan;
|
|
4038
|
+
this.startSourceSpan = startSourceSpan;
|
|
4039
|
+
this.endSourceSpan = endSourceSpan;
|
|
4040
|
+
}
|
|
4041
|
+
visit(visitor) {
|
|
4042
|
+
return visitor.visitSwitchBlock(this);
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
class SwitchBlockCase {
|
|
4046
|
+
constructor(expression, children, sourceSpan, startSourceSpan) {
|
|
4047
|
+
this.expression = expression;
|
|
4048
|
+
this.children = children;
|
|
4049
|
+
this.sourceSpan = sourceSpan;
|
|
4050
|
+
this.startSourceSpan = startSourceSpan;
|
|
4051
|
+
}
|
|
4052
|
+
visit(visitor) {
|
|
4053
|
+
return visitor.visitSwitchBlockCase(this);
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
class ForLoopBlock {
|
|
4057
|
+
constructor(itemName, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4058
|
+
this.itemName = itemName;
|
|
4059
|
+
this.expression = expression;
|
|
4060
|
+
this.trackBy = trackBy;
|
|
4061
|
+
this.contextVariables = contextVariables;
|
|
4062
|
+
this.children = children;
|
|
4063
|
+
this.empty = empty;
|
|
4064
|
+
this.sourceSpan = sourceSpan;
|
|
4065
|
+
this.startSourceSpan = startSourceSpan;
|
|
4066
|
+
this.endSourceSpan = endSourceSpan;
|
|
4067
|
+
}
|
|
4068
|
+
visit(visitor) {
|
|
4069
|
+
return visitor.visitForLoopBlock(this);
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
class ForLoopBlockEmpty {
|
|
4073
|
+
constructor(children, sourceSpan, startSourceSpan) {
|
|
4074
|
+
this.children = children;
|
|
4075
|
+
this.sourceSpan = sourceSpan;
|
|
4076
|
+
this.startSourceSpan = startSourceSpan;
|
|
4077
|
+
}
|
|
4078
|
+
visit(visitor) {
|
|
4079
|
+
return visitor.visitForLoopBlockEmpty(this);
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
class IfBlock {
|
|
4083
|
+
constructor(branches, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4084
|
+
this.branches = branches;
|
|
4085
|
+
this.sourceSpan = sourceSpan;
|
|
4086
|
+
this.startSourceSpan = startSourceSpan;
|
|
4087
|
+
this.endSourceSpan = endSourceSpan;
|
|
4088
|
+
}
|
|
4089
|
+
visit(visitor) {
|
|
4090
|
+
return visitor.visitIfBlock(this);
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
class IfBlockBranch {
|
|
4094
|
+
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan) {
|
|
4095
|
+
this.expression = expression;
|
|
4096
|
+
this.children = children;
|
|
4097
|
+
this.expressionAlias = expressionAlias;
|
|
4098
|
+
this.sourceSpan = sourceSpan;
|
|
4099
|
+
this.startSourceSpan = startSourceSpan;
|
|
4100
|
+
}
|
|
4101
|
+
visit(visitor) {
|
|
4102
|
+
return visitor.visitIfBlockBranch(this);
|
|
4103
|
+
}
|
|
3998
4104
|
}
|
|
3999
4105
|
class Template {
|
|
4000
4106
|
constructor(
|
|
@@ -4084,12 +4190,7 @@ class RecursiveVisitor$1 {
|
|
|
4084
4190
|
visitAll$1(this, template.variables);
|
|
4085
4191
|
}
|
|
4086
4192
|
visitDeferredBlock(deferred) {
|
|
4087
|
-
visitAll
|
|
4088
|
-
visitAll$1(this, deferred.prefetchTriggers);
|
|
4089
|
-
visitAll$1(this, deferred.children);
|
|
4090
|
-
deferred.placeholder?.visit(this);
|
|
4091
|
-
deferred.loading?.visit(this);
|
|
4092
|
-
deferred.error?.visit(this);
|
|
4193
|
+
deferred.visitAll(this);
|
|
4093
4194
|
}
|
|
4094
4195
|
visitDeferredBlockPlaceholder(block) {
|
|
4095
4196
|
visitAll$1(this, block.children);
|
|
@@ -4100,6 +4201,25 @@ class RecursiveVisitor$1 {
|
|
|
4100
4201
|
visitDeferredBlockLoading(block) {
|
|
4101
4202
|
visitAll$1(this, block.children);
|
|
4102
4203
|
}
|
|
4204
|
+
visitSwitchBlock(block) {
|
|
4205
|
+
visitAll$1(this, block.cases);
|
|
4206
|
+
}
|
|
4207
|
+
visitSwitchBlockCase(block) {
|
|
4208
|
+
visitAll$1(this, block.children);
|
|
4209
|
+
}
|
|
4210
|
+
visitForLoopBlock(block) {
|
|
4211
|
+
visitAll$1(this, block.children);
|
|
4212
|
+
block.empty?.visit(this);
|
|
4213
|
+
}
|
|
4214
|
+
visitForLoopBlockEmpty(block) {
|
|
4215
|
+
visitAll$1(this, block.children);
|
|
4216
|
+
}
|
|
4217
|
+
visitIfBlock(block) {
|
|
4218
|
+
visitAll$1(this, block.branches);
|
|
4219
|
+
}
|
|
4220
|
+
visitIfBlockBranch(block) {
|
|
4221
|
+
visitAll$1(this, block.children);
|
|
4222
|
+
}
|
|
4103
4223
|
visitContent(content) { }
|
|
4104
4224
|
visitVariable(variable) { }
|
|
4105
4225
|
visitReference(reference) { }
|
|
@@ -4749,7 +4869,7 @@ function declareI18nVariable(variable) {
|
|
|
4749
4869
|
/**
|
|
4750
4870
|
* Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
|
|
4751
4871
|
* quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
|
|
4752
|
-
*
|
|
4872
|
+
* not work in some cases when object keys are mangled by a minifier.
|
|
4753
4873
|
*
|
|
4754
4874
|
* TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
|
|
4755
4875
|
* inputs that contain potentially unsafe chars.
|
|
@@ -4769,6 +4889,8 @@ const IMPLICIT_REFERENCE = '$implicit';
|
|
|
4769
4889
|
const NON_BINDABLE_ATTR = 'ngNonBindable';
|
|
4770
4890
|
/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */
|
|
4771
4891
|
const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
|
|
4892
|
+
/** Special value representing a direct access to a template's context. */
|
|
4893
|
+
const DIRECT_CONTEXT_REFERENCE = '#context';
|
|
4772
4894
|
/**
|
|
4773
4895
|
* Maximum length of a single instruction chain. Because our output AST uses recursion, we're
|
|
4774
4896
|
* limited in how many expressions we can nest before we reach the call stack limit. This
|
|
@@ -8615,140 +8737,6 @@ function repeatGroups(groups, multiples) {
|
|
|
8615
8737
|
}
|
|
8616
8738
|
}
|
|
8617
8739
|
|
|
8618
|
-
var TagContentType;
|
|
8619
|
-
(function (TagContentType) {
|
|
8620
|
-
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
8621
|
-
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
8622
|
-
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
8623
|
-
})(TagContentType || (TagContentType = {}));
|
|
8624
|
-
function splitNsName(elementName) {
|
|
8625
|
-
if (elementName[0] != ':') {
|
|
8626
|
-
return [null, elementName];
|
|
8627
|
-
}
|
|
8628
|
-
const colonIndex = elementName.indexOf(':', 1);
|
|
8629
|
-
if (colonIndex === -1) {
|
|
8630
|
-
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
8631
|
-
}
|
|
8632
|
-
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
8633
|
-
}
|
|
8634
|
-
// `<ng-container>` tags work the same regardless the namespace
|
|
8635
|
-
function isNgContainer(tagName) {
|
|
8636
|
-
return splitNsName(tagName)[1] === 'ng-container';
|
|
8637
|
-
}
|
|
8638
|
-
// `<ng-content>` tags work the same regardless the namespace
|
|
8639
|
-
function isNgContent(tagName) {
|
|
8640
|
-
return splitNsName(tagName)[1] === 'ng-content';
|
|
8641
|
-
}
|
|
8642
|
-
// `<ng-template>` tags work the same regardless the namespace
|
|
8643
|
-
function isNgTemplate(tagName) {
|
|
8644
|
-
return splitNsName(tagName)[1] === 'ng-template';
|
|
8645
|
-
}
|
|
8646
|
-
function getNsPrefix(fullName) {
|
|
8647
|
-
return fullName === null ? null : splitNsName(fullName)[0];
|
|
8648
|
-
}
|
|
8649
|
-
function mergeNsAndName(prefix, localName) {
|
|
8650
|
-
return prefix ? `:${prefix}:${localName}` : localName;
|
|
8651
|
-
}
|
|
8652
|
-
|
|
8653
|
-
/**
|
|
8654
|
-
* Enumeration of the types of attributes which can be applied to an element.
|
|
8655
|
-
*/
|
|
8656
|
-
var BindingKind;
|
|
8657
|
-
(function (BindingKind) {
|
|
8658
|
-
/**
|
|
8659
|
-
* Static attributes.
|
|
8660
|
-
*/
|
|
8661
|
-
BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
|
|
8662
|
-
/**
|
|
8663
|
-
* Class bindings.
|
|
8664
|
-
*/
|
|
8665
|
-
BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
|
|
8666
|
-
/**
|
|
8667
|
-
* Style bindings.
|
|
8668
|
-
*/
|
|
8669
|
-
BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
|
|
8670
|
-
/**
|
|
8671
|
-
* Dynamic property bindings.
|
|
8672
|
-
*/
|
|
8673
|
-
BindingKind[BindingKind["Property"] = 3] = "Property";
|
|
8674
|
-
/**
|
|
8675
|
-
* Property or attribute bindings on a template.
|
|
8676
|
-
*/
|
|
8677
|
-
BindingKind[BindingKind["Template"] = 4] = "Template";
|
|
8678
|
-
/**
|
|
8679
|
-
* Internationalized attributes.
|
|
8680
|
-
*/
|
|
8681
|
-
BindingKind[BindingKind["I18n"] = 5] = "I18n";
|
|
8682
|
-
/**
|
|
8683
|
-
* TODO: Consider how Animations are handled, and if they should be a distinct BindingKind.
|
|
8684
|
-
*/
|
|
8685
|
-
BindingKind[BindingKind["Animation"] = 6] = "Animation";
|
|
8686
|
-
})(BindingKind || (BindingKind = {}));
|
|
8687
|
-
const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
8688
|
-
/**
|
|
8689
|
-
* Container for all of the various kinds of attributes which are applied on an element.
|
|
8690
|
-
*/
|
|
8691
|
-
class ElementAttributes {
|
|
8692
|
-
constructor() {
|
|
8693
|
-
this.known = new Set();
|
|
8694
|
-
this.byKind = new Map;
|
|
8695
|
-
this.projectAs = null;
|
|
8696
|
-
}
|
|
8697
|
-
get attributes() {
|
|
8698
|
-
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
8699
|
-
}
|
|
8700
|
-
get classes() {
|
|
8701
|
-
return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
|
|
8702
|
-
}
|
|
8703
|
-
get styles() {
|
|
8704
|
-
return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
|
|
8705
|
-
}
|
|
8706
|
-
get bindings() {
|
|
8707
|
-
return this.byKind.get(BindingKind.Property) ?? FLYWEIGHT_ARRAY;
|
|
8708
|
-
}
|
|
8709
|
-
get template() {
|
|
8710
|
-
return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
|
|
8711
|
-
}
|
|
8712
|
-
get i18n() {
|
|
8713
|
-
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
8714
|
-
}
|
|
8715
|
-
add(kind, name, value) {
|
|
8716
|
-
if (this.known.has(name)) {
|
|
8717
|
-
return;
|
|
8718
|
-
}
|
|
8719
|
-
this.known.add(name);
|
|
8720
|
-
const array = this.arrayFor(kind);
|
|
8721
|
-
array.push(...getAttributeNameLiterals$1(name));
|
|
8722
|
-
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
8723
|
-
if (value === null) {
|
|
8724
|
-
throw Error('Attribute & style element attributes must have a value');
|
|
8725
|
-
}
|
|
8726
|
-
array.push(value);
|
|
8727
|
-
}
|
|
8728
|
-
}
|
|
8729
|
-
arrayFor(kind) {
|
|
8730
|
-
if (!this.byKind.has(kind)) {
|
|
8731
|
-
this.byKind.set(kind, []);
|
|
8732
|
-
}
|
|
8733
|
-
return this.byKind.get(kind);
|
|
8734
|
-
}
|
|
8735
|
-
}
|
|
8736
|
-
function getAttributeNameLiterals$1(name) {
|
|
8737
|
-
const [attributeNamespace, attributeName] = splitNsName(name);
|
|
8738
|
-
const nameLiteral = literal(attributeName);
|
|
8739
|
-
if (attributeNamespace) {
|
|
8740
|
-
return [
|
|
8741
|
-
literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
8742
|
-
];
|
|
8743
|
-
}
|
|
8744
|
-
return [nameLiteral];
|
|
8745
|
-
}
|
|
8746
|
-
function assertIsElementAttributes(attrs) {
|
|
8747
|
-
if (!(attrs instanceof ElementAttributes)) {
|
|
8748
|
-
throw new Error(`AssertionError: ElementAttributes has already been coalesced into the view constants`);
|
|
8749
|
-
}
|
|
8750
|
-
}
|
|
8751
|
-
|
|
8752
8740
|
/**
|
|
8753
8741
|
* Distinguishes different kinds of IR operations.
|
|
8754
8742
|
*
|
|
@@ -8855,14 +8843,18 @@ var OpKind;
|
|
|
8855
8843
|
* An operation to associate an attribute with an element.
|
|
8856
8844
|
*/
|
|
8857
8845
|
OpKind[OpKind["Attribute"] = 23] = "Attribute";
|
|
8846
|
+
/**
|
|
8847
|
+
* An attribute that has been extracted for inclusion in the consts array.
|
|
8848
|
+
*/
|
|
8849
|
+
OpKind[OpKind["ExtractedAttribute"] = 24] = "ExtractedAttribute";
|
|
8858
8850
|
/**
|
|
8859
8851
|
* A host binding property.
|
|
8860
8852
|
*/
|
|
8861
|
-
OpKind[OpKind["HostProperty"] =
|
|
8853
|
+
OpKind[OpKind["HostProperty"] = 25] = "HostProperty";
|
|
8862
8854
|
/**
|
|
8863
8855
|
* A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
|
|
8864
8856
|
*/
|
|
8865
|
-
OpKind[OpKind["Namespace"] =
|
|
8857
|
+
OpKind[OpKind["Namespace"] = 26] = "Namespace";
|
|
8866
8858
|
// TODO: Add Host Listeners, and possibly other host ops also.
|
|
8867
8859
|
})(OpKind || (OpKind = {}));
|
|
8868
8860
|
/**
|
|
@@ -8991,6 +8983,40 @@ var SanitizerFn;
|
|
|
8991
8983
|
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
8992
8984
|
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
8993
8985
|
})(SanitizerFn || (SanitizerFn = {}));
|
|
8986
|
+
/**
|
|
8987
|
+
* Enumeration of the types of attributes which can be applied to an element.
|
|
8988
|
+
*/
|
|
8989
|
+
var BindingKind;
|
|
8990
|
+
(function (BindingKind) {
|
|
8991
|
+
/**
|
|
8992
|
+
* Static attributes.
|
|
8993
|
+
*/
|
|
8994
|
+
BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
|
|
8995
|
+
/**
|
|
8996
|
+
* Class bindings.
|
|
8997
|
+
*/
|
|
8998
|
+
BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
|
|
8999
|
+
/**
|
|
9000
|
+
* Style bindings.
|
|
9001
|
+
*/
|
|
9002
|
+
BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
|
|
9003
|
+
/**
|
|
9004
|
+
* Dynamic property bindings.
|
|
9005
|
+
*/
|
|
9006
|
+
BindingKind[BindingKind["Property"] = 3] = "Property";
|
|
9007
|
+
/**
|
|
9008
|
+
* Property or attribute bindings on a template.
|
|
9009
|
+
*/
|
|
9010
|
+
BindingKind[BindingKind["Template"] = 4] = "Template";
|
|
9011
|
+
/**
|
|
9012
|
+
* Internationalized attributes.
|
|
9013
|
+
*/
|
|
9014
|
+
BindingKind[BindingKind["I18n"] = 5] = "I18n";
|
|
9015
|
+
/**
|
|
9016
|
+
* Animation property bindings.
|
|
9017
|
+
*/
|
|
9018
|
+
BindingKind[BindingKind["Animation"] = 6] = "Animation";
|
|
9019
|
+
})(BindingKind || (BindingKind = {}));
|
|
8994
9020
|
|
|
8995
9021
|
/**
|
|
8996
9022
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9133,7 +9159,7 @@ class Interpolation {
|
|
|
9133
9159
|
/**
|
|
9134
9160
|
* Create a `BindingOp`, not yet transformed into a particular type of binding.
|
|
9135
9161
|
*/
|
|
9136
|
-
function createBindingOp(target, kind, name, expression, unit, securityContext, isTemplate, sourceSpan) {
|
|
9162
|
+
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isTemplate, sourceSpan) {
|
|
9137
9163
|
return {
|
|
9138
9164
|
kind: OpKind.Binding,
|
|
9139
9165
|
bindingKind: kind,
|
|
@@ -9142,6 +9168,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9142
9168
|
expression,
|
|
9143
9169
|
unit,
|
|
9144
9170
|
securityContext,
|
|
9171
|
+
isTextAttribute,
|
|
9145
9172
|
isTemplate,
|
|
9146
9173
|
sourceSpan,
|
|
9147
9174
|
...NEW_OP,
|
|
@@ -9224,7 +9251,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9224
9251
|
/**
|
|
9225
9252
|
* Create an `AttributeOp`.
|
|
9226
9253
|
*/
|
|
9227
|
-
function createAttributeOp(target, name, expression, securityContext, isTemplate, sourceSpan) {
|
|
9254
|
+
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isTemplate, sourceSpan) {
|
|
9228
9255
|
return {
|
|
9229
9256
|
kind: OpKind.Attribute,
|
|
9230
9257
|
target,
|
|
@@ -9232,6 +9259,7 @@ function createAttributeOp(target, name, expression, securityContext, isTemplate
|
|
|
9232
9259
|
expression,
|
|
9233
9260
|
securityContext,
|
|
9234
9261
|
sanitizer: null,
|
|
9262
|
+
isTextAttribute,
|
|
9235
9263
|
isTemplate,
|
|
9236
9264
|
sourceSpan,
|
|
9237
9265
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
@@ -9861,6 +9889,10 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9861
9889
|
transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
|
|
9862
9890
|
}
|
|
9863
9891
|
break;
|
|
9892
|
+
case OpKind.ExtractedAttribute:
|
|
9893
|
+
op.expression =
|
|
9894
|
+
op.expression && transformExpressionsInExpression(op.expression, transform, flags);
|
|
9895
|
+
break;
|
|
9864
9896
|
case OpKind.Element:
|
|
9865
9897
|
case OpKind.ElementStart:
|
|
9866
9898
|
case OpKind.ElementEnd:
|
|
@@ -9965,6 +9997,12 @@ function transformExpressionsInStatement(stmt, transform, flags) {
|
|
|
9965
9997
|
throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
|
|
9966
9998
|
}
|
|
9967
9999
|
}
|
|
10000
|
+
/**
|
|
10001
|
+
* Checks whether the given expression is a string literal.
|
|
10002
|
+
*/
|
|
10003
|
+
function isStringLiteral(expr) {
|
|
10004
|
+
return expr instanceof LiteralExpr && typeof expr.value === 'string';
|
|
10005
|
+
}
|
|
9968
10006
|
|
|
9969
10007
|
/**
|
|
9970
10008
|
* A linked list of `Op` nodes of a given subtype.
|
|
@@ -10227,7 +10265,7 @@ function createElementStartOp(tag, xref, namespace, sourceSpan) {
|
|
|
10227
10265
|
kind: OpKind.ElementStart,
|
|
10228
10266
|
xref,
|
|
10229
10267
|
tag,
|
|
10230
|
-
attributes:
|
|
10268
|
+
attributes: null,
|
|
10231
10269
|
localRefs: [],
|
|
10232
10270
|
nonBindable: false,
|
|
10233
10271
|
namespace,
|
|
@@ -10243,7 +10281,7 @@ function createTemplateOp(xref, tag, namespace, sourceSpan) {
|
|
|
10243
10281
|
return {
|
|
10244
10282
|
kind: OpKind.Template,
|
|
10245
10283
|
xref,
|
|
10246
|
-
attributes:
|
|
10284
|
+
attributes: null,
|
|
10247
10285
|
tag,
|
|
10248
10286
|
decls: null,
|
|
10249
10287
|
vars: null,
|
|
@@ -10354,6 +10392,19 @@ function createNamespaceOp(namespace) {
|
|
|
10354
10392
|
...NEW_OP,
|
|
10355
10393
|
};
|
|
10356
10394
|
}
|
|
10395
|
+
/**
|
|
10396
|
+
* Create an `ExtractedAttributeOp`.
|
|
10397
|
+
*/
|
|
10398
|
+
function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
10399
|
+
return {
|
|
10400
|
+
kind: OpKind.ExtractedAttribute,
|
|
10401
|
+
target,
|
|
10402
|
+
bindingKind,
|
|
10403
|
+
name,
|
|
10404
|
+
expression,
|
|
10405
|
+
...NEW_OP,
|
|
10406
|
+
};
|
|
10407
|
+
}
|
|
10357
10408
|
|
|
10358
10409
|
function createHostPropertyOp(name, expression, sourceSpan) {
|
|
10359
10410
|
return {
|
|
@@ -10663,86 +10714,7 @@ function removeAnys(e) {
|
|
|
10663
10714
|
}
|
|
10664
10715
|
|
|
10665
10716
|
/**
|
|
10666
|
-
*
|
|
10667
|
-
*
|
|
10668
|
-
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
10669
|
-
* Example: `color: red; height: auto`.
|
|
10670
|
-
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
10671
|
-
* 'auto']`
|
|
10672
|
-
*/
|
|
10673
|
-
function parse(value) {
|
|
10674
|
-
// we use a string array here instead of a string map
|
|
10675
|
-
// because a string-map is not guaranteed to retain the
|
|
10676
|
-
// order of the entries whereas a string array can be
|
|
10677
|
-
// constructed in a [key, value, key, value] format.
|
|
10678
|
-
const styles = [];
|
|
10679
|
-
let i = 0;
|
|
10680
|
-
let parenDepth = 0;
|
|
10681
|
-
let quote = 0 /* Char.QuoteNone */;
|
|
10682
|
-
let valueStart = 0;
|
|
10683
|
-
let propStart = 0;
|
|
10684
|
-
let currentProp = null;
|
|
10685
|
-
while (i < value.length) {
|
|
10686
|
-
const token = value.charCodeAt(i++);
|
|
10687
|
-
switch (token) {
|
|
10688
|
-
case 40 /* Char.OpenParen */:
|
|
10689
|
-
parenDepth++;
|
|
10690
|
-
break;
|
|
10691
|
-
case 41 /* Char.CloseParen */:
|
|
10692
|
-
parenDepth--;
|
|
10693
|
-
break;
|
|
10694
|
-
case 39 /* Char.QuoteSingle */:
|
|
10695
|
-
// valueStart needs to be there since prop values don't
|
|
10696
|
-
// have quotes in CSS
|
|
10697
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
10698
|
-
quote = 39 /* Char.QuoteSingle */;
|
|
10699
|
-
}
|
|
10700
|
-
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
10701
|
-
quote = 0 /* Char.QuoteNone */;
|
|
10702
|
-
}
|
|
10703
|
-
break;
|
|
10704
|
-
case 34 /* Char.QuoteDouble */:
|
|
10705
|
-
// same logic as above
|
|
10706
|
-
if (quote === 0 /* Char.QuoteNone */) {
|
|
10707
|
-
quote = 34 /* Char.QuoteDouble */;
|
|
10708
|
-
}
|
|
10709
|
-
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
10710
|
-
quote = 0 /* Char.QuoteNone */;
|
|
10711
|
-
}
|
|
10712
|
-
break;
|
|
10713
|
-
case 58 /* Char.Colon */:
|
|
10714
|
-
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
10715
|
-
currentProp = hyphenate$1(value.substring(propStart, i - 1).trim());
|
|
10716
|
-
valueStart = i;
|
|
10717
|
-
}
|
|
10718
|
-
break;
|
|
10719
|
-
case 59 /* Char.Semicolon */:
|
|
10720
|
-
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
10721
|
-
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
10722
|
-
styles.push(currentProp, styleVal);
|
|
10723
|
-
propStart = i;
|
|
10724
|
-
valueStart = 0;
|
|
10725
|
-
currentProp = null;
|
|
10726
|
-
}
|
|
10727
|
-
break;
|
|
10728
|
-
}
|
|
10729
|
-
}
|
|
10730
|
-
if (currentProp && valueStart) {
|
|
10731
|
-
const styleVal = value.slice(valueStart).trim();
|
|
10732
|
-
styles.push(currentProp, styleVal);
|
|
10733
|
-
}
|
|
10734
|
-
return styles;
|
|
10735
|
-
}
|
|
10736
|
-
function hyphenate$1(value) {
|
|
10737
|
-
return value
|
|
10738
|
-
.replace(/[a-z][A-Z]/g, v => {
|
|
10739
|
-
return v.charAt(0) + '-' + v.charAt(1);
|
|
10740
|
-
})
|
|
10741
|
-
.toLowerCase();
|
|
10742
|
-
}
|
|
10743
|
-
|
|
10744
|
-
/**
|
|
10745
|
-
* Gets a map of all elements in the given view by their xref id.
|
|
10717
|
+
* Gets a map of all elements in the given view by their xref id.
|
|
10746
10718
|
*/
|
|
10747
10719
|
function getElementsByXrefId(view) {
|
|
10748
10720
|
const elements = new Map();
|
|
@@ -10756,12 +10728,39 @@ function getElementsByXrefId(view) {
|
|
|
10756
10728
|
}
|
|
10757
10729
|
|
|
10758
10730
|
/**
|
|
10759
|
-
* Find all attribute and binding ops, and
|
|
10731
|
+
* Find all extractable attribute and binding ops, and create ExtractedAttributeOps for them.
|
|
10760
10732
|
* In cases where no instruction needs to be generated for the attribute or binding, it is removed.
|
|
10761
10733
|
*/
|
|
10762
10734
|
function phaseAttributeExtraction(cpl) {
|
|
10763
10735
|
for (const [_, view] of cpl.views) {
|
|
10764
|
-
|
|
10736
|
+
const elements = getElementsByXrefId(view);
|
|
10737
|
+
for (const op of view.ops()) {
|
|
10738
|
+
switch (op.kind) {
|
|
10739
|
+
case OpKind.Attribute:
|
|
10740
|
+
extractAttributeOp(view, op, elements);
|
|
10741
|
+
break;
|
|
10742
|
+
case OpKind.Property:
|
|
10743
|
+
if (!op.isAnimationTrigger) {
|
|
10744
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
|
|
10745
|
+
}
|
|
10746
|
+
break;
|
|
10747
|
+
case OpKind.StyleProp:
|
|
10748
|
+
case OpKind.ClassProp:
|
|
10749
|
+
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
10750
|
+
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
10751
|
+
// mode.
|
|
10752
|
+
if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
10753
|
+
op.expression instanceof EmptyExpr) {
|
|
10754
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
|
|
10755
|
+
}
|
|
10756
|
+
break;
|
|
10757
|
+
case OpKind.Listener:
|
|
10758
|
+
if (!op.isAnimationListener) {
|
|
10759
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
|
|
10760
|
+
}
|
|
10761
|
+
break;
|
|
10762
|
+
}
|
|
10763
|
+
}
|
|
10765
10764
|
}
|
|
10766
10765
|
}
|
|
10767
10766
|
/**
|
|
@@ -10775,84 +10774,28 @@ function lookupElement$2(elements, xref) {
|
|
|
10775
10774
|
return el;
|
|
10776
10775
|
}
|
|
10777
10776
|
/**
|
|
10778
|
-
*
|
|
10779
|
-
* not need further processing.
|
|
10777
|
+
* Extracts an attribute binding.
|
|
10780
10778
|
*/
|
|
10781
|
-
function populateElementAttributes(view) {
|
|
10782
|
-
const elements = getElementsByXrefId(view);
|
|
10783
|
-
for (const op of view.ops()) {
|
|
10784
|
-
let ownerOp;
|
|
10785
|
-
switch (op.kind) {
|
|
10786
|
-
case OpKind.Attribute:
|
|
10787
|
-
extractAttributeOp(view, op, elements);
|
|
10788
|
-
break;
|
|
10789
|
-
case OpKind.Property:
|
|
10790
|
-
if (op.isAnimationTrigger) {
|
|
10791
|
-
continue; // Don't extract animation properties.
|
|
10792
|
-
}
|
|
10793
|
-
ownerOp = lookupElement$2(elements, op.target);
|
|
10794
|
-
assertIsElementAttributes(ownerOp.attributes);
|
|
10795
|
-
ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null);
|
|
10796
|
-
break;
|
|
10797
|
-
case OpKind.StyleProp:
|
|
10798
|
-
case OpKind.ClassProp:
|
|
10799
|
-
ownerOp = lookupElement$2(elements, op.target);
|
|
10800
|
-
assertIsElementAttributes(ownerOp.attributes);
|
|
10801
|
-
// Empty StyleProperty and ClassName expressions are treated differently depending on
|
|
10802
|
-
// compatibility mode.
|
|
10803
|
-
if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
10804
|
-
op.expression instanceof EmptyExpr) {
|
|
10805
|
-
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
10806
|
-
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
10807
|
-
// mode.
|
|
10808
|
-
ownerOp.attributes.add(BindingKind.Property, op.name, null);
|
|
10809
|
-
}
|
|
10810
|
-
break;
|
|
10811
|
-
case OpKind.Listener:
|
|
10812
|
-
if (op.isAnimationListener) {
|
|
10813
|
-
continue; // Don't extract animation listeners.
|
|
10814
|
-
}
|
|
10815
|
-
ownerOp = lookupElement$2(elements, op.target);
|
|
10816
|
-
assertIsElementAttributes(ownerOp.attributes);
|
|
10817
|
-
ownerOp.attributes.add(BindingKind.Property, op.name, null);
|
|
10818
|
-
break;
|
|
10819
|
-
}
|
|
10820
|
-
}
|
|
10821
|
-
}
|
|
10822
|
-
function isStringLiteral(expr) {
|
|
10823
|
-
return expr instanceof LiteralExpr && typeof expr.value === 'string';
|
|
10824
|
-
}
|
|
10825
10779
|
function extractAttributeOp(view, op, elements) {
|
|
10826
10780
|
if (op.expression instanceof Interpolation) {
|
|
10827
10781
|
return;
|
|
10828
10782
|
}
|
|
10829
10783
|
const ownerOp = lookupElement$2(elements, op.target);
|
|
10830
|
-
|
|
10831
|
-
if (
|
|
10832
|
-
// TemplateDefinitionBuilder
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10784
|
+
let extractable = op.expression.isConstant();
|
|
10785
|
+
if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
10786
|
+
// TemplateDefinitionBuilder only extracted attributes that were string literals.
|
|
10787
|
+
extractable = isStringLiteral(op.expression);
|
|
10788
|
+
if (op.name === 'style' || op.name === 'class') {
|
|
10789
|
+
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
|
|
10790
|
+
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
|
|
10791
|
+
// string literal, because it is not a text attribute.
|
|
10792
|
+
extractable &&= op.isTextAttribute;
|
|
10793
|
+
}
|
|
10794
|
+
}
|
|
10795
|
+
if (extractable) {
|
|
10796
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression), ownerOp);
|
|
10842
10797
|
OpList.remove(op);
|
|
10843
10798
|
}
|
|
10844
|
-
else {
|
|
10845
|
-
// The old compiler only extracted string constants, so we emulate that behavior in
|
|
10846
|
-
// compaitiblity mode, otherwise we optimize more aggressively.
|
|
10847
|
-
let extractable = view.compatibility === CompatibilityMode.TemplateDefinitionBuilder ?
|
|
10848
|
-
(op.expression instanceof LiteralExpr && typeof op.expression.value === 'string') :
|
|
10849
|
-
op.expression.isConstant();
|
|
10850
|
-
// We don't need to generate instructions for attributes that can be extracted as consts.
|
|
10851
|
-
if (extractable) {
|
|
10852
|
-
ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression);
|
|
10853
|
-
OpList.remove(op);
|
|
10854
|
-
}
|
|
10855
|
-
}
|
|
10856
10799
|
}
|
|
10857
10800
|
|
|
10858
10801
|
/**
|
|
@@ -10888,7 +10831,7 @@ function phaseBindingSpecialization(job) {
|
|
|
10888
10831
|
target.nonBindable = true;
|
|
10889
10832
|
}
|
|
10890
10833
|
else {
|
|
10891
|
-
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTemplate, op.sourceSpan));
|
|
10834
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isTemplate, op.sourceSpan));
|
|
10892
10835
|
}
|
|
10893
10836
|
break;
|
|
10894
10837
|
case BindingKind.Property:
|
|
@@ -10997,30 +10940,142 @@ function chainOperationsInList(opList) {
|
|
|
10997
10940
|
}
|
|
10998
10941
|
}
|
|
10999
10942
|
|
|
10943
|
+
var TagContentType;
|
|
10944
|
+
(function (TagContentType) {
|
|
10945
|
+
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
10946
|
+
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
10947
|
+
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
10948
|
+
})(TagContentType || (TagContentType = {}));
|
|
10949
|
+
function splitNsName(elementName) {
|
|
10950
|
+
if (elementName[0] != ':') {
|
|
10951
|
+
return [null, elementName];
|
|
10952
|
+
}
|
|
10953
|
+
const colonIndex = elementName.indexOf(':', 1);
|
|
10954
|
+
if (colonIndex === -1) {
|
|
10955
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
10956
|
+
}
|
|
10957
|
+
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
10958
|
+
}
|
|
10959
|
+
// `<ng-container>` tags work the same regardless the namespace
|
|
10960
|
+
function isNgContainer(tagName) {
|
|
10961
|
+
return splitNsName(tagName)[1] === 'ng-container';
|
|
10962
|
+
}
|
|
10963
|
+
// `<ng-content>` tags work the same regardless the namespace
|
|
10964
|
+
function isNgContent(tagName) {
|
|
10965
|
+
return splitNsName(tagName)[1] === 'ng-content';
|
|
10966
|
+
}
|
|
10967
|
+
// `<ng-template>` tags work the same regardless the namespace
|
|
10968
|
+
function isNgTemplate(tagName) {
|
|
10969
|
+
return splitNsName(tagName)[1] === 'ng-template';
|
|
10970
|
+
}
|
|
10971
|
+
function getNsPrefix(fullName) {
|
|
10972
|
+
return fullName === null ? null : splitNsName(fullName)[0];
|
|
10973
|
+
}
|
|
10974
|
+
function mergeNsAndName(prefix, localName) {
|
|
10975
|
+
return prefix ? `:${prefix}:${localName}` : localName;
|
|
10976
|
+
}
|
|
10977
|
+
|
|
11000
10978
|
/**
|
|
11001
10979
|
* Converts the semantic attributes of element-like operations (elements, templates) into constant
|
|
11002
10980
|
* array expressions, and lifts them into the overall component `consts`.
|
|
11003
10981
|
*/
|
|
11004
10982
|
function phaseConstCollection(cpl) {
|
|
10983
|
+
// Collect all extracted attributes.
|
|
10984
|
+
const elementAttributes = new Map();
|
|
11005
10985
|
for (const [_, view] of cpl.views) {
|
|
11006
10986
|
for (const op of view.create) {
|
|
11007
|
-
if (op.kind
|
|
11008
|
-
op.
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
continue;
|
|
10987
|
+
if (op.kind === OpKind.ExtractedAttribute) {
|
|
10988
|
+
const attributes = elementAttributes.get(op.target) || new ElementAttributes();
|
|
10989
|
+
elementAttributes.set(op.target, attributes);
|
|
10990
|
+
attributes.add(op.bindingKind, op.name, op.expression);
|
|
10991
|
+
OpList.remove(op);
|
|
11013
10992
|
}
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
10993
|
+
}
|
|
10994
|
+
}
|
|
10995
|
+
// Serialize the extracted attributes into the const array.
|
|
10996
|
+
for (const [_, view] of cpl.views) {
|
|
10997
|
+
for (const op of view.create) {
|
|
10998
|
+
if (op.kind === OpKind.Element || op.kind === OpKind.ElementStart ||
|
|
10999
|
+
op.kind === OpKind.Template) {
|
|
11000
|
+
const attributes = elementAttributes.get(op.xref);
|
|
11001
|
+
if (attributes !== undefined) {
|
|
11002
|
+
const attrArray = serializeAttributes(attributes);
|
|
11003
|
+
if (attrArray.entries.length > 0) {
|
|
11004
|
+
op.attributes = cpl.addConst(attrArray);
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11017
11007
|
}
|
|
11018
|
-
|
|
11019
|
-
|
|
11008
|
+
}
|
|
11009
|
+
}
|
|
11010
|
+
}
|
|
11011
|
+
/**
|
|
11012
|
+
* Shared instance of an empty array to avoid unnecessary array allocations.
|
|
11013
|
+
*/
|
|
11014
|
+
const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
11015
|
+
/**
|
|
11016
|
+
* Container for all of the various kinds of attributes which are applied on an element.
|
|
11017
|
+
*/
|
|
11018
|
+
class ElementAttributes {
|
|
11019
|
+
constructor() {
|
|
11020
|
+
this.known = new Set();
|
|
11021
|
+
this.byKind = new Map;
|
|
11022
|
+
this.projectAs = null;
|
|
11023
|
+
}
|
|
11024
|
+
get attributes() {
|
|
11025
|
+
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
11026
|
+
}
|
|
11027
|
+
get classes() {
|
|
11028
|
+
return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
|
|
11029
|
+
}
|
|
11030
|
+
get styles() {
|
|
11031
|
+
return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
|
|
11032
|
+
}
|
|
11033
|
+
get bindings() {
|
|
11034
|
+
return this.byKind.get(BindingKind.Property) ?? FLYWEIGHT_ARRAY;
|
|
11035
|
+
}
|
|
11036
|
+
get template() {
|
|
11037
|
+
return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
|
|
11038
|
+
}
|
|
11039
|
+
get i18n() {
|
|
11040
|
+
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11041
|
+
}
|
|
11042
|
+
add(kind, name, value) {
|
|
11043
|
+
if (this.known.has(name)) {
|
|
11044
|
+
return;
|
|
11045
|
+
}
|
|
11046
|
+
this.known.add(name);
|
|
11047
|
+
const array = this.arrayFor(kind);
|
|
11048
|
+
array.push(...getAttributeNameLiterals$1(name));
|
|
11049
|
+
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11050
|
+
if (value === null) {
|
|
11051
|
+
throw Error('Attribute & style element attributes must have a value');
|
|
11020
11052
|
}
|
|
11053
|
+
array.push(value);
|
|
11054
|
+
}
|
|
11055
|
+
}
|
|
11056
|
+
arrayFor(kind) {
|
|
11057
|
+
if (!this.byKind.has(kind)) {
|
|
11058
|
+
this.byKind.set(kind, []);
|
|
11021
11059
|
}
|
|
11060
|
+
return this.byKind.get(kind);
|
|
11061
|
+
}
|
|
11062
|
+
}
|
|
11063
|
+
/**
|
|
11064
|
+
* Gets an array of literal expressions representing the attribute's namespaced name.
|
|
11065
|
+
*/
|
|
11066
|
+
function getAttributeNameLiterals$1(name) {
|
|
11067
|
+
const [attributeNamespace, attributeName] = splitNsName(name);
|
|
11068
|
+
const nameLiteral = literal(attributeName);
|
|
11069
|
+
if (attributeNamespace) {
|
|
11070
|
+
return [
|
|
11071
|
+
literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
11072
|
+
];
|
|
11022
11073
|
}
|
|
11074
|
+
return [nameLiteral];
|
|
11023
11075
|
}
|
|
11076
|
+
/**
|
|
11077
|
+
* Serializes an ElementAttributes object into an array expression.
|
|
11078
|
+
*/
|
|
11024
11079
|
function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, styles, template }) {
|
|
11025
11080
|
const attrArray = [...attributes];
|
|
11026
11081
|
if (projectAs !== null) {
|
|
@@ -11426,7 +11481,7 @@ function phaseHostStylePropertyParsing(job) {
|
|
|
11426
11481
|
op.bindingKind = BindingKind.StyleProperty;
|
|
11427
11482
|
op.name = op.name.substring(STYLE_DOT.length);
|
|
11428
11483
|
if (isCssCustomProperty$1(op.name)) {
|
|
11429
|
-
op.name = hyphenate(op.name);
|
|
11484
|
+
op.name = hyphenate$1(op.name);
|
|
11430
11485
|
}
|
|
11431
11486
|
const { property, suffix } = parseProperty$1(op.name);
|
|
11432
11487
|
op.name = property;
|
|
@@ -11449,7 +11504,7 @@ function phaseHostStylePropertyParsing(job) {
|
|
|
11449
11504
|
function isCssCustomProperty$1(name) {
|
|
11450
11505
|
return name.startsWith('--');
|
|
11451
11506
|
}
|
|
11452
|
-
function hyphenate(value) {
|
|
11507
|
+
function hyphenate$1(value) {
|
|
11453
11508
|
return value
|
|
11454
11509
|
.replace(/[a-z][A-Z]/g, v => {
|
|
11455
11510
|
return v.charAt(0) + '-' + v.charAt(1);
|
|
@@ -11524,6 +11579,85 @@ function phaseNamespace(job) {
|
|
|
11524
11579
|
}
|
|
11525
11580
|
}
|
|
11526
11581
|
|
|
11582
|
+
/**
|
|
11583
|
+
* Parses string representation of a style and converts it into object literal.
|
|
11584
|
+
*
|
|
11585
|
+
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
11586
|
+
* Example: `color: red; height: auto`.
|
|
11587
|
+
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
11588
|
+
* 'auto']`
|
|
11589
|
+
*/
|
|
11590
|
+
function parse(value) {
|
|
11591
|
+
// we use a string array here instead of a string map
|
|
11592
|
+
// because a string-map is not guaranteed to retain the
|
|
11593
|
+
// order of the entries whereas a string array can be
|
|
11594
|
+
// constructed in a [key, value, key, value] format.
|
|
11595
|
+
const styles = [];
|
|
11596
|
+
let i = 0;
|
|
11597
|
+
let parenDepth = 0;
|
|
11598
|
+
let quote = 0 /* Char.QuoteNone */;
|
|
11599
|
+
let valueStart = 0;
|
|
11600
|
+
let propStart = 0;
|
|
11601
|
+
let currentProp = null;
|
|
11602
|
+
while (i < value.length) {
|
|
11603
|
+
const token = value.charCodeAt(i++);
|
|
11604
|
+
switch (token) {
|
|
11605
|
+
case 40 /* Char.OpenParen */:
|
|
11606
|
+
parenDepth++;
|
|
11607
|
+
break;
|
|
11608
|
+
case 41 /* Char.CloseParen */:
|
|
11609
|
+
parenDepth--;
|
|
11610
|
+
break;
|
|
11611
|
+
case 39 /* Char.QuoteSingle */:
|
|
11612
|
+
// valueStart needs to be there since prop values don't
|
|
11613
|
+
// have quotes in CSS
|
|
11614
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
11615
|
+
quote = 39 /* Char.QuoteSingle */;
|
|
11616
|
+
}
|
|
11617
|
+
else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11618
|
+
quote = 0 /* Char.QuoteNone */;
|
|
11619
|
+
}
|
|
11620
|
+
break;
|
|
11621
|
+
case 34 /* Char.QuoteDouble */:
|
|
11622
|
+
// same logic as above
|
|
11623
|
+
if (quote === 0 /* Char.QuoteNone */) {
|
|
11624
|
+
quote = 34 /* Char.QuoteDouble */;
|
|
11625
|
+
}
|
|
11626
|
+
else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
|
|
11627
|
+
quote = 0 /* Char.QuoteNone */;
|
|
11628
|
+
}
|
|
11629
|
+
break;
|
|
11630
|
+
case 58 /* Char.Colon */:
|
|
11631
|
+
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11632
|
+
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
11633
|
+
valueStart = i;
|
|
11634
|
+
}
|
|
11635
|
+
break;
|
|
11636
|
+
case 59 /* Char.Semicolon */:
|
|
11637
|
+
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
11638
|
+
const styleVal = value.substring(valueStart, i - 1).trim();
|
|
11639
|
+
styles.push(currentProp, styleVal);
|
|
11640
|
+
propStart = i;
|
|
11641
|
+
valueStart = 0;
|
|
11642
|
+
currentProp = null;
|
|
11643
|
+
}
|
|
11644
|
+
break;
|
|
11645
|
+
}
|
|
11646
|
+
}
|
|
11647
|
+
if (currentProp && valueStart) {
|
|
11648
|
+
const styleVal = value.slice(valueStart).trim();
|
|
11649
|
+
styles.push(currentProp, styleVal);
|
|
11650
|
+
}
|
|
11651
|
+
return styles;
|
|
11652
|
+
}
|
|
11653
|
+
function hyphenate(value) {
|
|
11654
|
+
return value
|
|
11655
|
+
.replace(/[a-z][A-Z]/g, v => {
|
|
11656
|
+
return v.charAt(0) + '-' + v.charAt(1);
|
|
11657
|
+
})
|
|
11658
|
+
.toLowerCase();
|
|
11659
|
+
}
|
|
11660
|
+
|
|
11527
11661
|
const BINARY_OPERATORS = new Map([
|
|
11528
11662
|
['&&', BinaryOperator.And],
|
|
11529
11663
|
['>', BinaryOperator.Bigger],
|
|
@@ -11664,7 +11798,7 @@ function getVariableName(variable, state) {
|
|
|
11664
11798
|
* Normalizes a style prop name by hyphenating it (unless its a CSS variable).
|
|
11665
11799
|
*/
|
|
11666
11800
|
function normalizeStylePropName(name) {
|
|
11667
|
-
return name.startsWith('--') ? name : hyphenate
|
|
11801
|
+
return name.startsWith('--') ? name : hyphenate(name);
|
|
11668
11802
|
}
|
|
11669
11803
|
/**
|
|
11670
11804
|
* Strips `!important` out of the given style or class name.
|
|
@@ -11846,6 +11980,34 @@ function phaseNullishCoalescing(job) {
|
|
|
11846
11980
|
}
|
|
11847
11981
|
}
|
|
11848
11982
|
|
|
11983
|
+
/**
|
|
11984
|
+
* Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
|
|
11985
|
+
* class property.
|
|
11986
|
+
*/
|
|
11987
|
+
function phaseParseExtractedStyles(cpl) {
|
|
11988
|
+
for (const [_, view] of cpl.views) {
|
|
11989
|
+
for (const op of view.create) {
|
|
11990
|
+
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
11991
|
+
isStringLiteral(op.expression)) {
|
|
11992
|
+
if (op.name === 'style') {
|
|
11993
|
+
const parsedStyles = parse(op.expression.value);
|
|
11994
|
+
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
11995
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1])), op);
|
|
11996
|
+
}
|
|
11997
|
+
OpList.remove(op);
|
|
11998
|
+
}
|
|
11999
|
+
else if (op.name === 'class') {
|
|
12000
|
+
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
12001
|
+
for (const parsedClass of parsedClasses) {
|
|
12002
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null), op);
|
|
12003
|
+
}
|
|
12004
|
+
OpList.remove(op);
|
|
12005
|
+
}
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
12008
|
+
}
|
|
12009
|
+
}
|
|
12010
|
+
|
|
11849
12011
|
function phasePipeCreation(cpl) {
|
|
11850
12012
|
for (const view of cpl.views.values()) {
|
|
11851
12013
|
processPipeBindingsInView(view);
|
|
@@ -13593,6 +13755,7 @@ function transformTemplate(job) {
|
|
|
13593
13755
|
phaseStyleBindingSpecialization(job);
|
|
13594
13756
|
phaseBindingSpecialization(job);
|
|
13595
13757
|
phaseAttributeExtraction(job);
|
|
13758
|
+
phaseParseExtractedStyles(job);
|
|
13596
13759
|
phaseRemoveEmptyBindings(job);
|
|
13597
13760
|
phaseNoListenersOnTemplates(job);
|
|
13598
13761
|
phasePipeCreation(job);
|
|
@@ -13760,7 +13923,7 @@ function ingestComponent(componentName, template, constantPool) {
|
|
|
13760
13923
|
function ingestHostBinding(input, bindingParser, constantPool) {
|
|
13761
13924
|
const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
|
|
13762
13925
|
for (const property of input.properties ?? []) {
|
|
13763
|
-
ingestHostProperty(job, property);
|
|
13926
|
+
ingestHostProperty(job, property, false);
|
|
13764
13927
|
}
|
|
13765
13928
|
for (const event of input.events ?? []) {
|
|
13766
13929
|
ingestHostEvent(job, event);
|
|
@@ -13769,7 +13932,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
13769
13932
|
}
|
|
13770
13933
|
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
13771
13934
|
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
13772
|
-
function ingestHostProperty(job, property) {
|
|
13935
|
+
function ingestHostProperty(job, property, isTextAttribute) {
|
|
13773
13936
|
let expression;
|
|
13774
13937
|
const ast = property.expression.ast;
|
|
13775
13938
|
if (ast instanceof Interpolation$1) {
|
|
@@ -13786,7 +13949,7 @@ function ingestHostProperty(job, property) {
|
|
|
13786
13949
|
bindingKind = BindingKind.Attribute;
|
|
13787
13950
|
}
|
|
13788
13951
|
job.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
|
|
13789
|
-
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, false, property.sourceSpan));
|
|
13952
|
+
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, property.sourceSpan));
|
|
13790
13953
|
}
|
|
13791
13954
|
function ingestHostEvent(job, event) { }
|
|
13792
13955
|
/**
|
|
@@ -13964,10 +14127,10 @@ function ingestBindings(view, op, element) {
|
|
|
13964
14127
|
if (element instanceof Template) {
|
|
13965
14128
|
for (const attr of element.templateAttrs) {
|
|
13966
14129
|
if (attr instanceof TextAttribute) {
|
|
13967
|
-
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true);
|
|
14130
|
+
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, true);
|
|
13968
14131
|
}
|
|
13969
14132
|
else {
|
|
13970
|
-
ingestBinding(view, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, true);
|
|
14133
|
+
ingestBinding(view, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, false, true);
|
|
13971
14134
|
}
|
|
13972
14135
|
}
|
|
13973
14136
|
}
|
|
@@ -13975,10 +14138,10 @@ function ingestBindings(view, op, element) {
|
|
|
13975
14138
|
// This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
|
|
13976
14139
|
// `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
|
|
13977
14140
|
// `BindingType.Attribute`.
|
|
13978
|
-
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, false);
|
|
14141
|
+
ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, false);
|
|
13979
14142
|
}
|
|
13980
14143
|
for (const input of element.inputs) {
|
|
13981
|
-
ingestBinding(view, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false);
|
|
14144
|
+
ingestBinding(view, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false, false);
|
|
13982
14145
|
}
|
|
13983
14146
|
for (const output of element.outputs) {
|
|
13984
14147
|
let listenerOp;
|
|
@@ -14024,7 +14187,7 @@ const BINDING_KINDS = new Map([
|
|
|
14024
14187
|
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
14025
14188
|
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
14026
14189
|
]);
|
|
14027
|
-
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTemplateBinding) {
|
|
14190
|
+
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTextAttribute, isTemplateBinding) {
|
|
14028
14191
|
if (value instanceof ASTWithSource) {
|
|
14029
14192
|
value = value.ast;
|
|
14030
14193
|
}
|
|
@@ -14039,7 +14202,7 @@ function ingestBinding(view, xref, name, value, type, unit, securityContext, sou
|
|
|
14039
14202
|
expression = value;
|
|
14040
14203
|
}
|
|
14041
14204
|
const kind = BINDING_KINDS.get(type);
|
|
14042
|
-
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTemplateBinding, sourceSpan));
|
|
14205
|
+
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTextAttribute, isTemplateBinding, sourceSpan));
|
|
14043
14206
|
}
|
|
14044
14207
|
/**
|
|
14045
14208
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -14234,7 +14397,7 @@ class StylingBuilder {
|
|
|
14234
14397
|
// CSS custom properties are case-sensitive so we shouldn't normalize them.
|
|
14235
14398
|
// See: https://www.w3.org/TR/css-variables-1/#defining-variables
|
|
14236
14399
|
if (!isCssCustomProperty(name)) {
|
|
14237
|
-
name = hyphenate
|
|
14400
|
+
name = hyphenate(name);
|
|
14238
14401
|
}
|
|
14239
14402
|
const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
|
|
14240
14403
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
|
@@ -21301,6 +21464,328 @@ function normalizeNgContentSelect(selectAttr) {
|
|
|
21301
21464
|
return selectAttr;
|
|
21302
21465
|
}
|
|
21303
21466
|
|
|
21467
|
+
/** Pattern for the expression in a for loop block. */
|
|
21468
|
+
const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
|
|
21469
|
+
/** Pattern for the tracking expression in a for loop block. */
|
|
21470
|
+
const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
|
|
21471
|
+
/** Pattern for the `as` expression in a conditional block. */
|
|
21472
|
+
const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
|
|
21473
|
+
/** Pattern used to identify an `else if` block. */
|
|
21474
|
+
const ELSE_IF_PATTERN = /^if\s/;
|
|
21475
|
+
/** Pattern used to identify a `let` parameter. */
|
|
21476
|
+
const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/;
|
|
21477
|
+
/** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
|
|
21478
|
+
const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
|
|
21479
|
+
/** Creates an `if` loop block from an HTML AST node. */
|
|
21480
|
+
function createIfBlock(ast, visitor, bindingParser) {
|
|
21481
|
+
const errors = validateIfBlock(ast);
|
|
21482
|
+
const branches = [];
|
|
21483
|
+
if (errors.length > 0) {
|
|
21484
|
+
return { node: null, errors };
|
|
21485
|
+
}
|
|
21486
|
+
// Assumes that the structure is valid since we validated it above.
|
|
21487
|
+
for (const block of ast.blocks) {
|
|
21488
|
+
const children = visitAll(visitor, block.children);
|
|
21489
|
+
// `{:else}` block.
|
|
21490
|
+
if (block.name === 'else' && block.parameters.length === 0) {
|
|
21491
|
+
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan));
|
|
21492
|
+
continue;
|
|
21493
|
+
}
|
|
21494
|
+
const params = parseConditionalBlockParameters(block, errors, bindingParser);
|
|
21495
|
+
if (params !== null) {
|
|
21496
|
+
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan));
|
|
21497
|
+
}
|
|
21498
|
+
}
|
|
21499
|
+
return {
|
|
21500
|
+
node: new IfBlock(branches, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
21501
|
+
errors,
|
|
21502
|
+
};
|
|
21503
|
+
}
|
|
21504
|
+
/** Creates a `for` loop block from an HTML AST node. */
|
|
21505
|
+
function createForLoop(ast, visitor, bindingParser) {
|
|
21506
|
+
const [primaryBlock, ...secondaryBlocks] = ast.blocks;
|
|
21507
|
+
const errors = [];
|
|
21508
|
+
const params = parseForLoopParameters(primaryBlock, errors, bindingParser);
|
|
21509
|
+
let node = null;
|
|
21510
|
+
let empty = null;
|
|
21511
|
+
for (const block of secondaryBlocks) {
|
|
21512
|
+
if (block.name === 'empty') {
|
|
21513
|
+
if (empty !== null) {
|
|
21514
|
+
errors.push(new ParseError(block.sourceSpan, 'For loop can only have one "empty" block'));
|
|
21515
|
+
}
|
|
21516
|
+
else if (block.parameters.length > 0) {
|
|
21517
|
+
errors.push(new ParseError(block.sourceSpan, 'Empty block cannot have parameters'));
|
|
21518
|
+
}
|
|
21519
|
+
else {
|
|
21520
|
+
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children), block.sourceSpan, block.startSourceSpan);
|
|
21521
|
+
}
|
|
21522
|
+
}
|
|
21523
|
+
else {
|
|
21524
|
+
errors.push(new ParseError(block.sourceSpan, `Unrecognized loop block "${block.name}"`));
|
|
21525
|
+
}
|
|
21526
|
+
}
|
|
21527
|
+
if (params !== null) {
|
|
21528
|
+
if (params.trackBy === null) {
|
|
21529
|
+
errors.push(new ParseError(ast.sourceSpan, 'For loop must have a "track" expression'));
|
|
21530
|
+
}
|
|
21531
|
+
else {
|
|
21532
|
+
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, primaryBlock.children), empty, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
21533
|
+
}
|
|
21534
|
+
}
|
|
21535
|
+
return { node, errors };
|
|
21536
|
+
}
|
|
21537
|
+
/** Creates a switch block from an HTML AST node. */
|
|
21538
|
+
function createSwitchBlock(ast, visitor, bindingParser) {
|
|
21539
|
+
const [primaryBlock, ...secondaryBlocks] = ast.blocks;
|
|
21540
|
+
const errors = validateSwitchBlock(ast);
|
|
21541
|
+
if (errors.length > 0) {
|
|
21542
|
+
return { node: null, errors };
|
|
21543
|
+
}
|
|
21544
|
+
const primaryExpression = parseBlockParameterToBinding(primaryBlock.parameters[0], bindingParser);
|
|
21545
|
+
const cases = [];
|
|
21546
|
+
let defaultCase = null;
|
|
21547
|
+
// Here we assume that all the blocks are valid given that we validated them above.
|
|
21548
|
+
for (const block of secondaryBlocks) {
|
|
21549
|
+
const expression = block.name === 'case' ?
|
|
21550
|
+
parseBlockParameterToBinding(block.parameters[0], bindingParser) :
|
|
21551
|
+
null;
|
|
21552
|
+
const ast = new SwitchBlockCase(expression, visitAll(visitor, block.children), block.sourceSpan, block.startSourceSpan);
|
|
21553
|
+
if (expression === null) {
|
|
21554
|
+
defaultCase = ast;
|
|
21555
|
+
}
|
|
21556
|
+
else {
|
|
21557
|
+
cases.push(ast);
|
|
21558
|
+
}
|
|
21559
|
+
}
|
|
21560
|
+
// Ensure that the default case is last in the array.
|
|
21561
|
+
if (defaultCase !== null) {
|
|
21562
|
+
cases.push(defaultCase);
|
|
21563
|
+
}
|
|
21564
|
+
return {
|
|
21565
|
+
node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
21566
|
+
errors
|
|
21567
|
+
};
|
|
21568
|
+
}
|
|
21569
|
+
/** Parses the parameters of a `for` loop block. */
|
|
21570
|
+
function parseForLoopParameters(block, errors, bindingParser) {
|
|
21571
|
+
if (block.parameters.length === 0) {
|
|
21572
|
+
errors.push(new ParseError(block.sourceSpan, 'For loop does not have an expression'));
|
|
21573
|
+
return null;
|
|
21574
|
+
}
|
|
21575
|
+
const [expressionParam, ...secondaryParams] = block.parameters;
|
|
21576
|
+
const match = stripOptionalParentheses(expressionParam, errors)?.match(FOR_LOOP_EXPRESSION_PATTERN);
|
|
21577
|
+
if (!match || match[2].trim().length === 0) {
|
|
21578
|
+
errors.push(new ParseError(expressionParam.sourceSpan, 'Cannot parse expression. For loop expression must match the pattern "<identifier> of <expression>"'));
|
|
21579
|
+
return null;
|
|
21580
|
+
}
|
|
21581
|
+
const [, itemName, rawExpression] = match;
|
|
21582
|
+
const result = {
|
|
21583
|
+
itemName,
|
|
21584
|
+
trackBy: null,
|
|
21585
|
+
expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
|
|
21586
|
+
context: null,
|
|
21587
|
+
};
|
|
21588
|
+
for (const param of secondaryParams) {
|
|
21589
|
+
const letMatch = param.expression.match(FOR_LOOP_LET_PATTERN);
|
|
21590
|
+
if (letMatch !== null) {
|
|
21591
|
+
result.context = result.context || {};
|
|
21592
|
+
parseLetParameter(param.sourceSpan, letMatch[1], result.context, errors);
|
|
21593
|
+
continue;
|
|
21594
|
+
}
|
|
21595
|
+
const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
|
|
21596
|
+
if (trackMatch !== null) {
|
|
21597
|
+
if (result.trackBy !== null) {
|
|
21598
|
+
errors.push(new ParseError(param.sourceSpan, 'For loop can only have one "track" expression'));
|
|
21599
|
+
}
|
|
21600
|
+
else {
|
|
21601
|
+
result.trackBy = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
|
|
21602
|
+
}
|
|
21603
|
+
continue;
|
|
21604
|
+
}
|
|
21605
|
+
errors.push(new ParseError(param.sourceSpan, `Unrecognized loop paramater "${param.expression}"`));
|
|
21606
|
+
}
|
|
21607
|
+
return result;
|
|
21608
|
+
}
|
|
21609
|
+
/** Parses the `let` parameter of a `for` loop block. */
|
|
21610
|
+
function parseLetParameter(sourceSpan, expression, context, errors) {
|
|
21611
|
+
const parts = expression.split(',');
|
|
21612
|
+
for (const part of parts) {
|
|
21613
|
+
const expressionParts = part.split('=');
|
|
21614
|
+
const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
|
|
21615
|
+
const variableName = expressionParts.length === 2 ? expressionParts[1].trim() : '';
|
|
21616
|
+
if (name.length === 0 || variableName.length === 0) {
|
|
21617
|
+
errors.push(new ParseError(sourceSpan, `Invalid for loop "let" parameter. Parameter should match the pattern "<name> = <variable name>"`));
|
|
21618
|
+
}
|
|
21619
|
+
else if (!ALLOWED_FOR_LOOP_LET_VARIABLES.has(variableName)) {
|
|
21620
|
+
errors.push(new ParseError(sourceSpan, `Unknown "let" parameter variable "${variableName}". The allowed variables are: ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join(', ')}`));
|
|
21621
|
+
}
|
|
21622
|
+
else if (context.hasOwnProperty(variableName)) {
|
|
21623
|
+
errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
|
|
21624
|
+
}
|
|
21625
|
+
else {
|
|
21626
|
+
context[variableName] = name;
|
|
21627
|
+
}
|
|
21628
|
+
}
|
|
21629
|
+
}
|
|
21630
|
+
/** Checks that the shape of a `if` block is valid. Returns an array of errors. */
|
|
21631
|
+
function validateIfBlock(ast) {
|
|
21632
|
+
const errors = [];
|
|
21633
|
+
let hasElse = false;
|
|
21634
|
+
for (let i = 0; i < ast.blocks.length; i++) {
|
|
21635
|
+
const block = ast.blocks[i];
|
|
21636
|
+
// Conditional blocks only allow `if`, `else if` and `else` blocks.
|
|
21637
|
+
if ((block.name !== 'if' || i > 0) && block.name !== 'else') {
|
|
21638
|
+
errors.push(new ParseError(block.sourceSpan, `Unrecognized conditional block "${block.name}"`));
|
|
21639
|
+
continue;
|
|
21640
|
+
}
|
|
21641
|
+
if (block.name === 'if') {
|
|
21642
|
+
continue;
|
|
21643
|
+
}
|
|
21644
|
+
if (block.parameters.length === 0) {
|
|
21645
|
+
if (hasElse) {
|
|
21646
|
+
errors.push(new ParseError(block.sourceSpan, 'Conditional can only have one "else" block'));
|
|
21647
|
+
}
|
|
21648
|
+
else if (ast.blocks.length > 1 && i < ast.blocks.length - 1) {
|
|
21649
|
+
errors.push(new ParseError(block.sourceSpan, 'Else block must be last inside the conditional'));
|
|
21650
|
+
}
|
|
21651
|
+
hasElse = true;
|
|
21652
|
+
// `else if` is an edge case, because it has a space after the block name
|
|
21653
|
+
// which means that the `if` is captured as a part of the parameters.
|
|
21654
|
+
}
|
|
21655
|
+
else if (block.parameters.length > 0 && !ELSE_IF_PATTERN.test(block.parameters[0].expression)) {
|
|
21656
|
+
errors.push(new ParseError(block.sourceSpan, 'Else block cannot have parameters'));
|
|
21657
|
+
}
|
|
21658
|
+
}
|
|
21659
|
+
return errors;
|
|
21660
|
+
}
|
|
21661
|
+
/** Checks that the shape of a `switch` block is valid. Returns an array of errors. */
|
|
21662
|
+
function validateSwitchBlock(ast) {
|
|
21663
|
+
const [primaryBlock, ...secondaryBlocks] = ast.blocks;
|
|
21664
|
+
const errors = [];
|
|
21665
|
+
let hasDefault = false;
|
|
21666
|
+
if (primaryBlock.children.length > 0) {
|
|
21667
|
+
errors.push(new ParseError(primaryBlock.sourceSpan, 'Switch block can only contain "case" and "default" blocks'));
|
|
21668
|
+
}
|
|
21669
|
+
if (primaryBlock.parameters.length !== 1) {
|
|
21670
|
+
errors.push(new ParseError(primaryBlock.sourceSpan, 'Switch block must have exactly one parameter'));
|
|
21671
|
+
}
|
|
21672
|
+
for (const block of secondaryBlocks) {
|
|
21673
|
+
if (block.name === 'case') {
|
|
21674
|
+
if (block.parameters.length !== 1) {
|
|
21675
|
+
errors.push(new ParseError(block.sourceSpan, 'Case block must have exactly one parameter'));
|
|
21676
|
+
}
|
|
21677
|
+
}
|
|
21678
|
+
else if (block.name === 'default') {
|
|
21679
|
+
if (hasDefault) {
|
|
21680
|
+
errors.push(new ParseError(block.sourceSpan, 'Switch block can only have one "default" block'));
|
|
21681
|
+
}
|
|
21682
|
+
else if (block.parameters.length > 0) {
|
|
21683
|
+
errors.push(new ParseError(block.sourceSpan, 'Default block cannot have parameters'));
|
|
21684
|
+
}
|
|
21685
|
+
hasDefault = true;
|
|
21686
|
+
}
|
|
21687
|
+
else {
|
|
21688
|
+
errors.push(new ParseError(block.sourceSpan, 'Switch block can only contain "case" and "default" blocks'));
|
|
21689
|
+
}
|
|
21690
|
+
}
|
|
21691
|
+
return errors;
|
|
21692
|
+
}
|
|
21693
|
+
function parseBlockParameterToBinding(ast, bindingParser, part = 0) {
|
|
21694
|
+
let start;
|
|
21695
|
+
let end;
|
|
21696
|
+
if (typeof part === 'number') {
|
|
21697
|
+
start = part;
|
|
21698
|
+
end = ast.expression.length;
|
|
21699
|
+
}
|
|
21700
|
+
else {
|
|
21701
|
+
// Note: `lastIndexOf` here should be enough to know the start index of the expression,
|
|
21702
|
+
// because we know that it'll be at the end of the param. Ideally we could use the `d`
|
|
21703
|
+
// flag when matching via regex and get the index from `match.indices`, but it's unclear
|
|
21704
|
+
// if we can use it yet since it's a relatively new feature. See:
|
|
21705
|
+
// https://github.com/tc39/proposal-regexp-match-indices
|
|
21706
|
+
start = Math.max(0, ast.expression.lastIndexOf(part));
|
|
21707
|
+
end = start + part.length;
|
|
21708
|
+
}
|
|
21709
|
+
return bindingParser.parseBinding(ast.expression.slice(start, end), false, ast.sourceSpan, ast.sourceSpan.start.offset + start);
|
|
21710
|
+
}
|
|
21711
|
+
/** Parses the parameter of a conditional block (`if` or `else if`). */
|
|
21712
|
+
function parseConditionalBlockParameters(block, errors, bindingParser) {
|
|
21713
|
+
if (block.parameters.length === 0) {
|
|
21714
|
+
errors.push(new ParseError(block.sourceSpan, 'Conditional block does not have an expression'));
|
|
21715
|
+
return null;
|
|
21716
|
+
}
|
|
21717
|
+
const isPrimaryIfBlock = block.name === 'if';
|
|
21718
|
+
const expression =
|
|
21719
|
+
// Expressions for `{:else if}` blocks start at 2 to skip the `if` from the expression.
|
|
21720
|
+
parseBlockParameterToBinding(block.parameters[0], bindingParser, isPrimaryIfBlock ? 0 : 2);
|
|
21721
|
+
let expressionAlias = null;
|
|
21722
|
+
// Start from 1 since we processed the first parameter already.
|
|
21723
|
+
for (let i = 1; i < block.parameters.length; i++) {
|
|
21724
|
+
const param = block.parameters[i];
|
|
21725
|
+
const aliasMatch = param.expression.match(CONDITIONAL_ALIAS_PATTERN);
|
|
21726
|
+
// For now conditionals can only have an `as` parameter.
|
|
21727
|
+
// We may want to rework this later if we add more.
|
|
21728
|
+
if (aliasMatch === null) {
|
|
21729
|
+
errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional paramater "${param.expression}"`));
|
|
21730
|
+
}
|
|
21731
|
+
else if (!isPrimaryIfBlock) {
|
|
21732
|
+
errors.push(new ParseError(param.sourceSpan, '"as" expression is only allowed on the primary "if" block'));
|
|
21733
|
+
}
|
|
21734
|
+
else if (expressionAlias !== null) {
|
|
21735
|
+
errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
|
|
21736
|
+
}
|
|
21737
|
+
else {
|
|
21738
|
+
expressionAlias = aliasMatch[1].trim();
|
|
21739
|
+
}
|
|
21740
|
+
}
|
|
21741
|
+
return { expression, expressionAlias };
|
|
21742
|
+
}
|
|
21743
|
+
/** Strips optional parentheses around from a control from expression parameter. */
|
|
21744
|
+
function stripOptionalParentheses(param, errors) {
|
|
21745
|
+
const expression = param.expression;
|
|
21746
|
+
const spaceRegex = /^\s$/;
|
|
21747
|
+
let openParens = 0;
|
|
21748
|
+
let start = 0;
|
|
21749
|
+
let end = expression.length - 1;
|
|
21750
|
+
for (let i = 0; i < expression.length; i++) {
|
|
21751
|
+
const char = expression[i];
|
|
21752
|
+
if (char === '(') {
|
|
21753
|
+
start = i + 1;
|
|
21754
|
+
openParens++;
|
|
21755
|
+
}
|
|
21756
|
+
else if (spaceRegex.test(char)) {
|
|
21757
|
+
continue;
|
|
21758
|
+
}
|
|
21759
|
+
else {
|
|
21760
|
+
break;
|
|
21761
|
+
}
|
|
21762
|
+
}
|
|
21763
|
+
if (openParens === 0) {
|
|
21764
|
+
return expression;
|
|
21765
|
+
}
|
|
21766
|
+
for (let i = expression.length - 1; i > -1; i--) {
|
|
21767
|
+
const char = expression[i];
|
|
21768
|
+
if (char === ')') {
|
|
21769
|
+
end = i;
|
|
21770
|
+
openParens--;
|
|
21771
|
+
if (openParens === 0) {
|
|
21772
|
+
break;
|
|
21773
|
+
}
|
|
21774
|
+
}
|
|
21775
|
+
else if (spaceRegex.test(char)) {
|
|
21776
|
+
continue;
|
|
21777
|
+
}
|
|
21778
|
+
else {
|
|
21779
|
+
break;
|
|
21780
|
+
}
|
|
21781
|
+
}
|
|
21782
|
+
if (openParens !== 0) {
|
|
21783
|
+
errors.push(new ParseError(param.sourceSpan, 'Unclosed parentheses in expression'));
|
|
21784
|
+
return null;
|
|
21785
|
+
}
|
|
21786
|
+
return expression.slice(start, end);
|
|
21787
|
+
}
|
|
21788
|
+
|
|
21304
21789
|
/** Pattern for a timing value in a trigger. */
|
|
21305
21790
|
const TIME_PATTERN = /^\d+(ms|s)?$/;
|
|
21306
21791
|
/** Pattern for a separator between keywords in a trigger expression. */
|
|
@@ -21322,38 +21807,41 @@ var OnTriggerType;
|
|
|
21322
21807
|
OnTriggerType["VIEWPORT"] = "viewport";
|
|
21323
21808
|
})(OnTriggerType || (OnTriggerType = {}));
|
|
21324
21809
|
/** Parses a `when` deferred trigger. */
|
|
21325
|
-
function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
|
|
21810
|
+
function parseWhenTrigger({ expression, sourceSpan }, bindingParser, triggers, errors) {
|
|
21326
21811
|
const whenIndex = expression.indexOf('when');
|
|
21327
21812
|
// This is here just to be safe, we shouldn't enter this function
|
|
21328
21813
|
// in the first place if a block doesn't have the "when" keyword.
|
|
21329
21814
|
if (whenIndex === -1) {
|
|
21330
21815
|
errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
|
|
21331
|
-
return null;
|
|
21332
21816
|
}
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21817
|
+
else {
|
|
21818
|
+
const start = getTriggerParametersStart(expression, whenIndex + 1);
|
|
21819
|
+
const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
|
|
21820
|
+
trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan));
|
|
21821
|
+
}
|
|
21336
21822
|
}
|
|
21337
21823
|
/** Parses an `on` trigger */
|
|
21338
|
-
function parseOnTrigger({ expression, sourceSpan }, errors) {
|
|
21824
|
+
function parseOnTrigger({ expression, sourceSpan }, triggers, errors) {
|
|
21339
21825
|
const onIndex = expression.indexOf('on');
|
|
21340
21826
|
// This is here just to be safe, we shouldn't enter this function
|
|
21341
21827
|
// in the first place if a block doesn't have the "on" keyword.
|
|
21342
21828
|
if (onIndex === -1) {
|
|
21343
21829
|
errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
|
|
21344
|
-
return [];
|
|
21345
21830
|
}
|
|
21346
|
-
|
|
21347
|
-
|
|
21831
|
+
else {
|
|
21832
|
+
const start = getTriggerParametersStart(expression, onIndex + 1);
|
|
21833
|
+
const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors);
|
|
21834
|
+
parser.parse();
|
|
21835
|
+
}
|
|
21348
21836
|
}
|
|
21349
21837
|
class OnTriggerParser {
|
|
21350
|
-
constructor(expression, start, span, errors) {
|
|
21838
|
+
constructor(expression, start, span, triggers, errors) {
|
|
21351
21839
|
this.expression = expression;
|
|
21352
21840
|
this.start = start;
|
|
21353
21841
|
this.span = span;
|
|
21842
|
+
this.triggers = triggers;
|
|
21354
21843
|
this.errors = errors;
|
|
21355
21844
|
this.index = 0;
|
|
21356
|
-
this.triggers = [];
|
|
21357
21845
|
this.tokens = new Lexer().tokenize(expression.slice(start));
|
|
21358
21846
|
}
|
|
21359
21847
|
parse() {
|
|
@@ -21384,7 +21872,6 @@ class OnTriggerParser {
|
|
|
21384
21872
|
}
|
|
21385
21873
|
this.advance();
|
|
21386
21874
|
}
|
|
21387
|
-
return this.triggers;
|
|
21388
21875
|
}
|
|
21389
21876
|
advance() {
|
|
21390
21877
|
this.index++;
|
|
@@ -21405,22 +21892,22 @@ class OnTriggerParser {
|
|
|
21405
21892
|
try {
|
|
21406
21893
|
switch (identifier.toString()) {
|
|
21407
21894
|
case OnTriggerType.IDLE:
|
|
21408
|
-
this.
|
|
21895
|
+
this.trackTrigger('idle', createIdleTrigger(parameters, sourceSpan));
|
|
21409
21896
|
break;
|
|
21410
21897
|
case OnTriggerType.TIMER:
|
|
21411
|
-
this.
|
|
21898
|
+
this.trackTrigger('timer', createTimerTrigger(parameters, sourceSpan));
|
|
21412
21899
|
break;
|
|
21413
21900
|
case OnTriggerType.INTERACTION:
|
|
21414
|
-
this.
|
|
21901
|
+
this.trackTrigger('interaction', createInteractionTrigger(parameters, sourceSpan));
|
|
21415
21902
|
break;
|
|
21416
21903
|
case OnTriggerType.IMMEDIATE:
|
|
21417
|
-
this.
|
|
21904
|
+
this.trackTrigger('immediate', createImmediateTrigger(parameters, sourceSpan));
|
|
21418
21905
|
break;
|
|
21419
21906
|
case OnTriggerType.HOVER:
|
|
21420
|
-
this.
|
|
21907
|
+
this.trackTrigger('hover', createHoverTrigger(parameters, sourceSpan));
|
|
21421
21908
|
break;
|
|
21422
21909
|
case OnTriggerType.VIEWPORT:
|
|
21423
|
-
this.
|
|
21910
|
+
this.trackTrigger('viewport', createViewportTrigger(parameters, sourceSpan));
|
|
21424
21911
|
break;
|
|
21425
21912
|
default:
|
|
21426
21913
|
throw new Error(`Unrecognized trigger type "${identifier}"`);
|
|
@@ -21489,6 +21976,9 @@ class OnTriggerParser {
|
|
|
21489
21976
|
// Eventually we could expose this information on the token directly.
|
|
21490
21977
|
return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
|
|
21491
21978
|
}
|
|
21979
|
+
trackTrigger(name, trigger) {
|
|
21980
|
+
trackTrigger(name, this.triggers, this.errors, trigger);
|
|
21981
|
+
}
|
|
21492
21982
|
error(token, message) {
|
|
21493
21983
|
const newStart = this.span.start.moveBy(this.start + token.index);
|
|
21494
21984
|
const newEnd = newStart.moveBy(token.end - token.index);
|
|
@@ -21498,6 +21988,15 @@ class OnTriggerParser {
|
|
|
21498
21988
|
this.error(token, `Unexpected token "${token}"`);
|
|
21499
21989
|
}
|
|
21500
21990
|
}
|
|
21991
|
+
/** Adds a trigger to a map of triggers. */
|
|
21992
|
+
function trackTrigger(name, allTriggers, errors, trigger) {
|
|
21993
|
+
if (allTriggers[name]) {
|
|
21994
|
+
errors.push(new ParseError(trigger.sourceSpan, `Duplicate "${name}" trigger is not allowed`));
|
|
21995
|
+
}
|
|
21996
|
+
else {
|
|
21997
|
+
allTriggers[name] = trigger;
|
|
21998
|
+
}
|
|
21999
|
+
}
|
|
21501
22000
|
function createIdleTrigger(parameters, sourceSpan) {
|
|
21502
22001
|
if (parameters.length > 0) {
|
|
21503
22002
|
throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
|
|
@@ -21641,6 +22140,9 @@ function parsePlaceholderBlock(ast, visitor) {
|
|
|
21641
22140
|
let minimumTime = null;
|
|
21642
22141
|
for (const param of ast.parameters) {
|
|
21643
22142
|
if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
|
|
22143
|
+
if (minimumTime != null) {
|
|
22144
|
+
throw new Error(`Placeholder block can only have one "minimum" parameter`);
|
|
22145
|
+
}
|
|
21644
22146
|
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
21645
22147
|
if (parsedTime === null) {
|
|
21646
22148
|
throw new Error(`Could not parse time value of parameter "minimum"`);
|
|
@@ -21658,6 +22160,9 @@ function parseLoadingBlock(ast, visitor) {
|
|
|
21658
22160
|
let minimumTime = null;
|
|
21659
22161
|
for (const param of ast.parameters) {
|
|
21660
22162
|
if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
|
|
22163
|
+
if (afterTime != null) {
|
|
22164
|
+
throw new Error(`Loading block can only have one "after" parameter`);
|
|
22165
|
+
}
|
|
21661
22166
|
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
21662
22167
|
if (parsedTime === null) {
|
|
21663
22168
|
throw new Error(`Could not parse time value of parameter "after"`);
|
|
@@ -21665,6 +22170,9 @@ function parseLoadingBlock(ast, visitor) {
|
|
|
21665
22170
|
afterTime = parsedTime;
|
|
21666
22171
|
}
|
|
21667
22172
|
else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
|
|
22173
|
+
if (minimumTime != null) {
|
|
22174
|
+
throw new Error(`Loading block can only have one "minimum" parameter`);
|
|
22175
|
+
}
|
|
21668
22176
|
const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
|
|
21669
22177
|
if (parsedTime === null) {
|
|
21670
22178
|
throw new Error(`Could not parse time value of parameter "minimum"`);
|
|
@@ -21684,24 +22192,22 @@ function parseErrorBlock(ast, visitor) {
|
|
|
21684
22192
|
return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
21685
22193
|
}
|
|
21686
22194
|
function parsePrimaryTriggers(params, bindingParser, errors) {
|
|
21687
|
-
const triggers =
|
|
21688
|
-
const prefetchTriggers =
|
|
22195
|
+
const triggers = {};
|
|
22196
|
+
const prefetchTriggers = {};
|
|
21689
22197
|
for (const param of params) {
|
|
21690
22198
|
// The lexer ignores the leading spaces so we can assume
|
|
21691
22199
|
// that the expression starts with a keyword.
|
|
21692
22200
|
if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
|
|
21693
|
-
|
|
21694
|
-
result !== null && triggers.push(result);
|
|
22201
|
+
parseWhenTrigger(param, bindingParser, triggers, errors);
|
|
21695
22202
|
}
|
|
21696
22203
|
else if (ON_PARAMETER_PATTERN.test(param.expression)) {
|
|
21697
|
-
|
|
22204
|
+
parseOnTrigger(param, triggers, errors);
|
|
21698
22205
|
}
|
|
21699
22206
|
else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
|
|
21700
|
-
|
|
21701
|
-
result !== null && prefetchTriggers.push(result);
|
|
22207
|
+
parseWhenTrigger(param, bindingParser, prefetchTriggers, errors);
|
|
21702
22208
|
}
|
|
21703
22209
|
else if (PREFETCH_ON_PATTERN.test(param.expression)) {
|
|
21704
|
-
|
|
22210
|
+
parseOnTrigger(param, prefetchTriggers, errors);
|
|
21705
22211
|
}
|
|
21706
22212
|
else {
|
|
21707
22213
|
errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
|
|
@@ -21947,13 +22453,33 @@ class HtmlAstToIvyAst {
|
|
|
21947
22453
|
this.reportError('Block group must have at least one block.', group.sourceSpan);
|
|
21948
22454
|
return null;
|
|
21949
22455
|
}
|
|
21950
|
-
if (
|
|
21951
|
-
|
|
21952
|
-
|
|
21953
|
-
return node;
|
|
22456
|
+
if (!this.options.enabledBlockTypes.has(primaryBlock.name)) {
|
|
22457
|
+
this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
|
|
22458
|
+
return null;
|
|
21954
22459
|
}
|
|
21955
|
-
|
|
21956
|
-
|
|
22460
|
+
let result = null;
|
|
22461
|
+
switch (primaryBlock.name) {
|
|
22462
|
+
case 'defer':
|
|
22463
|
+
result = createDeferredBlock(group, this, this.bindingParser);
|
|
22464
|
+
break;
|
|
22465
|
+
case 'switch':
|
|
22466
|
+
result = createSwitchBlock(group, this, this.bindingParser);
|
|
22467
|
+
break;
|
|
22468
|
+
case 'for':
|
|
22469
|
+
result = createForLoop(group, this, this.bindingParser);
|
|
22470
|
+
break;
|
|
22471
|
+
case 'if':
|
|
22472
|
+
result = createIfBlock(group, this, this.bindingParser);
|
|
22473
|
+
break;
|
|
22474
|
+
default:
|
|
22475
|
+
result = {
|
|
22476
|
+
node: null,
|
|
22477
|
+
errors: [new ParseError(primaryBlock.sourceSpan, `Unrecognized block "${primaryBlock.name}".`)]
|
|
22478
|
+
};
|
|
22479
|
+
break;
|
|
22480
|
+
}
|
|
22481
|
+
this.errors.push(...result.errors);
|
|
22482
|
+
return result.node;
|
|
21957
22483
|
}
|
|
21958
22484
|
visitBlock(block, context) { }
|
|
21959
22485
|
visitBlockParameter(parameter, context) { }
|
|
@@ -23279,6 +23805,11 @@ class TemplateDefinitionBuilder {
|
|
|
23279
23805
|
this._currentIndex = 0;
|
|
23280
23806
|
/** Temporary variable declarations generated from visiting pipes, literals, etc. */
|
|
23281
23807
|
this._tempVariables = [];
|
|
23808
|
+
/**
|
|
23809
|
+
* Temporary variable used to store state between control flow instructions.
|
|
23810
|
+
* Should be accessed via the `allocateControlFlowTempVariable` method.
|
|
23811
|
+
*/
|
|
23812
|
+
this._controlFlowTempVariable = null;
|
|
23282
23813
|
/**
|
|
23283
23814
|
* List of callbacks to build nested templates. Nested templates must not be visited until
|
|
23284
23815
|
* after the parent template has finished visiting all of its nodes. This ensures that all
|
|
@@ -23308,6 +23839,12 @@ class TemplateDefinitionBuilder {
|
|
|
23308
23839
|
this.visitTextAttribute = invalid;
|
|
23309
23840
|
this.visitBoundAttribute = invalid;
|
|
23310
23841
|
this.visitBoundEvent = invalid;
|
|
23842
|
+
this.visitDeferredTrigger = invalid;
|
|
23843
|
+
this.visitDeferredBlockError = invalid;
|
|
23844
|
+
this.visitDeferredBlockLoading = invalid;
|
|
23845
|
+
this.visitDeferredBlockPlaceholder = invalid;
|
|
23846
|
+
this.visitIfBlockBranch = invalid;
|
|
23847
|
+
this.visitSwitchBlockCase = invalid;
|
|
23311
23848
|
this._bindingScope = parentBindingScope.nestedScope(level);
|
|
23312
23849
|
// Turn the relative context file path into an identifier by replacing non-alphanumeric
|
|
23313
23850
|
// characters with underscores.
|
|
@@ -23420,8 +23957,16 @@ class TemplateDefinitionBuilder {
|
|
|
23420
23957
|
registerContextVariables(variable$1) {
|
|
23421
23958
|
const scopedName = this._bindingScope.freshReferenceName();
|
|
23422
23959
|
const retrievalLevel = this.level;
|
|
23960
|
+
const isDirect = variable$1.value === DIRECT_CONTEXT_REFERENCE;
|
|
23423
23961
|
const lhs = variable(variable$1.name + scopedName);
|
|
23424
|
-
this._bindingScope.set(retrievalLevel, variable$1.name,
|
|
23962
|
+
this._bindingScope.set(retrievalLevel, variable$1.name, scope => {
|
|
23963
|
+
// If we're at the top level and we're referring to the context variable directly, we
|
|
23964
|
+
// can do so through the implicit receiver, instead of renaming it. Note that this does
|
|
23965
|
+
// not apply to listeners, because they need to restore the context.
|
|
23966
|
+
return isDirect && scope.bindingLevel === retrievalLevel && !scope.isListenerScope() ?
|
|
23967
|
+
variable(CONTEXT_NAME) :
|
|
23968
|
+
lhs;
|
|
23969
|
+
}, 1 /* DeclarationPriority.CONTEXT */, (scope, relativeLevel) => {
|
|
23425
23970
|
let rhs;
|
|
23426
23971
|
if (scope.bindingLevel === retrievalLevel) {
|
|
23427
23972
|
if (scope.isListenerScope() && scope.hasRestoreViewVariable()) {
|
|
@@ -23432,6 +23977,11 @@ class TemplateDefinitionBuilder {
|
|
|
23432
23977
|
rhs = variable(RESTORED_VIEW_CONTEXT_NAME);
|
|
23433
23978
|
scope.notifyRestoredViewContextUse();
|
|
23434
23979
|
}
|
|
23980
|
+
else if (isDirect) {
|
|
23981
|
+
// If we have a direct read of the context at the top level we don't need to
|
|
23982
|
+
// declare any variables and we can refer to it directly.
|
|
23983
|
+
return [];
|
|
23984
|
+
}
|
|
23435
23985
|
else {
|
|
23436
23986
|
// e.g. ctx
|
|
23437
23987
|
rhs = variable(CONTEXT_NAME);
|
|
@@ -23442,8 +23992,11 @@ class TemplateDefinitionBuilder {
|
|
|
23442
23992
|
// e.g. ctx_r0 OR x(2);
|
|
23443
23993
|
rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
|
|
23444
23994
|
}
|
|
23445
|
-
|
|
23446
|
-
|
|
23995
|
+
return [
|
|
23996
|
+
// e.g. const $items$ = x(2) for direct context references and
|
|
23997
|
+
// const $item$ = x(2).$implicit for indirect ones.
|
|
23998
|
+
lhs.set(isDirect ? rhs : rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()
|
|
23999
|
+
];
|
|
23447
24000
|
});
|
|
23448
24001
|
}
|
|
23449
24002
|
i18nAppendBindings(expressions) {
|
|
@@ -23864,28 +24417,22 @@ class TemplateDefinitionBuilder {
|
|
|
23864
24417
|
this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
|
|
23865
24418
|
}
|
|
23866
24419
|
}
|
|
23867
|
-
|
|
23868
|
-
const NG_TEMPLATE_TAG_NAME = 'ng-template';
|
|
24420
|
+
createEmbeddedTemplateFn(tagName, children, contextNameSuffix, sourceSpan, variables = [], attrsExprs, references, i18n) {
|
|
23869
24421
|
const templateIndex = this.allocateDataSlot();
|
|
23870
|
-
if (this.i18n) {
|
|
23871
|
-
this.i18n.appendTemplate(
|
|
24422
|
+
if (this.i18n && i18n) {
|
|
24423
|
+
this.i18n.appendTemplate(i18n, templateIndex);
|
|
23872
24424
|
}
|
|
23873
|
-
const
|
|
23874
|
-
const contextName = `${this.contextName}${template.tagName ? '_' + sanitizeIdentifier(template.tagName) : ''}_${templateIndex}`;
|
|
24425
|
+
const contextName = `${this.contextName}${contextNameSuffix}_${templateIndex}`;
|
|
23875
24426
|
const templateName = `${contextName}_Template`;
|
|
23876
24427
|
const parameters = [
|
|
23877
24428
|
literal(templateIndex),
|
|
23878
24429
|
variable(templateName),
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
literal(tagNameWithoutNamespace),
|
|
24430
|
+
literal(tagName),
|
|
24431
|
+
this.addAttrsToConsts(attrsExprs || null),
|
|
23882
24432
|
];
|
|
23883
|
-
// prepare attributes parameter (including attributes used for directive matching)
|
|
23884
|
-
const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
|
|
23885
|
-
parameters.push(this.addAttrsToConsts(attrsExprs));
|
|
23886
24433
|
// local refs (ex.: <ng-template #foo>)
|
|
23887
|
-
if (
|
|
23888
|
-
const refs = this.prepareRefsArray(
|
|
24434
|
+
if (references && references.length > 0) {
|
|
24435
|
+
const refs = this.prepareRefsArray(references);
|
|
23889
24436
|
parameters.push(this.addToConsts(refs));
|
|
23890
24437
|
parameters.push(importExpr(Identifiers.templateRefExtractor));
|
|
23891
24438
|
}
|
|
@@ -23896,17 +24443,28 @@ class TemplateDefinitionBuilder {
|
|
|
23896
24443
|
// be able to support bindings in nested templates to local refs that occur after the
|
|
23897
24444
|
// template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
|
|
23898
24445
|
this._nestedTemplateFns.push(() => {
|
|
23899
|
-
const templateFunctionExpr = templateVisitor.buildTemplateFunction(
|
|
24446
|
+
const templateFunctionExpr = templateVisitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18n);
|
|
23900
24447
|
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
|
|
23901
24448
|
if (templateVisitor._ngContentReservedSlots.length) {
|
|
23902
24449
|
this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
|
|
23903
24450
|
}
|
|
23904
24451
|
});
|
|
23905
24452
|
// e.g. template(1, MyComp_Template_1)
|
|
23906
|
-
this.creationInstruction(
|
|
24453
|
+
this.creationInstruction(sourceSpan, Identifiers.templateCreate, () => {
|
|
23907
24454
|
parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
|
|
23908
24455
|
return trimTrailingNulls(parameters);
|
|
23909
24456
|
});
|
|
24457
|
+
return templateIndex;
|
|
24458
|
+
}
|
|
24459
|
+
visitTemplate(template) {
|
|
24460
|
+
// We don't care about the tag's namespace here, because we infer
|
|
24461
|
+
// it based on the parent nodes inside the template instruction.
|
|
24462
|
+
const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
|
|
24463
|
+
const contextNameSuffix = template.tagName ? '_' + sanitizeIdentifier(template.tagName) : '';
|
|
24464
|
+
const NG_TEMPLATE_TAG_NAME = 'ng-template';
|
|
24465
|
+
// prepare attributes parameter (including attributes used for directive matching)
|
|
24466
|
+
const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
|
|
24467
|
+
const templateIndex = this.createEmbeddedTemplateFn(tagNameWithoutNamespace, template.children, contextNameSuffix, template.sourceSpan, template.variables, attrsExprs, template.references, template.i18n);
|
|
23910
24468
|
// handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
|
|
23911
24469
|
this.templatePropertyBindings(templateIndex, template.templateAttrs);
|
|
23912
24470
|
// Only add normal input/output binding instructions on explicit <ng-template> elements.
|
|
@@ -24000,50 +24558,224 @@ class TemplateDefinitionBuilder {
|
|
|
24000
24558
|
}
|
|
24001
24559
|
return null;
|
|
24002
24560
|
}
|
|
24003
|
-
|
|
24004
|
-
|
|
24005
|
-
|
|
24006
|
-
|
|
24007
|
-
const
|
|
24008
|
-
|
|
24009
|
-
|
|
24010
|
-
|
|
24011
|
-
|
|
24012
|
-
|
|
24013
|
-
//
|
|
24014
|
-
|
|
24015
|
-
|
|
24016
|
-
|
|
24017
|
-
|
|
24018
|
-
|
|
24019
|
-
|
|
24020
|
-
|
|
24021
|
-
|
|
24022
|
-
|
|
24561
|
+
visitIfBlock(block) {
|
|
24562
|
+
// We have to process the block in two steps: once here and again in the update instruction
|
|
24563
|
+
// callback in order to generate the correct expressions when pipes or pure functions are
|
|
24564
|
+
// used inside the branch expressions.
|
|
24565
|
+
const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
|
|
24566
|
+
let processedExpression = null;
|
|
24567
|
+
if (expression !== null) {
|
|
24568
|
+
processedExpression = expression.visit(this._valueConverter);
|
|
24569
|
+
this.allocateBindingSlots(processedExpression);
|
|
24570
|
+
}
|
|
24571
|
+
// If the branch has an alias, it'll be assigned directly to the container's context.
|
|
24572
|
+
// We define a variable referring directly to the context so that any nested usages can be
|
|
24573
|
+
// rewritten to refer to it.
|
|
24574
|
+
const variables = expressionAlias ?
|
|
24575
|
+
[new Variable(expressionAlias, DIRECT_CONTEXT_REFERENCE, sourceSpan, sourceSpan)] :
|
|
24576
|
+
undefined;
|
|
24577
|
+
return {
|
|
24578
|
+
index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
|
|
24579
|
+
expression: processedExpression,
|
|
24580
|
+
alias: expressionAlias
|
|
24581
|
+
};
|
|
24582
|
+
});
|
|
24583
|
+
// Use the index of the first block as the index for the entire container.
|
|
24584
|
+
const containerIndex = branchData[0].index;
|
|
24585
|
+
const paramsCallback = () => {
|
|
24586
|
+
let contextVariable = null;
|
|
24587
|
+
const generateBranch = (branchIndex) => {
|
|
24588
|
+
// If we've gone beyond the last branch, return the special -1 value which means that no
|
|
24589
|
+
// view will be rendered. Note that we don't need to reset the context here, because -1
|
|
24590
|
+
// won't render a view so the passed-in context won't be captured.
|
|
24591
|
+
if (branchIndex > branchData.length - 1) {
|
|
24592
|
+
return literal(-1);
|
|
24593
|
+
}
|
|
24594
|
+
const { index, expression, alias } = branchData[branchIndex];
|
|
24595
|
+
// If the branch has no expression, it means that it's the final `else`.
|
|
24596
|
+
// Return its index and stop the recursion. Assumes that there's only one
|
|
24597
|
+
// `else` condition and that it's the last branch.
|
|
24598
|
+
if (expression === null) {
|
|
24599
|
+
return literal(index);
|
|
24600
|
+
}
|
|
24601
|
+
let comparisonTarget;
|
|
24602
|
+
if (alias) {
|
|
24603
|
+
// If the branch is aliased, we need to assign the expression value to the temporary
|
|
24604
|
+
// variable and then pass it into `conditional`. E.g. for the expression:
|
|
24605
|
+
// `{#if foo(); as alias}...{/if}` we have to generate:
|
|
24606
|
+
// ```
|
|
24607
|
+
// let temp;
|
|
24608
|
+
// conditional(0, (temp = ctx.foo()) ? 0 : -1, temp);
|
|
24609
|
+
// ```
|
|
24610
|
+
contextVariable = this.allocateControlFlowTempVariable();
|
|
24611
|
+
comparisonTarget = contextVariable.set(this.convertPropertyBinding(expression));
|
|
24023
24612
|
}
|
|
24024
24613
|
else {
|
|
24025
|
-
|
|
24026
|
-
dependencyExp.push(deferredDep.type);
|
|
24614
|
+
comparisonTarget = this.convertPropertyBinding(expression);
|
|
24027
24615
|
}
|
|
24616
|
+
return comparisonTarget.conditional(literal(index), generateBranch(branchIndex + 1));
|
|
24617
|
+
};
|
|
24618
|
+
const params = [literal(containerIndex), generateBranch(0)];
|
|
24619
|
+
if (contextVariable !== null) {
|
|
24620
|
+
params.push(contextVariable);
|
|
24028
24621
|
}
|
|
24029
|
-
|
|
24030
|
-
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
|
|
24034
|
-
//
|
|
24035
|
-
|
|
24036
|
-
|
|
24622
|
+
return params;
|
|
24623
|
+
};
|
|
24624
|
+
this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
|
|
24625
|
+
}
|
|
24626
|
+
visitSwitchBlock(block) {
|
|
24627
|
+
// Allocate slots for the primary block expression.
|
|
24628
|
+
const blockExpression = block.expression.visit(this._valueConverter);
|
|
24629
|
+
this.allocateBindingSlots(blockExpression);
|
|
24630
|
+
// We have to process the block in two steps: once here and again in the update instruction
|
|
24631
|
+
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
24632
|
+
const caseData = block.cases.map(currentCase => {
|
|
24633
|
+
const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
|
|
24634
|
+
let expression = null;
|
|
24635
|
+
if (currentCase.expression !== null) {
|
|
24636
|
+
expression = currentCase.expression.visit(this._valueConverter);
|
|
24637
|
+
this.allocateBindingSlots(expression);
|
|
24638
|
+
}
|
|
24639
|
+
return { index, expression };
|
|
24640
|
+
});
|
|
24641
|
+
// Use the index of the first block as the index for the entire container.
|
|
24642
|
+
const containerIndex = caseData[0].index;
|
|
24643
|
+
this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
|
|
24644
|
+
const generateCases = (caseIndex) => {
|
|
24645
|
+
// If we've gone beyond the last branch, return the special -1
|
|
24646
|
+
// value which means that no view will be rendered.
|
|
24647
|
+
if (caseIndex > caseData.length - 1) {
|
|
24648
|
+
return literal(-1);
|
|
24649
|
+
}
|
|
24650
|
+
const { index, expression } = caseData[caseIndex];
|
|
24651
|
+
// If the case has no expression, it means that it's the `default` case.
|
|
24652
|
+
// Return its index and stop the recursion. Assumes that there's only one
|
|
24653
|
+
// `default` condition and that it's defined last.
|
|
24654
|
+
if (expression === null) {
|
|
24655
|
+
return literal(index);
|
|
24656
|
+
}
|
|
24657
|
+
// If this is the very first comparison, we need to assign the value of the primary
|
|
24658
|
+
// expression as a part of the comparison so the remaining cases can reuse it. In practice
|
|
24659
|
+
// this looks as follows:
|
|
24660
|
+
// ```
|
|
24661
|
+
// let temp;
|
|
24662
|
+
// conditional(1, (temp = ctx.foo) === 1 ? 1 : temp === 2 ? 2 : temp === 3 ? 3 : 4);
|
|
24663
|
+
// ```
|
|
24664
|
+
const comparisonTarget = caseIndex === 0 ?
|
|
24665
|
+
this.allocateControlFlowTempVariable().set(this.convertPropertyBinding(blockExpression)) :
|
|
24666
|
+
this.allocateControlFlowTempVariable();
|
|
24667
|
+
return comparisonTarget.identical(this.convertPropertyBinding(expression))
|
|
24668
|
+
.conditional(literal(index), generateCases(caseIndex + 1));
|
|
24669
|
+
};
|
|
24670
|
+
return [literal(containerIndex), generateCases(0)];
|
|
24037
24671
|
});
|
|
24038
24672
|
}
|
|
24039
|
-
|
|
24040
|
-
|
|
24041
|
-
|
|
24042
|
-
|
|
24043
|
-
|
|
24673
|
+
visitDeferredBlock(deferred) {
|
|
24674
|
+
const { loading, placeholder, error, triggers, prefetchTriggers } = deferred;
|
|
24675
|
+
const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan);
|
|
24676
|
+
const loadingIndex = loading ?
|
|
24677
|
+
this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan) :
|
|
24678
|
+
null;
|
|
24679
|
+
const loadingConsts = loading ?
|
|
24680
|
+
trimTrailingNulls([literal(loading.minimumTime), literal(loading.afterTime)]) :
|
|
24681
|
+
null;
|
|
24682
|
+
const placeholderIndex = placeholder ?
|
|
24683
|
+
this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan) :
|
|
24684
|
+
null;
|
|
24685
|
+
const placeholderConsts = placeholder && placeholder.minimumTime !== null ?
|
|
24686
|
+
// TODO(crisbeto): potentially pass the time directly instead of storing it in the `consts`
|
|
24687
|
+
// since `{:placeholder}` can only have one parameter?
|
|
24688
|
+
literalArr([literal(placeholder.minimumTime)]) :
|
|
24689
|
+
null;
|
|
24690
|
+
const errorIndex = error ?
|
|
24691
|
+
this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan) :
|
|
24692
|
+
null;
|
|
24693
|
+
// Note: we generate this last so the index matches the instruction order.
|
|
24694
|
+
const deferredIndex = this.allocateDataSlot();
|
|
24695
|
+
const depsFnName = `${this.contextName}_Defer_${deferredIndex}_DepsFn`;
|
|
24696
|
+
// e.g. `defer(1, 0, MyComp_Defer_1_DepsFn, ...)`
|
|
24697
|
+
this.creationInstruction(deferred.sourceSpan, Identifiers.defer, trimTrailingNulls([
|
|
24698
|
+
literal(deferredIndex),
|
|
24699
|
+
literal(primaryTemplateIndex),
|
|
24700
|
+
this.createDeferredDepsFunction(depsFnName, deferred),
|
|
24701
|
+
literal(loadingIndex),
|
|
24702
|
+
literal(placeholderIndex),
|
|
24703
|
+
literal(errorIndex),
|
|
24704
|
+
loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
|
|
24705
|
+
placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
|
|
24706
|
+
]));
|
|
24707
|
+
this.createDeferTriggerInstructions(deferredIndex, triggers, false);
|
|
24708
|
+
this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, true);
|
|
24709
|
+
}
|
|
24710
|
+
createDeferredDepsFunction(name, deferred) {
|
|
24711
|
+
const deferredDeps = this.deferBlocks.get(deferred);
|
|
24712
|
+
if (!deferredDeps || deferredDeps.length === 0) {
|
|
24713
|
+
return TYPED_NULL_EXPR;
|
|
24714
|
+
}
|
|
24715
|
+
// This defer block has deps for which we need to generate dynamic imports.
|
|
24716
|
+
const dependencyExp = [];
|
|
24717
|
+
for (const deferredDep of deferredDeps) {
|
|
24718
|
+
if (deferredDep.isDeferrable) {
|
|
24719
|
+
// Callback function, e.g. `function(m) { return m.MyCmp; }`.
|
|
24720
|
+
const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(deferredDep.symbolName))]);
|
|
24721
|
+
// Dynamic import, e.g. `import('./a').then(...)`.
|
|
24722
|
+
const importExpr = (new DynamicImportExpr(deferredDep.importPath)).prop('then').callFn([innerFn]);
|
|
24723
|
+
dependencyExp.push(importExpr);
|
|
24724
|
+
}
|
|
24725
|
+
else {
|
|
24726
|
+
// Non-deferrable symbol, just use a reference to the type.
|
|
24727
|
+
dependencyExp.push(deferredDep.type);
|
|
24728
|
+
}
|
|
24729
|
+
}
|
|
24730
|
+
const depsFnExpr = fn([], [new ReturnStatement(literalArr(dependencyExp))], INFERRED_TYPE, null, name);
|
|
24731
|
+
this.constantPool.statements.push(depsFnExpr.toDeclStmt(name));
|
|
24732
|
+
return variable(name);
|
|
24733
|
+
}
|
|
24734
|
+
createDeferTriggerInstructions(deferredIndex, triggers, prefetch) {
|
|
24735
|
+
const { when, idle, immediate, timer, hover, interaction, viewport } = triggers;
|
|
24736
|
+
// `deferWhen(ctx.someValue)`
|
|
24737
|
+
if (when) {
|
|
24738
|
+
const value = when.value.visit(this._valueConverter);
|
|
24739
|
+
this.allocateBindingSlots(value);
|
|
24740
|
+
this.updateInstructionWithAdvance(deferredIndex, when.sourceSpan, prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, () => this.convertPropertyBinding(value));
|
|
24741
|
+
}
|
|
24742
|
+
// Note that we generate an implicit `on idle` if the `deferred` block has no triggers.
|
|
24743
|
+
// TODO(crisbeto): decide if this should be baked into the `defer` instruction.
|
|
24744
|
+
// `deferOnIdle()`
|
|
24745
|
+
if (idle || (!prefetch && Object.keys(triggers).length === 0)) {
|
|
24746
|
+
this.creationInstruction(idle?.sourceSpan || null, prefetch ? Identifiers.deferPrefetchOnIdle : Identifiers.deferOnIdle);
|
|
24747
|
+
}
|
|
24748
|
+
// `deferOnImmediate()`
|
|
24749
|
+
if (immediate) {
|
|
24750
|
+
this.creationInstruction(immediate.sourceSpan, prefetch ? Identifiers.deferPrefetchOnImmediate : Identifiers.deferOnImmediate);
|
|
24751
|
+
}
|
|
24752
|
+
// `deferOnTimer(1337)`
|
|
24753
|
+
if (timer) {
|
|
24754
|
+
this.creationInstruction(timer.sourceSpan, prefetch ? Identifiers.deferPrefetchOnTimer : Identifiers.deferOnTimer, [literal(timer.delay)]);
|
|
24755
|
+
}
|
|
24756
|
+
// `deferOnHover()`
|
|
24757
|
+
if (hover) {
|
|
24758
|
+
this.creationInstruction(hover.sourceSpan, prefetch ? Identifiers.deferPrefetchOnHover : Identifiers.deferOnHover);
|
|
24759
|
+
}
|
|
24760
|
+
// TODO(crisbeto): currently the reference is passed as a string.
|
|
24761
|
+
// Update this once we figure out how we should refer to the target.
|
|
24762
|
+
// `deferOnInteraction(target)`
|
|
24763
|
+
if (interaction) {
|
|
24764
|
+
this.creationInstruction(interaction.sourceSpan, prefetch ? Identifiers.deferPrefetchOnInteraction : Identifiers.deferOnInteraction, [literal(interaction.reference)]);
|
|
24765
|
+
}
|
|
24766
|
+
// TODO(crisbeto): currently the reference is passed as a string.
|
|
24767
|
+
// Update this once we figure out how we should refer to the target.
|
|
24768
|
+
// `deferOnViewport(target)`
|
|
24769
|
+
if (viewport) {
|
|
24770
|
+
this.creationInstruction(viewport.sourceSpan, prefetch ? Identifiers.deferPrefetchOnViewport : Identifiers.deferOnViewport, [literal(viewport.reference)]);
|
|
24771
|
+
}
|
|
24772
|
+
}
|
|
24044
24773
|
allocateDataSlot() {
|
|
24045
24774
|
return this._dataIndex++;
|
|
24046
24775
|
}
|
|
24776
|
+
// TODO: implement for loop instructions
|
|
24777
|
+
visitForLoopBlock(block) { }
|
|
24778
|
+
visitForLoopBlockEmpty(block) { }
|
|
24047
24779
|
getConstCount() {
|
|
24048
24780
|
return this._dataIndex;
|
|
24049
24781
|
}
|
|
@@ -24168,6 +24900,21 @@ class TemplateDefinitionBuilder {
|
|
|
24168
24900
|
this._tempVariables.push(...stmts);
|
|
24169
24901
|
return args;
|
|
24170
24902
|
}
|
|
24903
|
+
/**
|
|
24904
|
+
* Creates and returns a variable that can be used to
|
|
24905
|
+
* store the state between control flow instructions.
|
|
24906
|
+
*/
|
|
24907
|
+
allocateControlFlowTempVariable() {
|
|
24908
|
+
// Note: the assumption here is that we'll only need one temporary variable for all control
|
|
24909
|
+
// flow instructions. It's expected that any instructions will overwrite it before passing it
|
|
24910
|
+
// into the parameters.
|
|
24911
|
+
if (this._controlFlowTempVariable === null) {
|
|
24912
|
+
const name = `${this.contextName}_contFlowTmp`;
|
|
24913
|
+
this._tempVariables.push(new DeclareVarStmt(name));
|
|
24914
|
+
this._controlFlowTempVariable = variable(name);
|
|
24915
|
+
}
|
|
24916
|
+
return this._controlFlowTempVariable;
|
|
24917
|
+
}
|
|
24171
24918
|
/**
|
|
24172
24919
|
* Prepares all attribute expression values for the `TAttributes` array.
|
|
24173
24920
|
*
|
|
@@ -24293,7 +25040,8 @@ class TemplateDefinitionBuilder {
|
|
|
24293
25040
|
return literal(consts.push(expression) - 1);
|
|
24294
25041
|
}
|
|
24295
25042
|
addAttrsToConsts(attrs) {
|
|
24296
|
-
return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) :
|
|
25043
|
+
return attrs !== null && attrs.length > 0 ? this.addToConsts(literalArr(attrs)) :
|
|
25044
|
+
TYPED_NULL_EXPR;
|
|
24297
25045
|
}
|
|
24298
25046
|
prepareRefsArray(references) {
|
|
24299
25047
|
if (!references || references.length === 0) {
|
|
@@ -24488,7 +25236,7 @@ class BindingScope {
|
|
|
24488
25236
|
if (value.declareLocalCallback && !value.declare) {
|
|
24489
25237
|
value.declare = true;
|
|
24490
25238
|
}
|
|
24491
|
-
return value.lhs;
|
|
25239
|
+
return typeof value.lhs === 'function' ? value.lhs(this) : value.lhs;
|
|
24492
25240
|
}
|
|
24493
25241
|
current = current.parent;
|
|
24494
25242
|
}
|
|
@@ -24592,7 +25340,8 @@ class BindingScope {
|
|
|
24592
25340
|
const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
|
|
24593
25341
|
componentValue.declare = true;
|
|
24594
25342
|
this.maybeRestoreView();
|
|
24595
|
-
|
|
25343
|
+
const lhs = typeof componentValue.lhs === 'function' ? componentValue.lhs(this) : componentValue.lhs;
|
|
25344
|
+
return name === DIRECT_CONTEXT_REFERENCE ? lhs : lhs.prop(name);
|
|
24596
25345
|
}
|
|
24597
25346
|
maybeRestoreView() {
|
|
24598
25347
|
// View restoration is required for listener instructions inside embedded views, because
|
|
@@ -25137,9 +25886,17 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
25137
25886
|
}
|
|
25138
25887
|
definitionMap.set('template', templateFn);
|
|
25139
25888
|
}
|
|
25140
|
-
if (meta.
|
|
25889
|
+
if (meta.declarationListEmitMode !== 3 /* DeclarationListEmitMode.RuntimeResolved */ &&
|
|
25890
|
+
meta.declarations.length > 0) {
|
|
25141
25891
|
definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
|
|
25142
25892
|
}
|
|
25893
|
+
else if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
|
|
25894
|
+
const args = [meta.type.value];
|
|
25895
|
+
if (meta.rawImports) {
|
|
25896
|
+
args.push(meta.rawImports);
|
|
25897
|
+
}
|
|
25898
|
+
definitionMap.set('dependencies', importExpr(Identifiers.getComponentDepsFactory).callFn(args));
|
|
25899
|
+
}
|
|
25143
25900
|
if (meta.encapsulation === null) {
|
|
25144
25901
|
meta.encapsulation = ViewEncapsulation.Emulated;
|
|
25145
25902
|
}
|
|
@@ -25211,6 +25968,8 @@ function compileDeclarationList(list, mode) {
|
|
|
25211
25968
|
// directives: function () { return [MyDir].map(ng.resolveForwardRef); }
|
|
25212
25969
|
const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
|
|
25213
25970
|
return fn([], [new ReturnStatement(resolvedList)]);
|
|
25971
|
+
case 3 /* DeclarationListEmitMode.RuntimeResolved */:
|
|
25972
|
+
throw new Error(`Unsupported with an array of pre-resolved dependencies`);
|
|
25214
25973
|
}
|
|
25215
25974
|
}
|
|
25216
25975
|
function prepareQueryParams(query, constantPool) {
|
|
@@ -26331,7 +27090,7 @@ function publishFacade(global) {
|
|
|
26331
27090
|
* @description
|
|
26332
27091
|
* Entry point for all public APIs of the compiler package.
|
|
26333
27092
|
*/
|
|
26334
|
-
const VERSION = new Version('
|
|
27093
|
+
const VERSION = new Version('17.0.0-next.1');
|
|
26335
27094
|
|
|
26336
27095
|
class CompilerConfig {
|
|
26337
27096
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -27891,6 +28650,25 @@ class Scope {
|
|
|
27891
28650
|
visitDeferredBlockLoading(block) {
|
|
27892
28651
|
block.children.forEach(node => node.visit(this));
|
|
27893
28652
|
}
|
|
28653
|
+
visitSwitchBlock(block) {
|
|
28654
|
+
block.cases.forEach(node => node.visit(this));
|
|
28655
|
+
}
|
|
28656
|
+
visitSwitchBlockCase(block) {
|
|
28657
|
+
block.children.forEach(node => node.visit(this));
|
|
28658
|
+
}
|
|
28659
|
+
visitForLoopBlock(block) {
|
|
28660
|
+
block.children.forEach(node => node.visit(this));
|
|
28661
|
+
block.empty?.visit(this);
|
|
28662
|
+
}
|
|
28663
|
+
visitForLoopBlockEmpty(block) {
|
|
28664
|
+
block.children.forEach(node => node.visit(this));
|
|
28665
|
+
}
|
|
28666
|
+
visitIfBlock(block) {
|
|
28667
|
+
block.branches.forEach(node => node.visit(this));
|
|
28668
|
+
}
|
|
28669
|
+
visitIfBlockBranch(block) {
|
|
28670
|
+
block.children.forEach(node => node.visit(this));
|
|
28671
|
+
}
|
|
27894
28672
|
// Unused visitors.
|
|
27895
28673
|
visitContent(content) { }
|
|
27896
28674
|
visitBoundAttribute(attr) { }
|
|
@@ -28045,9 +28823,10 @@ class DirectiveBinder {
|
|
|
28045
28823
|
node.children.forEach(child => child.visit(this));
|
|
28046
28824
|
}
|
|
28047
28825
|
visitDeferredBlock(deferred) {
|
|
28826
|
+
const wasInDeferBlock = this.isInDeferBlock;
|
|
28048
28827
|
this.isInDeferBlock = true;
|
|
28049
28828
|
deferred.children.forEach(child => child.visit(this));
|
|
28050
|
-
this.isInDeferBlock =
|
|
28829
|
+
this.isInDeferBlock = wasInDeferBlock;
|
|
28051
28830
|
deferred.placeholder?.visit(this);
|
|
28052
28831
|
deferred.loading?.visit(this);
|
|
28053
28832
|
deferred.error?.visit(this);
|
|
@@ -28061,6 +28840,25 @@ class DirectiveBinder {
|
|
|
28061
28840
|
visitDeferredBlockLoading(block) {
|
|
28062
28841
|
block.children.forEach(child => child.visit(this));
|
|
28063
28842
|
}
|
|
28843
|
+
visitSwitchBlock(block) {
|
|
28844
|
+
block.cases.forEach(node => node.visit(this));
|
|
28845
|
+
}
|
|
28846
|
+
visitSwitchBlockCase(block) {
|
|
28847
|
+
block.children.forEach(node => node.visit(this));
|
|
28848
|
+
}
|
|
28849
|
+
visitForLoopBlock(block) {
|
|
28850
|
+
block.children.forEach(node => node.visit(this));
|
|
28851
|
+
block.empty?.visit(this);
|
|
28852
|
+
}
|
|
28853
|
+
visitForLoopBlockEmpty(block) {
|
|
28854
|
+
block.children.forEach(node => node.visit(this));
|
|
28855
|
+
}
|
|
28856
|
+
visitIfBlock(block) {
|
|
28857
|
+
block.branches.forEach(node => node.visit(this));
|
|
28858
|
+
}
|
|
28859
|
+
visitIfBlockBranch(block) {
|
|
28860
|
+
block.children.forEach(node => node.visit(this));
|
|
28861
|
+
}
|
|
28064
28862
|
// Unused visitors.
|
|
28065
28863
|
visitContent(content) { }
|
|
28066
28864
|
visitVariable(variable) { }
|
|
@@ -28197,11 +28995,10 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
28197
28995
|
}
|
|
28198
28996
|
visitDeferredBlock(deferred) {
|
|
28199
28997
|
this.deferBlocks.add(deferred);
|
|
28998
|
+
const wasInDeferBlock = this.isInDeferBlock;
|
|
28200
28999
|
this.isInDeferBlock = true;
|
|
28201
29000
|
deferred.children.forEach(this.visitNode);
|
|
28202
|
-
this.isInDeferBlock =
|
|
28203
|
-
deferred.triggers.forEach(this.visitNode);
|
|
28204
|
-
deferred.prefetchTriggers.forEach(this.visitNode);
|
|
29001
|
+
this.isInDeferBlock = wasInDeferBlock;
|
|
28205
29002
|
deferred.placeholder && this.visitNode(deferred.placeholder);
|
|
28206
29003
|
deferred.loading && this.visitNode(deferred.loading);
|
|
28207
29004
|
deferred.error && this.visitNode(deferred.error);
|
|
@@ -28220,6 +29017,29 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
28220
29017
|
visitDeferredBlockLoading(block) {
|
|
28221
29018
|
block.children.forEach(this.visitNode);
|
|
28222
29019
|
}
|
|
29020
|
+
visitSwitchBlock(block) {
|
|
29021
|
+
block.expression.visit(this);
|
|
29022
|
+
block.cases.forEach(this.visitNode);
|
|
29023
|
+
}
|
|
29024
|
+
visitSwitchBlockCase(block) {
|
|
29025
|
+
block.expression?.visit(this);
|
|
29026
|
+
block.children.forEach(this.visitNode);
|
|
29027
|
+
}
|
|
29028
|
+
visitForLoopBlock(block) {
|
|
29029
|
+
block.expression.visit(this);
|
|
29030
|
+
block.children.forEach(this.visitNode);
|
|
29031
|
+
block.empty?.visit(this);
|
|
29032
|
+
}
|
|
29033
|
+
visitForLoopBlockEmpty(block) {
|
|
29034
|
+
block.children.forEach(this.visitNode);
|
|
29035
|
+
}
|
|
29036
|
+
visitIfBlock(block) {
|
|
29037
|
+
block.branches.forEach(node => node.visit(this));
|
|
29038
|
+
}
|
|
29039
|
+
visitIfBlockBranch(block) {
|
|
29040
|
+
block.expression?.visit(this);
|
|
29041
|
+
block.children.forEach(node => node.visit(this));
|
|
29042
|
+
}
|
|
28223
29043
|
visitBoundText(text) {
|
|
28224
29044
|
text.value.visit(this);
|
|
28225
29045
|
}
|
|
@@ -28362,6 +29182,60 @@ function compileClassMetadata(metadata) {
|
|
|
28362
29182
|
const iife = fn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
|
|
28363
29183
|
return iife.callFn([]);
|
|
28364
29184
|
}
|
|
29185
|
+
/**
|
|
29186
|
+
* Wraps the `setClassMetadata` function with extra logic that dynamically
|
|
29187
|
+
* loads dependencies from `{#defer}` blocks.
|
|
29188
|
+
*
|
|
29189
|
+
* Generates a call like this:
|
|
29190
|
+
* ```
|
|
29191
|
+
* setClassMetadataAsync(type, () => {
|
|
29192
|
+
* return [
|
|
29193
|
+
* import('./cmp-a').then(m => m.CmpA);
|
|
29194
|
+
* import('./cmp-b').then(m => m.CmpB);
|
|
29195
|
+
* ];
|
|
29196
|
+
* }, (CmpA, CmpB) => {
|
|
29197
|
+
* setClassMetadata(type, decorators, ctorParameters, propParameters);
|
|
29198
|
+
* });
|
|
29199
|
+
* ```
|
|
29200
|
+
*
|
|
29201
|
+
* Similar to the `setClassMetadata` call, it's wrapped into the `ngDevMode`
|
|
29202
|
+
* check to tree-shake away this code in production mode.
|
|
29203
|
+
*/
|
|
29204
|
+
function compileComponentClassMetadata(metadata, deferrableTypes) {
|
|
29205
|
+
if (deferrableTypes.size === 0) {
|
|
29206
|
+
// If there are no deferrable symbols - just generate a regular `setClassMetadata` call.
|
|
29207
|
+
return compileClassMetadata(metadata);
|
|
29208
|
+
}
|
|
29209
|
+
const dynamicImports = [];
|
|
29210
|
+
const importedSymbols = [];
|
|
29211
|
+
for (const [symbolName, importPath] of deferrableTypes) {
|
|
29212
|
+
// e.g. `function(m) { return m.CmpA; }`
|
|
29213
|
+
const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(symbolName))]);
|
|
29214
|
+
// e.g. `import('./cmp-a').then(...)`
|
|
29215
|
+
const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
|
|
29216
|
+
dynamicImports.push(importExpr);
|
|
29217
|
+
importedSymbols.push(new FnParam(symbolName, DYNAMIC_TYPE));
|
|
29218
|
+
}
|
|
29219
|
+
// e.g. `function() { return [ ... ]; }`
|
|
29220
|
+
const dependencyLoadingFn = fn([], [new ReturnStatement(literalArr(dynamicImports))]);
|
|
29221
|
+
// e.g. `setClassMetadata(...)`
|
|
29222
|
+
const setClassMetadataCall = importExpr(Identifiers.setClassMetadata).callFn([
|
|
29223
|
+
metadata.type,
|
|
29224
|
+
metadata.decorators,
|
|
29225
|
+
metadata.ctorParameters ?? literal(null),
|
|
29226
|
+
metadata.propDecorators ?? literal(null),
|
|
29227
|
+
]);
|
|
29228
|
+
// e.g. `function(CmpA) { setClassMetadata(...); }`
|
|
29229
|
+
const setClassMetaWrapper = fn(importedSymbols, [setClassMetadataCall.toStmt()]);
|
|
29230
|
+
// Final `setClassMetadataAsync()` call with all arguments
|
|
29231
|
+
const setClassMetaAsync = importExpr(Identifiers.setClassMetadataAsync).callFn([
|
|
29232
|
+
metadata.type, dependencyLoadingFn, setClassMetaWrapper
|
|
29233
|
+
]);
|
|
29234
|
+
// Generate an ngDevMode guarded call to `setClassMetadataAsync` with
|
|
29235
|
+
// the class identifier and its metadata, so that this call can be tree-shaken.
|
|
29236
|
+
const iife = fn([], [devOnlyGuardedExpression(setClassMetaAsync).toStmt()]);
|
|
29237
|
+
return iife.callFn([]);
|
|
29238
|
+
}
|
|
28365
29239
|
|
|
28366
29240
|
/**
|
|
28367
29241
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
@@ -28374,7 +29248,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
28374
29248
|
function compileDeclareClassMetadata(metadata) {
|
|
28375
29249
|
const definitionMap = new DefinitionMap();
|
|
28376
29250
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
28377
|
-
definitionMap.set('version', literal('
|
|
29251
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28378
29252
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28379
29253
|
definitionMap.set('type', metadata.type);
|
|
28380
29254
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -28482,7 +29356,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
28482
29356
|
// in 16.1 is actually used.
|
|
28483
29357
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
28484
29358
|
definitionMap.set('minVersion', literal(minVersion));
|
|
28485
|
-
definitionMap.set('version', literal('
|
|
29359
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28486
29360
|
// e.g. `type: MyDirective`
|
|
28487
29361
|
definitionMap.set('type', meta.type.value);
|
|
28488
29362
|
if (meta.isStandalone) {
|
|
@@ -28673,6 +29547,9 @@ function compileUsedDependenciesMetadata(meta) {
|
|
|
28673
29547
|
const wrapType = meta.declarationListEmitMode !== 0 /* DeclarationListEmitMode.Direct */ ?
|
|
28674
29548
|
generateForwardRef :
|
|
28675
29549
|
(expr) => expr;
|
|
29550
|
+
if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
|
|
29551
|
+
throw new Error(`Unsupported emit mode`);
|
|
29552
|
+
}
|
|
28676
29553
|
return toOptionalLiteralArray(meta.declarations, decl => {
|
|
28677
29554
|
switch (decl.kind) {
|
|
28678
29555
|
case R3TemplateDependencyKind.Directive:
|
|
@@ -28710,7 +29587,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
28710
29587
|
function compileDeclareFactoryFunction(meta) {
|
|
28711
29588
|
const definitionMap = new DefinitionMap();
|
|
28712
29589
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
28713
|
-
definitionMap.set('version', literal('
|
|
29590
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28714
29591
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28715
29592
|
definitionMap.set('type', meta.type.value);
|
|
28716
29593
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -28745,7 +29622,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
28745
29622
|
function createInjectableDefinitionMap(meta) {
|
|
28746
29623
|
const definitionMap = new DefinitionMap();
|
|
28747
29624
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
28748
|
-
definitionMap.set('version', literal('
|
|
29625
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28749
29626
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28750
29627
|
definitionMap.set('type', meta.type.value);
|
|
28751
29628
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -28796,7 +29673,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
28796
29673
|
function createInjectorDefinitionMap(meta) {
|
|
28797
29674
|
const definitionMap = new DefinitionMap();
|
|
28798
29675
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
28799
|
-
definitionMap.set('version', literal('
|
|
29676
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28800
29677
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28801
29678
|
definitionMap.set('type', meta.type.value);
|
|
28802
29679
|
definitionMap.set('providers', meta.providers);
|
|
@@ -28829,7 +29706,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
28829
29706
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
28830
29707
|
}
|
|
28831
29708
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
28832
|
-
definitionMap.set('version', literal('
|
|
29709
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28833
29710
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28834
29711
|
definitionMap.set('type', meta.type.value);
|
|
28835
29712
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -28880,7 +29757,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
28880
29757
|
function createPipeDefinitionMap(meta) {
|
|
28881
29758
|
const definitionMap = new DefinitionMap();
|
|
28882
29759
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
28883
|
-
definitionMap.set('version', literal('
|
|
29760
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
28884
29761
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
28885
29762
|
// e.g. `type: MyPipe`
|
|
28886
29763
|
definitionMap.set('type', meta.type.value);
|
|
@@ -28913,5 +29790,5 @@ publishFacade(_global);
|
|
|
28913
29790
|
|
|
28914
29791
|
// This file is not used to build this module. It is only used during editing
|
|
28915
29792
|
|
|
28916
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
29793
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, 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, compileComponentClassMetadata, 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 };
|
|
28917
29794
|
//# sourceMappingURL=compiler.mjs.map
|