@angular/compiler 17.1.0-next.3 → 17.1.0-next.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler.mjs +2 -2
- package/esm2022/src/compiler_facade_interface.mjs +1 -1
- package/esm2022/src/constant_pool.mjs +5 -3
- package/esm2022/src/jit_compiler_facade.mjs +46 -17
- package/esm2022/src/ml_parser/tags.mjs +8 -3
- package/esm2022/src/render3/partial/api.mjs +1 -1
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +112 -17
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_identifiers.mjs +4 -1
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +24 -9
- package/esm2022/src/render3/view/template.mjs +14 -9
- package/esm2022/src/render3/view/util.mjs +8 -2
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +15 -19
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +26 -20
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +47 -17
- package/esm2022/src/template/pipeline/ir/src/ops/host.mjs +4 -2
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +18 -10
- package/esm2022/src/template/pipeline/src/emit.mjs +6 -6
- package/esm2022/src/template/pipeline/src/ingest.mjs +295 -184
- package/esm2022/src/template/pipeline/src/instruction.mjs +30 -24
- package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +40 -56
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +24 -22
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +60 -15
- package/esm2022/src/template/pipeline/src/phases/convert_i18n_bindings.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/create_defer_deps_fns.mjs +3 -2
- package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +63 -29
- package/esm2022/src/template/pipeline/src/phases/deduplicate_text_bindings.mjs +40 -0
- package/esm2022/src/template/pipeline/src/phases/extract_i18n_messages.mjs +52 -49
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +7 -1
- package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +11 -8
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +22 -3
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +13 -5
- package/esm2022/src/template/pipeline/src/phases/ordering.mjs +17 -5
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +22 -3
- package/esm2022/src/template/pipeline/src/phases/phase_remove_content_selectors.mjs +1 -10
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +31 -14
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +46 -24
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_element_placeholders.mjs +60 -14
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +23 -10
- package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +78 -14
- package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +3 -1
- package/esm2022/src/template/pipeline/src/phases/track_fn_generation.mjs +4 -1
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +10 -1
- package/esm2022/src/template/pipeline/src/phases/wrap_icus.mjs +4 -3
- package/esm2022/src/template/pipeline/src/util/elements.mjs +8 -1
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1252 -650
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +41 -8
- package/package.json +2 -2
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_icu_placeholders.mjs +0 -62
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.1.0-next.
|
|
2
|
+
* @license Angular v17.1.0-next.5
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2308,7 +2308,9 @@ class ConstantPool {
|
|
|
2308
2308
|
}))));
|
|
2309
2309
|
}
|
|
2310
2310
|
}
|
|
2311
|
-
|
|
2311
|
+
// TODO: useUniqueName(false) is necessary for naming compatibility with
|
|
2312
|
+
// TemplateDefinitionBuilder, but should be removed once Template Pipeline is the default.
|
|
2313
|
+
getSharedFunctionReference(fn, prefix, useUniqueName = true) {
|
|
2312
2314
|
const isArrow = fn instanceof ArrowFunctionExpr;
|
|
2313
2315
|
for (const current of this.statements) {
|
|
2314
2316
|
// Arrow functions are saved as variables so we check if the
|
|
@@ -2323,7 +2325,7 @@ class ConstantPool {
|
|
|
2323
2325
|
}
|
|
2324
2326
|
}
|
|
2325
2327
|
// Otherwise declare the function.
|
|
2326
|
-
const name = this.uniqueName(prefix);
|
|
2328
|
+
const name = useUniqueName ? this.uniqueName(prefix) : prefix;
|
|
2327
2329
|
this.statements.push(fn.toDeclStmt(name, StmtModifier.Final));
|
|
2328
2330
|
return variable(name);
|
|
2329
2331
|
}
|
|
@@ -2636,6 +2638,9 @@ class Identifiers {
|
|
|
2636
2638
|
static { this.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE }; }
|
|
2637
2639
|
static { this.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE }; }
|
|
2638
2640
|
static { this.validateIframeAttribute = { name: 'ɵɵvalidateIframeAttribute', moduleName: CORE }; }
|
|
2641
|
+
// type-checking
|
|
2642
|
+
static { this.InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE }; }
|
|
2643
|
+
static { this.UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE }; }
|
|
2639
2644
|
}
|
|
2640
2645
|
|
|
2641
2646
|
const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
|
|
@@ -3685,13 +3690,18 @@ var TagContentType;
|
|
|
3685
3690
|
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
3686
3691
|
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
3687
3692
|
})(TagContentType || (TagContentType = {}));
|
|
3688
|
-
function splitNsName(elementName) {
|
|
3693
|
+
function splitNsName(elementName, fatal = true) {
|
|
3689
3694
|
if (elementName[0] != ':') {
|
|
3690
3695
|
return [null, elementName];
|
|
3691
3696
|
}
|
|
3692
3697
|
const colonIndex = elementName.indexOf(':', 1);
|
|
3693
3698
|
if (colonIndex === -1) {
|
|
3694
|
-
|
|
3699
|
+
if (fatal) {
|
|
3700
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
3701
|
+
}
|
|
3702
|
+
else {
|
|
3703
|
+
return [null, elementName];
|
|
3704
|
+
}
|
|
3695
3705
|
}
|
|
3696
3706
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
3697
3707
|
}
|
|
@@ -4957,6 +4967,12 @@ function asLiteral(value) {
|
|
|
4957
4967
|
}
|
|
4958
4968
|
return literal(value, INFERRED_TYPE);
|
|
4959
4969
|
}
|
|
4970
|
+
/**
|
|
4971
|
+
* Serializes inputs and outputs for `defineDirective` and `defineComponent`.
|
|
4972
|
+
*
|
|
4973
|
+
* This will attempt to generate optimized data structures to minimize memory or
|
|
4974
|
+
* file size of fully compiled applications.
|
|
4975
|
+
*/
|
|
4960
4976
|
function conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) {
|
|
4961
4977
|
const keys = Object.getOwnPropertyNames(map);
|
|
4962
4978
|
if (keys.length === 0) {
|
|
@@ -8966,14 +8982,18 @@ var OpKind;
|
|
|
8966
8982
|
* An instruction to update an ICU expression.
|
|
8967
8983
|
*/
|
|
8968
8984
|
OpKind[OpKind["IcuEnd"] = 42] = "IcuEnd";
|
|
8985
|
+
/**
|
|
8986
|
+
* An instruction representing a placeholder in an ICU expression.
|
|
8987
|
+
*/
|
|
8988
|
+
OpKind[OpKind["IcuPlaceholder"] = 43] = "IcuPlaceholder";
|
|
8969
8989
|
/**
|
|
8970
8990
|
* An i18n context containing information needed to generate an i18n message.
|
|
8971
8991
|
*/
|
|
8972
|
-
OpKind[OpKind["I18nContext"] =
|
|
8992
|
+
OpKind[OpKind["I18nContext"] = 44] = "I18nContext";
|
|
8973
8993
|
/**
|
|
8974
8994
|
* A creation op that corresponds to i18n attributes on an element.
|
|
8975
8995
|
*/
|
|
8976
|
-
OpKind[OpKind["I18nAttributes"] =
|
|
8996
|
+
OpKind[OpKind["I18nAttributes"] = 45] = "I18nAttributes";
|
|
8977
8997
|
})(OpKind || (OpKind = {}));
|
|
8978
8998
|
/**
|
|
8979
8999
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9064,23 +9084,27 @@ var ExpressionKind;
|
|
|
9064
9084
|
* An expression representing a sanitizer function.
|
|
9065
9085
|
*/
|
|
9066
9086
|
ExpressionKind[ExpressionKind["SanitizerExpr"] = 20] = "SanitizerExpr";
|
|
9087
|
+
/**
|
|
9088
|
+
* An expression representing a function to create trusted values.
|
|
9089
|
+
*/
|
|
9090
|
+
ExpressionKind[ExpressionKind["TrustedValueFnExpr"] = 21] = "TrustedValueFnExpr";
|
|
9067
9091
|
/**
|
|
9068
9092
|
* An expression that will cause a literal slot index to be emitted.
|
|
9069
9093
|
*/
|
|
9070
|
-
ExpressionKind[ExpressionKind["SlotLiteralExpr"] =
|
|
9094
|
+
ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
|
|
9071
9095
|
/**
|
|
9072
9096
|
* A test expression for a conditional op.
|
|
9073
9097
|
*/
|
|
9074
|
-
ExpressionKind[ExpressionKind["ConditionalCase"] =
|
|
9098
|
+
ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
|
|
9075
9099
|
/**
|
|
9076
9100
|
* A variable for use inside a repeater, providing one of the ambiently-available context
|
|
9077
9101
|
* properties ($even, $first, etc.).
|
|
9078
9102
|
*/
|
|
9079
|
-
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] =
|
|
9103
|
+
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 24] = "DerivedRepeaterVar";
|
|
9080
9104
|
/**
|
|
9081
9105
|
* An expression that will be automatically extracted to the component const array.
|
|
9082
9106
|
*/
|
|
9083
|
-
ExpressionKind[ExpressionKind["ConstCollected"] =
|
|
9107
|
+
ExpressionKind[ExpressionKind["ConstCollected"] = 25] = "ConstCollected";
|
|
9084
9108
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
9085
9109
|
var VariableFlags;
|
|
9086
9110
|
(function (VariableFlags) {
|
|
@@ -9124,18 +9148,6 @@ var CompatibilityMode;
|
|
|
9124
9148
|
CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
|
|
9125
9149
|
CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
|
|
9126
9150
|
})(CompatibilityMode || (CompatibilityMode = {}));
|
|
9127
|
-
/**
|
|
9128
|
-
* Represents functions used to sanitize different pieces of a template.
|
|
9129
|
-
*/
|
|
9130
|
-
var SanitizerFn;
|
|
9131
|
-
(function (SanitizerFn) {
|
|
9132
|
-
SanitizerFn[SanitizerFn["Html"] = 0] = "Html";
|
|
9133
|
-
SanitizerFn[SanitizerFn["Script"] = 1] = "Script";
|
|
9134
|
-
SanitizerFn[SanitizerFn["Style"] = 2] = "Style";
|
|
9135
|
-
SanitizerFn[SanitizerFn["Url"] = 3] = "Url";
|
|
9136
|
-
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
9137
|
-
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
9138
|
-
})(SanitizerFn || (SanitizerFn = {}));
|
|
9139
9151
|
/**
|
|
9140
9152
|
* Enumeration of the different kinds of `@defer` secondary blocks.
|
|
9141
9153
|
*/
|
|
@@ -9414,7 +9426,7 @@ class Interpolation {
|
|
|
9414
9426
|
/**
|
|
9415
9427
|
* Create a `BindingOp`, not yet transformed into a particular type of binding.
|
|
9416
9428
|
*/
|
|
9417
|
-
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute,
|
|
9429
|
+
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9418
9430
|
return {
|
|
9419
9431
|
kind: OpKind.Binding,
|
|
9420
9432
|
bindingKind: kind,
|
|
@@ -9424,8 +9436,10 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9424
9436
|
unit,
|
|
9425
9437
|
securityContext,
|
|
9426
9438
|
isTextAttribute,
|
|
9427
|
-
|
|
9428
|
-
|
|
9439
|
+
isStructuralTemplateAttribute,
|
|
9440
|
+
templateKind,
|
|
9441
|
+
i18nContext: null,
|
|
9442
|
+
i18nMessage,
|
|
9429
9443
|
sourceSpan,
|
|
9430
9444
|
...NEW_OP,
|
|
9431
9445
|
};
|
|
@@ -9433,7 +9447,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9433
9447
|
/**
|
|
9434
9448
|
* Create a `PropertyOp`.
|
|
9435
9449
|
*/
|
|
9436
|
-
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext,
|
|
9450
|
+
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
|
|
9437
9451
|
return {
|
|
9438
9452
|
kind: OpKind.Property,
|
|
9439
9453
|
target,
|
|
@@ -9442,8 +9456,10 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
|
|
|
9442
9456
|
isAnimationTrigger,
|
|
9443
9457
|
securityContext,
|
|
9444
9458
|
sanitizer: null,
|
|
9445
|
-
|
|
9459
|
+
isStructuralTemplateAttribute,
|
|
9460
|
+
templateKind,
|
|
9446
9461
|
i18nContext,
|
|
9462
|
+
i18nMessage,
|
|
9447
9463
|
sourceSpan,
|
|
9448
9464
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9449
9465
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9508,7 +9524,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9508
9524
|
/**
|
|
9509
9525
|
* Create an `AttributeOp`.
|
|
9510
9526
|
*/
|
|
9511
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute,
|
|
9527
|
+
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9512
9528
|
return {
|
|
9513
9529
|
kind: OpKind.Attribute,
|
|
9514
9530
|
target,
|
|
@@ -9517,8 +9533,10 @@ function createAttributeOp(target, name, expression, securityContext, isTextAttr
|
|
|
9517
9533
|
securityContext,
|
|
9518
9534
|
sanitizer: null,
|
|
9519
9535
|
isTextAttribute,
|
|
9520
|
-
|
|
9521
|
-
|
|
9536
|
+
isStructuralTemplateAttribute,
|
|
9537
|
+
templateKind,
|
|
9538
|
+
i18nContext: null,
|
|
9539
|
+
i18nMessage,
|
|
9522
9540
|
sourceSpan,
|
|
9523
9541
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9524
9542
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9574,12 +9592,13 @@ function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
|
|
|
9574
9592
|
sourceSpan,
|
|
9575
9593
|
...NEW_OP,
|
|
9576
9594
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9595
|
+
...TRAIT_CONSUMES_VARS,
|
|
9577
9596
|
};
|
|
9578
9597
|
}
|
|
9579
9598
|
/**
|
|
9580
9599
|
* Create an i18n expression op.
|
|
9581
9600
|
*/
|
|
9582
|
-
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9601
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9583
9602
|
return {
|
|
9584
9603
|
kind: OpKind.I18nExpression,
|
|
9585
9604
|
context,
|
|
@@ -9587,6 +9606,7 @@ function createI18nExpressionOp(context, target, i18nOwner, handle, expression,
|
|
|
9587
9606
|
i18nOwner,
|
|
9588
9607
|
handle,
|
|
9589
9608
|
expression,
|
|
9609
|
+
icuPlaceholder,
|
|
9590
9610
|
i18nPlaceholder,
|
|
9591
9611
|
resolutionTime,
|
|
9592
9612
|
usage,
|
|
@@ -10152,24 +10172,6 @@ class ReadTemporaryExpr extends ExpressionBase {
|
|
|
10152
10172
|
return r;
|
|
10153
10173
|
}
|
|
10154
10174
|
}
|
|
10155
|
-
class SanitizerExpr extends ExpressionBase {
|
|
10156
|
-
constructor(fn) {
|
|
10157
|
-
super();
|
|
10158
|
-
this.fn = fn;
|
|
10159
|
-
this.kind = ExpressionKind.SanitizerExpr;
|
|
10160
|
-
}
|
|
10161
|
-
visitExpression(visitor, context) { }
|
|
10162
|
-
isEquivalent(e) {
|
|
10163
|
-
return e instanceof SanitizerExpr && e.fn === this.fn;
|
|
10164
|
-
}
|
|
10165
|
-
isConstant() {
|
|
10166
|
-
return true;
|
|
10167
|
-
}
|
|
10168
|
-
clone() {
|
|
10169
|
-
return new SanitizerExpr(this.fn);
|
|
10170
|
-
}
|
|
10171
|
-
transformInternalExpressions() { }
|
|
10172
|
-
}
|
|
10173
10175
|
class SlotLiteralExpr extends ExpressionBase {
|
|
10174
10176
|
constructor(slot) {
|
|
10175
10177
|
super();
|
|
@@ -10300,7 +10302,6 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10300
10302
|
case OpKind.ClassProp:
|
|
10301
10303
|
case OpKind.ClassMap:
|
|
10302
10304
|
case OpKind.Binding:
|
|
10303
|
-
case OpKind.HostProperty:
|
|
10304
10305
|
if (op.expression instanceof Interpolation) {
|
|
10305
10306
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
10306
10307
|
}
|
|
@@ -10309,6 +10310,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10309
10310
|
}
|
|
10310
10311
|
break;
|
|
10311
10312
|
case OpKind.Property:
|
|
10313
|
+
case OpKind.HostProperty:
|
|
10312
10314
|
case OpKind.Attribute:
|
|
10313
10315
|
if (op.expression instanceof Interpolation) {
|
|
10314
10316
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
@@ -10354,6 +10356,8 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10354
10356
|
case OpKind.ExtractedAttribute:
|
|
10355
10357
|
op.expression =
|
|
10356
10358
|
op.expression && transformExpressionsInExpression(op.expression, transform, flags);
|
|
10359
|
+
op.trustedValueFn = op.trustedValueFn &&
|
|
10360
|
+
transformExpressionsInExpression(op.trustedValueFn, transform, flags);
|
|
10357
10361
|
break;
|
|
10358
10362
|
case OpKind.RepeaterCreate:
|
|
10359
10363
|
op.track = transformExpressionsInExpression(op.track, transform, flags);
|
|
@@ -10372,6 +10376,9 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10372
10376
|
op.placeholderConfig =
|
|
10373
10377
|
transformExpressionsInExpression(op.placeholderConfig, transform, flags);
|
|
10374
10378
|
}
|
|
10379
|
+
if (op.resolverFn !== null) {
|
|
10380
|
+
op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
|
|
10381
|
+
}
|
|
10375
10382
|
break;
|
|
10376
10383
|
case OpKind.I18nMessage:
|
|
10377
10384
|
for (const [placeholder, expr] of op.params) {
|
|
@@ -10408,6 +10415,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10408
10415
|
case OpKind.Template:
|
|
10409
10416
|
case OpKind.Text:
|
|
10410
10417
|
case OpKind.I18nAttributes:
|
|
10418
|
+
case OpKind.IcuPlaceholder:
|
|
10411
10419
|
// These operations contain no expressions.
|
|
10412
10420
|
break;
|
|
10413
10421
|
default:
|
|
@@ -10485,6 +10493,24 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10485
10493
|
else if (expr instanceof NotExpr) {
|
|
10486
10494
|
expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
|
|
10487
10495
|
}
|
|
10496
|
+
else if (expr instanceof TaggedTemplateExpr) {
|
|
10497
|
+
expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
|
|
10498
|
+
expr.template.expressions =
|
|
10499
|
+
expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
|
|
10500
|
+
}
|
|
10501
|
+
else if (expr instanceof ArrowFunctionExpr) {
|
|
10502
|
+
if (Array.isArray(expr.body)) {
|
|
10503
|
+
for (let i = 0; i < expr.body.length; i++) {
|
|
10504
|
+
transformExpressionsInStatement(expr.body[i], transform, flags);
|
|
10505
|
+
}
|
|
10506
|
+
}
|
|
10507
|
+
else {
|
|
10508
|
+
expr.body = transformExpressionsInExpression(expr.body, transform, flags);
|
|
10509
|
+
}
|
|
10510
|
+
}
|
|
10511
|
+
else if (expr instanceof WrappedNodeExpr) {
|
|
10512
|
+
// TODO: Do we need to transform any TS nodes nested inside of this expression?
|
|
10513
|
+
}
|
|
10488
10514
|
else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
|
|
10489
10515
|
expr instanceof LiteralExpr) {
|
|
10490
10516
|
// No action for these types.
|
|
@@ -10807,7 +10833,7 @@ function isElementOrContainerOp(op) {
|
|
|
10807
10833
|
/**
|
|
10808
10834
|
* Create an `ElementStartOp`.
|
|
10809
10835
|
*/
|
|
10810
|
-
function createElementStartOp(tag, xref, namespace, i18nPlaceholder,
|
|
10836
|
+
function createElementStartOp(tag, xref, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10811
10837
|
return {
|
|
10812
10838
|
kind: OpKind.ElementStart,
|
|
10813
10839
|
xref,
|
|
@@ -10818,7 +10844,8 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10818
10844
|
nonBindable: false,
|
|
10819
10845
|
namespace,
|
|
10820
10846
|
i18nPlaceholder,
|
|
10821
|
-
|
|
10847
|
+
startSourceSpan,
|
|
10848
|
+
wholeSourceSpan,
|
|
10822
10849
|
...TRAIT_CONSUMES_SLOT,
|
|
10823
10850
|
...NEW_OP,
|
|
10824
10851
|
};
|
|
@@ -10826,7 +10853,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10826
10853
|
/**
|
|
10827
10854
|
* Create a `TemplateOp`.
|
|
10828
10855
|
*/
|
|
10829
|
-
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder,
|
|
10856
|
+
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10830
10857
|
return {
|
|
10831
10858
|
kind: OpKind.Template,
|
|
10832
10859
|
xref,
|
|
@@ -10841,12 +10868,13 @@ function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace
|
|
|
10841
10868
|
nonBindable: false,
|
|
10842
10869
|
namespace,
|
|
10843
10870
|
i18nPlaceholder,
|
|
10844
|
-
|
|
10871
|
+
startSourceSpan,
|
|
10872
|
+
wholeSourceSpan,
|
|
10845
10873
|
...TRAIT_CONSUMES_SLOT,
|
|
10846
10874
|
...NEW_OP,
|
|
10847
10875
|
};
|
|
10848
10876
|
}
|
|
10849
|
-
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames,
|
|
10877
|
+
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, emptyTag, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10850
10878
|
return {
|
|
10851
10879
|
kind: OpKind.RepeaterCreate,
|
|
10852
10880
|
attributes: null,
|
|
@@ -10856,6 +10884,8 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, so
|
|
|
10856
10884
|
track,
|
|
10857
10885
|
trackByFn: null,
|
|
10858
10886
|
tag,
|
|
10887
|
+
emptyTag,
|
|
10888
|
+
emptyAttributes: null,
|
|
10859
10889
|
functionNameSuffix: 'For',
|
|
10860
10890
|
namespace: Namespace.HTML,
|
|
10861
10891
|
nonBindable: false,
|
|
@@ -10864,9 +10894,13 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, so
|
|
|
10864
10894
|
vars: null,
|
|
10865
10895
|
varNames,
|
|
10866
10896
|
usesComponentInstance: false,
|
|
10867
|
-
|
|
10897
|
+
i18nPlaceholder,
|
|
10898
|
+
emptyI18nPlaceholder,
|
|
10899
|
+
startSourceSpan,
|
|
10900
|
+
wholeSourceSpan,
|
|
10868
10901
|
...TRAIT_CONSUMES_SLOT,
|
|
10869
10902
|
...NEW_OP,
|
|
10903
|
+
...TRAIT_CONSUMES_VARS,
|
|
10870
10904
|
numSlotsUsed: emptyView === null ? 2 : 3,
|
|
10871
10905
|
};
|
|
10872
10906
|
}
|
|
@@ -10898,12 +10932,13 @@ function createEnableBindingsOp(xref) {
|
|
|
10898
10932
|
/**
|
|
10899
10933
|
* Create a `TextOp`.
|
|
10900
10934
|
*/
|
|
10901
|
-
function createTextOp(xref, initialValue, sourceSpan) {
|
|
10935
|
+
function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
|
|
10902
10936
|
return {
|
|
10903
10937
|
kind: OpKind.Text,
|
|
10904
10938
|
xref,
|
|
10905
10939
|
handle: new SlotHandle(),
|
|
10906
10940
|
initialValue,
|
|
10941
|
+
icuPlaceholder,
|
|
10907
10942
|
sourceSpan,
|
|
10908
10943
|
...TRAIT_CONSUMES_SLOT,
|
|
10909
10944
|
...NEW_OP,
|
|
@@ -10912,7 +10947,9 @@ function createTextOp(xref, initialValue, sourceSpan) {
|
|
|
10912
10947
|
/**
|
|
10913
10948
|
* Create a `ListenerOp`. Host bindings reuse all the listener logic.
|
|
10914
10949
|
*/
|
|
10915
|
-
function createListenerOp(target, targetSlot, name, tag, animationPhase, hostListener, sourceSpan) {
|
|
10950
|
+
function createListenerOp(target, targetSlot, name, tag, handlerOps, animationPhase, eventTarget, hostListener, sourceSpan) {
|
|
10951
|
+
const handlerList = new OpList();
|
|
10952
|
+
handlerList.push(handlerOps);
|
|
10916
10953
|
return {
|
|
10917
10954
|
kind: OpKind.Listener,
|
|
10918
10955
|
target,
|
|
@@ -10920,11 +10957,12 @@ function createListenerOp(target, targetSlot, name, tag, animationPhase, hostLis
|
|
|
10920
10957
|
tag,
|
|
10921
10958
|
hostListener,
|
|
10922
10959
|
name,
|
|
10923
|
-
handlerOps:
|
|
10960
|
+
handlerOps: handlerList,
|
|
10924
10961
|
handlerFnName: null,
|
|
10925
10962
|
consumesDollarEvent: false,
|
|
10926
10963
|
isAnimationListener: animationPhase !== null,
|
|
10927
|
-
animationPhase
|
|
10964
|
+
animationPhase,
|
|
10965
|
+
eventTarget,
|
|
10928
10966
|
sourceSpan,
|
|
10929
10967
|
...NEW_OP,
|
|
10930
10968
|
};
|
|
@@ -10953,7 +10991,7 @@ function createProjectionDefOp(def) {
|
|
|
10953
10991
|
...NEW_OP,
|
|
10954
10992
|
};
|
|
10955
10993
|
}
|
|
10956
|
-
function createProjectionOp(xref, selector, i18nPlaceholder,
|
|
10994
|
+
function createProjectionOp(xref, selector, i18nPlaceholder, sourceSpan) {
|
|
10957
10995
|
return {
|
|
10958
10996
|
kind: OpKind.Projection,
|
|
10959
10997
|
xref,
|
|
@@ -10961,7 +10999,7 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
|
|
|
10961
10999
|
selector,
|
|
10962
11000
|
i18nPlaceholder,
|
|
10963
11001
|
projectionSlotIndex: 0,
|
|
10964
|
-
attributes,
|
|
11002
|
+
attributes: null,
|
|
10965
11003
|
localRefs: [],
|
|
10966
11004
|
sourceSpan,
|
|
10967
11005
|
...NEW_OP,
|
|
@@ -10971,7 +11009,7 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
|
|
|
10971
11009
|
/**
|
|
10972
11010
|
* Create an `ExtractedAttributeOp`.
|
|
10973
11011
|
*/
|
|
10974
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext) {
|
|
11012
|
+
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10975
11013
|
return {
|
|
10976
11014
|
kind: OpKind.ExtractedAttribute,
|
|
10977
11015
|
target,
|
|
@@ -10979,6 +11017,9 @@ function createExtractedAttributeOp(target, bindingKind, name, expression, i18nC
|
|
|
10979
11017
|
name,
|
|
10980
11018
|
expression,
|
|
10981
11019
|
i18nContext,
|
|
11020
|
+
i18nMessage,
|
|
11021
|
+
securityContext,
|
|
11022
|
+
trustedValueFn: null,
|
|
10982
11023
|
...NEW_OP,
|
|
10983
11024
|
};
|
|
10984
11025
|
}
|
|
@@ -11039,7 +11080,7 @@ function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlace
|
|
|
11039
11080
|
/**
|
|
11040
11081
|
* Create an `I18nStartOp`.
|
|
11041
11082
|
*/
|
|
11042
|
-
function createI18nStartOp(xref, message, root) {
|
|
11083
|
+
function createI18nStartOp(xref, message, root, sourceSpan) {
|
|
11043
11084
|
return {
|
|
11044
11085
|
kind: OpKind.I18nStart,
|
|
11045
11086
|
xref,
|
|
@@ -11049,6 +11090,7 @@ function createI18nStartOp(xref, message, root) {
|
|
|
11049
11090
|
messageIndex: null,
|
|
11050
11091
|
subTemplateIndex: null,
|
|
11051
11092
|
context: null,
|
|
11093
|
+
sourceSpan,
|
|
11052
11094
|
...NEW_OP,
|
|
11053
11095
|
...TRAIT_CONSUMES_SLOT,
|
|
11054
11096
|
};
|
|
@@ -11056,10 +11098,11 @@ function createI18nStartOp(xref, message, root) {
|
|
|
11056
11098
|
/**
|
|
11057
11099
|
* Create an `I18nEndOp`.
|
|
11058
11100
|
*/
|
|
11059
|
-
function createI18nEndOp(xref) {
|
|
11101
|
+
function createI18nEndOp(xref, sourceSpan) {
|
|
11060
11102
|
return {
|
|
11061
11103
|
kind: OpKind.I18nEnd,
|
|
11062
11104
|
xref,
|
|
11105
|
+
sourceSpan,
|
|
11063
11106
|
...NEW_OP,
|
|
11064
11107
|
};
|
|
11065
11108
|
}
|
|
@@ -11087,6 +11130,19 @@ function createIcuEndOp(xref) {
|
|
|
11087
11130
|
...NEW_OP,
|
|
11088
11131
|
};
|
|
11089
11132
|
}
|
|
11133
|
+
/**
|
|
11134
|
+
* Creates an ICU placeholder op.
|
|
11135
|
+
*/
|
|
11136
|
+
function createIcuPlaceholderOp(xref, name, strings) {
|
|
11137
|
+
return {
|
|
11138
|
+
kind: OpKind.IcuPlaceholder,
|
|
11139
|
+
xref,
|
|
11140
|
+
name,
|
|
11141
|
+
strings,
|
|
11142
|
+
expressionPlaceholders: [],
|
|
11143
|
+
...NEW_OP,
|
|
11144
|
+
};
|
|
11145
|
+
}
|
|
11090
11146
|
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
11091
11147
|
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
11092
11148
|
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
@@ -11121,13 +11177,15 @@ function literalOrArrayLiteral$1(value) {
|
|
|
11121
11177
|
return literal(value, INFERRED_TYPE);
|
|
11122
11178
|
}
|
|
11123
11179
|
|
|
11124
|
-
function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, sourceSpan) {
|
|
11180
|
+
function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, securityContext, sourceSpan) {
|
|
11125
11181
|
return {
|
|
11126
11182
|
kind: OpKind.HostProperty,
|
|
11127
11183
|
name,
|
|
11128
11184
|
expression,
|
|
11129
11185
|
isAnimationTrigger,
|
|
11130
11186
|
i18nContext,
|
|
11187
|
+
securityContext,
|
|
11188
|
+
sanitizer: null,
|
|
11131
11189
|
sourceSpan,
|
|
11132
11190
|
...TRAIT_CONSUMES_VARS,
|
|
11133
11191
|
...NEW_OP,
|
|
@@ -11407,68 +11465,52 @@ function needsApplication(i18nContexts, op) {
|
|
|
11407
11465
|
* after the last update instruction that depends on that slot.
|
|
11408
11466
|
*/
|
|
11409
11467
|
function assignI18nSlotDependencies(job) {
|
|
11410
|
-
const i18nLastSlotConsumers = new Map();
|
|
11411
|
-
let lastSlotConsumer = null;
|
|
11412
|
-
let currentI18nOp = null;
|
|
11413
11468
|
for (const unit of job.units) {
|
|
11414
|
-
//
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11469
|
+
// The first update op.
|
|
11470
|
+
let updateOp = unit.update.head;
|
|
11471
|
+
// I18n expressions currently being moved during the iteration.
|
|
11472
|
+
let i18nExpressionsInProgress = [];
|
|
11473
|
+
// Non-null while we are iterating through an i18nStart/i18nEnd pair
|
|
11474
|
+
let state = null;
|
|
11475
|
+
for (const createOp of unit.create) {
|
|
11476
|
+
if (createOp.kind === OpKind.I18nStart) {
|
|
11477
|
+
state = {
|
|
11478
|
+
blockXref: createOp.xref,
|
|
11479
|
+
lastSlotConsumer: createOp.xref,
|
|
11480
|
+
};
|
|
11418
11481
|
}
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11482
|
+
else if (createOp.kind === OpKind.I18nEnd) {
|
|
11483
|
+
for (const op of i18nExpressionsInProgress) {
|
|
11484
|
+
op.target = state.lastSlotConsumer;
|
|
11485
|
+
OpList.insertBefore(op, updateOp);
|
|
11486
|
+
}
|
|
11487
|
+
i18nExpressionsInProgress.length = 0;
|
|
11488
|
+
state = null;
|
|
11489
|
+
}
|
|
11490
|
+
if (hasConsumesSlotTrait(createOp)) {
|
|
11491
|
+
if (state !== null) {
|
|
11492
|
+
state.lastSlotConsumer = createOp.xref;
|
|
11493
|
+
}
|
|
11494
|
+
while (true) {
|
|
11495
|
+
if (updateOp.next === null) {
|
|
11496
|
+
break;
|
|
11426
11497
|
}
|
|
11427
|
-
if (
|
|
11428
|
-
|
|
11498
|
+
if (state !== null && updateOp.kind === OpKind.I18nExpression &&
|
|
11499
|
+
updateOp.usage === I18nExpressionFor.I18nText &&
|
|
11500
|
+
updateOp.i18nOwner === state.blockXref) {
|
|
11501
|
+
const opToRemove = updateOp;
|
|
11502
|
+
updateOp = updateOp.next;
|
|
11503
|
+
OpList.remove(opToRemove);
|
|
11504
|
+
i18nExpressionsInProgress.push(opToRemove);
|
|
11505
|
+
continue;
|
|
11429
11506
|
}
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
}
|
|
11435
|
-
// Expresions that are currently being moved.
|
|
11436
|
-
let opsToMove = [];
|
|
11437
|
-
// Previously we found the last slot-consuming create mode op in the i18n block. That op will be
|
|
11438
|
-
// the new target for any moved i18n expresion inside the i18n block, and that op's slot is
|
|
11439
|
-
// stored here.
|
|
11440
|
-
let moveAfterTarget = null;
|
|
11441
|
-
// This is the last target in the create IR that we saw during iteration. Eventally, it will be
|
|
11442
|
-
// equal to moveAfterTarget. But wait! We need to find the *last* such op whose target is equal
|
|
11443
|
-
// to `moveAfterTarget`.
|
|
11444
|
-
let previousTarget = null;
|
|
11445
|
-
for (const op of unit.update) {
|
|
11446
|
-
if (hasDependsOnSlotContextTrait(op)) {
|
|
11447
|
-
// We've found an op that depends on another slot other than the one that we want to move
|
|
11448
|
-
// the expressions to, after previously having seen the one we want to move to.
|
|
11449
|
-
if (moveAfterTarget !== null && previousTarget === moveAfterTarget &&
|
|
11450
|
-
op.target !== previousTarget) {
|
|
11451
|
-
OpList.insertBefore(opsToMove, op);
|
|
11452
|
-
moveAfterTarget = null;
|
|
11453
|
-
opsToMove = [];
|
|
11454
|
-
}
|
|
11455
|
-
previousTarget = op.target;
|
|
11456
|
-
}
|
|
11457
|
-
if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nText) {
|
|
11458
|
-
// This is an I18nExpressionOps that is used for text (not attributes).
|
|
11459
|
-
OpList.remove(op);
|
|
11460
|
-
opsToMove.push(op);
|
|
11461
|
-
const target = i18nLastSlotConsumers.get(op.i18nOwner);
|
|
11462
|
-
if (target === undefined) {
|
|
11463
|
-
throw new Error('AssertionError: Expected to find a last slot consumer for an I18nExpressionOp');
|
|
11507
|
+
if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
|
|
11508
|
+
break;
|
|
11509
|
+
}
|
|
11510
|
+
updateOp = updateOp.next;
|
|
11464
11511
|
}
|
|
11465
|
-
op.target = target;
|
|
11466
|
-
moveAfterTarget = op.target;
|
|
11467
11512
|
}
|
|
11468
11513
|
}
|
|
11469
|
-
if (moveAfterTarget !== null) {
|
|
11470
|
-
unit.update.push(opsToMove);
|
|
11471
|
-
}
|
|
11472
11514
|
}
|
|
11473
11515
|
}
|
|
11474
11516
|
|
|
@@ -11482,6 +11524,13 @@ function createOpXrefMap(unit) {
|
|
|
11482
11524
|
continue;
|
|
11483
11525
|
}
|
|
11484
11526
|
map.set(op.xref, op);
|
|
11527
|
+
// TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
|
|
11528
|
+
// because the slot consumer trait currently only supports one slot per consumer and we
|
|
11529
|
+
// need two. This should be revisited when making the refactors mentioned in:
|
|
11530
|
+
// https://github.com/angular/angular/pull/53620#discussion_r1430918822
|
|
11531
|
+
if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
|
|
11532
|
+
map.set(op.emptyView, op);
|
|
11533
|
+
}
|
|
11485
11534
|
}
|
|
11486
11535
|
return map;
|
|
11487
11536
|
}
|
|
@@ -11501,19 +11550,21 @@ function extractAttributes(job) {
|
|
|
11501
11550
|
case OpKind.Property:
|
|
11502
11551
|
if (!op.isAnimationTrigger) {
|
|
11503
11552
|
let bindingKind;
|
|
11504
|
-
if (op.
|
|
11553
|
+
if (op.i18nMessage !== null && op.templateKind === null) {
|
|
11505
11554
|
// If the binding has an i18n context, it is an i18n attribute, and should have that
|
|
11506
11555
|
// kind in the consts array.
|
|
11507
11556
|
bindingKind = BindingKind.I18n;
|
|
11508
11557
|
}
|
|
11509
|
-
else if (op.
|
|
11510
|
-
// TODO: How do i18n attributes on templates work?!
|
|
11558
|
+
else if (op.isStructuralTemplateAttribute) {
|
|
11511
11559
|
bindingKind = BindingKind.Template;
|
|
11512
11560
|
}
|
|
11513
11561
|
else {
|
|
11514
11562
|
bindingKind = BindingKind.Property;
|
|
11515
11563
|
}
|
|
11516
|
-
OpList.insertBefore(
|
|
11564
|
+
OpList.insertBefore(
|
|
11565
|
+
// Deliberaly null i18nMessage value
|
|
11566
|
+
createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null, /* i18nContext */ null,
|
|
11567
|
+
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11517
11568
|
}
|
|
11518
11569
|
break;
|
|
11519
11570
|
case OpKind.StyleProp:
|
|
@@ -11524,13 +11575,22 @@ function extractAttributes(job) {
|
|
|
11524
11575
|
// mode.
|
|
11525
11576
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11526
11577
|
op.expression instanceof EmptyExpr) {
|
|
11527
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name,
|
|
11578
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11579
|
+
/* i18nContext */ null,
|
|
11580
|
+
/* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
|
|
11528
11581
|
}
|
|
11529
11582
|
break;
|
|
11530
11583
|
case OpKind.Listener:
|
|
11531
11584
|
if (!op.isAnimationListener) {
|
|
11532
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null,
|
|
11585
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11586
|
+
/* i18nContext */ null,
|
|
11587
|
+
/* i18nMessage */ null, SecurityContext.NONE);
|
|
11533
11588
|
if (job.kind === CompilationJobKind.Host) {
|
|
11589
|
+
if (job.compatibility) {
|
|
11590
|
+
// TemplateDefinitionBuilder does not extract listener bindings to the const array
|
|
11591
|
+
// (which is honestly pretty inconsistent).
|
|
11592
|
+
break;
|
|
11593
|
+
}
|
|
11534
11594
|
// This attribute will apply to the enclosing host binding compilation unit, so order
|
|
11535
11595
|
// doesn't matter.
|
|
11536
11596
|
unit.create.push(extractedAttributeOp);
|
|
@@ -11561,24 +11621,14 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
11561
11621
|
if (op.expression instanceof Interpolation) {
|
|
11562
11622
|
return;
|
|
11563
11623
|
}
|
|
11564
|
-
let extractable = op.expression.isConstant();
|
|
11624
|
+
let extractable = op.isTextAttribute || op.expression.isConstant();
|
|
11565
11625
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
11566
|
-
// TemplateDefinitionBuilder only
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
|
|
11570
|
-
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
|
|
11571
|
-
// string literal, because it is not a text attribute.
|
|
11572
|
-
extractable &&= op.isTextAttribute;
|
|
11573
|
-
}
|
|
11574
|
-
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11575
|
-
// TemplateDefinitionBuilder also does not seem to extract string literals if they are part of
|
|
11576
|
-
// a host attribute.
|
|
11577
|
-
extractable &&= op.isTextAttribute;
|
|
11578
|
-
}
|
|
11626
|
+
// TemplateDefinitionBuilder only extracts text attributes. It does not extract attriibute
|
|
11627
|
+
// bindings, even if they are constants.
|
|
11628
|
+
extractable &&= op.isTextAttribute;
|
|
11579
11629
|
}
|
|
11580
11630
|
if (extractable) {
|
|
11581
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.
|
|
11631
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11582
11632
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11583
11633
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
11584
11634
|
// matter.
|
|
@@ -11625,16 +11675,16 @@ function specializeBindings(job) {
|
|
|
11625
11675
|
target.nonBindable = true;
|
|
11626
11676
|
}
|
|
11627
11677
|
else {
|
|
11628
|
-
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.
|
|
11678
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
|
|
11629
11679
|
}
|
|
11630
11680
|
break;
|
|
11631
11681
|
case BindingKind.Property:
|
|
11632
11682
|
case BindingKind.Animation:
|
|
11633
11683
|
if (job.kind === CompilationJobKind.Host) {
|
|
11634
|
-
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.sourceSpan));
|
|
11684
|
+
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.securityContext, op.sourceSpan));
|
|
11635
11685
|
}
|
|
11636
11686
|
else {
|
|
11637
|
-
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.
|
|
11687
|
+
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
|
|
11638
11688
|
}
|
|
11639
11689
|
break;
|
|
11640
11690
|
case BindingKind.I18n:
|
|
@@ -11869,9 +11919,9 @@ function collectElementConsts(job) {
|
|
|
11869
11919
|
for (const unit of job.units) {
|
|
11870
11920
|
for (const op of unit.create) {
|
|
11871
11921
|
if (op.kind === OpKind.ExtractedAttribute) {
|
|
11872
|
-
const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
|
|
11922
|
+
const attributes = allElementAttributes.get(op.target) || new ElementAttributes(job.compatibility);
|
|
11873
11923
|
allElementAttributes.set(op.target, attributes);
|
|
11874
|
-
attributes.add(op.bindingKind, op.name, op.expression);
|
|
11924
|
+
attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
|
|
11875
11925
|
OpList.remove(op);
|
|
11876
11926
|
}
|
|
11877
11927
|
}
|
|
@@ -11880,15 +11930,26 @@ function collectElementConsts(job) {
|
|
|
11880
11930
|
if (job instanceof ComponentCompilationJob) {
|
|
11881
11931
|
for (const unit of job.units) {
|
|
11882
11932
|
for (const op of unit.create) {
|
|
11883
|
-
|
|
11933
|
+
// TODO: Simplify and combine these cases.
|
|
11934
|
+
if (op.kind == OpKind.Projection) {
|
|
11884
11935
|
const attributes = allElementAttributes.get(op.xref);
|
|
11885
11936
|
if (attributes !== undefined) {
|
|
11886
11937
|
const attrArray = serializeAttributes(attributes);
|
|
11887
11938
|
if (attrArray.entries.length > 0) {
|
|
11888
|
-
op.attributes =
|
|
11939
|
+
op.attributes = attrArray;
|
|
11889
11940
|
}
|
|
11890
11941
|
}
|
|
11891
11942
|
}
|
|
11943
|
+
else if (isElementOrContainerOp(op)) {
|
|
11944
|
+
op.attributes = getConstIndex(job, allElementAttributes, op.xref);
|
|
11945
|
+
// TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
|
|
11946
|
+
// because the slot consumer trait currently only supports one slot per consumer and we
|
|
11947
|
+
// need two. This should be revisited when making the refactors mentioned in:
|
|
11948
|
+
// https://github.com/angular/angular/pull/53620#discussion_r1430918822
|
|
11949
|
+
if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
|
|
11950
|
+
op.emptyAttributes = getConstIndex(job, allElementAttributes, op.emptyView);
|
|
11951
|
+
}
|
|
11952
|
+
}
|
|
11892
11953
|
}
|
|
11893
11954
|
}
|
|
11894
11955
|
}
|
|
@@ -11906,6 +11967,16 @@ function collectElementConsts(job) {
|
|
|
11906
11967
|
}
|
|
11907
11968
|
}
|
|
11908
11969
|
}
|
|
11970
|
+
function getConstIndex(job, allElementAttributes, xref) {
|
|
11971
|
+
const attributes = allElementAttributes.get(xref);
|
|
11972
|
+
if (attributes !== undefined) {
|
|
11973
|
+
const attrArray = serializeAttributes(attributes);
|
|
11974
|
+
if (attrArray.entries.length > 0) {
|
|
11975
|
+
return job.addConst(attrArray);
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
return null;
|
|
11979
|
+
}
|
|
11909
11980
|
/**
|
|
11910
11981
|
* Shared instance of an empty array to avoid unnecessary array allocations.
|
|
11911
11982
|
*/
|
|
@@ -11914,11 +11985,6 @@ const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
|
11914
11985
|
* Container for all of the various kinds of attributes which are applied on an element.
|
|
11915
11986
|
*/
|
|
11916
11987
|
class ElementAttributes {
|
|
11917
|
-
constructor() {
|
|
11918
|
-
this.known = new Set();
|
|
11919
|
-
this.byKind = new Map;
|
|
11920
|
-
this.projectAs = null;
|
|
11921
|
-
}
|
|
11922
11988
|
get attributes() {
|
|
11923
11989
|
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
11924
11990
|
}
|
|
@@ -11937,11 +12003,32 @@ class ElementAttributes {
|
|
|
11937
12003
|
get i18n() {
|
|
11938
12004
|
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11939
12005
|
}
|
|
11940
|
-
|
|
11941
|
-
|
|
12006
|
+
constructor(compatibility) {
|
|
12007
|
+
this.compatibility = compatibility;
|
|
12008
|
+
this.known = new Map();
|
|
12009
|
+
this.byKind = new Map;
|
|
12010
|
+
this.projectAs = null;
|
|
12011
|
+
}
|
|
12012
|
+
isKnown(kind, name, value) {
|
|
12013
|
+
const nameToValue = this.known.get(kind) ?? new Set();
|
|
12014
|
+
this.known.set(kind, nameToValue);
|
|
12015
|
+
if (nameToValue.has(name)) {
|
|
12016
|
+
return true;
|
|
12017
|
+
}
|
|
12018
|
+
nameToValue.add(name);
|
|
12019
|
+
return false;
|
|
12020
|
+
}
|
|
12021
|
+
add(kind, name, value, trustedValueFn) {
|
|
12022
|
+
// TemplateDefinitionBuilder puts duplicate attribute, class, and style values into the consts
|
|
12023
|
+
// array. This seems inefficient, we can probably keep just the first one or the last value
|
|
12024
|
+
// (whichever actually gets applied when multiple values are listed for the same attribute).
|
|
12025
|
+
const allowDuplicates = this.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
12026
|
+
(kind === BindingKind.Attribute || kind === BindingKind.ClassName ||
|
|
12027
|
+
kind === BindingKind.StyleProperty);
|
|
12028
|
+
if (!allowDuplicates && this.isKnown(kind, name, value)) {
|
|
11942
12029
|
return;
|
|
11943
12030
|
}
|
|
11944
|
-
this
|
|
12031
|
+
// TODO: Can this be its own phase
|
|
11945
12032
|
if (name === 'ngProjectAs') {
|
|
11946
12033
|
if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
|
|
11947
12034
|
(typeof value.value?.toString() !== 'string')) {
|
|
@@ -11957,7 +12044,15 @@ class ElementAttributes {
|
|
|
11957
12044
|
if (value === null) {
|
|
11958
12045
|
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
11959
12046
|
}
|
|
11960
|
-
|
|
12047
|
+
if (trustedValueFn !== null) {
|
|
12048
|
+
if (!isStringLiteral(value)) {
|
|
12049
|
+
throw Error('AssertionError: extracted attribute value should be string literal');
|
|
12050
|
+
}
|
|
12051
|
+
array.push(taggedTemplate(trustedValueFn, new TemplateLiteral([new TemplateLiteralElement(value.value)], []), undefined, value.sourceSpan));
|
|
12052
|
+
}
|
|
12053
|
+
else {
|
|
12054
|
+
array.push(value);
|
|
12055
|
+
}
|
|
11961
12056
|
}
|
|
11962
12057
|
}
|
|
11963
12058
|
arrayFor(kind) {
|
|
@@ -11971,7 +12066,7 @@ class ElementAttributes {
|
|
|
11971
12066
|
* Gets an array of literal expressions representing the attribute's namespaced name.
|
|
11972
12067
|
*/
|
|
11973
12068
|
function getAttributeNameLiterals$1(name) {
|
|
11974
|
-
const [attributeNamespace, attributeName] = splitNsName(name);
|
|
12069
|
+
const [attributeNamespace, attributeName] = splitNsName(name, false);
|
|
11975
12070
|
const nameLiteral = literal(attributeName);
|
|
11976
12071
|
if (attributeNamespace) {
|
|
11977
12072
|
return [
|
|
@@ -12044,7 +12139,7 @@ function convertI18nBindings(job) {
|
|
|
12044
12139
|
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
12045
12140
|
throw new Error(`AssertionError: An i18n attribute binding instruction requires the same number of expressions and placeholders, but found ${op.expression.i18nPlaceholders.length} placeholders and ${op.expression.expressions.length} expressions`);
|
|
12046
12141
|
}
|
|
12047
|
-
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12142
|
+
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, null, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12048
12143
|
}
|
|
12049
12144
|
OpList.replaceWithMany(op, ops);
|
|
12050
12145
|
break;
|
|
@@ -12081,7 +12176,8 @@ function createDeferDepsFns(job) {
|
|
|
12081
12176
|
if (op.handle.slot === null) {
|
|
12082
12177
|
throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
|
|
12083
12178
|
}
|
|
12084
|
-
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn
|
|
12179
|
+
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn`,
|
|
12180
|
+
/* Don't use unique names for TDB compatibility */ false);
|
|
12085
12181
|
}
|
|
12086
12182
|
}
|
|
12087
12183
|
}
|
|
@@ -12098,53 +12194,119 @@ function createDeferDepsFns(job) {
|
|
|
12098
12194
|
* message.)
|
|
12099
12195
|
*/
|
|
12100
12196
|
function createI18nContexts(job) {
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12197
|
+
// Create i18n context ops for i18n attrs.
|
|
12198
|
+
const attrContextByMessage = new Map();
|
|
12199
|
+
for (const unit of job.units) {
|
|
12200
|
+
for (const op of unit.ops()) {
|
|
12201
|
+
switch (op.kind) {
|
|
12202
|
+
case OpKind.Binding:
|
|
12203
|
+
case OpKind.Property:
|
|
12204
|
+
case OpKind.Attribute:
|
|
12205
|
+
case OpKind.ExtractedAttribute:
|
|
12206
|
+
if (op.i18nMessage === null) {
|
|
12207
|
+
continue;
|
|
12208
|
+
}
|
|
12209
|
+
if (!attrContextByMessage.has(op.i18nMessage)) {
|
|
12210
|
+
const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
|
|
12211
|
+
unit.create.push(i18nContext);
|
|
12212
|
+
attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
|
|
12213
|
+
}
|
|
12214
|
+
op.i18nContext = attrContextByMessage.get(op.i18nMessage);
|
|
12215
|
+
break;
|
|
12216
|
+
}
|
|
12217
|
+
}
|
|
12218
|
+
}
|
|
12219
|
+
// Create i18n context ops for root i18n blocks.
|
|
12220
|
+
const blockContextByI18nBlock = new Map();
|
|
12104
12221
|
for (const unit of job.units) {
|
|
12105
12222
|
for (const op of unit.create) {
|
|
12106
12223
|
switch (op.kind) {
|
|
12107
12224
|
case OpKind.I18nStart:
|
|
12108
|
-
currentI18nOp = op;
|
|
12109
|
-
// Each root i18n block gets its own context, child ones refer to the context for their
|
|
12110
|
-
// root block.
|
|
12111
12225
|
if (op.xref === op.root) {
|
|
12112
|
-
|
|
12113
|
-
unit.create.push(
|
|
12114
|
-
op.context = xref;
|
|
12115
|
-
|
|
12226
|
+
const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
|
|
12227
|
+
unit.create.push(contextOp);
|
|
12228
|
+
op.context = contextOp.xref;
|
|
12229
|
+
blockContextByI18nBlock.set(op.xref, contextOp);
|
|
12116
12230
|
}
|
|
12117
12231
|
break;
|
|
12232
|
+
}
|
|
12233
|
+
}
|
|
12234
|
+
}
|
|
12235
|
+
// Assign i18n contexts for child i18n blocks. These don't need their own conext, instead they
|
|
12236
|
+
// should inherit from their root i18n block.
|
|
12237
|
+
for (const unit of job.units) {
|
|
12238
|
+
for (const op of unit.create) {
|
|
12239
|
+
if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
|
|
12240
|
+
const rootContext = blockContextByI18nBlock.get(op.root);
|
|
12241
|
+
if (rootContext === undefined) {
|
|
12242
|
+
throw Error('AssertionError: Root i18n block i18n context should have been created.');
|
|
12243
|
+
}
|
|
12244
|
+
op.context = rootContext.xref;
|
|
12245
|
+
blockContextByI18nBlock.set(op.xref, rootContext);
|
|
12246
|
+
}
|
|
12247
|
+
}
|
|
12248
|
+
}
|
|
12249
|
+
// Create or assign i18n contexts for ICUs.
|
|
12250
|
+
let currentI18nOp = null;
|
|
12251
|
+
for (const unit of job.units) {
|
|
12252
|
+
for (const op of unit.create) {
|
|
12253
|
+
switch (op.kind) {
|
|
12254
|
+
case OpKind.I18nStart:
|
|
12255
|
+
currentI18nOp = op;
|
|
12256
|
+
break;
|
|
12118
12257
|
case OpKind.I18nEnd:
|
|
12119
12258
|
currentI18nOp = null;
|
|
12120
12259
|
break;
|
|
12121
12260
|
case OpKind.IcuStart:
|
|
12122
|
-
// If an ICU represents a different message than its containing block, we give it its own
|
|
12123
|
-
// i18n context.
|
|
12124
12261
|
if (currentI18nOp === null) {
|
|
12125
|
-
throw Error('Unexpected ICU outside of an i18n block.');
|
|
12262
|
+
throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
|
|
12126
12263
|
}
|
|
12127
12264
|
if (op.message.id !== currentI18nOp.message.id) {
|
|
12128
|
-
//
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12265
|
+
// This ICU is a sub-message inside its parent i18n block message. We need to give it
|
|
12266
|
+
// its own context.
|
|
12267
|
+
const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.xref, op.message, null);
|
|
12268
|
+
unit.create.push(contextOp);
|
|
12269
|
+
op.context = contextOp.xref;
|
|
12132
12270
|
}
|
|
12133
12271
|
else {
|
|
12134
|
-
//
|
|
12135
|
-
// the
|
|
12272
|
+
// This ICU is the only translatable content in its parent i18n block. We need to
|
|
12273
|
+
// convert the parent's context into an ICU context.
|
|
12136
12274
|
op.context = currentI18nOp.context;
|
|
12275
|
+
blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
|
|
12137
12276
|
}
|
|
12138
12277
|
break;
|
|
12139
12278
|
}
|
|
12140
12279
|
}
|
|
12141
12280
|
}
|
|
12142
|
-
|
|
12143
|
-
|
|
12281
|
+
}
|
|
12282
|
+
|
|
12283
|
+
/**
|
|
12284
|
+
* Deduplicate text bindings, e.g. <div class="cls1" class="cls2">
|
|
12285
|
+
*/
|
|
12286
|
+
function deduplicateTextBindings(job) {
|
|
12287
|
+
const seen = new Map();
|
|
12144
12288
|
for (const unit of job.units) {
|
|
12145
|
-
for (const op of unit.
|
|
12146
|
-
if (op.kind === OpKind.
|
|
12147
|
-
|
|
12289
|
+
for (const op of unit.update.reversed()) {
|
|
12290
|
+
if (op.kind === OpKind.Binding && op.isTextAttribute) {
|
|
12291
|
+
const seenForElement = seen.get(op.target) || new Set();
|
|
12292
|
+
if (seenForElement.has(op.name)) {
|
|
12293
|
+
if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
12294
|
+
// For most duplicated attributes, TemplateDefinitionBuilder lists all of the values in
|
|
12295
|
+
// the consts array. However, for style and class attributes it only keeps the last one.
|
|
12296
|
+
// We replicate that behavior here since it has actual consequences for apps with
|
|
12297
|
+
// duplicate class or style attrs.
|
|
12298
|
+
if (op.name === 'style' || op.name === 'class') {
|
|
12299
|
+
OpList.remove(op);
|
|
12300
|
+
}
|
|
12301
|
+
}
|
|
12302
|
+
else {
|
|
12303
|
+
// TODO: Determine the correct behavior. It would probably make sense to merge multiple
|
|
12304
|
+
// style and class attributes. Alternatively we could just throw an error, as HTML
|
|
12305
|
+
// doesn't permit duplicate attributes.
|
|
12306
|
+
}
|
|
12307
|
+
}
|
|
12308
|
+
seenForElement.add(op.name);
|
|
12309
|
+
seen.set(op.target, seenForElement);
|
|
12148
12310
|
}
|
|
12149
12311
|
}
|
|
12150
12312
|
}
|
|
@@ -12530,13 +12692,18 @@ const LIST_DELIMITER = '|';
|
|
|
12530
12692
|
* used in the final output.
|
|
12531
12693
|
*/
|
|
12532
12694
|
function extractI18nMessages(job) {
|
|
12533
|
-
//
|
|
12534
|
-
|
|
12695
|
+
// Create an i18n message for each context.
|
|
12696
|
+
// TODO: Merge the context op with the message op since they're 1:1 anyways.
|
|
12697
|
+
const i18nMessagesByContext = new Map();
|
|
12535
12698
|
const i18nBlocks = new Map();
|
|
12699
|
+
const i18nContexts = new Map();
|
|
12536
12700
|
for (const unit of job.units) {
|
|
12537
12701
|
for (const op of unit.create) {
|
|
12538
12702
|
switch (op.kind) {
|
|
12539
12703
|
case OpKind.I18nContext:
|
|
12704
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12705
|
+
unit.create.push(i18nMessageOp);
|
|
12706
|
+
i18nMessagesByContext.set(op.xref, i18nMessageOp);
|
|
12540
12707
|
i18nContexts.set(op.xref, op);
|
|
12541
12708
|
break;
|
|
12542
12709
|
case OpKind.I18nStart:
|
|
@@ -12545,54 +12712,47 @@ function extractI18nMessages(job) {
|
|
|
12545
12712
|
}
|
|
12546
12713
|
}
|
|
12547
12714
|
}
|
|
12548
|
-
//
|
|
12549
|
-
//
|
|
12550
|
-
|
|
12551
|
-
for (const unit of job.units) {
|
|
12552
|
-
for (const op of unit.create) {
|
|
12553
|
-
if (op.kind !== OpKind.I18nContext || op.contextKind !== I18nContextKind.Attr) {
|
|
12554
|
-
continue;
|
|
12555
|
-
}
|
|
12556
|
-
const i18nMessageOp = createI18nMessage(job, op);
|
|
12557
|
-
unit.create.push(i18nMessageOp);
|
|
12558
|
-
}
|
|
12559
|
-
}
|
|
12560
|
-
// Extract messages from root i18n blocks.
|
|
12561
|
-
const i18nBlockMessages = new Map();
|
|
12562
|
-
for (const unit of job.units) {
|
|
12563
|
-
for (const op of unit.create) {
|
|
12564
|
-
if (op.kind === OpKind.I18nStart && op.xref === op.root) {
|
|
12565
|
-
if (!op.context) {
|
|
12566
|
-
throw Error('I18n start op should have its context set.');
|
|
12567
|
-
}
|
|
12568
|
-
const i18nMessageOp = createI18nMessage(job, i18nContexts.get(op.context));
|
|
12569
|
-
i18nBlockMessages.set(op.xref, i18nMessageOp);
|
|
12570
|
-
unit.create.push(i18nMessageOp);
|
|
12571
|
-
}
|
|
12572
|
-
}
|
|
12573
|
-
}
|
|
12574
|
-
// Extract messages from ICUs with their own sub-context.
|
|
12715
|
+
// Associate sub-messages for ICUs with their root message. At this point we can also remove the
|
|
12716
|
+
// ICU start/end ops, as they are no longer needed.
|
|
12717
|
+
let currentIcu = null;
|
|
12575
12718
|
for (const unit of job.units) {
|
|
12576
12719
|
for (const op of unit.create) {
|
|
12577
12720
|
switch (op.kind) {
|
|
12578
12721
|
case OpKind.IcuStart:
|
|
12579
|
-
|
|
12580
|
-
|
|
12722
|
+
currentIcu = op;
|
|
12723
|
+
OpList.remove(op);
|
|
12724
|
+
// Skip any contexts not associated with an ICU.
|
|
12725
|
+
const icuContext = i18nContexts.get(op.context);
|
|
12726
|
+
if (icuContext.contextKind !== I18nContextKind.Icu) {
|
|
12727
|
+
continue;
|
|
12581
12728
|
}
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
|
|
12588
|
-
unit.create.push(subMessage);
|
|
12589
|
-
const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
|
|
12590
|
-
const parentMessage = i18nBlockMessages.get(rootI18nId);
|
|
12591
|
-
parentMessage?.subMessages.push(subMessage.xref);
|
|
12729
|
+
// Skip ICUs that share a context with their i18n message. These represent root-level
|
|
12730
|
+
// ICUs, not sub-messages.
|
|
12731
|
+
const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
|
|
12732
|
+
if (i18nBlock.context === icuContext.xref) {
|
|
12733
|
+
continue;
|
|
12592
12734
|
}
|
|
12593
|
-
|
|
12735
|
+
// Find the root message and push this ICUs message as a sub-message.
|
|
12736
|
+
const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
|
|
12737
|
+
const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
|
|
12738
|
+
if (rootMessage === undefined) {
|
|
12739
|
+
throw Error('AssertionError: ICU sub-message should belong to a root message.');
|
|
12740
|
+
}
|
|
12741
|
+
const subMessage = i18nMessagesByContext.get(icuContext.xref);
|
|
12742
|
+
subMessage.messagePlaceholder = op.messagePlaceholder;
|
|
12743
|
+
rootMessage.subMessages.push(subMessage.xref);
|
|
12594
12744
|
break;
|
|
12595
12745
|
case OpKind.IcuEnd:
|
|
12746
|
+
currentIcu = null;
|
|
12747
|
+
OpList.remove(op);
|
|
12748
|
+
break;
|
|
12749
|
+
case OpKind.IcuPlaceholder:
|
|
12750
|
+
// Add ICU placeholders to the message, then remove the ICU placeholder ops.
|
|
12751
|
+
if (currentIcu === null || currentIcu.context == null) {
|
|
12752
|
+
throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
|
|
12753
|
+
}
|
|
12754
|
+
const msg = i18nMessagesByContext.get(currentIcu.context);
|
|
12755
|
+
msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
|
|
12596
12756
|
OpList.remove(op);
|
|
12597
12757
|
break;
|
|
12598
12758
|
}
|
|
@@ -12605,14 +12765,19 @@ function extractI18nMessages(job) {
|
|
|
12605
12765
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
12606
12766
|
let formattedParams = formatParams(context.params);
|
|
12607
12767
|
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12608
|
-
let needsPostprocessing =
|
|
12609
|
-
for (const values of context.params.values()) {
|
|
12610
|
-
if (values.length > 1) {
|
|
12611
|
-
needsPostprocessing = true;
|
|
12612
|
-
}
|
|
12613
|
-
}
|
|
12768
|
+
let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
|
|
12614
12769
|
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12615
12770
|
}
|
|
12771
|
+
/**
|
|
12772
|
+
* Formats an ICU placeholder into a single string with expression placeholders.
|
|
12773
|
+
*/
|
|
12774
|
+
function formatIcuPlaceholder(op) {
|
|
12775
|
+
if (op.strings.length !== op.expressionPlaceholders.length + 1) {
|
|
12776
|
+
throw Error(`AsserionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
|
|
12777
|
+
}
|
|
12778
|
+
const values = op.expressionPlaceholders.map(formatValue);
|
|
12779
|
+
return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
|
|
12780
|
+
}
|
|
12616
12781
|
/**
|
|
12617
12782
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12618
12783
|
*/
|
|
@@ -12812,9 +12977,15 @@ function recursivelyProcessView(view, parentScope) {
|
|
|
12812
12977
|
for (const op of view.create) {
|
|
12813
12978
|
switch (op.kind) {
|
|
12814
12979
|
case OpKind.Template:
|
|
12980
|
+
// Descend into child embedded views.
|
|
12981
|
+
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12982
|
+
break;
|
|
12815
12983
|
case OpKind.RepeaterCreate:
|
|
12816
12984
|
// Descend into child embedded views.
|
|
12817
12985
|
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12986
|
+
if (op.emptyView) {
|
|
12987
|
+
recursivelyProcessView(view.job.views.get(op.emptyView), scope);
|
|
12988
|
+
}
|
|
12818
12989
|
break;
|
|
12819
12990
|
case OpKind.Listener:
|
|
12820
12991
|
// Prepend variables to listener handler functions.
|
|
@@ -12945,7 +13116,7 @@ const BANG_IMPORTANT = '!important';
|
|
|
12945
13116
|
*/
|
|
12946
13117
|
function parseHostStyleProperties(job) {
|
|
12947
13118
|
for (const op of job.root.update) {
|
|
12948
|
-
if (op.kind
|
|
13119
|
+
if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
|
|
12949
13120
|
continue;
|
|
12950
13121
|
}
|
|
12951
13122
|
if (op.name.endsWith(BANG_IMPORTANT)) {
|
|
@@ -19954,7 +20125,7 @@ const ESCAPE = '\uFFFD';
|
|
|
19954
20125
|
function collectI18nConsts(job) {
|
|
19955
20126
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
19956
20127
|
// Step One: Build up various lookup maps we need to collect all the consts.
|
|
19957
|
-
// Context Xref -> Extracted Attribute
|
|
20128
|
+
// Context Xref -> Extracted Attribute Ops
|
|
19958
20129
|
const extractedAttributesByI18nContext = new Map();
|
|
19959
20130
|
// Element/ElementStart Xref -> I18n Attributes config op
|
|
19960
20131
|
const i18nAttributesByElement = new Map();
|
|
@@ -19965,7 +20136,9 @@ function collectI18nConsts(job) {
|
|
|
19965
20136
|
for (const unit of job.units) {
|
|
19966
20137
|
for (const op of unit.ops()) {
|
|
19967
20138
|
if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
|
|
19968
|
-
extractedAttributesByI18nContext.
|
|
20139
|
+
const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
|
|
20140
|
+
attributes.push(op);
|
|
20141
|
+
extractedAttributesByI18nContext.set(op.i18nContext, attributes);
|
|
19969
20142
|
}
|
|
19970
20143
|
else if (op.kind === OpKind.I18nAttributes) {
|
|
19971
20144
|
i18nAttributesByElement.set(op.target, op);
|
|
@@ -20010,9 +20183,11 @@ function collectI18nConsts(job) {
|
|
|
20010
20183
|
i18nValuesByContext.set(op.i18nContext, mainVar);
|
|
20011
20184
|
// This i18n message may correspond to an individual extracted attribute. If so, The
|
|
20012
20185
|
// value of that attribute is updated to read the extracted i18n variable.
|
|
20013
|
-
const
|
|
20014
|
-
if (
|
|
20015
|
-
|
|
20186
|
+
const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
|
|
20187
|
+
if (attributesForMessage !== undefined) {
|
|
20188
|
+
for (const attr of attributesForMessage) {
|
|
20189
|
+
attr.expression = mainVar.clone();
|
|
20190
|
+
}
|
|
20016
20191
|
}
|
|
20017
20192
|
}
|
|
20018
20193
|
}
|
|
@@ -20099,7 +20274,7 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
20099
20274
|
let transformFn = undefined;
|
|
20100
20275
|
// If nescessary, add a post-processing step and resolve any placeholder params that are
|
|
20101
20276
|
// set in post-processing.
|
|
20102
|
-
if (messageOp.needsPostprocessing) {
|
|
20277
|
+
if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
|
|
20103
20278
|
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
20104
20279
|
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
20105
20280
|
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
@@ -20129,7 +20304,6 @@ function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
|
20129
20304
|
else {
|
|
20130
20305
|
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
20131
20306
|
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
20132
|
-
messageOp.needsPostprocessing = true;
|
|
20133
20307
|
}
|
|
20134
20308
|
}
|
|
20135
20309
|
}
|
|
@@ -20215,6 +20389,7 @@ function convertI18nText(job) {
|
|
|
20215
20389
|
let currentIcu = null;
|
|
20216
20390
|
const textNodeI18nBlocks = new Map();
|
|
20217
20391
|
const textNodeIcus = new Map();
|
|
20392
|
+
const icuPlaceholderByText = new Map();
|
|
20218
20393
|
for (const op of unit.create) {
|
|
20219
20394
|
switch (op.kind) {
|
|
20220
20395
|
case OpKind.I18nStart:
|
|
@@ -20239,7 +20414,19 @@ function convertI18nText(job) {
|
|
|
20239
20414
|
if (currentI18n !== null) {
|
|
20240
20415
|
textNodeI18nBlocks.set(op.xref, currentI18n);
|
|
20241
20416
|
textNodeIcus.set(op.xref, currentIcu);
|
|
20242
|
-
|
|
20417
|
+
if (op.icuPlaceholder !== null) {
|
|
20418
|
+
// Create an op to represent the ICU placeholder. Initially set its static text to the
|
|
20419
|
+
// value of the text op, though this may be overwritten later if this text op is a
|
|
20420
|
+
// placeholder for an interpolation.
|
|
20421
|
+
const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
|
|
20422
|
+
OpList.replace(op, icuPlaceholderOp);
|
|
20423
|
+
icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
|
|
20424
|
+
}
|
|
20425
|
+
else {
|
|
20426
|
+
// Otherwise just remove the text op, since its value is already accounted for in the
|
|
20427
|
+
// translated message.
|
|
20428
|
+
OpList.remove(op);
|
|
20429
|
+
}
|
|
20243
20430
|
}
|
|
20244
20431
|
break;
|
|
20245
20432
|
}
|
|
@@ -20254,6 +20441,7 @@ function convertI18nText(job) {
|
|
|
20254
20441
|
}
|
|
20255
20442
|
const i18nOp = textNodeI18nBlocks.get(op.target);
|
|
20256
20443
|
const icuOp = textNodeIcus.get(op.target);
|
|
20444
|
+
const icuPlaceholder = icuPlaceholderByText.get(op.target);
|
|
20257
20445
|
const contextId = icuOp ? icuOp.context : i18nOp.context;
|
|
20258
20446
|
const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing :
|
|
20259
20447
|
I18nParamResolutionTime.Creation;
|
|
@@ -20262,9 +20450,14 @@ function convertI18nText(job) {
|
|
|
20262
20450
|
const expr = op.interpolation.expressions[i];
|
|
20263
20451
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
20264
20452
|
// Later, we will modify this, and advance to a different point.
|
|
20265
|
-
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, op.interpolation.i18nPlaceholders[i], resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
20453
|
+
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, icuPlaceholder?.xref ?? null, op.interpolation.i18nPlaceholders[i] ?? null, resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
20266
20454
|
}
|
|
20267
20455
|
OpList.replaceWithMany(op, ops);
|
|
20456
|
+
// If this interpolation is part of an ICU placeholder, add the strings and expressions to
|
|
20457
|
+
// the placeholder.
|
|
20458
|
+
if (icuPlaceholder !== undefined) {
|
|
20459
|
+
icuPlaceholder.strings = op.interpolation.strings;
|
|
20460
|
+
}
|
|
20268
20461
|
break;
|
|
20269
20462
|
}
|
|
20270
20463
|
}
|
|
@@ -20447,7 +20640,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
20447
20640
|
op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
|
|
20448
20641
|
break;
|
|
20449
20642
|
case OpKind.Variable:
|
|
20450
|
-
varNames.set(op.xref, getVariableName(op.variable, state));
|
|
20643
|
+
varNames.set(op.xref, getVariableName(unit, op.variable, state));
|
|
20451
20644
|
break;
|
|
20452
20645
|
case OpKind.RepeaterCreate:
|
|
20453
20646
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
@@ -20502,15 +20695,23 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
20502
20695
|
});
|
|
20503
20696
|
}
|
|
20504
20697
|
}
|
|
20505
|
-
function getVariableName(variable, state) {
|
|
20698
|
+
function getVariableName(unit, variable, state) {
|
|
20506
20699
|
if (variable.name === null) {
|
|
20507
20700
|
switch (variable.kind) {
|
|
20508
20701
|
case SemanticVariableKind.Context:
|
|
20509
20702
|
variable.name = `ctx_r${state.index++}`;
|
|
20510
20703
|
break;
|
|
20511
20704
|
case SemanticVariableKind.Identifier:
|
|
20512
|
-
|
|
20513
|
-
|
|
20705
|
+
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
20706
|
+
// TODO: Prefix increment and `_r` are for compatiblity with the old naming scheme.
|
|
20707
|
+
// This has the potential to cause collisions when `ctx` is the identifier, so we need a
|
|
20708
|
+
// special check for that as well.
|
|
20709
|
+
const compatPrefix = variable.identifier === 'ctx' ? 'i' : '';
|
|
20710
|
+
variable.name = `${variable.identifier}_${compatPrefix}r${++state.index}`;
|
|
20711
|
+
}
|
|
20712
|
+
else {
|
|
20713
|
+
variable.name = `${variable.identifier}_i${state.index++}`;
|
|
20714
|
+
}
|
|
20514
20715
|
break;
|
|
20515
20716
|
default:
|
|
20516
20717
|
// TODO: Prefix increment for compatibility only.
|
|
@@ -20707,17 +20908,27 @@ const CREATE_ORDERING = [
|
|
|
20707
20908
|
* op kinds.
|
|
20708
20909
|
*/
|
|
20709
20910
|
const UPDATE_ORDERING = [
|
|
20710
|
-
{ test: kindWithInterpolationTest(OpKind.HostProperty, true) },
|
|
20711
|
-
{ test: kindWithInterpolationTest(OpKind.HostProperty, false) },
|
|
20712
20911
|
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
20713
20912
|
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
20714
20913
|
{ test: kindTest(OpKind.StyleProp) },
|
|
20715
20914
|
{ test: kindTest(OpKind.ClassProp) },
|
|
20716
|
-
{ test: kindWithInterpolationTest(OpKind.Property, true) },
|
|
20717
20915
|
{ test: kindWithInterpolationTest(OpKind.Attribute, true) },
|
|
20916
|
+
{ test: kindWithInterpolationTest(OpKind.Property, true) },
|
|
20718
20917
|
{ test: kindWithInterpolationTest(OpKind.Property, false) },
|
|
20719
20918
|
{ test: kindWithInterpolationTest(OpKind.Attribute, false) },
|
|
20720
20919
|
];
|
|
20920
|
+
/**
|
|
20921
|
+
* Host bindings have their own update ordering.
|
|
20922
|
+
*/
|
|
20923
|
+
const UPDATE_HOST_ORDERING = [
|
|
20924
|
+
{ test: kindWithInterpolationTest(OpKind.HostProperty, true) },
|
|
20925
|
+
{ test: kindWithInterpolationTest(OpKind.HostProperty, false) },
|
|
20926
|
+
{ test: kindTest(OpKind.Attribute) },
|
|
20927
|
+
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
20928
|
+
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
20929
|
+
{ test: kindTest(OpKind.StyleProp) },
|
|
20930
|
+
{ test: kindTest(OpKind.ClassProp) },
|
|
20931
|
+
];
|
|
20721
20932
|
/**
|
|
20722
20933
|
* The set of all op kinds we handle in the reordering phase.
|
|
20723
20934
|
*/
|
|
@@ -20738,7 +20949,8 @@ function orderOps(job) {
|
|
|
20738
20949
|
// Create mode:
|
|
20739
20950
|
orderWithin(unit.create, CREATE_ORDERING);
|
|
20740
20951
|
// Update mode:
|
|
20741
|
-
|
|
20952
|
+
const ordering = unit.job.kind === CompilationJobKind.Host ? UPDATE_HOST_ORDERING : UPDATE_ORDERING;
|
|
20953
|
+
orderWithin(unit.update, ordering);
|
|
20742
20954
|
}
|
|
20743
20955
|
}
|
|
20744
20956
|
/**
|
|
@@ -20793,21 +21005,39 @@ function keepLast(ops) {
|
|
|
20793
21005
|
* class property.
|
|
20794
21006
|
*/
|
|
20795
21007
|
function parseExtractedStyles(job) {
|
|
21008
|
+
const elements = new Map();
|
|
21009
|
+
for (const unit of job.units) {
|
|
21010
|
+
for (const op of unit.create) {
|
|
21011
|
+
if (isElementOrContainerOp(op)) {
|
|
21012
|
+
elements.set(op.xref, op);
|
|
21013
|
+
}
|
|
21014
|
+
}
|
|
21015
|
+
}
|
|
20796
21016
|
for (const unit of job.units) {
|
|
20797
21017
|
for (const op of unit.create) {
|
|
20798
21018
|
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
20799
21019
|
isStringLiteral(op.expression)) {
|
|
21020
|
+
const target = elements.get(op.target);
|
|
21021
|
+
if (target !== undefined && target.kind === OpKind.Template &&
|
|
21022
|
+
target.templateKind === TemplateKind.Structural) {
|
|
21023
|
+
// TemplateDefinitionBuilder will not apply class and style bindings to structural
|
|
21024
|
+
// directives; instead, it will leave them as attributes.
|
|
21025
|
+
// (It's not clear what that would mean, anyway -- classes and styles on a structural
|
|
21026
|
+
// element should probably be a parse error.)
|
|
21027
|
+
// TODO: We may be able to remove this once Template Pipeline is the default.
|
|
21028
|
+
continue;
|
|
21029
|
+
}
|
|
20800
21030
|
if (op.name === 'style') {
|
|
20801
21031
|
const parsedStyles = parse(op.expression.value);
|
|
20802
21032
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
20803
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null), op);
|
|
21033
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
20804
21034
|
}
|
|
20805
21035
|
OpList.remove(op);
|
|
20806
21036
|
}
|
|
20807
21037
|
else if (op.name === 'class') {
|
|
20808
21038
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
20809
21039
|
for (const parsedClass of parsedClasses) {
|
|
20810
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null), op);
|
|
21040
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
20811
21041
|
}
|
|
20812
21042
|
OpList.remove(op);
|
|
20813
21043
|
}
|
|
@@ -20831,15 +21061,6 @@ function removeContentSelectors(job) {
|
|
|
20831
21061
|
OpList.remove(op);
|
|
20832
21062
|
}
|
|
20833
21063
|
break;
|
|
20834
|
-
case OpKind.Projection:
|
|
20835
|
-
// op.attributes is an array of [attr1-name, attr1-value, attr2-name, attr2-value, ...],
|
|
20836
|
-
// find the "select" attribute and remove its name and corresponding value.
|
|
20837
|
-
for (let i = op.attributes.length - 2; i >= 0; i -= 2) {
|
|
20838
|
-
if (isSelectAttribute(op.attributes[i])) {
|
|
20839
|
-
op.attributes.splice(i, 2);
|
|
20840
|
-
}
|
|
20841
|
-
}
|
|
20842
|
-
break;
|
|
20843
21064
|
}
|
|
20844
21065
|
}
|
|
20845
21066
|
}
|
|
@@ -20973,22 +21194,37 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
|
20973
21194
|
i18nBlock = null;
|
|
20974
21195
|
break;
|
|
20975
21196
|
case OpKind.Template:
|
|
20976
|
-
|
|
20977
|
-
|
|
20978
|
-
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
|
|
20983
|
-
|
|
20984
|
-
|
|
21197
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
21198
|
+
break;
|
|
21199
|
+
case OpKind.RepeaterCreate:
|
|
21200
|
+
// Propagate i18n blocks to the @for template.
|
|
21201
|
+
const forView = unit.job.views.get(op.xref);
|
|
21202
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
21203
|
+
// Then if there's an @empty template, propagate the i18n blocks for it as well.
|
|
21204
|
+
if (op.emptyView !== null) {
|
|
21205
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
|
|
20985
21206
|
}
|
|
20986
|
-
|
|
20987
|
-
subTemplateIndex = propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
|
|
21207
|
+
break;
|
|
20988
21208
|
}
|
|
20989
21209
|
}
|
|
20990
21210
|
return subTemplateIndex;
|
|
20991
21211
|
}
|
|
21212
|
+
/**
|
|
21213
|
+
* Propagate i18n blocks for a view.
|
|
21214
|
+
*/
|
|
21215
|
+
function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
|
|
21216
|
+
// We found an <ng-template> inside an i18n block; increment the sub-template counter and
|
|
21217
|
+
// wrap the template's view in a child i18n block.
|
|
21218
|
+
if (i18nPlaceholder !== undefined) {
|
|
21219
|
+
if (i18nBlock === null) {
|
|
21220
|
+
throw Error('Expected template with i18n placeholder to be in an i18n block.');
|
|
21221
|
+
}
|
|
21222
|
+
subTemplateIndex++;
|
|
21223
|
+
wrapTemplateWithI18n(view, i18nBlock);
|
|
21224
|
+
}
|
|
21225
|
+
// Continue traversing inside the template's view.
|
|
21226
|
+
return propagateI18nBlocksToTemplates(view, subTemplateIndex);
|
|
21227
|
+
}
|
|
20992
21228
|
/**
|
|
20993
21229
|
* Wraps a template view with i18n start and end ops.
|
|
20994
21230
|
*/
|
|
@@ -20996,8 +21232,10 @@ function wrapTemplateWithI18n(unit, parentI18n) {
|
|
|
20996
21232
|
// Only add i18n ops if they have not already been propagated to this template.
|
|
20997
21233
|
if (unit.create.head.next?.kind !== OpKind.I18nStart) {
|
|
20998
21234
|
const id = unit.job.allocateXrefId();
|
|
20999
|
-
OpList.insertAfter(
|
|
21000
|
-
|
|
21235
|
+
OpList.insertAfter(
|
|
21236
|
+
// Nested ng-template i18n start/end ops should not recieve source spans.
|
|
21237
|
+
createI18nStartOp(id, parentI18n.message, parentI18n.root, null), unit.create.head);
|
|
21238
|
+
OpList.insertBefore(createI18nEndOp(id, null), unit.create.tail);
|
|
21001
21239
|
}
|
|
21002
21240
|
}
|
|
21003
21241
|
|
|
@@ -21154,17 +21392,13 @@ function disableBindings() {
|
|
|
21154
21392
|
function enableBindings() {
|
|
21155
21393
|
return call(Identifiers.enableBindings, [], null);
|
|
21156
21394
|
}
|
|
21157
|
-
function listener(name, handlerFn, sourceSpan) {
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
}
|
|
21163
|
-
|
|
21164
|
-
return call(Identifiers.syntheticHostListener, [
|
|
21165
|
-
literal(name),
|
|
21166
|
-
handlerFn,
|
|
21167
|
-
], sourceSpan);
|
|
21395
|
+
function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
|
|
21396
|
+
const args = [literal(name), handlerFn];
|
|
21397
|
+
if (eventTargetResolver !== null) {
|
|
21398
|
+
args.push(literal(false)); // `useCapture` flag, defaults to `false`
|
|
21399
|
+
args.push(importExpr(eventTargetResolver));
|
|
21400
|
+
}
|
|
21401
|
+
return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
|
|
21168
21402
|
}
|
|
21169
21403
|
function pipe(slot, name) {
|
|
21170
21404
|
return call(Identifiers.pipe, [
|
|
@@ -21262,22 +21496,22 @@ function projectionDef(def) {
|
|
|
21262
21496
|
}
|
|
21263
21497
|
function projection(slot, projectionSlotIndex, attributes, sourceSpan) {
|
|
21264
21498
|
const args = [literal(slot)];
|
|
21265
|
-
if (projectionSlotIndex !== 0 || attributes
|
|
21499
|
+
if (projectionSlotIndex !== 0 || attributes !== null) {
|
|
21266
21500
|
args.push(literal(projectionSlotIndex));
|
|
21267
|
-
if (attributes
|
|
21268
|
-
args.push(
|
|
21501
|
+
if (attributes !== null) {
|
|
21502
|
+
args.push(attributes);
|
|
21269
21503
|
}
|
|
21270
21504
|
}
|
|
21271
21505
|
return call(Identifiers.projection, args, sourceSpan);
|
|
21272
21506
|
}
|
|
21273
|
-
function i18nStart(slot, constIndex, subTemplateIndex) {
|
|
21507
|
+
function i18nStart(slot, constIndex, subTemplateIndex, sourceSpan) {
|
|
21274
21508
|
const args = [literal(slot), literal(constIndex)];
|
|
21275
21509
|
if (subTemplateIndex !== null) {
|
|
21276
21510
|
args.push(literal(subTemplateIndex));
|
|
21277
21511
|
}
|
|
21278
|
-
return call(Identifiers.i18nStart, args,
|
|
21512
|
+
return call(Identifiers.i18nStart, args, sourceSpan);
|
|
21279
21513
|
}
|
|
21280
|
-
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, sourceSpan) {
|
|
21514
|
+
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, emptyTag, emptyConstIndex, sourceSpan) {
|
|
21281
21515
|
const args = [
|
|
21282
21516
|
literal(slot),
|
|
21283
21517
|
variable(viewFnName),
|
|
@@ -21291,6 +21525,12 @@ function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByF
|
|
|
21291
21525
|
args.push(literal(trackByUsesComponentInstance));
|
|
21292
21526
|
if (emptyViewFnName !== null) {
|
|
21293
21527
|
args.push(variable(emptyViewFnName), literal(emptyDecls), literal(emptyVars));
|
|
21528
|
+
if (emptyTag !== null || emptyConstIndex !== null) {
|
|
21529
|
+
args.push(literal(emptyTag));
|
|
21530
|
+
}
|
|
21531
|
+
if (emptyConstIndex !== null) {
|
|
21532
|
+
args.push(literal(emptyConstIndex));
|
|
21533
|
+
}
|
|
21294
21534
|
}
|
|
21295
21535
|
}
|
|
21296
21536
|
return call(Identifiers.repeaterCreate, args, sourceSpan);
|
|
@@ -21301,15 +21541,15 @@ function repeater(collection, sourceSpan) {
|
|
|
21301
21541
|
function deferWhen(prefetch, expr, sourceSpan) {
|
|
21302
21542
|
return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
|
|
21303
21543
|
}
|
|
21304
|
-
function i18n(slot, constIndex, subTemplateIndex) {
|
|
21544
|
+
function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
|
|
21305
21545
|
const args = [literal(slot), literal(constIndex)];
|
|
21306
21546
|
if (subTemplateIndex) {
|
|
21307
21547
|
args.push(literal(subTemplateIndex));
|
|
21308
21548
|
}
|
|
21309
|
-
return call(Identifiers.i18n, args,
|
|
21549
|
+
return call(Identifiers.i18n, args, sourceSpan);
|
|
21310
21550
|
}
|
|
21311
|
-
function i18nEnd() {
|
|
21312
|
-
return call(Identifiers.i18nEnd, [],
|
|
21551
|
+
function i18nEnd(endSourceSpan) {
|
|
21552
|
+
return call(Identifiers.i18nEnd, [], endSourceSpan);
|
|
21313
21553
|
}
|
|
21314
21554
|
function i18nAttributes(slot, i18nAttributesConfig) {
|
|
21315
21555
|
const args = [literal(slot), literal(i18nAttributesConfig)];
|
|
@@ -21425,8 +21665,12 @@ function classMapInterpolate(strings, expressions, sourceSpan) {
|
|
|
21425
21665
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
21426
21666
|
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
|
|
21427
21667
|
}
|
|
21428
|
-
function hostProperty(name, expression, sourceSpan) {
|
|
21429
|
-
|
|
21668
|
+
function hostProperty(name, expression, sanitizer, sourceSpan) {
|
|
21669
|
+
const args = [literal(name), expression];
|
|
21670
|
+
if (sanitizer !== null) {
|
|
21671
|
+
args.push(sanitizer);
|
|
21672
|
+
}
|
|
21673
|
+
return call(Identifiers.hostProperty, args, sourceSpan);
|
|
21430
21674
|
}
|
|
21431
21675
|
function syntheticHostProperty(name, expression, sourceSpan) {
|
|
21432
21676
|
return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
|
|
@@ -21644,14 +21888,12 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
|
|
|
21644
21888
|
}
|
|
21645
21889
|
|
|
21646
21890
|
/**
|
|
21647
|
-
* Map of
|
|
21891
|
+
* Map of target resolvers for event listeners.
|
|
21648
21892
|
*/
|
|
21649
|
-
const
|
|
21650
|
-
[
|
|
21651
|
-
[
|
|
21652
|
-
[
|
|
21653
|
-
[SanitizerFn.Script, Identifiers.sanitizeScript],
|
|
21654
|
-
[SanitizerFn.Style, Identifiers.sanitizeStyle], [SanitizerFn.Url, Identifiers.sanitizeUrl]
|
|
21893
|
+
const GLOBAL_TARGET_RESOLVERS$1 = new Map([
|
|
21894
|
+
['window', Identifiers.resolveWindow],
|
|
21895
|
+
['document', Identifiers.resolveDocument],
|
|
21896
|
+
['body', Identifiers.resolveBody],
|
|
21655
21897
|
]);
|
|
21656
21898
|
/**
|
|
21657
21899
|
* Compiles semantic operations across all views and generates output `o.Statement`s with actual
|
|
@@ -21667,6 +21909,31 @@ function reify(job) {
|
|
|
21667
21909
|
reifyUpdateOperations(unit, unit.update);
|
|
21668
21910
|
}
|
|
21669
21911
|
}
|
|
21912
|
+
/**
|
|
21913
|
+
* This function can be used a sanity check -- it walks every expression in the const pool, and
|
|
21914
|
+
* every expression reachable from an op, and makes sure that there are no IR expressions
|
|
21915
|
+
* left. This is nice to use for debugging mysterious failures where an IR expression cannot be
|
|
21916
|
+
* output from the output AST code.
|
|
21917
|
+
*/
|
|
21918
|
+
function ensureNoIrForDebug(job) {
|
|
21919
|
+
for (const stmt of job.pool.statements) {
|
|
21920
|
+
transformExpressionsInStatement(stmt, expr => {
|
|
21921
|
+
if (isIrExpression(expr)) {
|
|
21922
|
+
throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
|
|
21923
|
+
}
|
|
21924
|
+
return expr;
|
|
21925
|
+
}, VisitorContextFlag.None);
|
|
21926
|
+
}
|
|
21927
|
+
for (const unit of job.units) {
|
|
21928
|
+
for (const op of unit.ops()) {
|
|
21929
|
+
visitExpressionsInOp(op, expr => {
|
|
21930
|
+
if (isIrExpression(expr)) {
|
|
21931
|
+
throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
|
|
21932
|
+
}
|
|
21933
|
+
});
|
|
21934
|
+
}
|
|
21935
|
+
}
|
|
21936
|
+
}
|
|
21670
21937
|
function reifyCreateOperations(unit, ops) {
|
|
21671
21938
|
for (const op of ops) {
|
|
21672
21939
|
transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
|
|
@@ -21675,31 +21942,31 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21675
21942
|
OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
|
|
21676
21943
|
break;
|
|
21677
21944
|
case OpKind.ElementStart:
|
|
21678
|
-
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21945
|
+
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21679
21946
|
break;
|
|
21680
21947
|
case OpKind.Element:
|
|
21681
|
-
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21948
|
+
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21682
21949
|
break;
|
|
21683
21950
|
case OpKind.ElementEnd:
|
|
21684
21951
|
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
21685
21952
|
break;
|
|
21686
21953
|
case OpKind.ContainerStart:
|
|
21687
|
-
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21954
|
+
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21688
21955
|
break;
|
|
21689
21956
|
case OpKind.Container:
|
|
21690
|
-
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21957
|
+
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21691
21958
|
break;
|
|
21692
21959
|
case OpKind.ContainerEnd:
|
|
21693
21960
|
OpList.replace(op, elementContainerEnd());
|
|
21694
21961
|
break;
|
|
21695
21962
|
case OpKind.I18nStart:
|
|
21696
|
-
OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21963
|
+
OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
|
|
21697
21964
|
break;
|
|
21698
21965
|
case OpKind.I18nEnd:
|
|
21699
|
-
OpList.replace(op, i18nEnd());
|
|
21966
|
+
OpList.replace(op, i18nEnd(op.sourceSpan));
|
|
21700
21967
|
break;
|
|
21701
21968
|
case OpKind.I18n:
|
|
21702
|
-
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21969
|
+
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
|
|
21703
21970
|
break;
|
|
21704
21971
|
case OpKind.I18nAttributes:
|
|
21705
21972
|
if (op.i18nAttributesConfig === null) {
|
|
@@ -21715,7 +21982,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21715
21982
|
throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
|
|
21716
21983
|
}
|
|
21717
21984
|
const childView = unit.job.views.get(op.xref);
|
|
21718
|
-
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.
|
|
21985
|
+
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21719
21986
|
break;
|
|
21720
21987
|
case OpKind.DisableBindings:
|
|
21721
21988
|
OpList.replace(op, disableBindings());
|
|
@@ -21728,10 +21995,11 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21728
21995
|
break;
|
|
21729
21996
|
case OpKind.Listener:
|
|
21730
21997
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
21731
|
-
const
|
|
21732
|
-
|
|
21733
|
-
|
|
21734
|
-
|
|
21998
|
+
const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
|
|
21999
|
+
if (eventTargetResolver === undefined) {
|
|
22000
|
+
throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
|
|
22001
|
+
}
|
|
22002
|
+
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
21735
22003
|
break;
|
|
21736
22004
|
case OpKind.Variable:
|
|
21737
22005
|
if (op.variable.name === null) {
|
|
@@ -21816,7 +22084,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21816
22084
|
emptyDecls = emptyView.decls;
|
|
21817
22085
|
emptyVars = emptyView.vars;
|
|
21818
22086
|
}
|
|
21819
|
-
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.
|
|
22087
|
+
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.emptyTag, op.emptyAttributes, op.wholeSourceSpan));
|
|
21820
22088
|
break;
|
|
21821
22089
|
case OpKind.Statement:
|
|
21822
22090
|
// Pass statement operations directly through.
|
|
@@ -21894,7 +22162,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21894
22162
|
OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
|
|
21895
22163
|
}
|
|
21896
22164
|
else {
|
|
21897
|
-
OpList.replace(op, hostProperty(op.name, op.expression, op.sourceSpan));
|
|
22165
|
+
OpList.replace(op, hostProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
21898
22166
|
}
|
|
21899
22167
|
}
|
|
21900
22168
|
break;
|
|
@@ -21973,8 +22241,6 @@ function reifyIrExpression(expr) {
|
|
|
21973
22241
|
return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21974
22242
|
case ExpressionKind.PipeBindingVariadic:
|
|
21975
22243
|
return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21976
|
-
case ExpressionKind.SanitizerExpr:
|
|
21977
|
-
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
21978
22244
|
case ExpressionKind.SlotLiteralExpr:
|
|
21979
22245
|
return literal(expr.slot.slot);
|
|
21980
22246
|
default:
|
|
@@ -22267,10 +22533,11 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingSt
|
|
|
22267
22533
|
}
|
|
22268
22534
|
break;
|
|
22269
22535
|
case OpKind.Template:
|
|
22536
|
+
const view = job.views.get(op.xref);
|
|
22270
22537
|
if (op.i18nPlaceholder === undefined) {
|
|
22271
22538
|
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22272
22539
|
// blocks.
|
|
22273
|
-
resolvePlaceholdersForView(job,
|
|
22540
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22274
22541
|
}
|
|
22275
22542
|
else {
|
|
22276
22543
|
if (currentOps === null) {
|
|
@@ -22281,14 +22548,59 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingSt
|
|
|
22281
22548
|
// the current template as a pending structural directive to be recorded when we find
|
|
22282
22549
|
// the element, content, or template it belongs to. This allows us to create combined
|
|
22283
22550
|
// values that represent, e.g. the start of a template and element at the same time.
|
|
22284
|
-
resolvePlaceholdersForView(job,
|
|
22551
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
|
|
22285
22552
|
}
|
|
22286
22553
|
else {
|
|
22287
22554
|
// If this is some other kind of template, we can record its start, recurse into its
|
|
22288
22555
|
// view, and then record its end.
|
|
22289
|
-
recordTemplateStart(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22290
|
-
resolvePlaceholdersForView(job,
|
|
22291
|
-
recordTemplateClose(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22556
|
+
recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22557
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22558
|
+
recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22559
|
+
pendingStructuralDirective = undefined;
|
|
22560
|
+
}
|
|
22561
|
+
}
|
|
22562
|
+
break;
|
|
22563
|
+
case OpKind.RepeaterCreate:
|
|
22564
|
+
if (pendingStructuralDirective !== undefined) {
|
|
22565
|
+
throw Error('AssertionError: Unexpected structural directive associated with @for block');
|
|
22566
|
+
}
|
|
22567
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22568
|
+
// template and the (optional) third is for the @empty template.
|
|
22569
|
+
const forSlot = op.handle.slot + 1;
|
|
22570
|
+
const forView = job.views.get(op.xref);
|
|
22571
|
+
// First record all of the placeholders for the @for template.
|
|
22572
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22573
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22574
|
+
// blocks.
|
|
22575
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22576
|
+
}
|
|
22577
|
+
else {
|
|
22578
|
+
if (currentOps === null) {
|
|
22579
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22580
|
+
}
|
|
22581
|
+
recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22582
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22583
|
+
recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22584
|
+
pendingStructuralDirective = undefined;
|
|
22585
|
+
}
|
|
22586
|
+
// Then if there's an @empty template, add its placeholders as well.
|
|
22587
|
+
if (op.emptyView !== null) {
|
|
22588
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22589
|
+
// template and the (optional) third is for the @empty template.
|
|
22590
|
+
const emptySlot = op.handle.slot + 2;
|
|
22591
|
+
const emptyView = job.views.get(op.emptyView);
|
|
22592
|
+
if (op.emptyI18nPlaceholder === undefined) {
|
|
22593
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22594
|
+
// blocks.
|
|
22595
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22596
|
+
}
|
|
22597
|
+
else {
|
|
22598
|
+
if (currentOps === null) {
|
|
22599
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22600
|
+
}
|
|
22601
|
+
recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22602
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22603
|
+
recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22292
22604
|
pendingStructuralDirective = undefined;
|
|
22293
22605
|
}
|
|
22294
22606
|
}
|
|
@@ -22336,8 +22648,8 @@ function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
|
|
|
22336
22648
|
/**
|
|
22337
22649
|
* Records an i18n param value for the start of a template.
|
|
22338
22650
|
*/
|
|
22339
|
-
function recordTemplateStart(job,
|
|
22340
|
-
let { startName, closeName } =
|
|
22651
|
+
function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22652
|
+
let { startName, closeName } = i18nPlaceholder;
|
|
22341
22653
|
let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
|
|
22342
22654
|
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22343
22655
|
// placeholder accounts for the start and close of the element.
|
|
@@ -22352,20 +22664,20 @@ function recordTemplateStart(job, op, i18nContext, i18nBlock, structuralDirectiv
|
|
|
22352
22664
|
}
|
|
22353
22665
|
// Record the start of the template. For the sub-template index, pass the index for the template's
|
|
22354
22666
|
// view, rather than the current i18n block's index.
|
|
22355
|
-
addParam(i18nContext.params, startName,
|
|
22667
|
+
addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22356
22668
|
}
|
|
22357
22669
|
/**
|
|
22358
22670
|
* Records an i18n param value for the closing of a template.
|
|
22359
22671
|
*/
|
|
22360
|
-
function recordTemplateClose(job,
|
|
22361
|
-
const { startName, closeName } =
|
|
22672
|
+
function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22673
|
+
const { startName, closeName } = i18nPlaceholder;
|
|
22362
22674
|
const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
|
|
22363
22675
|
// Self-closing tags don't have a closing tag placeholder, instead the template's closing is
|
|
22364
22676
|
// recorded via an additional flag on the template start value.
|
|
22365
22677
|
if (closeName) {
|
|
22366
22678
|
// Record the closing of the template. For the sub-template index, pass the index for the
|
|
22367
22679
|
// template's view, rather than the current i18n block's index.
|
|
22368
|
-
addParam(i18nContext.params, closeName,
|
|
22680
|
+
addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22369
22681
|
// If the template is associated with a structural directive, record the structural directive's
|
|
22370
22682
|
// closing after. Since this template must be in the structural directive's view, we can just
|
|
22371
22683
|
// directly use the current i18n block's sub-template index.
|
|
@@ -22378,8 +22690,8 @@ function recordTemplateClose(job, op, i18nContext, i18nBlock, structuralDirectiv
|
|
|
22378
22690
|
* Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
|
|
22379
22691
|
* the child i18n block inside the template.
|
|
22380
22692
|
*/
|
|
22381
|
-
function getSubTemplateIndexForTemplateTag(job, i18nOp,
|
|
22382
|
-
for (const childOp of
|
|
22693
|
+
function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
|
|
22694
|
+
for (const childOp of view.create) {
|
|
22383
22695
|
if (childOp.kind === OpKind.I18nStart) {
|
|
22384
22696
|
return childOp.subTemplateIndex;
|
|
22385
22697
|
}
|
|
@@ -22402,6 +22714,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22402
22714
|
// Record all of the i18n context ops, and the sub-template index for each i18n op.
|
|
22403
22715
|
const subTemplateIndicies = new Map();
|
|
22404
22716
|
const i18nContexts = new Map();
|
|
22717
|
+
const icuPlaceholders = new Map();
|
|
22405
22718
|
for (const unit of job.units) {
|
|
22406
22719
|
for (const op of unit.create) {
|
|
22407
22720
|
switch (op.kind) {
|
|
@@ -22411,6 +22724,9 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22411
22724
|
case OpKind.I18nContext:
|
|
22412
22725
|
i18nContexts.set(op.xref, op);
|
|
22413
22726
|
break;
|
|
22727
|
+
case OpKind.IcuPlaceholder:
|
|
22728
|
+
icuPlaceholders.set(op.xref, op);
|
|
22729
|
+
break;
|
|
22414
22730
|
}
|
|
22415
22731
|
}
|
|
22416
22732
|
}
|
|
@@ -22424,76 +22740,32 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22424
22740
|
for (const unit of job.units) {
|
|
22425
22741
|
for (const op of unit.update) {
|
|
22426
22742
|
if (op.kind === OpKind.I18nExpression) {
|
|
22427
|
-
const i18nContext = i18nContexts.get(op.context);
|
|
22428
22743
|
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22429
22744
|
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
22430
|
-
|
|
22431
|
-
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22432
|
-
i18nContext.params :
|
|
22433
|
-
i18nContext.postprocessingParams;
|
|
22434
|
-
const values = params.get(op.i18nPlaceholder) || [];
|
|
22435
|
-
values.push({
|
|
22745
|
+
const value = {
|
|
22436
22746
|
value: index,
|
|
22437
22747
|
subTemplateIndex: subTemplateIndex,
|
|
22438
22748
|
flags: I18nParamValueFlags.ExpressionIndex
|
|
22439
|
-
}
|
|
22440
|
-
|
|
22749
|
+
};
|
|
22750
|
+
updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
|
|
22441
22751
|
expressionIndices.set(referenceIndex(op), index + 1);
|
|
22442
22752
|
}
|
|
22443
22753
|
}
|
|
22444
22754
|
}
|
|
22445
22755
|
}
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
|
|
22453
|
-
|
|
22454
|
-
|
|
22455
|
-
node.visit(new ResolveIcuPlaceholdersVisitor(op.postprocessingParams));
|
|
22456
|
-
}
|
|
22457
|
-
}
|
|
22458
|
-
}
|
|
22756
|
+
function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
|
|
22757
|
+
if (op.i18nPlaceholder !== null) {
|
|
22758
|
+
const i18nContext = i18nContexts.get(op.context);
|
|
22759
|
+
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22760
|
+
i18nContext.params :
|
|
22761
|
+
i18nContext.postprocessingParams;
|
|
22762
|
+
const values = params.get(op.i18nPlaceholder) || [];
|
|
22763
|
+
values.push(value);
|
|
22764
|
+
params.set(op.i18nPlaceholder, values);
|
|
22459
22765
|
}
|
|
22460
|
-
|
|
22461
|
-
|
|
22462
|
-
|
|
22463
|
-
*/
|
|
22464
|
-
class ResolveIcuPlaceholdersVisitor extends RecurseVisitor {
|
|
22465
|
-
constructor(params) {
|
|
22466
|
-
super();
|
|
22467
|
-
this.params = params;
|
|
22468
|
-
}
|
|
22469
|
-
visitContainerPlaceholder(placeholder) {
|
|
22470
|
-
// Add the start and end source span for container placeholders. These need to be recorded for
|
|
22471
|
-
// elements inside ICUs. The slots for the nodes were recorded separately under the i18n
|
|
22472
|
-
// block's context as part of the `resolveI18nElementPlaceholders` phase.
|
|
22473
|
-
if (placeholder.startName && placeholder.startSourceSpan &&
|
|
22474
|
-
!this.params.has(placeholder.startName)) {
|
|
22475
|
-
this.params.set(placeholder.startName, [{
|
|
22476
|
-
value: placeholder.startSourceSpan?.toString(),
|
|
22477
|
-
subTemplateIndex: null,
|
|
22478
|
-
flags: I18nParamValueFlags.None
|
|
22479
|
-
}]);
|
|
22480
|
-
}
|
|
22481
|
-
if (placeholder.closeName && placeholder.endSourceSpan &&
|
|
22482
|
-
!this.params.has(placeholder.closeName)) {
|
|
22483
|
-
this.params.set(placeholder.closeName, [{
|
|
22484
|
-
value: placeholder.endSourceSpan?.toString(),
|
|
22485
|
-
subTemplateIndex: null,
|
|
22486
|
-
flags: I18nParamValueFlags.None
|
|
22487
|
-
}]);
|
|
22488
|
-
}
|
|
22489
|
-
}
|
|
22490
|
-
visitTagPlaceholder(placeholder) {
|
|
22491
|
-
super.visitTagPlaceholder(placeholder);
|
|
22492
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22493
|
-
}
|
|
22494
|
-
visitBlockPlaceholder(placeholder) {
|
|
22495
|
-
super.visitBlockPlaceholder(placeholder);
|
|
22496
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22766
|
+
if (op.icuPlaceholder !== null) {
|
|
22767
|
+
const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
|
|
22768
|
+
icuPlaceholderOp?.expressionPlaceholders.push(value);
|
|
22497
22769
|
}
|
|
22498
22770
|
}
|
|
22499
22771
|
|
|
@@ -22596,12 +22868,20 @@ function processLexicalScope(unit, ops, savedView) {
|
|
|
22596
22868
|
}
|
|
22597
22869
|
|
|
22598
22870
|
/**
|
|
22599
|
-
*
|
|
22871
|
+
* Map of security contexts to their sanitizer function.
|
|
22872
|
+
*/
|
|
22873
|
+
const sanitizerFns = new Map([
|
|
22874
|
+
[SecurityContext.HTML, Identifiers.sanitizeHtml],
|
|
22875
|
+
[SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl],
|
|
22876
|
+
[SecurityContext.SCRIPT, Identifiers.sanitizeScript],
|
|
22877
|
+
[SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl]
|
|
22878
|
+
]);
|
|
22879
|
+
/**
|
|
22880
|
+
* Map of security contexts to their trusted value function.
|
|
22600
22881
|
*/
|
|
22601
|
-
const
|
|
22602
|
-
[SecurityContext.HTML,
|
|
22603
|
-
[SecurityContext.
|
|
22604
|
-
[SecurityContext.RESOURCE_URL, SanitizerFn.ResourceUrl]
|
|
22882
|
+
const trustedValueFns = new Map([
|
|
22883
|
+
[SecurityContext.HTML, Identifiers.trustConstantHtml],
|
|
22884
|
+
[SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl],
|
|
22605
22885
|
]);
|
|
22606
22886
|
/**
|
|
22607
22887
|
* Resolves sanitization functions for ops that need them.
|
|
@@ -22609,24 +22889,61 @@ const sanitizers = new Map([
|
|
|
22609
22889
|
function resolveSanitizers(job) {
|
|
22610
22890
|
for (const unit of job.units) {
|
|
22611
22891
|
const elements = createOpXrefMap(unit);
|
|
22612
|
-
|
|
22892
|
+
// For normal element bindings we create trusted values for security sensitive constant
|
|
22893
|
+
// attributes. However, for host bindings we skip this step (this matches what
|
|
22894
|
+
// TemplateDefinitionBuilder does).
|
|
22895
|
+
// TODO: Is the TDB behavior correct here?
|
|
22896
|
+
if (job.kind !== CompilationJobKind.Host) {
|
|
22897
|
+
for (const op of unit.create) {
|
|
22898
|
+
if (op.kind === OpKind.ExtractedAttribute) {
|
|
22899
|
+
const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22900
|
+
op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
|
|
22901
|
+
}
|
|
22902
|
+
}
|
|
22903
|
+
}
|
|
22613
22904
|
for (const op of unit.update) {
|
|
22614
22905
|
switch (op.kind) {
|
|
22615
22906
|
case OpKind.Property:
|
|
22616
22907
|
case OpKind.Attribute:
|
|
22617
|
-
|
|
22618
|
-
|
|
22908
|
+
case OpKind.HostProperty:
|
|
22909
|
+
let sanitizerFn = null;
|
|
22910
|
+
if (Array.isArray(op.securityContext) && op.securityContext.length === 2 &&
|
|
22911
|
+
op.securityContext.indexOf(SecurityContext.URL) > -1 &&
|
|
22912
|
+
op.securityContext.indexOf(SecurityContext.RESOURCE_URL) > -1) {
|
|
22913
|
+
// When the host element isn't known, some URL attributes (such as "src" and "href") may
|
|
22914
|
+
// be part of multiple different security contexts. In this case we use special
|
|
22915
|
+
// sanitization function and select the actual sanitizer at runtime based on a tag name
|
|
22916
|
+
// that is provided while invoking sanitization function.
|
|
22917
|
+
sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
|
|
22918
|
+
}
|
|
22919
|
+
else {
|
|
22920
|
+
sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22921
|
+
}
|
|
22922
|
+
op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
|
|
22619
22923
|
// If there was no sanitization function found based on the security context of an
|
|
22620
22924
|
// attribute/property, check whether this attribute/property is one of the
|
|
22621
22925
|
// security-sensitive <iframe> attributes (and that the current element is actually an
|
|
22622
22926
|
// <iframe>).
|
|
22623
22927
|
if (op.sanitizer === null) {
|
|
22624
|
-
|
|
22625
|
-
if (
|
|
22626
|
-
|
|
22928
|
+
let isIframe = false;
|
|
22929
|
+
if (job.kind === CompilationJobKind.Host || op.kind === OpKind.HostProperty) {
|
|
22930
|
+
// Note: for host bindings defined on a directive, we do not try to find all
|
|
22931
|
+
// possible places where it can be matched, so we can not determine whether
|
|
22932
|
+
// the host element is an <iframe>. In this case, we just assume it is and append a
|
|
22933
|
+
// validation function, which is invoked at runtime and would have access to the
|
|
22934
|
+
// underlying DOM element to check if it's an <iframe> and if so - run extra checks.
|
|
22935
|
+
isIframe = true;
|
|
22936
|
+
}
|
|
22937
|
+
else {
|
|
22938
|
+
// For a normal binding we can just check if the element its on is an iframe.
|
|
22939
|
+
const ownerOp = elements.get(op.target);
|
|
22940
|
+
if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
|
|
22941
|
+
throw Error('Property should have an element-like owner');
|
|
22942
|
+
}
|
|
22943
|
+
isIframe = isIframeElement$1(ownerOp);
|
|
22627
22944
|
}
|
|
22628
|
-
if (
|
|
22629
|
-
op.sanitizer =
|
|
22945
|
+
if (isIframe && isIframeSecuritySensitiveAttr(op.name)) {
|
|
22946
|
+
op.sanitizer = importExpr(Identifiers.validateIframeAttribute);
|
|
22630
22947
|
}
|
|
22631
22948
|
}
|
|
22632
22949
|
break;
|
|
@@ -22640,6 +22957,22 @@ function resolveSanitizers(job) {
|
|
|
22640
22957
|
function isIframeElement$1(op) {
|
|
22641
22958
|
return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
|
|
22642
22959
|
}
|
|
22960
|
+
/**
|
|
22961
|
+
* Asserts that there is only a single security context and returns it.
|
|
22962
|
+
*/
|
|
22963
|
+
function getOnlySecurityContext(securityContext) {
|
|
22964
|
+
if (Array.isArray(securityContext)) {
|
|
22965
|
+
if (securityContext.length > 1) {
|
|
22966
|
+
// TODO: What should we do here? TDB just took the first one, but this feels like something we
|
|
22967
|
+
// would want to know about and create a special case for like we did for Url/ResourceUrl. My
|
|
22968
|
+
// guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
|
|
22969
|
+
// do turn out to be other cases, throwing an error until we can address it feels safer.
|
|
22970
|
+
throw Error(`AssertionError: Ambiguous security context`);
|
|
22971
|
+
}
|
|
22972
|
+
return securityContext[0] || SecurityContext.NONE;
|
|
22973
|
+
}
|
|
22974
|
+
return securityContext;
|
|
22975
|
+
}
|
|
22643
22976
|
|
|
22644
22977
|
/**
|
|
22645
22978
|
* When inside of a listener, we may need access to one or more enclosing views. Therefore, each
|
|
@@ -22743,6 +23076,8 @@ function allocateSlots(job) {
|
|
|
22743
23076
|
// operation itself, so it can be emitted later.
|
|
22744
23077
|
const childView = job.views.get(op.xref);
|
|
22745
23078
|
op.decls = childView.decls;
|
|
23079
|
+
// TODO: currently we handle the decls for the RepeaterCreate empty template in the reify
|
|
23080
|
+
// phase. We should handle that here instead.
|
|
22746
23081
|
}
|
|
22747
23082
|
}
|
|
22748
23083
|
}
|
|
@@ -22882,6 +23217,9 @@ function generateTrackFns(job) {
|
|
|
22882
23217
|
// Find all component context reads.
|
|
22883
23218
|
let usesComponentContext = false;
|
|
22884
23219
|
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
23220
|
+
if (expr instanceof PipeBindingExpr || expr instanceof PipeBindingVariadicExpr) {
|
|
23221
|
+
throw new Error(`Illegal State: Pipes are not allowed in this context`);
|
|
23222
|
+
}
|
|
22885
23223
|
if (expr instanceof TrackContextExpr) {
|
|
22886
23224
|
usesComponentContext = true;
|
|
22887
23225
|
return variable('this');
|
|
@@ -23066,6 +23404,8 @@ function countVariables(job) {
|
|
|
23066
23404
|
}
|
|
23067
23405
|
const childView = job.views.get(op.xref);
|
|
23068
23406
|
op.vars = childView.vars;
|
|
23407
|
+
// TODO: currently we handle the vars for the RepeaterCreate empty template in the reify
|
|
23408
|
+
// phase. We should handle that here instead.
|
|
23069
23409
|
}
|
|
23070
23410
|
}
|
|
23071
23411
|
}
|
|
@@ -23103,7 +23443,14 @@ function varsUsedByOp(op) {
|
|
|
23103
23443
|
return op.interpolation.expressions.length;
|
|
23104
23444
|
case OpKind.I18nExpression:
|
|
23105
23445
|
case OpKind.Conditional:
|
|
23446
|
+
case OpKind.DeferWhen:
|
|
23106
23447
|
return 1;
|
|
23448
|
+
case OpKind.RepeaterCreate:
|
|
23449
|
+
// Repeaters may require an extra variable binding slot, if they have an empty view, for the
|
|
23450
|
+
// empty block tracking.
|
|
23451
|
+
// TODO: It's a bit odd to have a create mode instruction consume variable slots. Maybe we can
|
|
23452
|
+
// find a way to use the Repeater update op instead.
|
|
23453
|
+
return op.emptyView ? 1 : 0;
|
|
23107
23454
|
default:
|
|
23108
23455
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
23109
23456
|
}
|
|
@@ -23559,12 +23906,13 @@ function wrapI18nIcus(job) {
|
|
|
23559
23906
|
case OpKind.IcuStart:
|
|
23560
23907
|
if (currentI18nOp === null) {
|
|
23561
23908
|
addedI18nId = job.allocateXrefId();
|
|
23562
|
-
|
|
23909
|
+
// ICU i18n start/end ops should not recieve source spans.
|
|
23910
|
+
OpList.insertBefore(createI18nStartOp(addedI18nId, op.message, undefined, null), op);
|
|
23563
23911
|
}
|
|
23564
23912
|
break;
|
|
23565
23913
|
case OpKind.IcuEnd:
|
|
23566
23914
|
if (addedI18nId !== null) {
|
|
23567
|
-
OpList.insertAfter(createI18nEndOp(addedI18nId), op);
|
|
23915
|
+
OpList.insertAfter(createI18nEndOp(addedI18nId, null), op);
|
|
23568
23916
|
addedI18nId = null;
|
|
23569
23917
|
}
|
|
23570
23918
|
break;
|
|
@@ -23587,10 +23935,11 @@ const phases = [
|
|
|
23587
23935
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
23588
23936
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
23589
23937
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
23590
|
-
{ kind: CompilationJobKind.
|
|
23938
|
+
{ kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
|
|
23591
23939
|
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23592
23940
|
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23593
23941
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
23942
|
+
{ kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
|
|
23594
23943
|
{ kind: CompilationJobKind.Both, fn: parseExtractedStyles },
|
|
23595
23944
|
{ kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
|
|
23596
23945
|
{ kind: CompilationJobKind.Both, fn: collapseSingletonInterpolations },
|
|
@@ -23608,7 +23957,7 @@ const phases = [
|
|
|
23608
23957
|
{ kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
|
|
23609
23958
|
{ kind: CompilationJobKind.Tmpl, fn: generateVariables },
|
|
23610
23959
|
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
23611
|
-
{ kind: CompilationJobKind.
|
|
23960
|
+
{ kind: CompilationJobKind.Both, fn: deleteAnyCasts },
|
|
23612
23961
|
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
23613
23962
|
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
23614
23963
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
@@ -23616,7 +23965,7 @@ const phases = [
|
|
|
23616
23965
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
23617
23966
|
{ kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
|
|
23618
23967
|
{ kind: CompilationJobKind.Both, fn: resolveContexts },
|
|
23619
|
-
{ kind: CompilationJobKind.
|
|
23968
|
+
{ kind: CompilationJobKind.Both, fn: resolveSanitizers },
|
|
23620
23969
|
{ kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
|
|
23621
23970
|
{ kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
|
|
23622
23971
|
{ kind: CompilationJobKind.Both, fn: expandSafeReads },
|
|
@@ -23625,7 +23974,6 @@ const phases = [
|
|
|
23625
23974
|
{ kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
|
|
23626
23975
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
23627
23976
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
23628
|
-
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nIcuPlaceholders },
|
|
23629
23977
|
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
23630
23978
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
23631
23979
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
@@ -23752,6 +24100,10 @@ function emitHostBindingFunction(job) {
|
|
|
23752
24100
|
}
|
|
23753
24101
|
|
|
23754
24102
|
const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
|
|
24103
|
+
// Schema containing DOM elements and their properties.
|
|
24104
|
+
const domSchema = new DomElementSchemaRegistry();
|
|
24105
|
+
// Tag name of the `ng-template` element.
|
|
24106
|
+
const NG_TEMPLATE_TAG_NAME$1 = 'ng-template';
|
|
23755
24107
|
/**
|
|
23756
24108
|
* Process a template AST and convert it into a `ComponentCompilation` in the intermediate
|
|
23757
24109
|
* representation.
|
|
@@ -23769,10 +24121,24 @@ function ingestComponent(componentName, template, constantPool, relativeContextF
|
|
|
23769
24121
|
function ingestHostBinding(input, bindingParser, constantPool) {
|
|
23770
24122
|
const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
|
|
23771
24123
|
for (const property of input.properties ?? []) {
|
|
23772
|
-
|
|
24124
|
+
let bindingKind = BindingKind.Property;
|
|
24125
|
+
// TODO: this should really be handled in the parser.
|
|
24126
|
+
if (property.name.startsWith('attr.')) {
|
|
24127
|
+
property.name = property.name.substring('attr.'.length);
|
|
24128
|
+
bindingKind = BindingKind.Attribute;
|
|
24129
|
+
}
|
|
24130
|
+
if (property.isAnimation) {
|
|
24131
|
+
bindingKind = BindingKind.Animation;
|
|
24132
|
+
}
|
|
24133
|
+
const securityContexts = bindingParser
|
|
24134
|
+
.calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
|
|
24135
|
+
.filter(context => context !== SecurityContext.NONE);
|
|
24136
|
+
ingestHostProperty(job, property, bindingKind, securityContexts);
|
|
23773
24137
|
}
|
|
23774
24138
|
for (const [name, expr] of Object.entries(input.attributes) ?? []) {
|
|
23775
|
-
|
|
24139
|
+
const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true)
|
|
24140
|
+
.filter(context => context !== SecurityContext.NONE);
|
|
24141
|
+
ingestHostAttribute(job, name, expr, securityContexts);
|
|
23776
24142
|
}
|
|
23777
24143
|
for (const event of input.events ?? []) {
|
|
23778
24144
|
ingestHostEvent(job, event);
|
|
@@ -23781,7 +24147,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23781
24147
|
}
|
|
23782
24148
|
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
23783
24149
|
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
23784
|
-
function ingestHostProperty(job, property,
|
|
24150
|
+
function ingestHostProperty(job, property, bindingKind, securityContexts) {
|
|
23785
24151
|
let expression;
|
|
23786
24152
|
const ast = property.expression.ast;
|
|
23787
24153
|
if (ast instanceof Interpolation$1) {
|
|
@@ -23790,28 +24156,21 @@ function ingestHostProperty(job, property, isTextAttribute) {
|
|
|
23790
24156
|
else {
|
|
23791
24157
|
expression = convertAst(ast, job, property.sourceSpan);
|
|
23792
24158
|
}
|
|
23793
|
-
|
|
23794
|
-
// TODO: this should really be handled in the parser.
|
|
23795
|
-
if (property.name.startsWith('attr.')) {
|
|
23796
|
-
property.name = property.name.substring('attr.'.length);
|
|
23797
|
-
bindingKind = BindingKind.Attribute;
|
|
23798
|
-
}
|
|
23799
|
-
if (property.isAnimation) {
|
|
23800
|
-
bindingKind = BindingKind.Animation;
|
|
23801
|
-
}
|
|
23802
|
-
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
|
|
23803
|
-
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
|
|
24159
|
+
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
|
|
23804
24160
|
}
|
|
23805
|
-
function ingestHostAttribute(job, name, value) {
|
|
23806
|
-
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null,
|
|
24161
|
+
function ingestHostAttribute(job, name, value, securityContexts) {
|
|
24162
|
+
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
|
|
24163
|
+
/* Host attributes should always be extracted to const hostAttrs, even if they are not
|
|
24164
|
+
*strictly* text literals */
|
|
24165
|
+
true, false, null,
|
|
23807
24166
|
/* TODO */ null,
|
|
23808
|
-
|
|
24167
|
+
/** TODO: May be null? */ value.sourceSpan);
|
|
23809
24168
|
job.root.update.push(attrBinding);
|
|
23810
24169
|
}
|
|
23811
24170
|
function ingestHostEvent(job, event) {
|
|
23812
|
-
const
|
|
23813
|
-
|
|
23814
|
-
eventBinding.
|
|
24171
|
+
const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
|
|
24172
|
+
[event.targetOrPhase, null];
|
|
24173
|
+
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
|
|
23815
24174
|
job.root.create.push(eventBinding);
|
|
23816
24175
|
}
|
|
23817
24176
|
/**
|
|
@@ -23829,10 +24188,10 @@ function ingestNodes(unit, template) {
|
|
|
23829
24188
|
ingestContent(unit, node);
|
|
23830
24189
|
}
|
|
23831
24190
|
else if (node instanceof Text$3) {
|
|
23832
|
-
ingestText(unit, node);
|
|
24191
|
+
ingestText(unit, node, null);
|
|
23833
24192
|
}
|
|
23834
24193
|
else if (node instanceof BoundText) {
|
|
23835
|
-
ingestBoundText(unit, node);
|
|
24194
|
+
ingestBoundText(unit, node, null);
|
|
23836
24195
|
}
|
|
23837
24196
|
else if (node instanceof IfBlock) {
|
|
23838
24197
|
ingestIfBlock(unit, node);
|
|
@@ -23864,10 +24223,16 @@ function ingestElement(unit, element) {
|
|
|
23864
24223
|
}
|
|
23865
24224
|
const id = unit.job.allocateXrefId();
|
|
23866
24225
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
23867
|
-
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
24226
|
+
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
|
|
23868
24227
|
unit.create.push(startOp);
|
|
23869
|
-
|
|
24228
|
+
ingestElementBindings(unit, startOp, element);
|
|
23870
24229
|
ingestReferences(startOp, element);
|
|
24230
|
+
// Start i18n, if needed, goes after the element create and bindings, but before the nodes
|
|
24231
|
+
let i18nBlockId = null;
|
|
24232
|
+
if (element.i18n instanceof Message) {
|
|
24233
|
+
i18nBlockId = unit.job.allocateXrefId();
|
|
24234
|
+
unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
|
|
24235
|
+
}
|
|
23871
24236
|
ingestNodes(unit, element.children);
|
|
23872
24237
|
// The source span for the end op is typically the element closing tag. However, if no closing tag
|
|
23873
24238
|
// exists, such as in `<input>`, we use the start source span instead. Usually the start and end
|
|
@@ -23877,10 +24242,8 @@ function ingestElement(unit, element) {
|
|
|
23877
24242
|
const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
|
|
23878
24243
|
unit.create.push(endOp);
|
|
23879
24244
|
// If there is an i18n message associated with this element, insert i18n start and end ops.
|
|
23880
|
-
if (
|
|
23881
|
-
|
|
23882
|
-
OpList.insertAfter(createI18nStartOp(i18nBlockId, element.i18n), startOp);
|
|
23883
|
-
OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
|
|
24245
|
+
if (i18nBlockId !== null) {
|
|
24246
|
+
OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
|
|
23884
24247
|
}
|
|
23885
24248
|
}
|
|
23886
24249
|
/**
|
|
@@ -23903,9 +24266,9 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23903
24266
|
'' :
|
|
23904
24267
|
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
23905
24268
|
const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
|
|
23906
|
-
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
24269
|
+
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
|
|
23907
24270
|
unit.create.push(templateOp);
|
|
23908
|
-
|
|
24271
|
+
ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
|
|
23909
24272
|
ingestReferences(templateOp, tmpl);
|
|
23910
24273
|
ingestNodes(childView, tmpl.children);
|
|
23911
24274
|
for (const { name, value } of tmpl.variables) {
|
|
@@ -23916,34 +24279,34 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23916
24279
|
// element/template the directive is placed on.
|
|
23917
24280
|
if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
|
|
23918
24281
|
const id = unit.job.allocateXrefId();
|
|
23919
|
-
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
23920
|
-
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
24282
|
+
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n, undefined, tmpl.startSourceSpan), childView.create.head);
|
|
24283
|
+
OpList.insertBefore(createI18nEndOp(id, tmpl.endSourceSpan ?? tmpl.startSourceSpan), childView.create.tail);
|
|
23921
24284
|
}
|
|
23922
24285
|
}
|
|
23923
24286
|
/**
|
|
23924
|
-
* Ingest a
|
|
24287
|
+
* Ingest a content node from the AST into the given `ViewCompilation`.
|
|
23925
24288
|
*/
|
|
23926
24289
|
function ingestContent(unit, content) {
|
|
23927
24290
|
if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
|
|
23928
24291
|
throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
|
|
23929
24292
|
}
|
|
23930
|
-
const
|
|
23931
|
-
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, attrs, content.sourceSpan);
|
|
24293
|
+
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, content.sourceSpan);
|
|
23932
24294
|
for (const attr of content.attributes) {
|
|
23933
|
-
|
|
24295
|
+
const securityContext = domSchema.securityContext(content.name, attr.name, true);
|
|
24296
|
+
unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
23934
24297
|
}
|
|
23935
24298
|
unit.create.push(op);
|
|
23936
24299
|
}
|
|
23937
24300
|
/**
|
|
23938
24301
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
23939
24302
|
*/
|
|
23940
|
-
function ingestText(unit, text) {
|
|
23941
|
-
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, text.sourceSpan));
|
|
24303
|
+
function ingestText(unit, text, icuPlaceholder) {
|
|
24304
|
+
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, icuPlaceholder, text.sourceSpan));
|
|
23942
24305
|
}
|
|
23943
24306
|
/**
|
|
23944
24307
|
* Ingest an interpolated text node from the AST into the given `ViewCompilation`.
|
|
23945
24308
|
*/
|
|
23946
|
-
function ingestBoundText(unit, text,
|
|
24309
|
+
function ingestBoundText(unit, text, icuPlaceholder) {
|
|
23947
24310
|
let value = text.value;
|
|
23948
24311
|
if (value instanceof ASTWithSource) {
|
|
23949
24312
|
value = value.ast;
|
|
@@ -23954,19 +24317,16 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
23954
24317
|
if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
|
|
23955
24318
|
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
23956
24319
|
}
|
|
23957
|
-
|
|
23958
|
-
|
|
23959
|
-
|
|
23960
|
-
|
|
23961
|
-
|
|
23962
|
-
.map(placeholder => placeholder.name) :
|
|
23963
|
-
[];
|
|
23964
|
-
}
|
|
24320
|
+
const i18nPlaceholders = text.i18n instanceof Container ?
|
|
24321
|
+
text.i18n.children
|
|
24322
|
+
.filter((node) => node instanceof Placeholder)
|
|
24323
|
+
.map(placeholder => placeholder.name) :
|
|
24324
|
+
[];
|
|
23965
24325
|
if (i18nPlaceholders.length > 0 && i18nPlaceholders.length !== value.expressions.length) {
|
|
23966
24326
|
throw Error(`Unexpected number of i18n placeholders (${value.expressions.length}) for BoundText with ${value.expressions.length} expressions`);
|
|
23967
24327
|
}
|
|
23968
24328
|
const textXref = unit.job.allocateXrefId();
|
|
23969
|
-
unit.create.push(createTextOp(textXref, '', text.sourceSpan));
|
|
24329
|
+
unit.create.push(createTextOp(textXref, '', icuPlaceholder, text.sourceSpan));
|
|
23970
24330
|
// TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
|
|
23971
24331
|
// interpolation. We copy that behavior in compatibility mode.
|
|
23972
24332
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
@@ -23999,7 +24359,7 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
23999
24359
|
}
|
|
24000
24360
|
ifCaseI18nMeta = ifCase.i18n;
|
|
24001
24361
|
}
|
|
24002
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.sourceSpan);
|
|
24362
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
|
|
24003
24363
|
unit.create.push(templateOp);
|
|
24004
24364
|
if (firstXref === null) {
|
|
24005
24365
|
firstXref = cView.xref;
|
|
@@ -24029,7 +24389,7 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
24029
24389
|
}
|
|
24030
24390
|
switchCaseI18nMeta = switchCase.i18n;
|
|
24031
24391
|
}
|
|
24032
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.sourceSpan);
|
|
24392
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
|
|
24033
24393
|
unit.create.push(templateOp);
|
|
24034
24394
|
if (firstXref === null) {
|
|
24035
24395
|
firstXref = cView.xref;
|
|
@@ -24045,13 +24405,16 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
24045
24405
|
const conditional = createConditionalOp(firstXref, firstSlotHandle, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
|
|
24046
24406
|
unit.update.push(conditional);
|
|
24047
24407
|
}
|
|
24048
|
-
function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
24408
|
+
function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
|
|
24409
|
+
if (i18nMeta !== undefined && !(i18nMeta instanceof BlockPlaceholder)) {
|
|
24410
|
+
throw Error('Unhandled i18n metadata type for defer block');
|
|
24411
|
+
}
|
|
24049
24412
|
if (children === undefined) {
|
|
24050
24413
|
return null;
|
|
24051
24414
|
}
|
|
24052
24415
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
24053
24416
|
ingestNodes(secondaryView, children);
|
|
24054
|
-
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML,
|
|
24417
|
+
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan, sourceSpan);
|
|
24055
24418
|
unit.create.push(templateOp);
|
|
24056
24419
|
return templateOp;
|
|
24057
24420
|
}
|
|
@@ -24061,10 +24424,10 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
24061
24424
|
throw new Error(`AssertionError: unable to find metadata for deferred block`);
|
|
24062
24425
|
}
|
|
24063
24426
|
// Generate the defer main view and all secondary views.
|
|
24064
|
-
const main = ingestDeferView(unit, '', deferBlock.children, deferBlock.sourceSpan);
|
|
24065
|
-
const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
|
|
24066
|
-
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
24067
|
-
const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
24427
|
+
const main = ingestDeferView(unit, '', deferBlock.i18n, deferBlock.children, deferBlock.sourceSpan);
|
|
24428
|
+
const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.i18n, deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
|
|
24429
|
+
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.i18n, deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
24430
|
+
const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
24068
24431
|
// Create the main defer op, and ops for all secondary views.
|
|
24069
24432
|
const deferXref = unit.job.allocateXrefId();
|
|
24070
24433
|
const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, deferBlock.sourceSpan);
|
|
@@ -24129,6 +24492,11 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
24129
24492
|
deferOnOps.push(deferOnOp);
|
|
24130
24493
|
}
|
|
24131
24494
|
if (triggers.when !== undefined) {
|
|
24495
|
+
if (triggers.when.value instanceof Interpolation$1) {
|
|
24496
|
+
// TemplateDefinitionBuilder supports this case, but it's very strange to me. What would it
|
|
24497
|
+
// even mean?
|
|
24498
|
+
throw new Error(`Unexpected interpolation in defer block when trigger`);
|
|
24499
|
+
}
|
|
24132
24500
|
const deferOnOp = createDeferWhenOp(deferXref, convertAst(triggers.when.value, unit.job, triggers.when.sourceSpan), prefetch, triggers.when.sourceSpan);
|
|
24133
24501
|
deferWhenOps.push(deferOnOp);
|
|
24134
24502
|
}
|
|
@@ -24148,10 +24516,10 @@ function ingestIcu(unit, icu) {
|
|
|
24148
24516
|
unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
|
|
24149
24517
|
for (const [placeholder, text] of Object.entries({ ...icu.vars, ...icu.placeholders })) {
|
|
24150
24518
|
if (text instanceof BoundText) {
|
|
24151
|
-
ingestBoundText(unit, text,
|
|
24519
|
+
ingestBoundText(unit, text, placeholder);
|
|
24152
24520
|
}
|
|
24153
24521
|
else {
|
|
24154
|
-
ingestText(unit, text);
|
|
24522
|
+
ingestText(unit, text, placeholder);
|
|
24155
24523
|
}
|
|
24156
24524
|
}
|
|
24157
24525
|
unit.create.push(createIcuEndOp(xref));
|
|
@@ -24185,9 +24553,11 @@ function ingestForBlock(unit, forBlock) {
|
|
|
24185
24553
|
const track = convertAst(forBlock.trackBy, unit.job, sourceSpan);
|
|
24186
24554
|
ingestNodes(repeaterView, forBlock.children);
|
|
24187
24555
|
let emptyView = null;
|
|
24556
|
+
let emptyTagName = null;
|
|
24188
24557
|
if (forBlock.empty !== null) {
|
|
24189
24558
|
emptyView = unit.job.allocateView(unit.xref);
|
|
24190
24559
|
ingestNodes(emptyView, forBlock.empty.children);
|
|
24560
|
+
emptyTagName = ingestControlFlowInsertionPoint(unit, emptyView.xref, forBlock.empty);
|
|
24191
24561
|
}
|
|
24192
24562
|
const varNames = {
|
|
24193
24563
|
$index: forBlock.contextVariables.$index.name,
|
|
@@ -24198,8 +24568,17 @@ function ingestForBlock(unit, forBlock) {
|
|
|
24198
24568
|
$odd: forBlock.contextVariables.$odd.name,
|
|
24199
24569
|
$implicit: forBlock.item.name,
|
|
24200
24570
|
};
|
|
24571
|
+
if (forBlock.i18n !== undefined && !(forBlock.i18n instanceof BlockPlaceholder)) {
|
|
24572
|
+
throw Error('AssertionError: Unhandled i18n metadata type or @for');
|
|
24573
|
+
}
|
|
24574
|
+
if (forBlock.empty?.i18n !== undefined &&
|
|
24575
|
+
!(forBlock.empty.i18n instanceof BlockPlaceholder)) {
|
|
24576
|
+
throw Error('AssertionError: Unhandled i18n metadata type or @empty');
|
|
24577
|
+
}
|
|
24578
|
+
const i18nPlaceholder = forBlock.i18n;
|
|
24579
|
+
const emptyI18nPlaceholder = forBlock.empty?.i18n;
|
|
24201
24580
|
const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
|
|
24202
|
-
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, forBlock.sourceSpan);
|
|
24581
|
+
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, emptyTagName, i18nPlaceholder, emptyI18nPlaceholder, forBlock.startSourceSpan, forBlock.sourceSpan);
|
|
24203
24582
|
unit.create.push(repeaterCreate);
|
|
24204
24583
|
const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
|
|
24205
24584
|
const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
|
|
@@ -24213,7 +24592,29 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24213
24592
|
return convertAst(ast.ast, job, baseSourceSpan);
|
|
24214
24593
|
}
|
|
24215
24594
|
else if (ast instanceof PropertyRead) {
|
|
24216
|
-
|
|
24595
|
+
const isThisReceiver = ast.receiver instanceof ThisReceiver;
|
|
24596
|
+
// Whether this is an implicit receiver, *excluding* explicit reads of `this`.
|
|
24597
|
+
const isImplicitReceiver = ast.receiver instanceof ImplicitReceiver && !(ast.receiver instanceof ThisReceiver);
|
|
24598
|
+
// Whether the name of the read is a node that should be never retain its explicit this
|
|
24599
|
+
// receiver.
|
|
24600
|
+
const isSpecialNode = ast.name === '$any' || ast.name === '$event';
|
|
24601
|
+
// TODO: The most sensible condition here would be simply `isImplicitReceiver`, to convert only
|
|
24602
|
+
// actual implicit `this` reads, and not explicit ones. However, TemplateDefinitionBuilder (and
|
|
24603
|
+
// the Typecheck block!) both have the same bug, in which they also consider explicit `this`
|
|
24604
|
+
// reads to be implicit. This causes problems when the explicit `this` read is inside a
|
|
24605
|
+
// template with a context that also provides the variable name being read:
|
|
24606
|
+
// ```
|
|
24607
|
+
// <ng-template let-a>{{this.a}}</ng-template>
|
|
24608
|
+
// ```
|
|
24609
|
+
// The whole point of the explicit `this` was to access the class property, but TDB and the
|
|
24610
|
+
// current TCB treat the read as implicit, and give you the context property instead!
|
|
24611
|
+
//
|
|
24612
|
+
// For now, we emulate this old behvaior by aggressively converting explicit reads to to
|
|
24613
|
+
// implicit reads, except for the special cases that TDB and the current TCB protect. However,
|
|
24614
|
+
// it would be an improvement to fix this.
|
|
24615
|
+
//
|
|
24616
|
+
// See also the corresponding comment for the TCB, in `type_check_block.ts`.
|
|
24617
|
+
if (isImplicitReceiver || (isThisReceiver && !isSpecialNode)) {
|
|
24217
24618
|
return new LexicalReadExpr(ast.name);
|
|
24218
24619
|
}
|
|
24219
24620
|
else {
|
|
@@ -24317,6 +24718,27 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24317
24718
|
throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
|
|
24318
24719
|
}
|
|
24319
24720
|
}
|
|
24721
|
+
function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
|
|
24722
|
+
let expression;
|
|
24723
|
+
if (value instanceof Interpolation$1) {
|
|
24724
|
+
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, sourceSpan ?? null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24725
|
+
}
|
|
24726
|
+
else if (value instanceof AST) {
|
|
24727
|
+
expression = convertAst(value, job, sourceSpan ?? null);
|
|
24728
|
+
}
|
|
24729
|
+
else {
|
|
24730
|
+
expression = literal(value);
|
|
24731
|
+
}
|
|
24732
|
+
return expression;
|
|
24733
|
+
}
|
|
24734
|
+
// TODO: Can we populate Template binding kinds in ingest?
|
|
24735
|
+
const BINDING_KINDS = new Map([
|
|
24736
|
+
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
24737
|
+
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
24738
|
+
[2 /* e.BindingType.Class */, BindingKind.ClassName],
|
|
24739
|
+
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
24740
|
+
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
24741
|
+
]);
|
|
24320
24742
|
/**
|
|
24321
24743
|
* Checks whether the given template is a plain ng-template (as opposed to another kind of template
|
|
24322
24744
|
* such as a structural directive template or control flow template). This is checked based on the
|
|
@@ -24335,149 +24757,184 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24335
24757
|
* | `<ng-template *ngIf>` (structural) | null |
|
|
24336
24758
|
*/
|
|
24337
24759
|
function isPlainTemplate(tmpl) {
|
|
24338
|
-
return splitNsName(tmpl.tagName ?? '')[1] ===
|
|
24760
|
+
return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME$1;
|
|
24339
24761
|
}
|
|
24340
24762
|
/**
|
|
24341
|
-
*
|
|
24342
|
-
* to their IR representation.
|
|
24763
|
+
* Ensures that the i18nMeta, if provided, is an i18n.Message.
|
|
24343
24764
|
*/
|
|
24344
|
-
function
|
|
24345
|
-
|
|
24346
|
-
|
|
24347
|
-
if (element instanceof Template) {
|
|
24348
|
-
flags |= BindingFlags.OnNgTemplateElement;
|
|
24349
|
-
if (element instanceof Template && isPlainTemplate(element)) {
|
|
24350
|
-
flags |= BindingFlags.BindingTargetsTemplate;
|
|
24351
|
-
}
|
|
24352
|
-
const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
|
|
24353
|
-
for (const attr of element.templateAttrs) {
|
|
24354
|
-
if (attr instanceof TextAttribute) {
|
|
24355
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue, attr.i18n);
|
|
24356
|
-
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
24357
|
-
}
|
|
24358
|
-
else {
|
|
24359
|
-
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags, attr.i18n);
|
|
24360
|
-
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
24361
|
-
}
|
|
24362
|
-
}
|
|
24765
|
+
function asMessage(i18nMeta) {
|
|
24766
|
+
if (i18nMeta == null) {
|
|
24767
|
+
return null;
|
|
24363
24768
|
}
|
|
24769
|
+
if (!(i18nMeta instanceof Message)) {
|
|
24770
|
+
throw Error(`Expected i18n meta to be a Message, but got: ${i18nMeta.constructor.name}`);
|
|
24771
|
+
}
|
|
24772
|
+
return i18nMeta;
|
|
24773
|
+
}
|
|
24774
|
+
/**
|
|
24775
|
+
* Process all of the bindings on an element in the template AST and convert them to their IR
|
|
24776
|
+
* representation.
|
|
24777
|
+
*/
|
|
24778
|
+
function ingestElementBindings(unit, op, element) {
|
|
24779
|
+
let bindings = new Array();
|
|
24364
24780
|
for (const attr of element.attributes) {
|
|
24365
|
-
//
|
|
24366
|
-
|
|
24367
|
-
|
|
24368
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue, attr.i18n);
|
|
24369
|
-
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
24781
|
+
// Attribute literal bindings, such as `attr.foo="bar"`.
|
|
24782
|
+
const securityContext = domSchema.securityContext(element.name, attr.name, true);
|
|
24783
|
+
bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
24370
24784
|
}
|
|
24371
24785
|
for (const input of element.inputs) {
|
|
24372
|
-
|
|
24373
|
-
|
|
24786
|
+
// All dynamic bindings (both attribute and property bindings).
|
|
24787
|
+
bindings.push(createBindingOp(op.xref, BINDING_KINDS.get(input.type), input.name, convertAstWithInterpolation(unit.job, astOf(input.value), input.i18n), input.unit, input.securityContext, false, false, null, asMessage(input.i18n) ?? null, input.sourceSpan));
|
|
24374
24788
|
}
|
|
24789
|
+
unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
|
|
24790
|
+
unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
|
|
24375
24791
|
for (const output of element.outputs) {
|
|
24376
|
-
|
|
24377
|
-
|
|
24378
|
-
if (output.phase === null) {
|
|
24379
|
-
throw Error('Animation listener should have a phase');
|
|
24380
|
-
}
|
|
24381
|
-
}
|
|
24382
|
-
if (element instanceof Template && !isPlainTemplate(element)) {
|
|
24383
|
-
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null));
|
|
24384
|
-
continue;
|
|
24385
|
-
}
|
|
24386
|
-
listenerOp = createListenerOp(op.xref, op.handle, output.name, op.tag, output.phase, false, output.sourceSpan);
|
|
24387
|
-
// if output.handler is a chain, then push each statement from the chain separately, and
|
|
24388
|
-
// return the last one?
|
|
24389
|
-
let handlerExprs;
|
|
24390
|
-
let handler = output.handler;
|
|
24391
|
-
if (handler instanceof ASTWithSource) {
|
|
24392
|
-
handler = handler.ast;
|
|
24792
|
+
if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
|
|
24793
|
+
throw Error('Animation listener should have a phase');
|
|
24393
24794
|
}
|
|
24394
|
-
|
|
24395
|
-
|
|
24795
|
+
unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
|
|
24796
|
+
}
|
|
24797
|
+
// If any of the bindings on this element have an i18n message, then an i18n attrs configuration
|
|
24798
|
+
// op is also required.
|
|
24799
|
+
if (bindings.some(b => b?.i18nMessage) !== null) {
|
|
24800
|
+
unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
|
|
24801
|
+
}
|
|
24802
|
+
}
|
|
24803
|
+
/**
|
|
24804
|
+
* Process all of the bindings on a template in the template AST and convert them to their IR
|
|
24805
|
+
* representation.
|
|
24806
|
+
*/
|
|
24807
|
+
function ingestTemplateBindings(unit, op, template, templateKind) {
|
|
24808
|
+
let bindings = new Array();
|
|
24809
|
+
for (const attr of template.templateAttrs) {
|
|
24810
|
+
if (attr instanceof TextAttribute) {
|
|
24811
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
24812
|
+
bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
24396
24813
|
}
|
|
24397
24814
|
else {
|
|
24398
|
-
|
|
24815
|
+
bindings.push(createTemplateBinding(unit, op.xref, attr.type, attr.name, astOf(attr.value), attr.unit, attr.securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
24816
|
+
}
|
|
24817
|
+
}
|
|
24818
|
+
for (const attr of template.attributes) {
|
|
24819
|
+
// Attribute literal bindings, such as `attr.foo="bar"`.
|
|
24820
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
24821
|
+
bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, false, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
24822
|
+
}
|
|
24823
|
+
for (const input of template.inputs) {
|
|
24824
|
+
// Dynamic bindings (both attribute and property bindings).
|
|
24825
|
+
bindings.push(createTemplateBinding(unit, op.xref, input.type, input.name, astOf(input.value), input.unit, input.securityContext, false, templateKind, asMessage(input.i18n), input.sourceSpan));
|
|
24826
|
+
}
|
|
24827
|
+
unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
|
|
24828
|
+
unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
|
|
24829
|
+
for (const output of template.outputs) {
|
|
24830
|
+
if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
|
|
24831
|
+
throw Error('Animation listener should have a phase');
|
|
24399
24832
|
}
|
|
24400
|
-
if (
|
|
24401
|
-
|
|
24833
|
+
if (templateKind === TemplateKind.NgTemplate) {
|
|
24834
|
+
unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
|
|
24402
24835
|
}
|
|
24403
|
-
|
|
24404
|
-
|
|
24405
|
-
|
|
24406
|
-
const
|
|
24407
|
-
|
|
24836
|
+
if (templateKind === TemplateKind.Structural &&
|
|
24837
|
+
output.type !== 1 /* e.ParsedEventType.Animation */) {
|
|
24838
|
+
// Animation bindings are excluded from the structural template's const array.
|
|
24839
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
|
|
24840
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null, null, securityContext));
|
|
24408
24841
|
}
|
|
24409
|
-
listenerOp.handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
24410
|
-
unit.create.push(listenerOp);
|
|
24411
24842
|
}
|
|
24412
24843
|
// TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
|
|
24413
|
-
if (
|
|
24844
|
+
if (bindings.some(b => b?.i18nMessage) !== null) {
|
|
24414
24845
|
unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
|
|
24415
24846
|
}
|
|
24416
24847
|
}
|
|
24417
|
-
|
|
24418
|
-
|
|
24419
|
-
|
|
24420
|
-
|
|
24421
|
-
|
|
24422
|
-
|
|
24423
|
-
|
|
24424
|
-
|
|
24425
|
-
|
|
24426
|
-
|
|
24427
|
-
|
|
24428
|
-
|
|
24429
|
-
|
|
24430
|
-
|
|
24431
|
-
|
|
24432
|
-
|
|
24433
|
-
|
|
24434
|
-
|
|
24435
|
-
|
|
24436
|
-
|
|
24437
|
-
|
|
24438
|
-
|
|
24439
|
-
|
|
24440
|
-
|
|
24441
|
-
|
|
24442
|
-
|
|
24443
|
-
|
|
24444
|
-
|
|
24445
|
-
|
|
24446
|
-
|
|
24447
|
-
|
|
24448
|
-
|
|
24449
|
-
if (
|
|
24450
|
-
if (!
|
|
24451
|
-
|
|
24848
|
+
/**
|
|
24849
|
+
* Helper to ingest an individual binding on a template, either an explicit `ng-template`, or an
|
|
24850
|
+
* implicit template created via structural directive.
|
|
24851
|
+
*
|
|
24852
|
+
* Bindings on templates are *extremely* tricky. I have tried to isolate all of the confusing edge
|
|
24853
|
+
* cases into this function, and to comment it well to document the behavior.
|
|
24854
|
+
*
|
|
24855
|
+
* Some of this behavior is intuitively incorrect, and we should consider changing it in the future.
|
|
24856
|
+
*
|
|
24857
|
+
* @param view The compilation unit for the view containing the template.
|
|
24858
|
+
* @param xref The xref of the template op.
|
|
24859
|
+
* @param type The binding type, according to the parser. This is fairly reasonable, e.g. both
|
|
24860
|
+
* dynamic and static attributes have e.BindingType.Attribute.
|
|
24861
|
+
* @param name The binding's name.
|
|
24862
|
+
* @param value The bindings's value, which will either be an input AST expression, or a string
|
|
24863
|
+
* literal. Note that the input AST expression may or may not be const -- it will only be a
|
|
24864
|
+
* string literal if the parser considered it a text binding.
|
|
24865
|
+
* @param unit If the binding has a unit (e.g. `px` for style bindings), then this is the unit.
|
|
24866
|
+
* @param securityContext The security context of the binding.
|
|
24867
|
+
* @param isStructuralTemplateAttribute Whether this binding actually applies to the structural
|
|
24868
|
+
* ng-template. For example, an `ngFor` would actually apply to the structural template. (Most
|
|
24869
|
+
* bindings on structural elements target the inner element, not the template.)
|
|
24870
|
+
* @param templateKind Whether this is an explicit `ng-template` or an implicit template created by
|
|
24871
|
+
* a structural directive. This should never be a block template.
|
|
24872
|
+
* @param i18nMessage The i18n metadata for the binding, if any.
|
|
24873
|
+
* @param sourceSpan The source span of the binding.
|
|
24874
|
+
* @returns An IR binding op, or null if the binding should be skipped.
|
|
24875
|
+
*/
|
|
24876
|
+
function createTemplateBinding(view, xref, type, name, value, unit, securityContext, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
24877
|
+
const isTextBinding = typeof value === 'string';
|
|
24878
|
+
// If this is a structural template, then several kinds of bindings should not result in an
|
|
24879
|
+
// update instruction.
|
|
24880
|
+
if (templateKind === TemplateKind.Structural) {
|
|
24881
|
+
if (!isStructuralTemplateAttribute &&
|
|
24882
|
+
(type === 0 /* e.BindingType.Property */ || type === 2 /* e.BindingType.Class */ ||
|
|
24883
|
+
type === 3 /* e.BindingType.Style */)) {
|
|
24884
|
+
// Because this binding doesn't really target the ng-template, it must be a binding on an
|
|
24885
|
+
// inner node of a structural template. We can't skip it entirely, because we still need it on
|
|
24886
|
+
// the ng-template's consts (e.g. for the purposes of directive matching). However, we should
|
|
24887
|
+
// not generate an update instruction for it.
|
|
24888
|
+
return createExtractedAttributeOp(xref, BindingKind.Property, name, null, null, i18nMessage, securityContext);
|
|
24889
|
+
}
|
|
24890
|
+
if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
|
|
24891
|
+
// Again, this binding doesn't really target the ng-template; it actually targets the element
|
|
24892
|
+
// inside the structural template. In the case of non-text attribute or animation bindings,
|
|
24893
|
+
// the binding doesn't even show up on the ng-template const array, so we just skip it
|
|
24894
|
+
// entirely.
|
|
24895
|
+
return null;
|
|
24452
24896
|
}
|
|
24453
|
-
i18nContext = view.job.allocateXrefId();
|
|
24454
|
-
view.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, i18nMeta, null));
|
|
24455
|
-
}
|
|
24456
|
-
if (flags & BindingFlags.OnNgTemplateElement && !(flags & BindingFlags.BindingTargetsTemplate) &&
|
|
24457
|
-
type === 0 /* e.BindingType.Property */) {
|
|
24458
|
-
// This binding only exists for later const extraction, and is not an actual binding to be
|
|
24459
|
-
// created.
|
|
24460
|
-
view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null, i18nContext));
|
|
24461
|
-
return;
|
|
24462
24897
|
}
|
|
24463
|
-
let
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24468
|
-
|
|
24469
|
-
|
|
24898
|
+
let bindingType = BINDING_KINDS.get(type);
|
|
24899
|
+
if (templateKind === TemplateKind.NgTemplate) {
|
|
24900
|
+
// We know we are dealing with bindings directly on an explicit ng-template.
|
|
24901
|
+
// Static attribute bindings should be collected into the const array as k/v pairs. Property
|
|
24902
|
+
// bindings should result in a `property` instruction, and `AttributeMarker.Bindings` const
|
|
24903
|
+
// entries.
|
|
24904
|
+
//
|
|
24905
|
+
// The difficulty is with dynamic attribute, style, and class bindings. These don't really make
|
|
24906
|
+
// sense on an `ng-template` and should probably be parser errors. However,
|
|
24907
|
+
// TemplateDefinitionBuilder generates `property` instructions for them, and so we do that as
|
|
24908
|
+
// well.
|
|
24909
|
+
//
|
|
24910
|
+
// Note that we do have a slight behavior difference with TemplateDefinitionBuilder: although
|
|
24911
|
+
// TDB emits `property` instructions for dynamic attributes, styles, and classes, only styles
|
|
24912
|
+
// and classes also get const collected into the `AttributeMarker.Bindings` field. Dynamic
|
|
24913
|
+
// attribute bindings are missing from the consts entirely. We choose to emit them into the
|
|
24914
|
+
// consts field anyway, to avoid creating special cases for something so arcane and nonsensical.
|
|
24915
|
+
if (type === 2 /* e.BindingType.Class */ || type === 3 /* e.BindingType.Style */ ||
|
|
24916
|
+
(type === 1 /* e.BindingType.Attribute */ && !isTextBinding)) {
|
|
24917
|
+
// TODO: These cases should be parse errors.
|
|
24918
|
+
bindingType = BindingKind.Property;
|
|
24470
24919
|
}
|
|
24471
|
-
expression = new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, view.job, null)), i18nPlaceholders);
|
|
24472
24920
|
}
|
|
24473
|
-
|
|
24474
|
-
|
|
24475
|
-
|
|
24476
|
-
|
|
24477
|
-
|
|
24921
|
+
return createBindingOp(xref, bindingType, name, convertAstWithInterpolation(view.job, value, i18nMessage), unit, securityContext, isTextBinding, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan);
|
|
24922
|
+
}
|
|
24923
|
+
function makeListenerHandlerOps(unit, handler, handlerSpan) {
|
|
24924
|
+
handler = astOf(handler);
|
|
24925
|
+
const handlerOps = new Array();
|
|
24926
|
+
let handlerExprs = handler instanceof Chain ? handler.expressions : [handler];
|
|
24927
|
+
if (handlerExprs.length === 0) {
|
|
24928
|
+
throw new Error('Expected listener to have non-empty expression list.');
|
|
24478
24929
|
}
|
|
24479
|
-
const
|
|
24480
|
-
|
|
24930
|
+
const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, handlerSpan));
|
|
24931
|
+
const returnExpr = expressions.pop();
|
|
24932
|
+
handlerOps.push(...expressions.map(e => createStatementOp(new ExpressionStatement(e, e.sourceSpan))));
|
|
24933
|
+
handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
24934
|
+
return handlerOps;
|
|
24935
|
+
}
|
|
24936
|
+
function astOf(ast) {
|
|
24937
|
+
return ast instanceof ASTWithSource ? ast.ast : ast;
|
|
24481
24938
|
}
|
|
24482
24939
|
/**
|
|
24483
24940
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -24565,11 +25022,12 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
|
|
|
24565
25022
|
// and they can be used in directive matching (in the case of `Template.templateAttrs`).
|
|
24566
25023
|
if (root !== null) {
|
|
24567
25024
|
for (const attr of root.attributes) {
|
|
24568
|
-
|
|
25025
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
25026
|
+
unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
24569
25027
|
}
|
|
24570
25028
|
const tagName = root instanceof Element$1 ? root.name : root.tagName;
|
|
24571
25029
|
// Don't pass along `ng-template` tag name since it enables directive matching.
|
|
24572
|
-
return tagName ===
|
|
25030
|
+
return tagName === NG_TEMPLATE_TAG_NAME$1 ? null : tagName;
|
|
24573
25031
|
}
|
|
24574
25032
|
return null;
|
|
24575
25033
|
}
|
|
@@ -28458,7 +28916,12 @@ class TemplateDefinitionBuilder {
|
|
|
28458
28916
|
});
|
|
28459
28917
|
const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
|
|
28460
28918
|
let emptyData = null;
|
|
28919
|
+
let emptyTagName = null;
|
|
28920
|
+
let emptyAttrsExprs;
|
|
28461
28921
|
if (block.empty !== null) {
|
|
28922
|
+
const emptyInferred = this.inferProjectionDataFromInsertionPoint(block.empty);
|
|
28923
|
+
emptyTagName = emptyInferred.tagName;
|
|
28924
|
+
emptyAttrsExprs = emptyInferred.attrsExprs;
|
|
28462
28925
|
emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty', undefined, block.empty.i18n);
|
|
28463
28926
|
// Allocate an extra slot for the empty block tracking.
|
|
28464
28927
|
this.allocateBindingSlots(null);
|
|
@@ -28476,13 +28939,13 @@ class TemplateDefinitionBuilder {
|
|
|
28476
28939
|
trackByExpression,
|
|
28477
28940
|
];
|
|
28478
28941
|
if (emptyData !== null) {
|
|
28479
|
-
params.push(literal(trackByUsesComponentInstance), variable(emptyData.name), literal(emptyData.getConstCount()), literal(emptyData.getVarCount()));
|
|
28942
|
+
params.push(literal(trackByUsesComponentInstance), variable(emptyData.name), literal(emptyData.getConstCount()), literal(emptyData.getVarCount()), literal(emptyTagName), this.addAttrsToConsts(emptyAttrsExprs || null));
|
|
28480
28943
|
}
|
|
28481
28944
|
else if (trackByUsesComponentInstance) {
|
|
28482
28945
|
// If the tracking function doesn't use the component instance, we can omit the flag.
|
|
28483
28946
|
params.push(literal(trackByUsesComponentInstance));
|
|
28484
28947
|
}
|
|
28485
|
-
return params;
|
|
28948
|
+
return trimTrailingNulls(params);
|
|
28486
28949
|
});
|
|
28487
28950
|
// Note: the expression needs to be processed *after* the template,
|
|
28488
28951
|
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
@@ -29241,12 +29704,16 @@ class BindingScope {
|
|
|
29241
29704
|
}
|
|
29242
29705
|
/** Binding scope of a `track` function inside a `for` loop block. */
|
|
29243
29706
|
class TrackByBindingScope extends BindingScope {
|
|
29244
|
-
constructor(parentScope,
|
|
29707
|
+
constructor(parentScope, globalOverrides) {
|
|
29245
29708
|
super(parentScope.bindingLevel + 1, parentScope);
|
|
29246
|
-
this.
|
|
29709
|
+
this.globalOverrides = globalOverrides;
|
|
29247
29710
|
this.componentAccessCount = 0;
|
|
29248
29711
|
}
|
|
29249
29712
|
get(name) {
|
|
29713
|
+
// Intercept any overridden globals.
|
|
29714
|
+
if (this.globalOverrides.hasOwnProperty(name)) {
|
|
29715
|
+
return variable(this.globalOverrides[name]);
|
|
29716
|
+
}
|
|
29250
29717
|
let current = this.parent;
|
|
29251
29718
|
// Prevent accesses of template variables outside the `for` loop.
|
|
29252
29719
|
while (current) {
|
|
@@ -29255,10 +29722,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
29255
29722
|
}
|
|
29256
29723
|
current = current.parent;
|
|
29257
29724
|
}
|
|
29258
|
-
// Intercept any aliased globals.
|
|
29259
|
-
if (this.globalAliases[name]) {
|
|
29260
|
-
return variable(this.globalAliases[name]);
|
|
29261
|
-
}
|
|
29262
29725
|
// When the component scope is accessed, we redirect it through `this`.
|
|
29263
29726
|
this.componentAccessCount++;
|
|
29264
29727
|
return variable('this').prop(name);
|
|
@@ -29923,14 +30386,16 @@ function createBaseDirectiveTypeParams(meta) {
|
|
|
29923
30386
|
function getInputsTypeExpression(meta) {
|
|
29924
30387
|
return literalMap(Object.keys(meta.inputs).map(key => {
|
|
29925
30388
|
const value = meta.inputs[key];
|
|
29926
|
-
|
|
29927
|
-
key,
|
|
29928
|
-
value:
|
|
29929
|
-
|
|
29930
|
-
|
|
29931
|
-
|
|
29932
|
-
|
|
29933
|
-
|
|
30389
|
+
const values = [
|
|
30390
|
+
{ key: 'alias', value: literal(value.bindingPropertyName), quoted: true },
|
|
30391
|
+
{ key: 'required', value: literal(value.required), quoted: true },
|
|
30392
|
+
];
|
|
30393
|
+
// TODO(legacy-partial-output-inputs): Consider always emitting this information,
|
|
30394
|
+
// or leaving it as is.
|
|
30395
|
+
if (value.isSignal) {
|
|
30396
|
+
values.push({ key: 'isSignal', value: literal(value.isSignal), quoted: true });
|
|
30397
|
+
}
|
|
30398
|
+
return { key, value: literalMap(values), quoted: true };
|
|
29934
30399
|
}));
|
|
29935
30400
|
}
|
|
29936
30401
|
/**
|
|
@@ -29996,6 +30461,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29996
30461
|
}
|
|
29997
30462
|
const hostJob = ingestHostBinding({
|
|
29998
30463
|
componentName: name,
|
|
30464
|
+
componentSelector: selector,
|
|
29999
30465
|
properties: bindings,
|
|
30000
30466
|
events: eventBindings,
|
|
30001
30467
|
attributes: hostBindingsMetadata.attributes,
|
|
@@ -30306,6 +30772,18 @@ function compileStyles(styles, selector, hostSelector) {
|
|
|
30306
30772
|
return shadowCss.shimCssText(style, selector, hostSelector);
|
|
30307
30773
|
});
|
|
30308
30774
|
}
|
|
30775
|
+
/**
|
|
30776
|
+
* Encapsulates a CSS stylesheet with emulated view encapsulation.
|
|
30777
|
+
* This allows a stylesheet to be used with an Angular component that
|
|
30778
|
+
* is using the `ViewEncapsulation.Emulated` mode.
|
|
30779
|
+
*
|
|
30780
|
+
* @param style The content of a CSS stylesheet.
|
|
30781
|
+
* @returns The encapsulated content for the style.
|
|
30782
|
+
*/
|
|
30783
|
+
function encapsulateStyle(style) {
|
|
30784
|
+
const shadowCss = new ShadowCss();
|
|
30785
|
+
return shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR);
|
|
30786
|
+
}
|
|
30309
30787
|
function createHostDirectivesType(meta) {
|
|
30310
30788
|
if (!meta.hostDirectives?.length) {
|
|
30311
30789
|
return NONE_TYPE;
|
|
@@ -31371,6 +31849,8 @@ function convertDirectiveFacadeToMetadata(facade) {
|
|
|
31371
31849
|
bindingPropertyName: ann.alias || field,
|
|
31372
31850
|
classPropertyName: field,
|
|
31373
31851
|
required: ann.required || false,
|
|
31852
|
+
// TODO(signals): Support JIT signal inputs via decorator transform.
|
|
31853
|
+
isSignal: false,
|
|
31374
31854
|
transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null,
|
|
31375
31855
|
};
|
|
31376
31856
|
}
|
|
@@ -31402,7 +31882,7 @@ function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
|
|
|
31402
31882
|
type: wrapReference(declaration.type),
|
|
31403
31883
|
typeSourceSpan,
|
|
31404
31884
|
selector: declaration.selector ?? null,
|
|
31405
|
-
inputs: declaration.inputs ?
|
|
31885
|
+
inputs: declaration.inputs ? inputsPartialMetadataToInputMetadata(declaration.inputs) : {},
|
|
31406
31886
|
outputs: declaration.outputs ?? {},
|
|
31407
31887
|
host: convertHostDeclarationToMetadata(declaration.host),
|
|
31408
31888
|
queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata),
|
|
@@ -31665,28 +32145,51 @@ function isInput(value) {
|
|
|
31665
32145
|
function isOutput(value) {
|
|
31666
32146
|
return value.ngMetadataName === 'Output';
|
|
31667
32147
|
}
|
|
31668
|
-
function
|
|
31669
|
-
return Object.keys(inputs).reduce((result,
|
|
31670
|
-
const value = inputs[
|
|
31671
|
-
|
|
31672
|
-
|
|
31673
|
-
|
|
31674
|
-
classPropertyName: value,
|
|
31675
|
-
transformFunction: null,
|
|
31676
|
-
required: false,
|
|
31677
|
-
};
|
|
32148
|
+
function inputsPartialMetadataToInputMetadata(inputs) {
|
|
32149
|
+
return Object.keys(inputs).reduce((result, minifiedClassName) => {
|
|
32150
|
+
const value = inputs[minifiedClassName];
|
|
32151
|
+
// Handle legacy partial input output.
|
|
32152
|
+
if (typeof value === 'string' || Array.isArray(value)) {
|
|
32153
|
+
result[minifiedClassName] = parseLegacyInputPartialOutput(value);
|
|
31678
32154
|
}
|
|
31679
32155
|
else {
|
|
31680
|
-
result[
|
|
31681
|
-
bindingPropertyName: value
|
|
31682
|
-
classPropertyName:
|
|
31683
|
-
transformFunction: value
|
|
31684
|
-
|
|
32156
|
+
result[minifiedClassName] = {
|
|
32157
|
+
bindingPropertyName: value.publicName,
|
|
32158
|
+
classPropertyName: minifiedClassName,
|
|
32159
|
+
transformFunction: value.transformFunction !== null ?
|
|
32160
|
+
new WrappedNodeExpr(value.transformFunction) :
|
|
32161
|
+
null,
|
|
32162
|
+
required: value.isRequired,
|
|
32163
|
+
isSignal: value.isSignal,
|
|
31685
32164
|
};
|
|
31686
32165
|
}
|
|
31687
32166
|
return result;
|
|
31688
32167
|
}, {});
|
|
31689
32168
|
}
|
|
32169
|
+
/**
|
|
32170
|
+
* Parses the legacy input partial output. For more details see `partial/directive.ts`.
|
|
32171
|
+
* TODO(legacy-partial-output-inputs): Remove in v18.
|
|
32172
|
+
*/
|
|
32173
|
+
function parseLegacyInputPartialOutput(value) {
|
|
32174
|
+
if (typeof value === 'string') {
|
|
32175
|
+
return {
|
|
32176
|
+
bindingPropertyName: value,
|
|
32177
|
+
classPropertyName: value,
|
|
32178
|
+
transformFunction: null,
|
|
32179
|
+
required: false,
|
|
32180
|
+
// legacy partial output does not capture signal inputs.
|
|
32181
|
+
isSignal: false,
|
|
32182
|
+
};
|
|
32183
|
+
}
|
|
32184
|
+
return {
|
|
32185
|
+
bindingPropertyName: value[0],
|
|
32186
|
+
classPropertyName: value[1],
|
|
32187
|
+
transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
|
|
32188
|
+
required: false,
|
|
32189
|
+
// legacy partial output does not capture signal inputs.
|
|
32190
|
+
isSignal: false,
|
|
32191
|
+
};
|
|
32192
|
+
}
|
|
31690
32193
|
function parseInputsArray(values) {
|
|
31691
32194
|
return values.reduce((results, value) => {
|
|
31692
32195
|
if (typeof value === 'string') {
|
|
@@ -31695,6 +32198,8 @@ function parseInputsArray(values) {
|
|
|
31695
32198
|
bindingPropertyName,
|
|
31696
32199
|
classPropertyName,
|
|
31697
32200
|
required: false,
|
|
32201
|
+
// Signal inputs not supported for the inputs array.
|
|
32202
|
+
isSignal: false,
|
|
31698
32203
|
transformFunction: null,
|
|
31699
32204
|
};
|
|
31700
32205
|
}
|
|
@@ -31703,6 +32208,8 @@ function parseInputsArray(values) {
|
|
|
31703
32208
|
bindingPropertyName: value.alias || value.name,
|
|
31704
32209
|
classPropertyName: value.name,
|
|
31705
32210
|
required: value.required || false,
|
|
32211
|
+
// Signal inputs not supported for the inputs array.
|
|
32212
|
+
isSignal: false,
|
|
31706
32213
|
transformFunction: value.transform != null ? new WrappedNodeExpr(value.transform) : null,
|
|
31707
32214
|
};
|
|
31708
32215
|
}
|
|
@@ -31755,7 +32262,7 @@ function publishFacade(global) {
|
|
|
31755
32262
|
* @description
|
|
31756
32263
|
* Entry point for all public APIs of the compiler package.
|
|
31757
32264
|
*/
|
|
31758
|
-
const VERSION = new Version('17.1.0-next.
|
|
32265
|
+
const VERSION = new Version('17.1.0-next.5');
|
|
31759
32266
|
|
|
31760
32267
|
class CompilerConfig {
|
|
31761
32268
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -33317,11 +33824,11 @@ function compileClassDebugInfo(debugInfo) {
|
|
|
33317
33824
|
*
|
|
33318
33825
|
* Do not include any prerelease in these versions as they are ignored.
|
|
33319
33826
|
*/
|
|
33320
|
-
const MINIMUM_PARTIAL_LINKER_VERSION$
|
|
33827
|
+
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
|
|
33321
33828
|
function compileDeclareClassMetadata(metadata) {
|
|
33322
33829
|
const definitionMap = new DefinitionMap();
|
|
33323
|
-
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$
|
|
33324
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33830
|
+
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
33831
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33325
33832
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33326
33833
|
definitionMap.set('type', metadata.type);
|
|
33327
33834
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -33400,14 +33907,6 @@ function compileDependency(dep) {
|
|
|
33400
33907
|
return depMeta.toLiteralMap();
|
|
33401
33908
|
}
|
|
33402
33909
|
|
|
33403
|
-
/**
|
|
33404
|
-
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
33405
|
-
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
33406
|
-
* declaration.
|
|
33407
|
-
*
|
|
33408
|
-
* Do not include any prerelease in these versions as they are ignored.
|
|
33409
|
-
*/
|
|
33410
|
-
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '16.1.0';
|
|
33411
33910
|
/**
|
|
33412
33911
|
* Compile a directive declaration defined by the `R3DirectiveMetadata`.
|
|
33413
33912
|
*/
|
|
@@ -33423,13 +33922,9 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
33423
33922
|
*/
|
|
33424
33923
|
function createDirectiveDefinitionMap(meta) {
|
|
33425
33924
|
const definitionMap = new DefinitionMap();
|
|
33426
|
-
const
|
|
33427
|
-
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
33428
|
-
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
33429
|
-
// in 16.1 is actually used.
|
|
33430
|
-
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
33925
|
+
const minVersion = getMinimumVersionForPartialOutput(meta);
|
|
33431
33926
|
definitionMap.set('minVersion', literal(minVersion));
|
|
33432
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33927
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33433
33928
|
// e.g. `type: MyDirective`
|
|
33434
33929
|
definitionMap.set('type', meta.type.value);
|
|
33435
33930
|
if (meta.isStandalone) {
|
|
@@ -33442,7 +33937,8 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
33442
33937
|
if (meta.selector !== null) {
|
|
33443
33938
|
definitionMap.set('selector', literal(meta.selector));
|
|
33444
33939
|
}
|
|
33445
|
-
definitionMap.set('inputs',
|
|
33940
|
+
definitionMap.set('inputs', needsNewInputPartialOutput(meta) ? createInputsPartialMetadata(meta.inputs) :
|
|
33941
|
+
legacyInputsPartialMetadata(meta.inputs));
|
|
33446
33942
|
definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
|
|
33447
33943
|
definitionMap.set('host', compileHostMetadata(meta.host));
|
|
33448
33944
|
definitionMap.set('providers', meta.providers);
|
|
@@ -33467,6 +33963,44 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
33467
33963
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33468
33964
|
return definitionMap;
|
|
33469
33965
|
}
|
|
33966
|
+
/**
|
|
33967
|
+
* Determines the minimum linker version for the partial output
|
|
33968
|
+
* generated for this directive.
|
|
33969
|
+
*
|
|
33970
|
+
* Every time we make a breaking change to the declaration interface or partial-linker
|
|
33971
|
+
* behavior, we must update the minimum versions to prevent old partial-linkers from
|
|
33972
|
+
* incorrectly processing the declaration.
|
|
33973
|
+
*
|
|
33974
|
+
* NOTE: Do not include any prerelease in these versions as they are ignored.
|
|
33975
|
+
*/
|
|
33976
|
+
function getMinimumVersionForPartialOutput(meta) {
|
|
33977
|
+
// We are starting with the oldest minimum version that can work for common
|
|
33978
|
+
// directive partial compilation output. As we discover usages of new features
|
|
33979
|
+
// that require a newer partial output emit, we bump the `minVersion`. Our goal
|
|
33980
|
+
// is to keep libraries as much compatible with older linker versions as possible.
|
|
33981
|
+
let minVersion = '14.0.0';
|
|
33982
|
+
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
33983
|
+
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
33984
|
+
// in 16.1 is actually used.
|
|
33985
|
+
const hasTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
|
|
33986
|
+
if (hasTransformFunctions) {
|
|
33987
|
+
minVersion = '16.1.0';
|
|
33988
|
+
}
|
|
33989
|
+
// If there are input flags and we need the new emit, use the actual minimum version,
|
|
33990
|
+
// where this was introduced. i.e. in 17.1.0
|
|
33991
|
+
// TODO(legacy-partial-output-inputs): Remove in v18.
|
|
33992
|
+
if (needsNewInputPartialOutput(meta)) {
|
|
33993
|
+
minVersion = '17.1.0';
|
|
33994
|
+
}
|
|
33995
|
+
return minVersion;
|
|
33996
|
+
}
|
|
33997
|
+
/**
|
|
33998
|
+
* Gets whether the given directive needs the new input partial output structure
|
|
33999
|
+
* that can hold additional metadata like `isRequired`, `isSignal` etc.
|
|
34000
|
+
*/
|
|
34001
|
+
function needsNewInputPartialOutput(meta) {
|
|
34002
|
+
return Object.values(meta.inputs).some(input => input.isSignal);
|
|
34003
|
+
}
|
|
33470
34004
|
/**
|
|
33471
34005
|
* Compiles the metadata of a single query into its partial declaration form as declared
|
|
33472
34006
|
* by `R3DeclareQueryMetadata`.
|
|
@@ -33540,6 +34074,74 @@ function createHostDirectives(hostDirectives) {
|
|
|
33540
34074
|
// otherwise we can save some bytes by using a plain array, e.g. `[{directive: HostDir}]`.
|
|
33541
34075
|
return literalArr(expressions);
|
|
33542
34076
|
}
|
|
34077
|
+
/**
|
|
34078
|
+
* Generates partial output metadata for inputs of a directive.
|
|
34079
|
+
*
|
|
34080
|
+
* The generated structure is expected to match `R3DeclareDirectiveFacade['inputs']`.
|
|
34081
|
+
*/
|
|
34082
|
+
function createInputsPartialMetadata(inputs) {
|
|
34083
|
+
const keys = Object.getOwnPropertyNames(inputs);
|
|
34084
|
+
if (keys.length === 0) {
|
|
34085
|
+
return null;
|
|
34086
|
+
}
|
|
34087
|
+
return literalMap(keys.map(declaredName => {
|
|
34088
|
+
const value = inputs[declaredName];
|
|
34089
|
+
return {
|
|
34090
|
+
key: declaredName,
|
|
34091
|
+
// put quotes around keys that contain potentially unsafe characters
|
|
34092
|
+
quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
|
|
34093
|
+
value: literalMap([
|
|
34094
|
+
{ key: 'classPropertyName', quoted: false, value: asLiteral(value.classPropertyName) },
|
|
34095
|
+
{ key: 'publicName', quoted: false, value: asLiteral(value.bindingPropertyName) },
|
|
34096
|
+
{ key: 'isSignal', quoted: false, value: asLiteral(value.isSignal) },
|
|
34097
|
+
{ key: 'isRequired', quoted: false, value: asLiteral(value.required) },
|
|
34098
|
+
{ key: 'transformFunction', quoted: false, value: value.transformFunction ?? NULL_EXPR },
|
|
34099
|
+
])
|
|
34100
|
+
};
|
|
34101
|
+
}));
|
|
34102
|
+
}
|
|
34103
|
+
/**
|
|
34104
|
+
* Pre v18 legacy partial output for inputs.
|
|
34105
|
+
*
|
|
34106
|
+
* Previously, inputs did not capture metadata like `isSignal` in the partial compilation output.
|
|
34107
|
+
* To enable capturing such metadata, we restructured how input metadata is communicated in the
|
|
34108
|
+
* partial output. This would make libraries incompatible with older Angular FW versions where the
|
|
34109
|
+
* linker would not know how to handle this new "format". For this reason, if we know this metadata
|
|
34110
|
+
* does not need to be captured- we fall back to the old format. This is what this function
|
|
34111
|
+
* generates.
|
|
34112
|
+
*
|
|
34113
|
+
* See:
|
|
34114
|
+
* https://github.com/angular/angular/blob/d4b423690210872b5c32a322a6090beda30b05a3/packages/core/src/compiler/compiler_facade_interface.ts#L197-L199
|
|
34115
|
+
*/
|
|
34116
|
+
function legacyInputsPartialMetadata(inputs) {
|
|
34117
|
+
// TODO(legacy-partial-output-inputs): Remove function in v18.
|
|
34118
|
+
const keys = Object.getOwnPropertyNames(inputs);
|
|
34119
|
+
if (keys.length === 0) {
|
|
34120
|
+
return null;
|
|
34121
|
+
}
|
|
34122
|
+
return literalMap(keys.map(declaredName => {
|
|
34123
|
+
const value = inputs[declaredName];
|
|
34124
|
+
const publicName = value.bindingPropertyName;
|
|
34125
|
+
const differentDeclaringName = publicName !== declaredName;
|
|
34126
|
+
let result;
|
|
34127
|
+
if (differentDeclaringName || value.transformFunction !== null) {
|
|
34128
|
+
const values = [asLiteral(publicName), asLiteral(declaredName)];
|
|
34129
|
+
if (value.transformFunction !== null) {
|
|
34130
|
+
values.push(value.transformFunction);
|
|
34131
|
+
}
|
|
34132
|
+
result = literalArr(values);
|
|
34133
|
+
}
|
|
34134
|
+
else {
|
|
34135
|
+
result = asLiteral(publicName);
|
|
34136
|
+
}
|
|
34137
|
+
return {
|
|
34138
|
+
key: declaredName,
|
|
34139
|
+
// put quotes around keys that contain potentially unsafe characters
|
|
34140
|
+
quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
|
|
34141
|
+
value: result,
|
|
34142
|
+
};
|
|
34143
|
+
}));
|
|
34144
|
+
}
|
|
33543
34145
|
|
|
33544
34146
|
/**
|
|
33545
34147
|
* Compile a component declaration defined by the `R3ComponentMetadata`.
|
|
@@ -33706,7 +34308,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
33706
34308
|
function compileDeclareFactoryFunction(meta) {
|
|
33707
34309
|
const definitionMap = new DefinitionMap();
|
|
33708
34310
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
33709
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34311
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33710
34312
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33711
34313
|
definitionMap.set('type', meta.type.value);
|
|
33712
34314
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -33741,7 +34343,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
33741
34343
|
function createInjectableDefinitionMap(meta) {
|
|
33742
34344
|
const definitionMap = new DefinitionMap();
|
|
33743
34345
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
33744
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34346
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33745
34347
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33746
34348
|
definitionMap.set('type', meta.type.value);
|
|
33747
34349
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -33792,7 +34394,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
33792
34394
|
function createInjectorDefinitionMap(meta) {
|
|
33793
34395
|
const definitionMap = new DefinitionMap();
|
|
33794
34396
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
33795
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34397
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33796
34398
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33797
34399
|
definitionMap.set('type', meta.type.value);
|
|
33798
34400
|
definitionMap.set('providers', meta.providers);
|
|
@@ -33825,7 +34427,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
33825
34427
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
33826
34428
|
}
|
|
33827
34429
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
33828
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34430
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33829
34431
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33830
34432
|
definitionMap.set('type', meta.type.value);
|
|
33831
34433
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -33876,7 +34478,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
33876
34478
|
function createPipeDefinitionMap(meta) {
|
|
33877
34479
|
const definitionMap = new DefinitionMap();
|
|
33878
34480
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
33879
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34481
|
+
definitionMap.set('version', literal('17.1.0-next.5'));
|
|
33880
34482
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33881
34483
|
// e.g. `type: MyPipe`
|
|
33882
34484
|
definitionMap.set('type', meta.type.value);
|
|
@@ -33909,5 +34511,5 @@ publishFacade(_global);
|
|
|
33909
34511
|
|
|
33910
34512
|
// This file is not used to build this module. It is only used during editing
|
|
33911
34513
|
|
|
33912
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, 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, UnknownBlock as TmplAstUnknownBlock, 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, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createCssSelectorFromNode, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
34514
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, 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, UnknownBlock as TmplAstUnknownBlock, 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, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createCssSelectorFromNode, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, encapsulateStyle, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
33913
34515
|
//# sourceMappingURL=compiler.mjs.map
|