@angular/compiler 17.1.0-next.2 → 17.1.0-next.4
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/jit_compiler_facade.mjs +46 -17
- 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 +43 -16
- package/esm2022/src/render3/view/util.mjs +8 -2
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +34 -17
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +19 -20
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +37 -11
- package/esm2022/src/template/pipeline/ir/src/ops/host.mjs +5 -2
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +29 -14
- package/esm2022/src/template/pipeline/src/emit.mjs +13 -9
- package/esm2022/src/template/pipeline/src/ingest.mjs +293 -158
- package/esm2022/src/template/pipeline/src/instruction.mjs +18 -14
- package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +20 -4
- package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +44 -22
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +26 -5
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +15 -6
- package/esm2022/src/template/pipeline/src/phases/convert_i18n_bindings.mjs +52 -0
- package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +23 -1
- package/esm2022/src/template/pipeline/src/phases/extract_i18n_messages.mjs +65 -88
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +7 -1
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +147 -35
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +5 -3
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +4 -3
- package/esm2022/src/template/pipeline/src/phases/phase_remove_content_selectors.mjs +15 -3
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +31 -12
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +18 -15
- package/esm2022/src/template/pipeline/src/phases/remove_unused_i18n_attrs.mjs +33 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_element_placeholders.mjs +175 -31
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +10 -5
- 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/var_counting.mjs +3 -1
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1394 -532
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +39 -6
- package/package.json +2 -2
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.4
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2636,6 +2636,9 @@ class Identifiers {
|
|
|
2636
2636
|
static { this.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE }; }
|
|
2637
2637
|
static { this.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE }; }
|
|
2638
2638
|
static { this.validateIframeAttribute = { name: 'ɵɵvalidateIframeAttribute', moduleName: CORE }; }
|
|
2639
|
+
// type-checking
|
|
2640
|
+
static { this.InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE }; }
|
|
2641
|
+
static { this.UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE }; }
|
|
2639
2642
|
}
|
|
2640
2643
|
|
|
2641
2644
|
const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
|
|
@@ -4712,7 +4715,7 @@ const I18N_ATTR_PREFIX = 'i18n-';
|
|
|
4712
4715
|
/** Prefix of var expressions used in ICUs */
|
|
4713
4716
|
const I18N_ICU_VAR_PREFIX = 'VAR_';
|
|
4714
4717
|
/** Prefix of ICU expressions for post processing */
|
|
4715
|
-
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
4718
|
+
const I18N_ICU_MAPPING_PREFIX$1 = 'I18N_EXP_';
|
|
4716
4719
|
/** Placeholder wrapper for i18n expressions **/
|
|
4717
4720
|
const I18N_PLACEHOLDER_SYMBOL = '�';
|
|
4718
4721
|
function isI18nAttribute(name) {
|
|
@@ -4957,6 +4960,12 @@ function asLiteral(value) {
|
|
|
4957
4960
|
}
|
|
4958
4961
|
return literal(value, INFERRED_TYPE);
|
|
4959
4962
|
}
|
|
4963
|
+
/**
|
|
4964
|
+
* Serializes inputs and outputs for `defineDirective` and `defineComponent`.
|
|
4965
|
+
*
|
|
4966
|
+
* This will attempt to generate optimized data structures to minimize memory or
|
|
4967
|
+
* file size of fully compiled applications.
|
|
4968
|
+
*/
|
|
4960
4969
|
function conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) {
|
|
4961
4970
|
const keys = Object.getOwnPropertyNames(map);
|
|
4962
4971
|
if (keys.length === 0) {
|
|
@@ -8970,6 +8979,10 @@ var OpKind;
|
|
|
8970
8979
|
* An i18n context containing information needed to generate an i18n message.
|
|
8971
8980
|
*/
|
|
8972
8981
|
OpKind[OpKind["I18nContext"] = 43] = "I18nContext";
|
|
8982
|
+
/**
|
|
8983
|
+
* A creation op that corresponds to i18n attributes on an element.
|
|
8984
|
+
*/
|
|
8985
|
+
OpKind[OpKind["I18nAttributes"] = 44] = "I18nAttributes";
|
|
8973
8986
|
})(OpKind || (OpKind = {}));
|
|
8974
8987
|
/**
|
|
8975
8988
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9060,23 +9073,27 @@ var ExpressionKind;
|
|
|
9060
9073
|
* An expression representing a sanitizer function.
|
|
9061
9074
|
*/
|
|
9062
9075
|
ExpressionKind[ExpressionKind["SanitizerExpr"] = 20] = "SanitizerExpr";
|
|
9076
|
+
/**
|
|
9077
|
+
* An expression representing a function to create trusted values.
|
|
9078
|
+
*/
|
|
9079
|
+
ExpressionKind[ExpressionKind["TrustedValueFnExpr"] = 21] = "TrustedValueFnExpr";
|
|
9063
9080
|
/**
|
|
9064
9081
|
* An expression that will cause a literal slot index to be emitted.
|
|
9065
9082
|
*/
|
|
9066
|
-
ExpressionKind[ExpressionKind["SlotLiteralExpr"] =
|
|
9083
|
+
ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
|
|
9067
9084
|
/**
|
|
9068
9085
|
* A test expression for a conditional op.
|
|
9069
9086
|
*/
|
|
9070
|
-
ExpressionKind[ExpressionKind["ConditionalCase"] =
|
|
9087
|
+
ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
|
|
9071
9088
|
/**
|
|
9072
9089
|
* A variable for use inside a repeater, providing one of the ambiently-available context
|
|
9073
9090
|
* properties ($even, $first, etc.).
|
|
9074
9091
|
*/
|
|
9075
|
-
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] =
|
|
9092
|
+
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 24] = "DerivedRepeaterVar";
|
|
9076
9093
|
/**
|
|
9077
9094
|
* An expression that will be automatically extracted to the component const array.
|
|
9078
9095
|
*/
|
|
9079
|
-
ExpressionKind[ExpressionKind["ConstCollected"] =
|
|
9096
|
+
ExpressionKind[ExpressionKind["ConstCollected"] = 25] = "ConstCollected";
|
|
9080
9097
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
9081
9098
|
var VariableFlags;
|
|
9082
9099
|
(function (VariableFlags) {
|
|
@@ -9120,18 +9137,6 @@ var CompatibilityMode;
|
|
|
9120
9137
|
CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
|
|
9121
9138
|
CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
|
|
9122
9139
|
})(CompatibilityMode || (CompatibilityMode = {}));
|
|
9123
|
-
/**
|
|
9124
|
-
* Represents functions used to sanitize different pieces of a template.
|
|
9125
|
-
*/
|
|
9126
|
-
var SanitizerFn;
|
|
9127
|
-
(function (SanitizerFn) {
|
|
9128
|
-
SanitizerFn[SanitizerFn["Html"] = 0] = "Html";
|
|
9129
|
-
SanitizerFn[SanitizerFn["Script"] = 1] = "Script";
|
|
9130
|
-
SanitizerFn[SanitizerFn["Style"] = 2] = "Style";
|
|
9131
|
-
SanitizerFn[SanitizerFn["Url"] = 3] = "Url";
|
|
9132
|
-
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
9133
|
-
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
9134
|
-
})(SanitizerFn || (SanitizerFn = {}));
|
|
9135
9140
|
/**
|
|
9136
9141
|
* Enumeration of the different kinds of `@defer` secondary blocks.
|
|
9137
9142
|
*/
|
|
@@ -9191,6 +9196,20 @@ var I18nParamResolutionTime;
|
|
|
9191
9196
|
*/
|
|
9192
9197
|
I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
|
|
9193
9198
|
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
|
|
9199
|
+
/**
|
|
9200
|
+
* The contexts in which an i18n expression can be used.
|
|
9201
|
+
*/
|
|
9202
|
+
var I18nExpressionFor;
|
|
9203
|
+
(function (I18nExpressionFor) {
|
|
9204
|
+
/**
|
|
9205
|
+
* This expression is used as a value (i.e. inside an i18n block).
|
|
9206
|
+
*/
|
|
9207
|
+
I18nExpressionFor[I18nExpressionFor["I18nText"] = 0] = "I18nText";
|
|
9208
|
+
/**
|
|
9209
|
+
* This expression is used in a binding.
|
|
9210
|
+
*/
|
|
9211
|
+
I18nExpressionFor[I18nExpressionFor["I18nAttribute"] = 1] = "I18nAttribute";
|
|
9212
|
+
})(I18nExpressionFor || (I18nExpressionFor = {}));
|
|
9194
9213
|
/**
|
|
9195
9214
|
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
9196
9215
|
* the final map.
|
|
@@ -9257,7 +9276,14 @@ var I18nContextKind;
|
|
|
9257
9276
|
(function (I18nContextKind) {
|
|
9258
9277
|
I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
|
|
9259
9278
|
I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
|
|
9279
|
+
I18nContextKind[I18nContextKind["Attr"] = 2] = "Attr";
|
|
9260
9280
|
})(I18nContextKind || (I18nContextKind = {}));
|
|
9281
|
+
var TemplateKind;
|
|
9282
|
+
(function (TemplateKind) {
|
|
9283
|
+
TemplateKind[TemplateKind["NgTemplate"] = 0] = "NgTemplate";
|
|
9284
|
+
TemplateKind[TemplateKind["Structural"] = 1] = "Structural";
|
|
9285
|
+
TemplateKind[TemplateKind["Block"] = 2] = "Block";
|
|
9286
|
+
})(TemplateKind || (TemplateKind = {}));
|
|
9261
9287
|
|
|
9262
9288
|
/**
|
|
9263
9289
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9365,12 +9391,11 @@ const NEW_OP = {
|
|
|
9365
9391
|
/**
|
|
9366
9392
|
* Create an `InterpolationTextOp`.
|
|
9367
9393
|
*/
|
|
9368
|
-
function createInterpolateTextOp(xref, interpolation,
|
|
9394
|
+
function createInterpolateTextOp(xref, interpolation, sourceSpan) {
|
|
9369
9395
|
return {
|
|
9370
9396
|
kind: OpKind.InterpolateText,
|
|
9371
9397
|
target: xref,
|
|
9372
9398
|
interpolation,
|
|
9373
|
-
i18nPlaceholders,
|
|
9374
9399
|
sourceSpan,
|
|
9375
9400
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9376
9401
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9378,15 +9403,19 @@ function createInterpolateTextOp(xref, interpolation, i18nPlaceholders, sourceSp
|
|
|
9378
9403
|
};
|
|
9379
9404
|
}
|
|
9380
9405
|
class Interpolation {
|
|
9381
|
-
constructor(strings, expressions) {
|
|
9406
|
+
constructor(strings, expressions, i18nPlaceholders) {
|
|
9382
9407
|
this.strings = strings;
|
|
9383
9408
|
this.expressions = expressions;
|
|
9409
|
+
this.i18nPlaceholders = i18nPlaceholders;
|
|
9410
|
+
if (i18nPlaceholders.length !== 0 && i18nPlaceholders.length !== expressions.length) {
|
|
9411
|
+
throw new Error(`Expected ${expressions.length} placeholders to match interpolation expression count, but got ${i18nPlaceholders.length}`);
|
|
9412
|
+
}
|
|
9384
9413
|
}
|
|
9385
9414
|
}
|
|
9386
9415
|
/**
|
|
9387
9416
|
* Create a `BindingOp`, not yet transformed into a particular type of binding.
|
|
9388
9417
|
*/
|
|
9389
|
-
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute,
|
|
9418
|
+
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9390
9419
|
return {
|
|
9391
9420
|
kind: OpKind.Binding,
|
|
9392
9421
|
bindingKind: kind,
|
|
@@ -9396,7 +9425,10 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9396
9425
|
unit,
|
|
9397
9426
|
securityContext,
|
|
9398
9427
|
isTextAttribute,
|
|
9399
|
-
|
|
9428
|
+
isStructuralTemplateAttribute,
|
|
9429
|
+
templateKind,
|
|
9430
|
+
i18nContext: null,
|
|
9431
|
+
i18nMessage,
|
|
9400
9432
|
sourceSpan,
|
|
9401
9433
|
...NEW_OP,
|
|
9402
9434
|
};
|
|
@@ -9404,7 +9436,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9404
9436
|
/**
|
|
9405
9437
|
* Create a `PropertyOp`.
|
|
9406
9438
|
*/
|
|
9407
|
-
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext,
|
|
9439
|
+
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
|
|
9408
9440
|
return {
|
|
9409
9441
|
kind: OpKind.Property,
|
|
9410
9442
|
target,
|
|
@@ -9413,7 +9445,10 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
|
|
|
9413
9445
|
isAnimationTrigger,
|
|
9414
9446
|
securityContext,
|
|
9415
9447
|
sanitizer: null,
|
|
9416
|
-
|
|
9448
|
+
isStructuralTemplateAttribute,
|
|
9449
|
+
templateKind,
|
|
9450
|
+
i18nContext,
|
|
9451
|
+
i18nMessage,
|
|
9417
9452
|
sourceSpan,
|
|
9418
9453
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9419
9454
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9478,7 +9513,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9478
9513
|
/**
|
|
9479
9514
|
* Create an `AttributeOp`.
|
|
9480
9515
|
*/
|
|
9481
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute,
|
|
9516
|
+
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9482
9517
|
return {
|
|
9483
9518
|
kind: OpKind.Attribute,
|
|
9484
9519
|
target,
|
|
@@ -9487,7 +9522,10 @@ function createAttributeOp(target, name, expression, securityContext, isTextAttr
|
|
|
9487
9522
|
securityContext,
|
|
9488
9523
|
sanitizer: null,
|
|
9489
9524
|
isTextAttribute,
|
|
9490
|
-
|
|
9525
|
+
isStructuralTemplateAttribute,
|
|
9526
|
+
templateKind,
|
|
9527
|
+
i18nContext: null,
|
|
9528
|
+
i18nMessage,
|
|
9491
9529
|
sourceSpan,
|
|
9492
9530
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9493
9531
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9548,15 +9586,18 @@ function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
|
|
|
9548
9586
|
/**
|
|
9549
9587
|
* Create an i18n expression op.
|
|
9550
9588
|
*/
|
|
9551
|
-
function createI18nExpressionOp(context, target, handle, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9589
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9552
9590
|
return {
|
|
9553
9591
|
kind: OpKind.I18nExpression,
|
|
9554
9592
|
context,
|
|
9555
9593
|
target,
|
|
9594
|
+
i18nOwner,
|
|
9556
9595
|
handle,
|
|
9557
9596
|
expression,
|
|
9558
9597
|
i18nPlaceholder,
|
|
9559
9598
|
resolutionTime,
|
|
9599
|
+
usage,
|
|
9600
|
+
name,
|
|
9560
9601
|
sourceSpan,
|
|
9561
9602
|
...NEW_OP,
|
|
9562
9603
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9564,12 +9605,12 @@ function createI18nExpressionOp(context, target, handle, expression, i18nPlaceho
|
|
|
9564
9605
|
};
|
|
9565
9606
|
}
|
|
9566
9607
|
/**
|
|
9567
|
-
*Creates an op to apply i18n expression ops
|
|
9608
|
+
* Creates an op to apply i18n expression ops.
|
|
9568
9609
|
*/
|
|
9569
|
-
function createI18nApplyOp(
|
|
9610
|
+
function createI18nApplyOp(owner, handle, sourceSpan) {
|
|
9570
9611
|
return {
|
|
9571
9612
|
kind: OpKind.I18nApply,
|
|
9572
|
-
|
|
9613
|
+
owner,
|
|
9573
9614
|
handle,
|
|
9574
9615
|
sourceSpan,
|
|
9575
9616
|
...NEW_OP,
|
|
@@ -10118,24 +10159,6 @@ class ReadTemporaryExpr extends ExpressionBase {
|
|
|
10118
10159
|
return r;
|
|
10119
10160
|
}
|
|
10120
10161
|
}
|
|
10121
|
-
class SanitizerExpr extends ExpressionBase {
|
|
10122
|
-
constructor(fn) {
|
|
10123
|
-
super();
|
|
10124
|
-
this.fn = fn;
|
|
10125
|
-
this.kind = ExpressionKind.SanitizerExpr;
|
|
10126
|
-
}
|
|
10127
|
-
visitExpression(visitor, context) { }
|
|
10128
|
-
isEquivalent(e) {
|
|
10129
|
-
return e instanceof SanitizerExpr && e.fn === this.fn;
|
|
10130
|
-
}
|
|
10131
|
-
isConstant() {
|
|
10132
|
-
return true;
|
|
10133
|
-
}
|
|
10134
|
-
clone() {
|
|
10135
|
-
return new SanitizerExpr(this.fn);
|
|
10136
|
-
}
|
|
10137
|
-
transformInternalExpressions() { }
|
|
10138
|
-
}
|
|
10139
10162
|
class SlotLiteralExpr extends ExpressionBase {
|
|
10140
10163
|
constructor(slot) {
|
|
10141
10164
|
super();
|
|
@@ -10266,7 +10289,6 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10266
10289
|
case OpKind.ClassProp:
|
|
10267
10290
|
case OpKind.ClassMap:
|
|
10268
10291
|
case OpKind.Binding:
|
|
10269
|
-
case OpKind.HostProperty:
|
|
10270
10292
|
if (op.expression instanceof Interpolation) {
|
|
10271
10293
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
10272
10294
|
}
|
|
@@ -10275,6 +10297,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10275
10297
|
}
|
|
10276
10298
|
break;
|
|
10277
10299
|
case OpKind.Property:
|
|
10300
|
+
case OpKind.HostProperty:
|
|
10278
10301
|
case OpKind.Attribute:
|
|
10279
10302
|
if (op.expression instanceof Interpolation) {
|
|
10280
10303
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
@@ -10320,6 +10343,8 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10320
10343
|
case OpKind.ExtractedAttribute:
|
|
10321
10344
|
op.expression =
|
|
10322
10345
|
op.expression && transformExpressionsInExpression(op.expression, transform, flags);
|
|
10346
|
+
op.trustedValueFn = op.trustedValueFn &&
|
|
10347
|
+
transformExpressionsInExpression(op.trustedValueFn, transform, flags);
|
|
10323
10348
|
break;
|
|
10324
10349
|
case OpKind.RepeaterCreate:
|
|
10325
10350
|
op.track = transformExpressionsInExpression(op.track, transform, flags);
|
|
@@ -10373,6 +10398,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10373
10398
|
case OpKind.ProjectionDef:
|
|
10374
10399
|
case OpKind.Template:
|
|
10375
10400
|
case OpKind.Text:
|
|
10401
|
+
case OpKind.I18nAttributes:
|
|
10376
10402
|
// These operations contain no expressions.
|
|
10377
10403
|
break;
|
|
10378
10404
|
default:
|
|
@@ -10393,6 +10419,9 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10393
10419
|
expr.lhs = transformExpressionsInExpression(expr.lhs, transform, flags);
|
|
10394
10420
|
expr.rhs = transformExpressionsInExpression(expr.rhs, transform, flags);
|
|
10395
10421
|
}
|
|
10422
|
+
else if (expr instanceof UnaryOperatorExpr) {
|
|
10423
|
+
expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
|
|
10424
|
+
}
|
|
10396
10425
|
else if (expr instanceof ReadPropExpr) {
|
|
10397
10426
|
expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
|
|
10398
10427
|
}
|
|
@@ -10444,6 +10473,17 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10444
10473
|
expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
|
|
10445
10474
|
}
|
|
10446
10475
|
}
|
|
10476
|
+
else if (expr instanceof NotExpr) {
|
|
10477
|
+
expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
|
|
10478
|
+
}
|
|
10479
|
+
else if (expr instanceof TaggedTemplateExpr) {
|
|
10480
|
+
expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
|
|
10481
|
+
expr.template.expressions =
|
|
10482
|
+
expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
|
|
10483
|
+
}
|
|
10484
|
+
else if (expr instanceof WrappedNodeExpr) {
|
|
10485
|
+
// TODO: Do we need to transform any TS nodes nested inside of this expression?
|
|
10486
|
+
}
|
|
10447
10487
|
else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
|
|
10448
10488
|
expr instanceof LiteralExpr) {
|
|
10449
10489
|
// No action for these types.
|
|
@@ -10785,10 +10825,11 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10785
10825
|
/**
|
|
10786
10826
|
* Create a `TemplateOp`.
|
|
10787
10827
|
*/
|
|
10788
|
-
function createTemplateOp(xref, tag, functionNameSuffix, namespace, i18nPlaceholder, sourceSpan) {
|
|
10828
|
+
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, sourceSpan) {
|
|
10789
10829
|
return {
|
|
10790
10830
|
kind: OpKind.Template,
|
|
10791
10831
|
xref,
|
|
10832
|
+
templateKind,
|
|
10792
10833
|
attributes: null,
|
|
10793
10834
|
tag,
|
|
10794
10835
|
handle: new SlotHandle(),
|
|
@@ -10804,7 +10845,7 @@ function createTemplateOp(xref, tag, functionNameSuffix, namespace, i18nPlacehol
|
|
|
10804
10845
|
...NEW_OP,
|
|
10805
10846
|
};
|
|
10806
10847
|
}
|
|
10807
|
-
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, sourceSpan) {
|
|
10848
|
+
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, sourceSpan) {
|
|
10808
10849
|
return {
|
|
10809
10850
|
kind: OpKind.RepeaterCreate,
|
|
10810
10851
|
attributes: null,
|
|
@@ -10822,6 +10863,8 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, so
|
|
|
10822
10863
|
vars: null,
|
|
10823
10864
|
varNames,
|
|
10824
10865
|
usesComponentInstance: false,
|
|
10866
|
+
i18nPlaceholder,
|
|
10867
|
+
emptyI18nPlaceholder,
|
|
10825
10868
|
sourceSpan,
|
|
10826
10869
|
...TRAIT_CONSUMES_SLOT,
|
|
10827
10870
|
...NEW_OP,
|
|
@@ -10870,7 +10913,9 @@ function createTextOp(xref, initialValue, sourceSpan) {
|
|
|
10870
10913
|
/**
|
|
10871
10914
|
* Create a `ListenerOp`. Host bindings reuse all the listener logic.
|
|
10872
10915
|
*/
|
|
10873
|
-
function createListenerOp(target, targetSlot, name, tag, animationPhase, hostListener, sourceSpan) {
|
|
10916
|
+
function createListenerOp(target, targetSlot, name, tag, handlerOps, animationPhase, eventTarget, hostListener, sourceSpan) {
|
|
10917
|
+
const handlerList = new OpList();
|
|
10918
|
+
handlerList.push(handlerOps);
|
|
10874
10919
|
return {
|
|
10875
10920
|
kind: OpKind.Listener,
|
|
10876
10921
|
target,
|
|
@@ -10878,11 +10923,12 @@ function createListenerOp(target, targetSlot, name, tag, animationPhase, hostLis
|
|
|
10878
10923
|
tag,
|
|
10879
10924
|
hostListener,
|
|
10880
10925
|
name,
|
|
10881
|
-
handlerOps:
|
|
10926
|
+
handlerOps: handlerList,
|
|
10882
10927
|
handlerFnName: null,
|
|
10883
10928
|
consumesDollarEvent: false,
|
|
10884
10929
|
isAnimationListener: animationPhase !== null,
|
|
10885
|
-
animationPhase
|
|
10930
|
+
animationPhase,
|
|
10931
|
+
eventTarget,
|
|
10886
10932
|
sourceSpan,
|
|
10887
10933
|
...NEW_OP,
|
|
10888
10934
|
};
|
|
@@ -10911,14 +10957,15 @@ function createProjectionDefOp(def) {
|
|
|
10911
10957
|
...NEW_OP,
|
|
10912
10958
|
};
|
|
10913
10959
|
}
|
|
10914
|
-
function createProjectionOp(xref, selector, sourceSpan) {
|
|
10960
|
+
function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceSpan) {
|
|
10915
10961
|
return {
|
|
10916
10962
|
kind: OpKind.Projection,
|
|
10917
10963
|
xref,
|
|
10918
10964
|
handle: new SlotHandle(),
|
|
10919
10965
|
selector,
|
|
10966
|
+
i18nPlaceholder,
|
|
10920
10967
|
projectionSlotIndex: 0,
|
|
10921
|
-
attributes
|
|
10968
|
+
attributes,
|
|
10922
10969
|
localRefs: [],
|
|
10923
10970
|
sourceSpan,
|
|
10924
10971
|
...NEW_OP,
|
|
@@ -10928,13 +10975,17 @@ function createProjectionOp(xref, selector, sourceSpan) {
|
|
|
10928
10975
|
/**
|
|
10929
10976
|
* Create an `ExtractedAttributeOp`.
|
|
10930
10977
|
*/
|
|
10931
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
10978
|
+
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10932
10979
|
return {
|
|
10933
10980
|
kind: OpKind.ExtractedAttribute,
|
|
10934
10981
|
target,
|
|
10935
10982
|
bindingKind,
|
|
10936
10983
|
name,
|
|
10937
10984
|
expression,
|
|
10985
|
+
i18nContext,
|
|
10986
|
+
i18nMessage,
|
|
10987
|
+
securityContext,
|
|
10988
|
+
trustedValueFn: null,
|
|
10938
10989
|
...NEW_OP,
|
|
10939
10990
|
};
|
|
10940
10991
|
}
|
|
@@ -10977,10 +11028,11 @@ function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
|
|
|
10977
11028
|
/**
|
|
10978
11029
|
* Create an `ExtractedMessageOp`.
|
|
10979
11030
|
*/
|
|
10980
|
-
function createI18nMessageOp(xref, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
11031
|
+
function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
10981
11032
|
return {
|
|
10982
11033
|
kind: OpKind.I18nMessage,
|
|
10983
11034
|
xref,
|
|
11035
|
+
i18nContext,
|
|
10984
11036
|
i18nBlock,
|
|
10985
11037
|
message,
|
|
10986
11038
|
messagePlaceholder,
|
|
@@ -11043,6 +11095,9 @@ function createIcuEndOp(xref) {
|
|
|
11043
11095
|
};
|
|
11044
11096
|
}
|
|
11045
11097
|
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
11098
|
+
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
11099
|
+
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
11100
|
+
}
|
|
11046
11101
|
return {
|
|
11047
11102
|
kind: OpKind.I18nContext,
|
|
11048
11103
|
contextKind,
|
|
@@ -11055,6 +11110,17 @@ function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan)
|
|
|
11055
11110
|
...NEW_OP,
|
|
11056
11111
|
};
|
|
11057
11112
|
}
|
|
11113
|
+
function createI18nAttributesOp(xref, handle, target) {
|
|
11114
|
+
return {
|
|
11115
|
+
kind: OpKind.I18nAttributes,
|
|
11116
|
+
xref,
|
|
11117
|
+
handle,
|
|
11118
|
+
target,
|
|
11119
|
+
i18nAttributesConfig: null,
|
|
11120
|
+
...NEW_OP,
|
|
11121
|
+
...TRAIT_CONSUMES_SLOT,
|
|
11122
|
+
};
|
|
11123
|
+
}
|
|
11058
11124
|
function literalOrArrayLiteral$1(value) {
|
|
11059
11125
|
if (Array.isArray(value)) {
|
|
11060
11126
|
return literalArr(value.map(literalOrArrayLiteral$1));
|
|
@@ -11062,12 +11128,15 @@ function literalOrArrayLiteral$1(value) {
|
|
|
11062
11128
|
return literal(value, INFERRED_TYPE);
|
|
11063
11129
|
}
|
|
11064
11130
|
|
|
11065
|
-
function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan) {
|
|
11131
|
+
function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, securityContext, sourceSpan) {
|
|
11066
11132
|
return {
|
|
11067
11133
|
kind: OpKind.HostProperty,
|
|
11068
11134
|
name,
|
|
11069
11135
|
expression,
|
|
11070
11136
|
isAnimationTrigger,
|
|
11137
|
+
i18nContext,
|
|
11138
|
+
securityContext,
|
|
11139
|
+
sanitizer: null,
|
|
11071
11140
|
sourceSpan,
|
|
11072
11141
|
...TRAIT_CONSUMES_VARS,
|
|
11073
11142
|
...NEW_OP,
|
|
@@ -11304,7 +11373,7 @@ function applyI18nExpressions(job) {
|
|
|
11304
11373
|
// Only add apply after expressions that are not followed by more expressions.
|
|
11305
11374
|
if (op.kind === OpKind.I18nExpression && needsApplication(i18nContexts, op)) {
|
|
11306
11375
|
// TODO: what should be the source span for the apply op?
|
|
11307
|
-
OpList.insertAfter(createI18nApplyOp(op.
|
|
11376
|
+
OpList.insertAfter(createI18nApplyOp(op.i18nOwner, op.handle, null), op);
|
|
11308
11377
|
}
|
|
11309
11378
|
}
|
|
11310
11379
|
}
|
|
@@ -11317,42 +11386,80 @@ function needsApplication(i18nContexts, op) {
|
|
|
11317
11386
|
if (op.next?.kind !== OpKind.I18nExpression) {
|
|
11318
11387
|
return true;
|
|
11319
11388
|
}
|
|
11320
|
-
// If the next op is an expression targeting a different i18n block, we need to apply.
|
|
11321
11389
|
const context = i18nContexts.get(op.context);
|
|
11322
11390
|
const nextContext = i18nContexts.get(op.next.context);
|
|
11323
|
-
if (context
|
|
11391
|
+
if (context === undefined) {
|
|
11392
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the I18nExpressionOp\'s context');
|
|
11393
|
+
}
|
|
11394
|
+
if (nextContext === undefined) {
|
|
11395
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the next I18nExpressionOp\'s context');
|
|
11396
|
+
}
|
|
11397
|
+
// If the next op is an expression targeting a different i18n block (or different element, in the
|
|
11398
|
+
// case of i18n attributes), we need to apply.
|
|
11399
|
+
// First, handle the case of i18n blocks.
|
|
11400
|
+
if (context.i18nBlock !== null) {
|
|
11401
|
+
// This is a block context. Compare the blocks.
|
|
11402
|
+
if (context.i18nBlock !== nextContext.i18nBlock) {
|
|
11403
|
+
return true;
|
|
11404
|
+
}
|
|
11405
|
+
return false;
|
|
11406
|
+
}
|
|
11407
|
+
// Second, handle the case of i18n attributes.
|
|
11408
|
+
if (op.i18nOwner !== op.next.i18nOwner) {
|
|
11324
11409
|
return true;
|
|
11325
11410
|
}
|
|
11326
11411
|
return false;
|
|
11327
11412
|
}
|
|
11328
11413
|
|
|
11329
11414
|
/**
|
|
11330
|
-
* Updates i18n expression ops to
|
|
11415
|
+
* Updates i18n expression ops to target the last slot in their owning i18n block, and moves them
|
|
11416
|
+
* after the last update instruction that depends on that slot.
|
|
11331
11417
|
*/
|
|
11332
11418
|
function assignI18nSlotDependencies(job) {
|
|
11333
|
-
const i18nLastSlotConsumers = new Map();
|
|
11334
|
-
let lastSlotConsumer = null;
|
|
11335
|
-
let currentI18nOp = null;
|
|
11336
11419
|
for (const unit of job.units) {
|
|
11337
|
-
//
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11420
|
+
// The first update op.
|
|
11421
|
+
let updateOp = unit.update.head;
|
|
11422
|
+
// I18n expressions currently being moved during the iteration.
|
|
11423
|
+
let i18nExpressionsInProgress = [];
|
|
11424
|
+
// Non-null while we are iterating through an i18nStart/i18nEnd pair
|
|
11425
|
+
let state = null;
|
|
11426
|
+
for (const createOp of unit.create) {
|
|
11427
|
+
if (createOp.kind === OpKind.I18nStart) {
|
|
11428
|
+
state = {
|
|
11429
|
+
blockXref: createOp.xref,
|
|
11430
|
+
lastSlotConsumer: createOp.xref,
|
|
11431
|
+
};
|
|
11341
11432
|
}
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
break;
|
|
11433
|
+
else if (createOp.kind === OpKind.I18nEnd) {
|
|
11434
|
+
for (const op of i18nExpressionsInProgress) {
|
|
11435
|
+
op.target = state.lastSlotConsumer;
|
|
11436
|
+
OpList.insertBefore(op, updateOp);
|
|
11437
|
+
}
|
|
11438
|
+
i18nExpressionsInProgress.length = 0;
|
|
11439
|
+
state = null;
|
|
11350
11440
|
}
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11441
|
+
if (hasConsumesSlotTrait(createOp)) {
|
|
11442
|
+
if (state !== null) {
|
|
11443
|
+
state.lastSlotConsumer = createOp.xref;
|
|
11444
|
+
}
|
|
11445
|
+
while (true) {
|
|
11446
|
+
if (updateOp.next === null) {
|
|
11447
|
+
break;
|
|
11448
|
+
}
|
|
11449
|
+
if (state !== null && updateOp.kind === OpKind.I18nExpression &&
|
|
11450
|
+
updateOp.usage === I18nExpressionFor.I18nText &&
|
|
11451
|
+
updateOp.i18nOwner === state.blockXref) {
|
|
11452
|
+
const opToRemove = updateOp;
|
|
11453
|
+
updateOp = updateOp.next;
|
|
11454
|
+
OpList.remove(opToRemove);
|
|
11455
|
+
i18nExpressionsInProgress.push(opToRemove);
|
|
11456
|
+
continue;
|
|
11457
|
+
}
|
|
11458
|
+
if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
|
|
11459
|
+
break;
|
|
11460
|
+
}
|
|
11461
|
+
updateOp = updateOp.next;
|
|
11462
|
+
}
|
|
11356
11463
|
}
|
|
11357
11464
|
}
|
|
11358
11465
|
}
|
|
@@ -11386,22 +11493,42 @@ function extractAttributes(job) {
|
|
|
11386
11493
|
break;
|
|
11387
11494
|
case OpKind.Property:
|
|
11388
11495
|
if (!op.isAnimationTrigger) {
|
|
11389
|
-
|
|
11496
|
+
let bindingKind;
|
|
11497
|
+
if (op.i18nMessage !== null && op.templateKind === null) {
|
|
11498
|
+
// If the binding has an i18n context, it is an i18n attribute, and should have that
|
|
11499
|
+
// kind in the consts array.
|
|
11500
|
+
bindingKind = BindingKind.I18n;
|
|
11501
|
+
}
|
|
11502
|
+
else if (op.isStructuralTemplateAttribute) {
|
|
11503
|
+
bindingKind = BindingKind.Template;
|
|
11504
|
+
}
|
|
11505
|
+
else {
|
|
11506
|
+
bindingKind = BindingKind.Property;
|
|
11507
|
+
}
|
|
11508
|
+
OpList.insertBefore(
|
|
11509
|
+
// Deliberaly null i18nMessage value
|
|
11510
|
+
createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null, /* i18nContext */ null,
|
|
11511
|
+
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11390
11512
|
}
|
|
11391
11513
|
break;
|
|
11392
11514
|
case OpKind.StyleProp:
|
|
11393
11515
|
case OpKind.ClassProp:
|
|
11516
|
+
// TODO: Can style or class bindings be i18n attributes?
|
|
11394
11517
|
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
11395
11518
|
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
11396
11519
|
// mode.
|
|
11397
11520
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11398
11521
|
op.expression instanceof EmptyExpr) {
|
|
11399
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null
|
|
11522
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11523
|
+
/* i18nContext */ null,
|
|
11524
|
+
/* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
|
|
11400
11525
|
}
|
|
11401
11526
|
break;
|
|
11402
11527
|
case OpKind.Listener:
|
|
11403
11528
|
if (!op.isAnimationListener) {
|
|
11404
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null
|
|
11529
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11530
|
+
/* i18nContext */ null,
|
|
11531
|
+
/* i18nMessage */ null, SecurityContext.NONE);
|
|
11405
11532
|
if (job.kind === CompilationJobKind.Host) {
|
|
11406
11533
|
// This attribute will apply to the enclosing host binding compilation unit, so order
|
|
11407
11534
|
// doesn't matter.
|
|
@@ -11450,7 +11577,7 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
11450
11577
|
}
|
|
11451
11578
|
}
|
|
11452
11579
|
if (extractable) {
|
|
11453
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.
|
|
11580
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11454
11581
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11455
11582
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
11456
11583
|
// matter.
|
|
@@ -11497,16 +11624,16 @@ function specializeBindings(job) {
|
|
|
11497
11624
|
target.nonBindable = true;
|
|
11498
11625
|
}
|
|
11499
11626
|
else {
|
|
11500
|
-
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.
|
|
11627
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
|
|
11501
11628
|
}
|
|
11502
11629
|
break;
|
|
11503
11630
|
case BindingKind.Property:
|
|
11504
11631
|
case BindingKind.Animation:
|
|
11505
11632
|
if (job.kind === CompilationJobKind.Host) {
|
|
11506
|
-
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.sourceSpan));
|
|
11633
|
+
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.securityContext, op.sourceSpan));
|
|
11507
11634
|
}
|
|
11508
11635
|
else {
|
|
11509
|
-
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.
|
|
11636
|
+
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));
|
|
11510
11637
|
}
|
|
11511
11638
|
break;
|
|
11512
11639
|
case BindingKind.I18n:
|
|
@@ -11743,7 +11870,7 @@ function collectElementConsts(job) {
|
|
|
11743
11870
|
if (op.kind === OpKind.ExtractedAttribute) {
|
|
11744
11871
|
const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
|
|
11745
11872
|
allElementAttributes.set(op.target, attributes);
|
|
11746
|
-
attributes.add(op.bindingKind, op.name, op.expression);
|
|
11873
|
+
attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
|
|
11747
11874
|
OpList.remove(op);
|
|
11748
11875
|
}
|
|
11749
11876
|
}
|
|
@@ -11809,11 +11936,12 @@ class ElementAttributes {
|
|
|
11809
11936
|
get i18n() {
|
|
11810
11937
|
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11811
11938
|
}
|
|
11812
|
-
add(kind, name, value) {
|
|
11939
|
+
add(kind, name, value, trustedValueFn) {
|
|
11813
11940
|
if (this.known.has(name)) {
|
|
11814
11941
|
return;
|
|
11815
11942
|
}
|
|
11816
11943
|
this.known.add(name);
|
|
11944
|
+
// TODO: Can this be its own phase
|
|
11817
11945
|
if (name === 'ngProjectAs') {
|
|
11818
11946
|
if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
|
|
11819
11947
|
(typeof value.value?.toString() !== 'string')) {
|
|
@@ -11827,9 +11955,17 @@ class ElementAttributes {
|
|
|
11827
11955
|
array.push(...getAttributeNameLiterals$1(name));
|
|
11828
11956
|
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11829
11957
|
if (value === null) {
|
|
11830
|
-
throw Error('Attribute & style element attributes must have a value');
|
|
11958
|
+
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
11959
|
+
}
|
|
11960
|
+
if (trustedValueFn !== null) {
|
|
11961
|
+
if (!isStringLiteral(value)) {
|
|
11962
|
+
throw Error('AssertionError: extracted attribute value should be string literal');
|
|
11963
|
+
}
|
|
11964
|
+
array.push(taggedTemplate(trustedValueFn, new TemplateLiteral([new TemplateLiteralElement(value.value)], []), undefined, value.sourceSpan));
|
|
11965
|
+
}
|
|
11966
|
+
else {
|
|
11967
|
+
array.push(value);
|
|
11831
11968
|
}
|
|
11832
|
-
array.push(value);
|
|
11833
11969
|
}
|
|
11834
11970
|
}
|
|
11835
11971
|
arrayFor(kind) {
|
|
@@ -11881,6 +12017,50 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
|
|
|
11881
12017
|
return literalArr(attrArray);
|
|
11882
12018
|
}
|
|
11883
12019
|
|
|
12020
|
+
/**
|
|
12021
|
+
* Some binding instructions in the update block may actually correspond to i18n bindings. In that
|
|
12022
|
+
* case, they should be replaced with i18nExp instructions for the dynamic portions.
|
|
12023
|
+
*/
|
|
12024
|
+
function convertI18nBindings(job) {
|
|
12025
|
+
const i18nAttributesByElem = new Map();
|
|
12026
|
+
for (const unit of job.units) {
|
|
12027
|
+
for (const op of unit.create) {
|
|
12028
|
+
if (op.kind === OpKind.I18nAttributes) {
|
|
12029
|
+
i18nAttributesByElem.set(op.target, op);
|
|
12030
|
+
}
|
|
12031
|
+
}
|
|
12032
|
+
for (const op of unit.update) {
|
|
12033
|
+
switch (op.kind) {
|
|
12034
|
+
case OpKind.Property:
|
|
12035
|
+
case OpKind.Attribute:
|
|
12036
|
+
if (op.i18nContext === null) {
|
|
12037
|
+
continue;
|
|
12038
|
+
}
|
|
12039
|
+
if (!(op.expression instanceof Interpolation)) {
|
|
12040
|
+
continue;
|
|
12041
|
+
}
|
|
12042
|
+
const i18nAttributesForElem = i18nAttributesByElem.get(op.target);
|
|
12043
|
+
if (i18nAttributesForElem === undefined) {
|
|
12044
|
+
throw new Error('AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction');
|
|
12045
|
+
}
|
|
12046
|
+
if (i18nAttributesForElem.target !== op.target) {
|
|
12047
|
+
throw new Error('AssertionError: Expected i18nAttributes target element to match binding target element');
|
|
12048
|
+
}
|
|
12049
|
+
const ops = [];
|
|
12050
|
+
for (let i = 0; i < op.expression.expressions.length; i++) {
|
|
12051
|
+
const expr = op.expression.expressions[i];
|
|
12052
|
+
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
12053
|
+
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`);
|
|
12054
|
+
}
|
|
12055
|
+
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12056
|
+
}
|
|
12057
|
+
OpList.replaceWithMany(op, ops);
|
|
12058
|
+
break;
|
|
12059
|
+
}
|
|
12060
|
+
}
|
|
12061
|
+
}
|
|
12062
|
+
}
|
|
12063
|
+
|
|
11884
12064
|
/**
|
|
11885
12065
|
* Create extracted deps functions for defer ops.
|
|
11886
12066
|
*/
|
|
@@ -11929,6 +12109,9 @@ function createI18nContexts(job) {
|
|
|
11929
12109
|
const rootContexts = new Map();
|
|
11930
12110
|
let currentI18nOp = null;
|
|
11931
12111
|
let xref;
|
|
12112
|
+
// We use the message instead of the message ID, because placeholder values might differ even
|
|
12113
|
+
// when IDs are the same.
|
|
12114
|
+
const messageToContext = new Map();
|
|
11932
12115
|
for (const unit of job.units) {
|
|
11933
12116
|
for (const op of unit.create) {
|
|
11934
12117
|
switch (op.kind) {
|
|
@@ -11966,6 +12149,25 @@ function createI18nContexts(job) {
|
|
|
11966
12149
|
break;
|
|
11967
12150
|
}
|
|
11968
12151
|
}
|
|
12152
|
+
for (const op of unit.ops()) {
|
|
12153
|
+
switch (op.kind) {
|
|
12154
|
+
case OpKind.Binding:
|
|
12155
|
+
case OpKind.Property:
|
|
12156
|
+
case OpKind.Attribute:
|
|
12157
|
+
case OpKind.ExtractedAttribute:
|
|
12158
|
+
if (!op.i18nMessage) {
|
|
12159
|
+
continue;
|
|
12160
|
+
}
|
|
12161
|
+
if (!messageToContext.has(op.i18nMessage)) {
|
|
12162
|
+
// create the context
|
|
12163
|
+
const i18nContext = job.allocateXrefId();
|
|
12164
|
+
unit.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, op.i18nMessage, null));
|
|
12165
|
+
messageToContext.set(op.i18nMessage, i18nContext);
|
|
12166
|
+
}
|
|
12167
|
+
op.i18nContext = messageToContext.get(op.i18nMessage);
|
|
12168
|
+
break;
|
|
12169
|
+
}
|
|
12170
|
+
}
|
|
11969
12171
|
}
|
|
11970
12172
|
// Assign contexts to child i18n blocks, now that all root i18n blocks have their context
|
|
11971
12173
|
// assigned.
|
|
@@ -12324,7 +12526,7 @@ function ternaryTransform(e) {
|
|
|
12324
12526
|
/**
|
|
12325
12527
|
* The escape sequence used indicate message param values.
|
|
12326
12528
|
*/
|
|
12327
|
-
const ESCAPE = '\uFFFD';
|
|
12529
|
+
const ESCAPE$1 = '\uFFFD';
|
|
12328
12530
|
/**
|
|
12329
12531
|
* Marker used to indicate an element tag.
|
|
12330
12532
|
*/
|
|
@@ -12373,6 +12575,18 @@ function extractI18nMessages(job) {
|
|
|
12373
12575
|
}
|
|
12374
12576
|
}
|
|
12375
12577
|
}
|
|
12578
|
+
// TODO: Miles and I think that contexts have a 1-to-1 correspondence with extracted messages, so
|
|
12579
|
+
// this phase can probably be simplified.
|
|
12580
|
+
// Extract messages from contexts of i18n attributes.
|
|
12581
|
+
for (const unit of job.units) {
|
|
12582
|
+
for (const op of unit.create) {
|
|
12583
|
+
if (op.kind !== OpKind.I18nContext || op.contextKind !== I18nContextKind.Attr) {
|
|
12584
|
+
continue;
|
|
12585
|
+
}
|
|
12586
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12587
|
+
unit.create.push(i18nMessageOp);
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12376
12590
|
// Extract messages from root i18n blocks.
|
|
12377
12591
|
const i18nBlockMessages = new Map();
|
|
12378
12592
|
for (const unit of job.units) {
|
|
@@ -12397,6 +12611,9 @@ function extractI18nMessages(job) {
|
|
|
12397
12611
|
}
|
|
12398
12612
|
const i18nContext = i18nContexts.get(op.context);
|
|
12399
12613
|
if (i18nContext.contextKind === I18nContextKind.Icu) {
|
|
12614
|
+
if (i18nContext.i18nBlock === null) {
|
|
12615
|
+
throw Error('ICU context should have its i18n block set.');
|
|
12616
|
+
}
|
|
12400
12617
|
const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
|
|
12401
12618
|
unit.create.push(subMessage);
|
|
12402
12619
|
const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
|
|
@@ -12416,119 +12633,86 @@ function extractI18nMessages(job) {
|
|
|
12416
12633
|
* Create an i18n message op from an i18n context op.
|
|
12417
12634
|
*/
|
|
12418
12635
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
12419
|
-
let
|
|
12420
|
-
const
|
|
12421
|
-
needsPostprocessing
|
|
12422
|
-
|
|
12636
|
+
let formattedParams = formatParams(context.params);
|
|
12637
|
+
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12638
|
+
let needsPostprocessing = formattedPostprocessingParams.size > 0;
|
|
12639
|
+
for (const values of context.params.values()) {
|
|
12640
|
+
if (values.length > 1) {
|
|
12641
|
+
needsPostprocessing = true;
|
|
12642
|
+
}
|
|
12643
|
+
}
|
|
12644
|
+
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12423
12645
|
}
|
|
12424
12646
|
/**
|
|
12425
12647
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12426
|
-
* @return A tuple of the formatted params and a boolean indicating whether postprocessing is needed
|
|
12427
|
-
* for any of the params
|
|
12428
12648
|
*/
|
|
12429
12649
|
function formatParams(params) {
|
|
12430
12650
|
const formattedParams = new Map();
|
|
12431
|
-
let needsPostprocessing = false;
|
|
12432
12651
|
for (const [placeholder, placeholderValues] of params) {
|
|
12433
|
-
const
|
|
12434
|
-
needsPostprocessing ||= paramNeedsPostprocessing;
|
|
12652
|
+
const serializedValues = formatParamValues(placeholderValues);
|
|
12435
12653
|
if (serializedValues !== null) {
|
|
12436
12654
|
formattedParams.set(placeholder, literal(serializedValues));
|
|
12437
12655
|
}
|
|
12438
12656
|
}
|
|
12439
|
-
return
|
|
12657
|
+
return formattedParams;
|
|
12440
12658
|
}
|
|
12441
12659
|
/**
|
|
12442
12660
|
* Formats an `I18nParamValue[]` into a string (or null for empty array).
|
|
12443
|
-
* @return A tuple of the formatted value and a boolean indicating whether postprocessing is needed
|
|
12444
|
-
* for the value
|
|
12445
12661
|
*/
|
|
12446
12662
|
function formatParamValues(values) {
|
|
12447
12663
|
if (values.length === 0) {
|
|
12448
|
-
return
|
|
12664
|
+
return null;
|
|
12449
12665
|
}
|
|
12450
|
-
collapseElementTemplatePairs(values);
|
|
12451
12666
|
const serializedValues = values.map(value => formatValue(value));
|
|
12452
12667
|
return serializedValues.length === 1 ?
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
}
|
|
12456
|
-
/**
|
|
12457
|
-
* Collapses element/template pairs that refer to the same subTemplateIndex, i.e. elements and
|
|
12458
|
-
* templates that refer to the same element instance.
|
|
12459
|
-
*
|
|
12460
|
-
* This accounts for the case of a structural directive inside an i18n block, e.g.:
|
|
12461
|
-
* ```
|
|
12462
|
-
* <div i18n>
|
|
12463
|
-
* <div *ngIf="condition">
|
|
12464
|
-
* </div>
|
|
12465
|
-
* ```
|
|
12466
|
-
*
|
|
12467
|
-
* In this case, both the element start and template start placeholders are the same,
|
|
12468
|
-
* and we collapse them down into a single compound placeholder value. Rather than produce
|
|
12469
|
-
* `[\uFFFD#1:1\uFFFD|\uFFFD*2:1\uFFFD]`, we want to produce `\uFFFD#1:1\uFFFD\uFFFD*2:1\uFFFD`,
|
|
12470
|
-
* likewise for the closing of the element/template.
|
|
12471
|
-
*/
|
|
12472
|
-
function collapseElementTemplatePairs(values) {
|
|
12473
|
-
// Record the indicies of element and template values in the values array by subTemplateIndex.
|
|
12474
|
-
const valueIndiciesBySubTemplateIndex = new Map();
|
|
12475
|
-
for (let i = 0; i < values.length; i++) {
|
|
12476
|
-
const value = values[i];
|
|
12477
|
-
if (value.subTemplateIndex !== null &&
|
|
12478
|
-
(value.flags & (I18nParamValueFlags.ElementTag | I18nParamValueFlags.TemplateTag))) {
|
|
12479
|
-
const valueIndicies = valueIndiciesBySubTemplateIndex.get(value.subTemplateIndex) ?? [];
|
|
12480
|
-
valueIndicies.push(i);
|
|
12481
|
-
valueIndiciesBySubTemplateIndex.set(value.subTemplateIndex, valueIndicies);
|
|
12482
|
-
}
|
|
12483
|
-
}
|
|
12484
|
-
// For each subTemplateIndex, check if any values can be collapsed.
|
|
12485
|
-
for (const [subTemplateIndex, valueIndicies] of valueIndiciesBySubTemplateIndex) {
|
|
12486
|
-
if (valueIndicies.length > 1) {
|
|
12487
|
-
const elementIndex = valueIndicies.find(index => values[index].flags & I18nParamValueFlags.ElementTag);
|
|
12488
|
-
const templateIndex = valueIndicies.find(index => values[index].flags & I18nParamValueFlags.TemplateTag);
|
|
12489
|
-
// If the values list contains both an element and template value, we can collapse.
|
|
12490
|
-
if (elementIndex !== undefined && templateIndex !== undefined) {
|
|
12491
|
-
const elementValue = values[elementIndex];
|
|
12492
|
-
const templateValue = values[templateIndex];
|
|
12493
|
-
// To match the TemplateDefinitionBuilder output, flip the order depending on whether the
|
|
12494
|
-
// values represent a closing or opening tag (or both).
|
|
12495
|
-
// TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
|
|
12496
|
-
// or the resulting message ID. If not, we can remove the special-casing in the future.
|
|
12497
|
-
let compundValue;
|
|
12498
|
-
if ((elementValue.flags & I18nParamValueFlags.OpenTag) &&
|
|
12499
|
-
(elementValue.flags & I18nParamValueFlags.CloseTag)) {
|
|
12500
|
-
// TODO(mmalerba): Is this a TDB bug? I don't understand why it would put the template
|
|
12501
|
-
// value twice.
|
|
12502
|
-
compundValue = `${formatValue(templateValue)}${formatValue(elementValue)}${formatValue(templateValue)}`;
|
|
12503
|
-
}
|
|
12504
|
-
else if (elementValue.flags & I18nParamValueFlags.OpenTag) {
|
|
12505
|
-
compundValue = `${formatValue(templateValue)}${formatValue(elementValue)}`;
|
|
12506
|
-
}
|
|
12507
|
-
else {
|
|
12508
|
-
compundValue = `${formatValue(elementValue)}${formatValue(templateValue)}`;
|
|
12509
|
-
}
|
|
12510
|
-
// Replace the element value with the combined value.
|
|
12511
|
-
values.splice(elementIndex, 1, { value: compundValue, subTemplateIndex, flags: I18nParamValueFlags.None });
|
|
12512
|
-
// Replace the template value with null to preserve the indicies we calculated earlier.
|
|
12513
|
-
values.splice(templateIndex, 1, null);
|
|
12514
|
-
}
|
|
12515
|
-
}
|
|
12516
|
-
}
|
|
12517
|
-
// Strip out any nulled out values we introduced above.
|
|
12518
|
-
for (let i = values.length - 1; i >= 0; i--) {
|
|
12519
|
-
if (values[i] === null) {
|
|
12520
|
-
values.splice(i, 1);
|
|
12521
|
-
}
|
|
12522
|
-
}
|
|
12668
|
+
serializedValues[0] :
|
|
12669
|
+
`${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
|
|
12523
12670
|
}
|
|
12524
12671
|
/**
|
|
12525
12672
|
* Formats a single `I18nParamValue` into a string
|
|
12526
12673
|
*/
|
|
12527
12674
|
function formatValue(value) {
|
|
12675
|
+
// Element tags with a structural directive use a special form that concatenates the element and
|
|
12676
|
+
// template values.
|
|
12677
|
+
if ((value.flags & I18nParamValueFlags.ElementTag) &&
|
|
12678
|
+
(value.flags & I18nParamValueFlags.TemplateTag)) {
|
|
12679
|
+
if (typeof value.value !== 'object') {
|
|
12680
|
+
throw Error('AssertionError: Expected i18n param value to have an element and template slot');
|
|
12681
|
+
}
|
|
12682
|
+
const elementValue = formatValue({
|
|
12683
|
+
...value,
|
|
12684
|
+
value: value.value.element,
|
|
12685
|
+
flags: value.flags & ~I18nParamValueFlags.TemplateTag
|
|
12686
|
+
});
|
|
12687
|
+
const templateValue = formatValue({
|
|
12688
|
+
...value,
|
|
12689
|
+
value: value.value.template,
|
|
12690
|
+
flags: value.flags & ~I18nParamValueFlags.ElementTag
|
|
12691
|
+
});
|
|
12692
|
+
// TODO(mmalerba): This is likely a bug in TemplateDefinitionBuilder, we should not need to
|
|
12693
|
+
// record the template value twice. For now I'm re-implementing the behavior here to keep the
|
|
12694
|
+
// output consistent with TemplateDefinitionBuilder.
|
|
12695
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12696
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12697
|
+
return `${templateValue}${elementValue}${templateValue}`;
|
|
12698
|
+
}
|
|
12699
|
+
// To match the TemplateDefinitionBuilder output, flip the order depending on whether the
|
|
12700
|
+
// values represent a closing or opening tag (or both).
|
|
12701
|
+
// TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
|
|
12702
|
+
// or the resulting message ID. If not, we can remove the special-casing in the future.
|
|
12703
|
+
return value.flags & I18nParamValueFlags.CloseTag ? `${elementValue}${templateValue}` :
|
|
12704
|
+
`${templateValue}${elementValue}`;
|
|
12705
|
+
}
|
|
12706
|
+
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
12707
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12708
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12709
|
+
return `${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.CloseTag })}${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.OpenTag })}`;
|
|
12710
|
+
}
|
|
12528
12711
|
// If there are no special flags, just return the raw value.
|
|
12529
12712
|
if (value.flags === I18nParamValueFlags.None) {
|
|
12530
12713
|
return `${value.value}`;
|
|
12531
12714
|
}
|
|
12715
|
+
// Encode the remaining flags as part of the value.
|
|
12532
12716
|
let tagMarker = '';
|
|
12533
12717
|
let closeMarker = '';
|
|
12534
12718
|
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
@@ -12541,12 +12725,7 @@ function formatValue(value) {
|
|
|
12541
12725
|
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
12542
12726
|
}
|
|
12543
12727
|
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
12544
|
-
|
|
12545
|
-
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12546
|
-
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12547
|
-
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12548
|
-
}
|
|
12549
|
-
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12728
|
+
return `${ESCAPE$1}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE$1}`;
|
|
12550
12729
|
}
|
|
12551
12730
|
|
|
12552
12731
|
/**
|
|
@@ -12580,7 +12759,7 @@ function generateAdvance(job) {
|
|
|
12580
12759
|
else if (!slotMap.has(op.target)) {
|
|
12581
12760
|
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
12582
12761
|
// the `slotMap`.
|
|
12583
|
-
throw new Error(`AssertionError: reference to unknown slot for
|
|
12762
|
+
throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
|
|
12584
12763
|
}
|
|
12585
12764
|
const slot = slotMap.get(op.target);
|
|
12586
12765
|
// Does the slot counter need to be adjusted?
|
|
@@ -12663,9 +12842,15 @@ function recursivelyProcessView(view, parentScope) {
|
|
|
12663
12842
|
for (const op of view.create) {
|
|
12664
12843
|
switch (op.kind) {
|
|
12665
12844
|
case OpKind.Template:
|
|
12845
|
+
// Descend into child embedded views.
|
|
12846
|
+
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12847
|
+
break;
|
|
12666
12848
|
case OpKind.RepeaterCreate:
|
|
12667
12849
|
// Descend into child embedded views.
|
|
12668
12850
|
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12851
|
+
if (op.emptyView) {
|
|
12852
|
+
recursivelyProcessView(view.job.views.get(op.emptyView), scope);
|
|
12853
|
+
}
|
|
12669
12854
|
break;
|
|
12670
12855
|
case OpKind.Listener:
|
|
12671
12856
|
// Prepend variables to listener handler functions.
|
|
@@ -19790,35 +19975,136 @@ const NG_I18N_CLOSURE_MODE$1 = 'ngI18nClosureMode';
|
|
|
19790
19975
|
* considers variables like `I18N_0` as constants and throws an error when their value changes.
|
|
19791
19976
|
*/
|
|
19792
19977
|
const TRANSLATION_VAR_PREFIX = 'i18n_';
|
|
19978
|
+
/** Prefix of ICU expressions for post processing */
|
|
19979
|
+
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
19980
|
+
/**
|
|
19981
|
+
* The escape sequence used for message param values.
|
|
19982
|
+
*/
|
|
19983
|
+
const ESCAPE = '\uFFFD';
|
|
19793
19984
|
/**
|
|
19794
19985
|
* Lifts i18n properties into the consts array.
|
|
19795
19986
|
* TODO: Can we use `ConstCollectedExpr`?
|
|
19987
|
+
* TODO: The way the various attributes are linked together is very complex. Perhaps we could
|
|
19988
|
+
* simplify the process, maybe by combining the context and message ops?
|
|
19796
19989
|
*/
|
|
19797
19990
|
function collectI18nConsts(job) {
|
|
19798
19991
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
19799
|
-
|
|
19800
|
-
//
|
|
19992
|
+
// Step One: Build up various lookup maps we need to collect all the consts.
|
|
19993
|
+
// Context Xref -> Extracted Attribute Ops
|
|
19994
|
+
const extractedAttributesByI18nContext = new Map();
|
|
19995
|
+
// Element/ElementStart Xref -> I18n Attributes config op
|
|
19996
|
+
const i18nAttributesByElement = new Map();
|
|
19997
|
+
// Element/ElementStart Xref -> All I18n Expression ops for attrs on that target
|
|
19998
|
+
const i18nExpressionsByElement = new Map();
|
|
19999
|
+
// I18n Message Xref -> I18n Message Op (TODO: use a central op map)
|
|
19801
20000
|
const messages = new Map();
|
|
20001
|
+
for (const unit of job.units) {
|
|
20002
|
+
for (const op of unit.ops()) {
|
|
20003
|
+
if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
|
|
20004
|
+
const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
|
|
20005
|
+
attributes.push(op);
|
|
20006
|
+
extractedAttributesByI18nContext.set(op.i18nContext, attributes);
|
|
20007
|
+
}
|
|
20008
|
+
else if (op.kind === OpKind.I18nAttributes) {
|
|
20009
|
+
i18nAttributesByElement.set(op.target, op);
|
|
20010
|
+
}
|
|
20011
|
+
else if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nAttribute) {
|
|
20012
|
+
const expressions = i18nExpressionsByElement.get(op.target) ?? [];
|
|
20013
|
+
expressions.push(op);
|
|
20014
|
+
i18nExpressionsByElement.set(op.target, expressions);
|
|
20015
|
+
}
|
|
20016
|
+
else if (op.kind === OpKind.I18nMessage) {
|
|
20017
|
+
messages.set(op.xref, op);
|
|
20018
|
+
}
|
|
20019
|
+
}
|
|
20020
|
+
}
|
|
20021
|
+
// Step Two: Serialize the extracted i18n messages for root i18n blocks and i18n attributes into
|
|
20022
|
+
// the const array.
|
|
20023
|
+
//
|
|
20024
|
+
// Also, each i18n message will have a variable expression that can refer to its
|
|
20025
|
+
// value. Store these expressions in the appropriate place:
|
|
20026
|
+
// 1. For normal i18n content, it also goes in the const array. We save the const index to use
|
|
20027
|
+
// later.
|
|
20028
|
+
// 2. For extracted attributes, it becomes the value of the extracted attribute instruction.
|
|
20029
|
+
// 3. For i18n bindings, it will go in a separate const array instruction below; for now, we just
|
|
20030
|
+
// save it.
|
|
20031
|
+
const i18nValuesByContext = new Map();
|
|
20032
|
+
const messageConstIndices = new Map();
|
|
19802
20033
|
for (const unit of job.units) {
|
|
19803
20034
|
for (const op of unit.create) {
|
|
19804
20035
|
if (op.kind === OpKind.I18nMessage) {
|
|
19805
|
-
|
|
20036
|
+
if (op.messagePlaceholder === null) {
|
|
20037
|
+
const { mainVar, statements } = collectMessage(job, fileBasedI18nSuffix, messages, op);
|
|
20038
|
+
if (op.i18nBlock !== null) {
|
|
20039
|
+
// This is a regular i18n message with a corresponding i18n block. Collect it into the
|
|
20040
|
+
// const array.
|
|
20041
|
+
const i18nConst = job.addConst(mainVar, statements);
|
|
20042
|
+
messageConstIndices.set(op.i18nBlock, i18nConst);
|
|
20043
|
+
}
|
|
20044
|
+
else {
|
|
20045
|
+
// This is an i18n attribute. Extract the initializers into the const pool.
|
|
20046
|
+
job.constsInitializers.push(...statements);
|
|
20047
|
+
// Save the i18n variable value for later.
|
|
20048
|
+
i18nValuesByContext.set(op.i18nContext, mainVar);
|
|
20049
|
+
// This i18n message may correspond to an individual extracted attribute. If so, The
|
|
20050
|
+
// value of that attribute is updated to read the extracted i18n variable.
|
|
20051
|
+
const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
|
|
20052
|
+
if (attributesForMessage !== undefined) {
|
|
20053
|
+
for (const attr of attributesForMessage) {
|
|
20054
|
+
attr.expression = mainVar.clone();
|
|
20055
|
+
}
|
|
20056
|
+
}
|
|
20057
|
+
}
|
|
20058
|
+
}
|
|
19806
20059
|
OpList.remove(op);
|
|
19807
20060
|
}
|
|
19808
20061
|
}
|
|
19809
20062
|
}
|
|
19810
|
-
//
|
|
19811
|
-
|
|
19812
|
-
|
|
19813
|
-
|
|
19814
|
-
|
|
20063
|
+
// Step Three: Serialize I18nAttributes configurations into the const array. Each I18nAttributes
|
|
20064
|
+
// instruction has a config array, which contains k-v pairs describing each binding name, and the
|
|
20065
|
+
// i18n variable that provides the value.
|
|
20066
|
+
for (const unit of job.units) {
|
|
20067
|
+
for (const elem of unit.create) {
|
|
20068
|
+
if (isElementOrContainerOp(elem)) {
|
|
20069
|
+
const i18nAttributes = i18nAttributesByElement.get(elem.xref);
|
|
20070
|
+
if (i18nAttributes === undefined) {
|
|
20071
|
+
// This element is not associated with an i18n attributes configuration instruction.
|
|
20072
|
+
continue;
|
|
20073
|
+
}
|
|
20074
|
+
let i18nExpressions = i18nExpressionsByElement.get(elem.xref);
|
|
20075
|
+
if (i18nExpressions === undefined) {
|
|
20076
|
+
// Unused i18nAttributes should have already been removed.
|
|
20077
|
+
// TODO: Should the removal of those dead instructions be merged with this phase?
|
|
20078
|
+
throw new Error('AssertionError: Could not find any i18n expressions associated with an I18nAttributes instruction');
|
|
20079
|
+
}
|
|
20080
|
+
// Find expressions for all the unique property names, removing duplicates.
|
|
20081
|
+
const seenPropertyNames = new Set();
|
|
20082
|
+
i18nExpressions = i18nExpressions.filter(i18nExpr => {
|
|
20083
|
+
const seen = (seenPropertyNames.has(i18nExpr.name));
|
|
20084
|
+
seenPropertyNames.add(i18nExpr.name);
|
|
20085
|
+
return !seen;
|
|
20086
|
+
});
|
|
20087
|
+
const i18nAttributeConfig = i18nExpressions.flatMap(i18nExpr => {
|
|
20088
|
+
const i18nExprValue = i18nValuesByContext.get(i18nExpr.context);
|
|
20089
|
+
if (i18nExprValue === undefined) {
|
|
20090
|
+
throw new Error('AssertionError: Could not find i18n expression\'s value');
|
|
20091
|
+
}
|
|
20092
|
+
return [literal(i18nExpr.name), i18nExprValue];
|
|
20093
|
+
});
|
|
20094
|
+
i18nAttributes.i18nAttributesConfig =
|
|
20095
|
+
job.addConst(new LiteralArrayExpr(i18nAttributeConfig));
|
|
20096
|
+
}
|
|
19815
20097
|
}
|
|
19816
20098
|
}
|
|
19817
|
-
//
|
|
20099
|
+
// Step Four: Propagate the extracted const index into i18n ops that messages were extracted from.
|
|
19818
20100
|
for (const unit of job.units) {
|
|
19819
20101
|
for (const op of unit.create) {
|
|
19820
20102
|
if (op.kind === OpKind.I18nStart) {
|
|
19821
|
-
|
|
20103
|
+
const msgIndex = messageConstIndices.get(op.root);
|
|
20104
|
+
if (msgIndex === undefined) {
|
|
20105
|
+
throw new Error('AssertionError: Could not find corresponding i18n block index for an i18n message op; was an i18n message incorrectly assumed to correspond to an attribute?');
|
|
20106
|
+
}
|
|
20107
|
+
op.messageIndex = msgIndex;
|
|
19822
20108
|
}
|
|
19823
20109
|
}
|
|
19824
20110
|
}
|
|
@@ -19828,18 +20114,23 @@ function collectI18nConsts(job) {
|
|
|
19828
20114
|
* This will recursively collect any sub-messages referenced from the parent message as well.
|
|
19829
20115
|
*/
|
|
19830
20116
|
function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
19831
|
-
// Recursively collect any sub-messages,
|
|
20117
|
+
// Recursively collect any sub-messages, record each sub-message's main variable under its
|
|
20118
|
+
// placeholder so that we can add them to the params for the parent message. It is possible
|
|
20119
|
+
// that multiple sub-messages will share the same placeholder, so we need to track an array of
|
|
20120
|
+
// variables for each placeholder.
|
|
19832
20121
|
const statements = [];
|
|
20122
|
+
const subMessagePlaceholders = new Map();
|
|
19833
20123
|
for (const subMessageId of messageOp.subMessages) {
|
|
19834
20124
|
const subMessage = messages.get(subMessageId);
|
|
19835
20125
|
const { mainVar: subMessageVar, statements: subMessageStatements } = collectMessage(job, fileBasedI18nSuffix, messages, subMessage);
|
|
19836
20126
|
statements.push(...subMessageStatements);
|
|
19837
|
-
|
|
20127
|
+
const subMessages = subMessagePlaceholders.get(subMessage.messagePlaceholder) ?? [];
|
|
20128
|
+
subMessages.push(subMessageVar);
|
|
20129
|
+
subMessagePlaceholders.set(subMessage.messagePlaceholder, subMessages);
|
|
19838
20130
|
}
|
|
20131
|
+
addSubMessageParams(messageOp, subMessagePlaceholders);
|
|
19839
20132
|
// Sort the params for consistency with TemaplateDefinitionBuilder output.
|
|
19840
20133
|
messageOp.params = new Map([...messageOp.params.entries()].sort());
|
|
19841
|
-
// Check that the message has all of its parameters filled out.
|
|
19842
|
-
assertAllParamsResolved(messageOp);
|
|
19843
20134
|
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
19844
20135
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other
|
|
19845
20136
|
// const to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
@@ -19850,10 +20141,11 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19850
20141
|
// set in post-processing.
|
|
19851
20142
|
if (messageOp.needsPostprocessing) {
|
|
19852
20143
|
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
19853
|
-
|
|
20144
|
+
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
20145
|
+
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
19854
20146
|
const extraTransformFnParams = [];
|
|
19855
20147
|
if (messageOp.postprocessingParams.size > 0) {
|
|
19856
|
-
extraTransformFnParams.push(
|
|
20148
|
+
extraTransformFnParams.push(mapLiteral(formattedPostprocessingParams, /* quoted */ true));
|
|
19857
20149
|
}
|
|
19858
20150
|
transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
|
|
19859
20151
|
}
|
|
@@ -19861,6 +20153,26 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19861
20153
|
statements.push(...getTranslationDeclStmts$1(messageOp.message, mainVar, closureVar, messageOp.params, transformFn));
|
|
19862
20154
|
return { mainVar, statements };
|
|
19863
20155
|
}
|
|
20156
|
+
/**
|
|
20157
|
+
* Adds the given subMessage placeholders to the given message op.
|
|
20158
|
+
*
|
|
20159
|
+
* If a placeholder only corresponds to a single sub-message variable, we just set that variable
|
|
20160
|
+
* as the param value. However, if the placeholder corresponds to multiple sub-message
|
|
20161
|
+
* variables, we need to add a special placeholder value that is handled by the post-processing
|
|
20162
|
+
* step. We then add the array of variables as a post-processing param.
|
|
20163
|
+
*/
|
|
20164
|
+
function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
20165
|
+
for (const [placeholder, subMessages] of subMessagePlaceholders) {
|
|
20166
|
+
if (subMessages.length === 1) {
|
|
20167
|
+
messageOp.params.set(placeholder, subMessages[0]);
|
|
20168
|
+
}
|
|
20169
|
+
else {
|
|
20170
|
+
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
20171
|
+
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
20172
|
+
messageOp.needsPostprocessing = true;
|
|
20173
|
+
}
|
|
20174
|
+
}
|
|
20175
|
+
}
|
|
19864
20176
|
/**
|
|
19865
20177
|
* Generate statements that define a given translation message.
|
|
19866
20178
|
*
|
|
@@ -19883,7 +20195,8 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19883
20195
|
* @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
|
|
19884
20196
|
* @param params Object mapping placeholder names to their values (e.g.
|
|
19885
20197
|
* `{ "interpolation": "\uFFFD0\uFFFD" }`).
|
|
19886
|
-
* @param transformFn Optional transformation function that will be applied to the translation
|
|
20198
|
+
* @param transformFn Optional transformation function that will be applied to the translation
|
|
20199
|
+
* (e.g.
|
|
19887
20200
|
* post-processing).
|
|
19888
20201
|
* @returns An array of statements that defined a given translation.
|
|
19889
20202
|
*/
|
|
@@ -19928,28 +20241,13 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
|
|
|
19928
20241
|
}
|
|
19929
20242
|
return variable(name);
|
|
19930
20243
|
}
|
|
19931
|
-
/**
|
|
19932
|
-
* Asserts that all of the message's placeholders have values.
|
|
19933
|
-
*/
|
|
19934
|
-
function assertAllParamsResolved(op) {
|
|
19935
|
-
for (let placeholder in op.message.placeholders) {
|
|
19936
|
-
placeholder = placeholder.trimEnd();
|
|
19937
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19938
|
-
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
19939
|
-
}
|
|
19940
|
-
}
|
|
19941
|
-
for (let placeholder in op.message.placeholderToMessage) {
|
|
19942
|
-
placeholder = placeholder.trimEnd();
|
|
19943
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19944
|
-
throw Error(`Failed to resolve i18n message placeholder: ${placeholder}`);
|
|
19945
|
-
}
|
|
19946
|
-
}
|
|
19947
|
-
}
|
|
19948
20244
|
|
|
19949
20245
|
/**
|
|
19950
20246
|
* Removes text nodes within i18n blocks since they are already hardcoded into the i18n message.
|
|
20247
|
+
* Also, replaces interpolations on these text nodes with i18n expressions of the non-text portions,
|
|
20248
|
+
* which will be applied later.
|
|
19951
20249
|
*/
|
|
19952
|
-
function
|
|
20250
|
+
function convertI18nText(job) {
|
|
19953
20251
|
for (const unit of job.units) {
|
|
19954
20252
|
// Remove all text nodes within i18n blocks, their content is already captured in the i18n
|
|
19955
20253
|
// message.
|
|
@@ -20004,7 +20302,7 @@ function extractI18nText(job) {
|
|
|
20004
20302
|
const expr = op.interpolation.expressions[i];
|
|
20005
20303
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
20006
20304
|
// Later, we will modify this, and advance to a different point.
|
|
20007
|
-
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.handle, expr, op.i18nPlaceholders[i], resolutionTime, expr.sourceSpan ?? op.sourceSpan));
|
|
20305
|
+
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, op.interpolation.i18nPlaceholders[i], resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
20008
20306
|
}
|
|
20009
20307
|
OpList.replaceWithMany(op, ops);
|
|
20010
20308
|
break;
|
|
@@ -20542,14 +20840,14 @@ function parseExtractedStyles(job) {
|
|
|
20542
20840
|
if (op.name === 'style') {
|
|
20543
20841
|
const parsedStyles = parse(op.expression.value);
|
|
20544
20842
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
20545
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1])), op);
|
|
20843
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
20546
20844
|
}
|
|
20547
20845
|
OpList.remove(op);
|
|
20548
20846
|
}
|
|
20549
20847
|
else if (op.name === 'class') {
|
|
20550
20848
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
20551
20849
|
for (const parsedClass of parsedClasses) {
|
|
20552
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null), op);
|
|
20850
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
20553
20851
|
}
|
|
20554
20852
|
OpList.remove(op);
|
|
20555
20853
|
}
|
|
@@ -20565,18 +20863,30 @@ function parseExtractedStyles(job) {
|
|
|
20565
20863
|
function removeContentSelectors(job) {
|
|
20566
20864
|
for (const unit of job.units) {
|
|
20567
20865
|
const elements = createOpXrefMap(unit);
|
|
20568
|
-
for (const op of unit.
|
|
20866
|
+
for (const op of unit.ops()) {
|
|
20569
20867
|
switch (op.kind) {
|
|
20570
20868
|
case OpKind.Binding:
|
|
20571
20869
|
const target = lookupInXrefMap(elements, op.target);
|
|
20572
|
-
if (op.name
|
|
20870
|
+
if (isSelectAttribute(op.name) && target.kind === OpKind.Projection) {
|
|
20573
20871
|
OpList.remove(op);
|
|
20574
20872
|
}
|
|
20575
20873
|
break;
|
|
20874
|
+
case OpKind.Projection:
|
|
20875
|
+
// op.attributes is an array of [attr1-name, attr1-value, attr2-name, attr2-value, ...],
|
|
20876
|
+
// find the "select" attribute and remove its name and corresponding value.
|
|
20877
|
+
for (let i = op.attributes.length - 2; i >= 0; i -= 2) {
|
|
20878
|
+
if (isSelectAttribute(op.attributes[i])) {
|
|
20879
|
+
op.attributes.splice(i, 2);
|
|
20880
|
+
}
|
|
20881
|
+
}
|
|
20882
|
+
break;
|
|
20576
20883
|
}
|
|
20577
20884
|
}
|
|
20578
20885
|
}
|
|
20579
20886
|
}
|
|
20887
|
+
function isSelectAttribute(name) {
|
|
20888
|
+
return name.toLowerCase() === 'select';
|
|
20889
|
+
}
|
|
20580
20890
|
/**
|
|
20581
20891
|
* Looks up an element in the given map by xref ID.
|
|
20582
20892
|
*/
|
|
@@ -20696,25 +21006,44 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
|
20696
21006
|
i18nBlock = op;
|
|
20697
21007
|
break;
|
|
20698
21008
|
case OpKind.I18nEnd:
|
|
21009
|
+
// When we exit a root-level i18n block, reset the sub-template index counter.
|
|
21010
|
+
if (i18nBlock.subTemplateIndex === null) {
|
|
21011
|
+
subTemplateIndex = 0;
|
|
21012
|
+
}
|
|
20699
21013
|
i18nBlock = null;
|
|
20700
21014
|
break;
|
|
20701
21015
|
case OpKind.Template:
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
21016
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
21017
|
+
break;
|
|
21018
|
+
case OpKind.RepeaterCreate:
|
|
21019
|
+
// Propagate i18n blocks to the @for template.
|
|
21020
|
+
const forView = unit.job.views.get(op.xref);
|
|
21021
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
21022
|
+
// Then if there's an @empty template, propagate the i18n blocks for it as well.
|
|
21023
|
+
if (op.emptyView !== null) {
|
|
21024
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
|
|
20711
21025
|
}
|
|
20712
|
-
|
|
20713
|
-
subTemplateIndex = propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
|
|
21026
|
+
break;
|
|
20714
21027
|
}
|
|
20715
21028
|
}
|
|
20716
21029
|
return subTemplateIndex;
|
|
20717
21030
|
}
|
|
21031
|
+
/**
|
|
21032
|
+
* Propagate i18n blocks for a view.
|
|
21033
|
+
*/
|
|
21034
|
+
function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
|
|
21035
|
+
// We found an <ng-template> inside an i18n block; increment the sub-template counter and
|
|
21036
|
+
// wrap the template's view in a child i18n block.
|
|
21037
|
+
if (i18nPlaceholder !== undefined) {
|
|
21038
|
+
if (i18nBlock === null) {
|
|
21039
|
+
throw Error('Expected template with i18n placeholder to be in an i18n block.');
|
|
21040
|
+
}
|
|
21041
|
+
subTemplateIndex++;
|
|
21042
|
+
wrapTemplateWithI18n(view, i18nBlock);
|
|
21043
|
+
}
|
|
21044
|
+
// Continue traversing inside the template's view.
|
|
21045
|
+
return propagateI18nBlocksToTemplates(view, subTemplateIndex);
|
|
21046
|
+
}
|
|
20718
21047
|
/**
|
|
20719
21048
|
* Wraps a template view with i18n start and end ops.
|
|
20720
21049
|
*/
|
|
@@ -20880,17 +21209,13 @@ function disableBindings() {
|
|
|
20880
21209
|
function enableBindings() {
|
|
20881
21210
|
return call(Identifiers.enableBindings, [], null);
|
|
20882
21211
|
}
|
|
20883
|
-
function listener(name, handlerFn, sourceSpan) {
|
|
20884
|
-
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
}
|
|
20889
|
-
|
|
20890
|
-
return call(Identifiers.syntheticHostListener, [
|
|
20891
|
-
literal(name),
|
|
20892
|
-
handlerFn,
|
|
20893
|
-
], sourceSpan);
|
|
21212
|
+
function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
|
|
21213
|
+
const args = [literal(name), handlerFn];
|
|
21214
|
+
if (eventTargetResolver !== null) {
|
|
21215
|
+
args.push(literal(false)); // `useCapture` flag, defaults to `false`
|
|
21216
|
+
args.push(importExpr(eventTargetResolver));
|
|
21217
|
+
}
|
|
21218
|
+
return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
|
|
20894
21219
|
}
|
|
20895
21220
|
function pipe(slot, name) {
|
|
20896
21221
|
return call(Identifiers.pipe, [
|
|
@@ -21037,6 +21362,10 @@ function i18n(slot, constIndex, subTemplateIndex) {
|
|
|
21037
21362
|
function i18nEnd() {
|
|
21038
21363
|
return call(Identifiers.i18nEnd, [], null);
|
|
21039
21364
|
}
|
|
21365
|
+
function i18nAttributes(slot, i18nAttributesConfig) {
|
|
21366
|
+
const args = [literal(slot), literal(i18nAttributesConfig)];
|
|
21367
|
+
return call(Identifiers.i18nAttributes, args, null);
|
|
21368
|
+
}
|
|
21040
21369
|
function property(name, expression, sanitizer, sourceSpan) {
|
|
21041
21370
|
const args = [literal(name), expression];
|
|
21042
21371
|
if (sanitizer !== null) {
|
|
@@ -21147,8 +21476,12 @@ function classMapInterpolate(strings, expressions, sourceSpan) {
|
|
|
21147
21476
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
21148
21477
|
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
|
|
21149
21478
|
}
|
|
21150
|
-
function hostProperty(name, expression, sourceSpan) {
|
|
21151
|
-
|
|
21479
|
+
function hostProperty(name, expression, sanitizer, sourceSpan) {
|
|
21480
|
+
const args = [literal(name), expression];
|
|
21481
|
+
if (sanitizer !== null) {
|
|
21482
|
+
args.push(sanitizer);
|
|
21483
|
+
}
|
|
21484
|
+
return call(Identifiers.hostProperty, args, sourceSpan);
|
|
21152
21485
|
}
|
|
21153
21486
|
function syntheticHostProperty(name, expression, sourceSpan) {
|
|
21154
21487
|
return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
|
|
@@ -21366,14 +21699,12 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
|
|
|
21366
21699
|
}
|
|
21367
21700
|
|
|
21368
21701
|
/**
|
|
21369
|
-
* Map of
|
|
21702
|
+
* Map of target resolvers for event listeners.
|
|
21370
21703
|
*/
|
|
21371
|
-
const
|
|
21372
|
-
[
|
|
21373
|
-
[
|
|
21374
|
-
[
|
|
21375
|
-
[SanitizerFn.Script, Identifiers.sanitizeScript],
|
|
21376
|
-
[SanitizerFn.Style, Identifiers.sanitizeStyle], [SanitizerFn.Url, Identifiers.sanitizeUrl]
|
|
21704
|
+
const GLOBAL_TARGET_RESOLVERS$1 = new Map([
|
|
21705
|
+
['window', Identifiers.resolveWindow],
|
|
21706
|
+
['document', Identifiers.resolveDocument],
|
|
21707
|
+
['body', Identifiers.resolveBody],
|
|
21377
21708
|
]);
|
|
21378
21709
|
/**
|
|
21379
21710
|
* Compiles semantic operations across all views and generates output `o.Statement`s with actual
|
|
@@ -21423,6 +21754,12 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21423
21754
|
case OpKind.I18n:
|
|
21424
21755
|
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21425
21756
|
break;
|
|
21757
|
+
case OpKind.I18nAttributes:
|
|
21758
|
+
if (op.i18nAttributesConfig === null) {
|
|
21759
|
+
throw new Error(`AssertionError: i18nAttributesConfig was not set`);
|
|
21760
|
+
}
|
|
21761
|
+
OpList.replace(op, i18nAttributes(op.handle.slot, op.i18nAttributesConfig));
|
|
21762
|
+
break;
|
|
21426
21763
|
case OpKind.Template:
|
|
21427
21764
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
21428
21765
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
@@ -21444,10 +21781,11 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21444
21781
|
break;
|
|
21445
21782
|
case OpKind.Listener:
|
|
21446
21783
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
21447
|
-
const
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21784
|
+
const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
|
|
21785
|
+
if (eventTargetResolver === undefined) {
|
|
21786
|
+
throw new Error(`AssertionError: unknown event target ${op.eventTarget}`);
|
|
21787
|
+
}
|
|
21788
|
+
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
21451
21789
|
break;
|
|
21452
21790
|
case OpKind.Variable:
|
|
21453
21791
|
if (op.variable.name === null) {
|
|
@@ -21610,7 +21948,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21610
21948
|
OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
|
|
21611
21949
|
}
|
|
21612
21950
|
else {
|
|
21613
|
-
OpList.replace(op, hostProperty(op.name, op.expression, op.sourceSpan));
|
|
21951
|
+
OpList.replace(op, hostProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
21614
21952
|
}
|
|
21615
21953
|
}
|
|
21616
21954
|
break;
|
|
@@ -21689,8 +22027,6 @@ function reifyIrExpression(expr) {
|
|
|
21689
22027
|
return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21690
22028
|
case ExpressionKind.PipeBindingVariadic:
|
|
21691
22029
|
return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21692
|
-
case ExpressionKind.SanitizerExpr:
|
|
21693
|
-
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
21694
22030
|
case ExpressionKind.SlotLiteralExpr:
|
|
21695
22031
|
return literal(expr.slot.slot);
|
|
21696
22032
|
default:
|
|
@@ -21764,6 +22100,31 @@ function removeI18nContexts(job) {
|
|
|
21764
22100
|
}
|
|
21765
22101
|
}
|
|
21766
22102
|
|
|
22103
|
+
/**
|
|
22104
|
+
* i18nAttributes ops will be generated for each i18n attribute. However, not all i18n attribues
|
|
22105
|
+
* will contain dynamic content, and so some of these i18nAttributes ops may be unnecessary.
|
|
22106
|
+
*/
|
|
22107
|
+
function removeUnusedI18nAttributesOps(job) {
|
|
22108
|
+
for (const unit of job.units) {
|
|
22109
|
+
const ownersWithI18nExpressions = new Set();
|
|
22110
|
+
for (const op of unit.update) {
|
|
22111
|
+
switch (op.kind) {
|
|
22112
|
+
case OpKind.I18nExpression:
|
|
22113
|
+
ownersWithI18nExpressions.add(op.i18nOwner);
|
|
22114
|
+
}
|
|
22115
|
+
}
|
|
22116
|
+
for (const op of unit.create) {
|
|
22117
|
+
switch (op.kind) {
|
|
22118
|
+
case OpKind.I18nAttributes:
|
|
22119
|
+
if (ownersWithI18nExpressions.has(op.xref)) {
|
|
22120
|
+
continue;
|
|
22121
|
+
}
|
|
22122
|
+
OpList.remove(op);
|
|
22123
|
+
}
|
|
22124
|
+
}
|
|
22125
|
+
}
|
|
22126
|
+
}
|
|
22127
|
+
|
|
21767
22128
|
/**
|
|
21768
22129
|
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
21769
22130
|
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
@@ -21895,10 +22256,14 @@ function resolveI18nElementPlaceholders(job) {
|
|
|
21895
22256
|
}
|
|
21896
22257
|
resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
|
|
21897
22258
|
}
|
|
21898
|
-
|
|
22259
|
+
/**
|
|
22260
|
+
* Recursively resolves element and template tag placeholders in the given view.
|
|
22261
|
+
*/
|
|
22262
|
+
function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingStructuralDirective) {
|
|
21899
22263
|
// Track the current i18n op and corresponding i18n context op as we step through the creation
|
|
21900
22264
|
// IR.
|
|
21901
22265
|
let currentOps = null;
|
|
22266
|
+
let pendingStructuralDirectiveCloses = new Map();
|
|
21902
22267
|
for (const op of unit.create) {
|
|
21903
22268
|
switch (op.kind) {
|
|
21904
22269
|
case OpKind.I18nStart:
|
|
@@ -21917,14 +22282,14 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements) {
|
|
|
21917
22282
|
if (currentOps === null) {
|
|
21918
22283
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21919
22284
|
}
|
|
21920
|
-
|
|
21921
|
-
|
|
21922
|
-
//
|
|
21923
|
-
|
|
21924
|
-
|
|
21925
|
-
flags |= I18nParamValueFlags.CloseTag;
|
|
22285
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22286
|
+
// If there is a separate close tag placeholder for this element, save the pending
|
|
22287
|
+
// structural directive so we can pass it to the closing tag as well.
|
|
22288
|
+
if (pendingStructuralDirective && op.i18nPlaceholder.closeName) {
|
|
22289
|
+
pendingStructuralDirectiveCloses.set(op.xref, pendingStructuralDirective);
|
|
21926
22290
|
}
|
|
21927
|
-
|
|
22291
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
22292
|
+
pendingStructuralDirective = undefined;
|
|
21928
22293
|
}
|
|
21929
22294
|
break;
|
|
21930
22295
|
case OpKind.ElementEnd:
|
|
@@ -21933,55 +22298,195 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements) {
|
|
|
21933
22298
|
const startOp = elements.get(op.xref);
|
|
21934
22299
|
if (startOp && startOp.i18nPlaceholder !== undefined) {
|
|
21935
22300
|
if (currentOps === null) {
|
|
21936
|
-
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22301
|
+
throw Error('AssertionError: i18n tag placeholder should only occur inside an i18n block');
|
|
21937
22302
|
}
|
|
21938
|
-
|
|
21939
|
-
//
|
|
21940
|
-
|
|
21941
|
-
|
|
22303
|
+
recordElementClose(startOp, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirectiveCloses.get(op.xref));
|
|
22304
|
+
// Clear out the pending structural directive close that was accounted for.
|
|
22305
|
+
pendingStructuralDirectiveCloses.delete(op.xref);
|
|
22306
|
+
}
|
|
22307
|
+
break;
|
|
22308
|
+
case OpKind.Projection:
|
|
22309
|
+
// For content projections with i18n placeholders, record its slot value in the params map
|
|
22310
|
+
// under the corresponding tag start and close placeholders.
|
|
22311
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
22312
|
+
if (currentOps === null) {
|
|
22313
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21942
22314
|
}
|
|
22315
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22316
|
+
recordElementClose(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22317
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
22318
|
+
pendingStructuralDirective = undefined;
|
|
21943
22319
|
}
|
|
21944
22320
|
break;
|
|
21945
22321
|
case OpKind.Template:
|
|
21946
|
-
|
|
21947
|
-
|
|
21948
|
-
|
|
22322
|
+
const view = job.views.get(op.xref);
|
|
22323
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22324
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22325
|
+
// blocks.
|
|
22326
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22327
|
+
}
|
|
22328
|
+
else {
|
|
21949
22329
|
if (currentOps === null) {
|
|
21950
22330
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21951
22331
|
}
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
|
|
21956
|
-
|
|
21957
|
-
|
|
22332
|
+
if (op.templateKind === TemplateKind.Structural) {
|
|
22333
|
+
// If this is a structural directive template, don't record anything yet. Instead pass
|
|
22334
|
+
// the current template as a pending structural directive to be recorded when we find
|
|
22335
|
+
// the element, content, or template it belongs to. This allows us to create combined
|
|
22336
|
+
// values that represent, e.g. the start of a template and element at the same time.
|
|
22337
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
|
|
21958
22338
|
}
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
21962
|
-
|
|
22339
|
+
else {
|
|
22340
|
+
// If this is some other kind of template, we can record its start, recurse into its
|
|
22341
|
+
// view, and then record its end.
|
|
22342
|
+
recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22343
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22344
|
+
recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22345
|
+
pendingStructuralDirective = undefined;
|
|
21963
22346
|
}
|
|
21964
22347
|
}
|
|
22348
|
+
break;
|
|
22349
|
+
case OpKind.RepeaterCreate:
|
|
22350
|
+
if (pendingStructuralDirective !== undefined) {
|
|
22351
|
+
throw Error('AssertionError: Unexpected structural directive associated with @for block');
|
|
22352
|
+
}
|
|
22353
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22354
|
+
// template and the (optional) third is for the @empty template.
|
|
22355
|
+
const forSlot = op.handle.slot + 1;
|
|
22356
|
+
const forView = job.views.get(op.xref);
|
|
22357
|
+
// First record all of the placeholders for the @for template.
|
|
22358
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22359
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22360
|
+
// blocks.
|
|
22361
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22362
|
+
}
|
|
21965
22363
|
else {
|
|
21966
|
-
|
|
22364
|
+
if (currentOps === null) {
|
|
22365
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22366
|
+
}
|
|
22367
|
+
recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22368
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22369
|
+
recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22370
|
+
pendingStructuralDirective = undefined;
|
|
22371
|
+
}
|
|
22372
|
+
// Then if there's an @empty template, add its placeholders as well.
|
|
22373
|
+
if (op.emptyView !== null) {
|
|
22374
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22375
|
+
// template and the (optional) third is for the @empty template.
|
|
22376
|
+
const emptySlot = op.handle.slot + 2;
|
|
22377
|
+
const emptyView = job.views.get(op.emptyView);
|
|
22378
|
+
if (op.emptyI18nPlaceholder === undefined) {
|
|
22379
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22380
|
+
// blocks.
|
|
22381
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22382
|
+
}
|
|
22383
|
+
else {
|
|
22384
|
+
if (currentOps === null) {
|
|
22385
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22386
|
+
}
|
|
22387
|
+
recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22388
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22389
|
+
recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22390
|
+
pendingStructuralDirective = undefined;
|
|
22391
|
+
}
|
|
21967
22392
|
}
|
|
21968
22393
|
break;
|
|
21969
22394
|
}
|
|
21970
22395
|
}
|
|
21971
22396
|
}
|
|
22397
|
+
/**
|
|
22398
|
+
* Records an i18n param value for the start of an element.
|
|
22399
|
+
*/
|
|
22400
|
+
function recordElementStart(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22401
|
+
const { startName, closeName } = op.i18nPlaceholder;
|
|
22402
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
22403
|
+
let value = op.handle.slot;
|
|
22404
|
+
// If the element is associated with a structural directive, start it as well.
|
|
22405
|
+
if (structuralDirective !== undefined) {
|
|
22406
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22407
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22408
|
+
}
|
|
22409
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22410
|
+
// placeholder accounts for the start and close of the element.
|
|
22411
|
+
if (!closeName) {
|
|
22412
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22413
|
+
}
|
|
22414
|
+
addParam(i18nContext.params, startName, value, i18nBlock.subTemplateIndex, flags);
|
|
22415
|
+
}
|
|
22416
|
+
/**
|
|
22417
|
+
* Records an i18n param value for the closing of an element.
|
|
22418
|
+
*/
|
|
22419
|
+
function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22420
|
+
const { closeName } = op.i18nPlaceholder;
|
|
22421
|
+
// Self-closing tags don't have a closing tag placeholder, instead the element closing is
|
|
22422
|
+
// recorded via an additional flag on the element start value.
|
|
22423
|
+
if (closeName) {
|
|
22424
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag;
|
|
22425
|
+
let value = op.handle.slot;
|
|
22426
|
+
// If the element is associated with a structural directive, close it as well.
|
|
22427
|
+
if (structuralDirective !== undefined) {
|
|
22428
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22429
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22430
|
+
}
|
|
22431
|
+
addParam(i18nContext.params, closeName, value, i18nBlock.subTemplateIndex, flags);
|
|
22432
|
+
}
|
|
22433
|
+
}
|
|
22434
|
+
/**
|
|
22435
|
+
* Records an i18n param value for the start of a template.
|
|
22436
|
+
*/
|
|
22437
|
+
function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22438
|
+
let { startName, closeName } = i18nPlaceholder;
|
|
22439
|
+
let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
|
|
22440
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22441
|
+
// placeholder accounts for the start and close of the element.
|
|
22442
|
+
if (!closeName) {
|
|
22443
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22444
|
+
}
|
|
22445
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22446
|
+
// start first. Since this template must be in the structural directive's view, we can just
|
|
22447
|
+
// directly use the current i18n block's sub-template index.
|
|
22448
|
+
if (structuralDirective !== undefined) {
|
|
22449
|
+
addParam(i18nContext.params, startName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
22450
|
+
}
|
|
22451
|
+
// Record the start of the template. For the sub-template index, pass the index for the template's
|
|
22452
|
+
// view, rather than the current i18n block's index.
|
|
22453
|
+
addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22454
|
+
}
|
|
22455
|
+
/**
|
|
22456
|
+
* Records an i18n param value for the closing of a template.
|
|
22457
|
+
*/
|
|
22458
|
+
function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22459
|
+
const { startName, closeName } = i18nPlaceholder;
|
|
22460
|
+
const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
|
|
22461
|
+
// Self-closing tags don't have a closing tag placeholder, instead the template's closing is
|
|
22462
|
+
// recorded via an additional flag on the template start value.
|
|
22463
|
+
if (closeName) {
|
|
22464
|
+
// Record the closing of the template. For the sub-template index, pass the index for the
|
|
22465
|
+
// template's view, rather than the current i18n block's index.
|
|
22466
|
+
addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22467
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22468
|
+
// closing after. Since this template must be in the structural directive's view, we can just
|
|
22469
|
+
// directly use the current i18n block's sub-template index.
|
|
22470
|
+
if (structuralDirective !== undefined) {
|
|
22471
|
+
addParam(i18nContext.params, closeName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
22472
|
+
}
|
|
22473
|
+
}
|
|
22474
|
+
}
|
|
21972
22475
|
/**
|
|
21973
22476
|
* Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
|
|
21974
22477
|
* the child i18n block inside the template.
|
|
21975
22478
|
*/
|
|
21976
|
-
function getSubTemplateIndexForTemplateTag(job, i18nOp,
|
|
21977
|
-
for (const childOp of
|
|
22479
|
+
function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
|
|
22480
|
+
for (const childOp of view.create) {
|
|
21978
22481
|
if (childOp.kind === OpKind.I18nStart) {
|
|
21979
22482
|
return childOp.subTemplateIndex;
|
|
21980
22483
|
}
|
|
21981
22484
|
}
|
|
21982
22485
|
return i18nOp.subTemplateIndex;
|
|
21983
22486
|
}
|
|
21984
|
-
/**
|
|
22487
|
+
/**
|
|
22488
|
+
* Add a param value to the given params map.
|
|
22489
|
+
*/
|
|
21985
22490
|
function addParam(params, placeholder, value, subTemplateIndex, flags) {
|
|
21986
22491
|
const values = params.get(placeholder) ?? [];
|
|
21987
22492
|
values.push({ value, subTemplateIndex, flags });
|
|
@@ -22007,14 +22512,19 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22007
22512
|
}
|
|
22008
22513
|
}
|
|
22009
22514
|
}
|
|
22010
|
-
// Keep track of the next available expression index
|
|
22515
|
+
// Keep track of the next available expression index for each i18n message.
|
|
22011
22516
|
const expressionIndices = new Map();
|
|
22517
|
+
// Keep track of a reference index for each expression.
|
|
22518
|
+
// We use different references for normal i18n expressio and attribute i18n expressions. This is
|
|
22519
|
+
// because child i18n blocks in templates don't get their own context, since they're rolled into
|
|
22520
|
+
// the translated message of the parent, but they may target a different slot.
|
|
22521
|
+
const referenceIndex = (op) => op.usage === I18nExpressionFor.I18nText ? op.i18nOwner : op.context;
|
|
22012
22522
|
for (const unit of job.units) {
|
|
22013
22523
|
for (const op of unit.update) {
|
|
22014
22524
|
if (op.kind === OpKind.I18nExpression) {
|
|
22015
22525
|
const i18nContext = i18nContexts.get(op.context);
|
|
22016
|
-
const index = expressionIndices.get(op
|
|
22017
|
-
const subTemplateIndex = subTemplateIndicies.get(op.
|
|
22526
|
+
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22527
|
+
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
22018
22528
|
// Add the expression index in the appropriate params map.
|
|
22019
22529
|
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22020
22530
|
i18nContext.params :
|
|
@@ -22026,7 +22536,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22026
22536
|
flags: I18nParamValueFlags.ExpressionIndex
|
|
22027
22537
|
});
|
|
22028
22538
|
params.set(op.i18nPlaceholder, values);
|
|
22029
|
-
expressionIndices.set(op
|
|
22539
|
+
expressionIndices.set(referenceIndex(op), index + 1);
|
|
22030
22540
|
}
|
|
22031
22541
|
}
|
|
22032
22542
|
}
|
|
@@ -22184,12 +22694,20 @@ function processLexicalScope(unit, ops, savedView) {
|
|
|
22184
22694
|
}
|
|
22185
22695
|
|
|
22186
22696
|
/**
|
|
22187
|
-
*
|
|
22697
|
+
* Map of security contexts to their sanitizer function.
|
|
22188
22698
|
*/
|
|
22189
|
-
const
|
|
22190
|
-
[SecurityContext.HTML,
|
|
22191
|
-
[SecurityContext.
|
|
22192
|
-
[SecurityContext.
|
|
22699
|
+
const sanitizerFns = new Map([
|
|
22700
|
+
[SecurityContext.HTML, Identifiers.sanitizeHtml],
|
|
22701
|
+
[SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl],
|
|
22702
|
+
[SecurityContext.SCRIPT, Identifiers.sanitizeScript],
|
|
22703
|
+
[SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl]
|
|
22704
|
+
]);
|
|
22705
|
+
/**
|
|
22706
|
+
* Map of security contexts to their trusted value function.
|
|
22707
|
+
*/
|
|
22708
|
+
const trustedValueFns = new Map([
|
|
22709
|
+
[SecurityContext.HTML, Identifiers.trustConstantHtml],
|
|
22710
|
+
[SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl],
|
|
22193
22711
|
]);
|
|
22194
22712
|
/**
|
|
22195
22713
|
* Resolves sanitization functions for ops that need them.
|
|
@@ -22197,24 +22715,61 @@ const sanitizers = new Map([
|
|
|
22197
22715
|
function resolveSanitizers(job) {
|
|
22198
22716
|
for (const unit of job.units) {
|
|
22199
22717
|
const elements = createOpXrefMap(unit);
|
|
22200
|
-
|
|
22718
|
+
// For normal element bindings we create trusted values for security sensitive constant
|
|
22719
|
+
// attributes. However, for host bindings we skip this step (this matches what
|
|
22720
|
+
// TemplateDefinitionBuilder does).
|
|
22721
|
+
// TODO: Is the TDB behavior correct here?
|
|
22722
|
+
if (job.kind !== CompilationJobKind.Host) {
|
|
22723
|
+
for (const op of unit.create) {
|
|
22724
|
+
if (op.kind === OpKind.ExtractedAttribute) {
|
|
22725
|
+
const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22726
|
+
op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
|
|
22727
|
+
}
|
|
22728
|
+
}
|
|
22729
|
+
}
|
|
22201
22730
|
for (const op of unit.update) {
|
|
22202
22731
|
switch (op.kind) {
|
|
22203
22732
|
case OpKind.Property:
|
|
22204
22733
|
case OpKind.Attribute:
|
|
22205
|
-
|
|
22206
|
-
|
|
22734
|
+
case OpKind.HostProperty:
|
|
22735
|
+
let sanitizerFn = null;
|
|
22736
|
+
if (Array.isArray(op.securityContext) && op.securityContext.length === 2 &&
|
|
22737
|
+
op.securityContext.indexOf(SecurityContext.URL) > -1 &&
|
|
22738
|
+
op.securityContext.indexOf(SecurityContext.RESOURCE_URL) > -1) {
|
|
22739
|
+
// When the host element isn't known, some URL attributes (such as "src" and "href") may
|
|
22740
|
+
// be part of multiple different security contexts. In this case we use special
|
|
22741
|
+
// sanitization function and select the actual sanitizer at runtime based on a tag name
|
|
22742
|
+
// that is provided while invoking sanitization function.
|
|
22743
|
+
sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
|
|
22744
|
+
}
|
|
22745
|
+
else {
|
|
22746
|
+
sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22747
|
+
}
|
|
22748
|
+
op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
|
|
22207
22749
|
// If there was no sanitization function found based on the security context of an
|
|
22208
22750
|
// attribute/property, check whether this attribute/property is one of the
|
|
22209
22751
|
// security-sensitive <iframe> attributes (and that the current element is actually an
|
|
22210
22752
|
// <iframe>).
|
|
22211
22753
|
if (op.sanitizer === null) {
|
|
22212
|
-
|
|
22213
|
-
if (
|
|
22214
|
-
|
|
22754
|
+
let isIframe = false;
|
|
22755
|
+
if (job.kind === CompilationJobKind.Host || op.kind === OpKind.HostProperty) {
|
|
22756
|
+
// Note: for host bindings defined on a directive, we do not try to find all
|
|
22757
|
+
// possible places where it can be matched, so we can not determine whether
|
|
22758
|
+
// the host element is an <iframe>. In this case, we just assume it is and append a
|
|
22759
|
+
// validation function, which is invoked at runtime and would have access to the
|
|
22760
|
+
// underlying DOM element to check if it's an <iframe> and if so - run extra checks.
|
|
22761
|
+
isIframe = true;
|
|
22762
|
+
}
|
|
22763
|
+
else {
|
|
22764
|
+
// For a normal binding we can just check if the element its on is an iframe.
|
|
22765
|
+
const ownerOp = elements.get(op.target);
|
|
22766
|
+
if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
|
|
22767
|
+
throw Error('Property should have an element-like owner');
|
|
22768
|
+
}
|
|
22769
|
+
isIframe = isIframeElement$1(ownerOp);
|
|
22215
22770
|
}
|
|
22216
|
-
if (
|
|
22217
|
-
op.sanitizer =
|
|
22771
|
+
if (isIframe && isIframeSecuritySensitiveAttr(op.name)) {
|
|
22772
|
+
op.sanitizer = importExpr(Identifiers.validateIframeAttribute);
|
|
22218
22773
|
}
|
|
22219
22774
|
}
|
|
22220
22775
|
break;
|
|
@@ -22228,6 +22783,22 @@ function resolveSanitizers(job) {
|
|
|
22228
22783
|
function isIframeElement$1(op) {
|
|
22229
22784
|
return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
|
|
22230
22785
|
}
|
|
22786
|
+
/**
|
|
22787
|
+
* Asserts that there is only a single security context and returns it.
|
|
22788
|
+
*/
|
|
22789
|
+
function getOnlySecurityContext(securityContext) {
|
|
22790
|
+
if (Array.isArray(securityContext)) {
|
|
22791
|
+
if (securityContext.length > 1) {
|
|
22792
|
+
// TODO: What should we do here? TDB just took the first one, but this feels like something we
|
|
22793
|
+
// would want to know about and create a special case for like we did for Url/ResourceUrl. My
|
|
22794
|
+
// guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
|
|
22795
|
+
// do turn out to be other cases, throwing an error until we can address it feels safer.
|
|
22796
|
+
throw Error(`AssertionError: Ambiguous security context`);
|
|
22797
|
+
}
|
|
22798
|
+
return securityContext[0] || SecurityContext.NONE;
|
|
22799
|
+
}
|
|
22800
|
+
return securityContext;
|
|
22801
|
+
}
|
|
22231
22802
|
|
|
22232
22803
|
/**
|
|
22233
22804
|
* When inside of a listener, we may need access to one or more enclosing views. Therefore, each
|
|
@@ -22331,6 +22902,8 @@ function allocateSlots(job) {
|
|
|
22331
22902
|
// operation itself, so it can be emitted later.
|
|
22332
22903
|
const childView = job.views.get(op.xref);
|
|
22333
22904
|
op.decls = childView.decls;
|
|
22905
|
+
// TODO: currently we handle the decls for the RepeaterCreate empty template in the reify
|
|
22906
|
+
// phase. We should handle that here instead.
|
|
22334
22907
|
}
|
|
22335
22908
|
}
|
|
22336
22909
|
}
|
|
@@ -22654,6 +23227,8 @@ function countVariables(job) {
|
|
|
22654
23227
|
}
|
|
22655
23228
|
const childView = job.views.get(op.xref);
|
|
22656
23229
|
op.vars = childView.vars;
|
|
23230
|
+
// TODO: currently we handle the vars for the RepeaterCreate empty template in the reify
|
|
23231
|
+
// phase. We should handle that here instead.
|
|
22657
23232
|
}
|
|
22658
23233
|
}
|
|
22659
23234
|
}
|
|
@@ -23173,12 +23748,12 @@ const phases = [
|
|
|
23173
23748
|
{ kind: CompilationJobKind.Tmpl, fn: removeContentSelectors },
|
|
23174
23749
|
{ kind: CompilationJobKind.Host, fn: parseHostStyleProperties },
|
|
23175
23750
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
23176
|
-
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23177
|
-
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23178
23751
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
23179
23752
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
23180
|
-
{ kind: CompilationJobKind.
|
|
23753
|
+
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23754
|
+
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23181
23755
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
23756
|
+
{ kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
|
|
23182
23757
|
{ kind: CompilationJobKind.Both, fn: parseExtractedStyles },
|
|
23183
23758
|
{ kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
|
|
23184
23759
|
{ kind: CompilationJobKind.Both, fn: collapseSingletonInterpolations },
|
|
@@ -23186,14 +23761,17 @@ const phases = [
|
|
|
23186
23761
|
{ kind: CompilationJobKind.Tmpl, fn: generateConditionalExpressions },
|
|
23187
23762
|
{ kind: CompilationJobKind.Tmpl, fn: createPipes },
|
|
23188
23763
|
{ kind: CompilationJobKind.Tmpl, fn: configureDeferInstructions },
|
|
23189
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
23764
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nText },
|
|
23765
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nBindings },
|
|
23766
|
+
{ kind: CompilationJobKind.Tmpl, fn: removeUnusedI18nAttributesOps },
|
|
23767
|
+
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
23190
23768
|
{ kind: CompilationJobKind.Tmpl, fn: applyI18nExpressions },
|
|
23191
23769
|
{ kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
|
|
23192
23770
|
{ kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
|
|
23193
23771
|
{ kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
|
|
23194
23772
|
{ kind: CompilationJobKind.Tmpl, fn: generateVariables },
|
|
23195
23773
|
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
23196
|
-
{ kind: CompilationJobKind.
|
|
23774
|
+
{ kind: CompilationJobKind.Both, fn: deleteAnyCasts },
|
|
23197
23775
|
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
23198
23776
|
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
23199
23777
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
@@ -23201,7 +23779,7 @@ const phases = [
|
|
|
23201
23779
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
23202
23780
|
{ kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
|
|
23203
23781
|
{ kind: CompilationJobKind.Both, fn: resolveContexts },
|
|
23204
|
-
{ kind: CompilationJobKind.
|
|
23782
|
+
{ kind: CompilationJobKind.Both, fn: resolveSanitizers },
|
|
23205
23783
|
{ kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
|
|
23206
23784
|
{ kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
|
|
23207
23785
|
{ kind: CompilationJobKind.Both, fn: expandSafeReads },
|
|
@@ -23216,7 +23794,6 @@ const phases = [
|
|
|
23216
23794
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
23217
23795
|
{ kind: CompilationJobKind.Tmpl, fn: collectConstExpressions },
|
|
23218
23796
|
{ kind: CompilationJobKind.Both, fn: collectElementConsts },
|
|
23219
|
-
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
23220
23797
|
{ kind: CompilationJobKind.Tmpl, fn: removeI18nContexts },
|
|
23221
23798
|
{ kind: CompilationJobKind.Both, fn: countVariables },
|
|
23222
23799
|
{ kind: CompilationJobKind.Tmpl, fn: generateAdvance },
|
|
@@ -23338,6 +23915,10 @@ function emitHostBindingFunction(job) {
|
|
|
23338
23915
|
}
|
|
23339
23916
|
|
|
23340
23917
|
const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
|
|
23918
|
+
// Schema containing DOM elements and their properties.
|
|
23919
|
+
const domSchema = new DomElementSchemaRegistry();
|
|
23920
|
+
// Tag name of the `ng-template` element.
|
|
23921
|
+
const NG_TEMPLATE_TAG_NAME$1 = 'ng-template';
|
|
23341
23922
|
/**
|
|
23342
23923
|
* Process a template AST and convert it into a `ComponentCompilation` in the intermediate
|
|
23343
23924
|
* representation.
|
|
@@ -23355,10 +23936,24 @@ function ingestComponent(componentName, template, constantPool, relativeContextF
|
|
|
23355
23936
|
function ingestHostBinding(input, bindingParser, constantPool) {
|
|
23356
23937
|
const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
|
|
23357
23938
|
for (const property of input.properties ?? []) {
|
|
23358
|
-
|
|
23939
|
+
let bindingKind = BindingKind.Property;
|
|
23940
|
+
// TODO: this should really be handled in the parser.
|
|
23941
|
+
if (property.name.startsWith('attr.')) {
|
|
23942
|
+
property.name = property.name.substring('attr.'.length);
|
|
23943
|
+
bindingKind = BindingKind.Attribute;
|
|
23944
|
+
}
|
|
23945
|
+
if (property.isAnimation) {
|
|
23946
|
+
bindingKind = BindingKind.Animation;
|
|
23947
|
+
}
|
|
23948
|
+
const securityContexts = bindingParser
|
|
23949
|
+
.calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
|
|
23950
|
+
.filter(context => context !== SecurityContext.NONE);
|
|
23951
|
+
ingestHostProperty(job, property, bindingKind, false, securityContexts);
|
|
23359
23952
|
}
|
|
23360
23953
|
for (const [name, expr] of Object.entries(input.attributes) ?? []) {
|
|
23361
|
-
|
|
23954
|
+
const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true)
|
|
23955
|
+
.filter(context => context !== SecurityContext.NONE);
|
|
23956
|
+
ingestHostAttribute(job, name, expr, securityContexts);
|
|
23362
23957
|
}
|
|
23363
23958
|
for (const event of input.events ?? []) {
|
|
23364
23959
|
ingestHostEvent(job, event);
|
|
@@ -23367,34 +23962,27 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23367
23962
|
}
|
|
23368
23963
|
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
23369
23964
|
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
23370
|
-
function ingestHostProperty(job, property, isTextAttribute) {
|
|
23965
|
+
function ingestHostProperty(job, property, bindingKind, isTextAttribute, securityContexts) {
|
|
23371
23966
|
let expression;
|
|
23372
23967
|
const ast = property.expression.ast;
|
|
23373
23968
|
if (ast instanceof Interpolation$1) {
|
|
23374
|
-
expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)));
|
|
23969
|
+
expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)), []);
|
|
23375
23970
|
}
|
|
23376
23971
|
else {
|
|
23377
23972
|
expression = convertAst(ast, job, property.sourceSpan);
|
|
23378
23973
|
}
|
|
23379
|
-
|
|
23380
|
-
// TODO: this should really be handled in the parser.
|
|
23381
|
-
if (property.name.startsWith('attr.')) {
|
|
23382
|
-
property.name = property.name.substring('attr.'.length);
|
|
23383
|
-
bindingKind = BindingKind.Attribute;
|
|
23384
|
-
}
|
|
23385
|
-
if (property.isAnimation) {
|
|
23386
|
-
bindingKind = BindingKind.Animation;
|
|
23387
|
-
}
|
|
23388
|
-
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
|
|
23389
|
-
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, property.sourceSpan));
|
|
23974
|
+
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, isTextAttribute, false, null, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
|
|
23390
23975
|
}
|
|
23391
|
-
function ingestHostAttribute(job, name, value) {
|
|
23392
|
-
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null,
|
|
23976
|
+
function ingestHostAttribute(job, name, value, securityContexts) {
|
|
23977
|
+
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts, true, false, null,
|
|
23978
|
+
/* TODO */ null,
|
|
23393
23979
|
/* TODO: host attribute source spans */ null);
|
|
23394
23980
|
job.root.update.push(attrBinding);
|
|
23395
23981
|
}
|
|
23396
23982
|
function ingestHostEvent(job, event) {
|
|
23397
|
-
const
|
|
23983
|
+
const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
|
|
23984
|
+
[event.targetOrPhase, null];
|
|
23985
|
+
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, [], phase, target, true, event.sourceSpan);
|
|
23398
23986
|
// TODO: Can this be a chain?
|
|
23399
23987
|
eventBinding.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(event.handler.ast, job, event.sourceSpan), event.handlerSpan)));
|
|
23400
23988
|
job.root.create.push(eventBinding);
|
|
@@ -23451,8 +24039,14 @@ function ingestElement(unit, element) {
|
|
|
23451
24039
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
23452
24040
|
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
23453
24041
|
unit.create.push(startOp);
|
|
23454
|
-
|
|
24042
|
+
ingestElementBindings(unit, startOp, element);
|
|
23455
24043
|
ingestReferences(startOp, element);
|
|
24044
|
+
// Start i18n, if needed, goes after the element create and bindings, but before the nodes
|
|
24045
|
+
let i18nBlockId = null;
|
|
24046
|
+
if (element.i18n instanceof Message) {
|
|
24047
|
+
i18nBlockId = unit.job.allocateXrefId();
|
|
24048
|
+
unit.create.push(createI18nStartOp(i18nBlockId, element.i18n));
|
|
24049
|
+
}
|
|
23456
24050
|
ingestNodes(unit, element.children);
|
|
23457
24051
|
// The source span for the end op is typically the element closing tag. However, if no closing tag
|
|
23458
24052
|
// exists, such as in `<input>`, we use the start source span instead. Usually the start and end
|
|
@@ -23462,9 +24056,7 @@ function ingestElement(unit, element) {
|
|
|
23462
24056
|
const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
|
|
23463
24057
|
unit.create.push(endOp);
|
|
23464
24058
|
// If there is an i18n message associated with this element, insert i18n start and end ops.
|
|
23465
|
-
if (
|
|
23466
|
-
const i18nBlockId = unit.job.allocateXrefId();
|
|
23467
|
-
OpList.insertAfter(createI18nStartOp(i18nBlockId, element.i18n), startOp);
|
|
24059
|
+
if (i18nBlockId !== null) {
|
|
23468
24060
|
OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
|
|
23469
24061
|
}
|
|
23470
24062
|
}
|
|
@@ -23487,10 +24079,11 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23487
24079
|
const functionNameSuffix = tagNameWithoutNamespace === null ?
|
|
23488
24080
|
'' :
|
|
23489
24081
|
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
23490
|
-
const
|
|
23491
|
-
|
|
23492
|
-
|
|
23493
|
-
|
|
24082
|
+
const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
|
|
24083
|
+
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
24084
|
+
unit.create.push(templateOp);
|
|
24085
|
+
ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
|
|
24086
|
+
ingestReferences(templateOp, tmpl);
|
|
23494
24087
|
ingestNodes(childView, tmpl.children);
|
|
23495
24088
|
for (const { name, value } of tmpl.variables) {
|
|
23496
24089
|
childView.contextVariables.set(name, value !== '' ? value : '$implicit');
|
|
@@ -23498,19 +24091,24 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23498
24091
|
// If this is a plain template and there is an i18n message associated with it, insert i18n start
|
|
23499
24092
|
// and end ops. For structural directive templates, the i18n ops will be added when ingesting the
|
|
23500
24093
|
// element/template the directive is placed on.
|
|
23501
|
-
if (
|
|
24094
|
+
if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
|
|
23502
24095
|
const id = unit.job.allocateXrefId();
|
|
23503
24096
|
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
23504
24097
|
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
23505
24098
|
}
|
|
23506
24099
|
}
|
|
23507
24100
|
/**
|
|
23508
|
-
* Ingest a
|
|
24101
|
+
* Ingest a content node from the AST into the given `ViewCompilation`.
|
|
23509
24102
|
*/
|
|
23510
24103
|
function ingestContent(unit, content) {
|
|
23511
|
-
|
|
24104
|
+
if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
|
|
24105
|
+
throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
|
|
24106
|
+
}
|
|
24107
|
+
const attrs = content.attributes.flatMap(a => [a.name, a.value]);
|
|
24108
|
+
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, attrs, content.sourceSpan);
|
|
23512
24109
|
for (const attr of content.attributes) {
|
|
23513
|
-
|
|
24110
|
+
const securityContext = domSchema.securityContext(content.name, attr.name, true);
|
|
24111
|
+
unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
23514
24112
|
}
|
|
23515
24113
|
unit.create.push(op);
|
|
23516
24114
|
}
|
|
@@ -23535,6 +24133,7 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
23535
24133
|
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
23536
24134
|
}
|
|
23537
24135
|
if (i18nPlaceholders === undefined) {
|
|
24136
|
+
// TODO: We probably can just use the placeholders field, instead of walking the AST.
|
|
23538
24137
|
i18nPlaceholders = text.i18n instanceof Container ?
|
|
23539
24138
|
text.i18n.children
|
|
23540
24139
|
.filter((node) => node instanceof Placeholder)
|
|
@@ -23550,7 +24149,7 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
23550
24149
|
// interpolation. We copy that behavior in compatibility mode.
|
|
23551
24150
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
23552
24151
|
const baseSourceSpan = unit.job.compatibility ? null : text.sourceSpan;
|
|
23553
|
-
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))
|
|
24152
|
+
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan)), i18nPlaceholders), text.sourceSpan));
|
|
23554
24153
|
}
|
|
23555
24154
|
/**
|
|
23556
24155
|
* Ingest an `@if` block into the given `ViewCompilation`.
|
|
@@ -23571,14 +24170,21 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
23571
24170
|
if (ifCase.expressionAlias !== null) {
|
|
23572
24171
|
cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
|
|
23573
24172
|
}
|
|
23574
|
-
|
|
23575
|
-
|
|
24173
|
+
let ifCaseI18nMeta = undefined;
|
|
24174
|
+
if (ifCase.i18n !== undefined) {
|
|
24175
|
+
if (!(ifCase.i18n instanceof BlockPlaceholder)) {
|
|
24176
|
+
throw Error(`Unhandled i18n metadata type for if block: ${ifCase.i18n?.constructor.name}`);
|
|
24177
|
+
}
|
|
24178
|
+
ifCaseI18nMeta = ifCase.i18n;
|
|
24179
|
+
}
|
|
24180
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.sourceSpan);
|
|
24181
|
+
unit.create.push(templateOp);
|
|
23576
24182
|
if (firstXref === null) {
|
|
23577
24183
|
firstXref = cView.xref;
|
|
23578
|
-
firstSlotHandle =
|
|
24184
|
+
firstSlotHandle = templateOp.handle;
|
|
23579
24185
|
}
|
|
23580
24186
|
const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
|
|
23581
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
24187
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle, ifCase.expressionAlias);
|
|
23582
24188
|
conditions.push(conditionalCaseExpr);
|
|
23583
24189
|
ingestNodes(cView, ifCase.children);
|
|
23584
24190
|
}
|
|
@@ -23594,29 +24200,39 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
23594
24200
|
let conditions = [];
|
|
23595
24201
|
for (const switchCase of switchBlock.cases) {
|
|
23596
24202
|
const cView = unit.job.allocateView(unit.xref);
|
|
23597
|
-
|
|
23598
|
-
|
|
24203
|
+
let switchCaseI18nMeta = undefined;
|
|
24204
|
+
if (switchCase.i18n !== undefined) {
|
|
24205
|
+
if (!(switchCase.i18n instanceof BlockPlaceholder)) {
|
|
24206
|
+
throw Error(`Unhandled i18n metadata type for switch block: ${switchCase.i18n?.constructor.name}`);
|
|
24207
|
+
}
|
|
24208
|
+
switchCaseI18nMeta = switchCase.i18n;
|
|
24209
|
+
}
|
|
24210
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.sourceSpan);
|
|
24211
|
+
unit.create.push(templateOp);
|
|
23599
24212
|
if (firstXref === null) {
|
|
23600
24213
|
firstXref = cView.xref;
|
|
23601
|
-
firstSlotHandle =
|
|
24214
|
+
firstSlotHandle = templateOp.handle;
|
|
23602
24215
|
}
|
|
23603
24216
|
const caseExpr = switchCase.expression ?
|
|
23604
24217
|
convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
|
|
23605
24218
|
null;
|
|
23606
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
24219
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle);
|
|
23607
24220
|
conditions.push(conditionalCaseExpr);
|
|
23608
24221
|
ingestNodes(cView, switchCase.children);
|
|
23609
24222
|
}
|
|
23610
24223
|
const conditional = createConditionalOp(firstXref, firstSlotHandle, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
|
|
23611
24224
|
unit.update.push(conditional);
|
|
23612
24225
|
}
|
|
23613
|
-
function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
24226
|
+
function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
|
|
24227
|
+
if (i18nMeta !== undefined && !(i18nMeta instanceof BlockPlaceholder)) {
|
|
24228
|
+
throw Error('Unhandled i18n metadata type for defer block');
|
|
24229
|
+
}
|
|
23614
24230
|
if (children === undefined) {
|
|
23615
24231
|
return null;
|
|
23616
24232
|
}
|
|
23617
24233
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
23618
24234
|
ingestNodes(secondaryView, children);
|
|
23619
|
-
const templateOp = createTemplateOp(secondaryView.xref, null, `Defer${suffix}`, Namespace.HTML,
|
|
24235
|
+
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan);
|
|
23620
24236
|
unit.create.push(templateOp);
|
|
23621
24237
|
return templateOp;
|
|
23622
24238
|
}
|
|
@@ -23626,10 +24242,10 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
23626
24242
|
throw new Error(`AssertionError: unable to find metadata for deferred block`);
|
|
23627
24243
|
}
|
|
23628
24244
|
// Generate the defer main view and all secondary views.
|
|
23629
|
-
const main = ingestDeferView(unit, '', deferBlock.children, deferBlock.sourceSpan);
|
|
23630
|
-
const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
|
|
23631
|
-
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
23632
|
-
const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
24245
|
+
const main = ingestDeferView(unit, '', deferBlock.i18n, deferBlock.children, deferBlock.sourceSpan);
|
|
24246
|
+
const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.i18n, deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
|
|
24247
|
+
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.i18n, deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
24248
|
+
const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
23633
24249
|
// Create the main defer op, and ops for all secondary views.
|
|
23634
24250
|
const deferXref = unit.job.allocateXrefId();
|
|
23635
24251
|
const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, deferBlock.sourceSpan);
|
|
@@ -23711,12 +24327,7 @@ function ingestIcu(unit, icu) {
|
|
|
23711
24327
|
const xref = unit.job.allocateXrefId();
|
|
23712
24328
|
const icuNode = icu.i18n.nodes[0];
|
|
23713
24329
|
unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
|
|
23714
|
-
const
|
|
23715
|
-
if (expressionPlaceholder === undefined || icu.vars[expressionPlaceholder] === undefined) {
|
|
23716
|
-
throw Error('ICU should have a text binding');
|
|
23717
|
-
}
|
|
23718
|
-
ingestBoundText(unit, icu.vars[expressionPlaceholder], [expressionPlaceholder]);
|
|
23719
|
-
for (const [placeholder, text] of Object.entries(icu.placeholders)) {
|
|
24330
|
+
for (const [placeholder, text] of Object.entries({ ...icu.vars, ...icu.placeholders })) {
|
|
23720
24331
|
if (text instanceof BoundText) {
|
|
23721
24332
|
ingestBoundText(unit, text, [placeholder]);
|
|
23722
24333
|
}
|
|
@@ -23768,8 +24379,17 @@ function ingestForBlock(unit, forBlock) {
|
|
|
23768
24379
|
$odd: forBlock.contextVariables.$odd.name,
|
|
23769
24380
|
$implicit: forBlock.item.name,
|
|
23770
24381
|
};
|
|
24382
|
+
if (forBlock.i18n !== undefined && !(forBlock.i18n instanceof BlockPlaceholder)) {
|
|
24383
|
+
throw Error('AssertionError: Unhandled i18n metadata type or @for');
|
|
24384
|
+
}
|
|
24385
|
+
if (forBlock.empty?.i18n !== undefined &&
|
|
24386
|
+
!(forBlock.empty.i18n instanceof BlockPlaceholder)) {
|
|
24387
|
+
throw Error('AssertionError: Unhandled i18n metadata type or @empty');
|
|
24388
|
+
}
|
|
24389
|
+
const i18nPlaceholder = forBlock.i18n;
|
|
24390
|
+
const emptyI18nPlaceholder = forBlock.empty?.i18n;
|
|
23771
24391
|
const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
|
|
23772
|
-
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, forBlock.sourceSpan);
|
|
24392
|
+
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, forBlock.sourceSpan);
|
|
23773
24393
|
unit.create.push(repeaterCreate);
|
|
23774
24394
|
const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
|
|
23775
24395
|
const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
|
|
@@ -23812,6 +24432,16 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23812
24432
|
else if (ast instanceof LiteralPrimitive) {
|
|
23813
24433
|
return literal(ast.value, undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
23814
24434
|
}
|
|
24435
|
+
else if (ast instanceof Unary) {
|
|
24436
|
+
switch (ast.operator) {
|
|
24437
|
+
case '+':
|
|
24438
|
+
return new UnaryOperatorExpr(UnaryOperator.Plus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
24439
|
+
case '-':
|
|
24440
|
+
return new UnaryOperatorExpr(UnaryOperator.Minus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
24441
|
+
default:
|
|
24442
|
+
throw new Error(`AssertionError: unknown unary operator ${ast.operator}`);
|
|
24443
|
+
}
|
|
24444
|
+
}
|
|
23815
24445
|
else if (ast instanceof Binary) {
|
|
23816
24446
|
const operator = BINARY_OPERATORS.get(ast.operation);
|
|
23817
24447
|
if (operator === undefined) {
|
|
@@ -23870,10 +24500,34 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23870
24500
|
else if (ast instanceof EmptyExpr$1) {
|
|
23871
24501
|
return new EmptyExpr(convertSourceSpan(ast.span, baseSourceSpan));
|
|
23872
24502
|
}
|
|
24503
|
+
else if (ast instanceof PrefixNot) {
|
|
24504
|
+
return not(convertAst(ast.expression, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
|
|
24505
|
+
}
|
|
23873
24506
|
else {
|
|
23874
24507
|
throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
|
|
23875
24508
|
}
|
|
23876
24509
|
}
|
|
24510
|
+
function convertAstWithInterpolation(job, value, i18nMeta) {
|
|
24511
|
+
let expression;
|
|
24512
|
+
if (value instanceof Interpolation$1) {
|
|
24513
|
+
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24514
|
+
}
|
|
24515
|
+
else if (value instanceof AST) {
|
|
24516
|
+
expression = convertAst(value, job, null);
|
|
24517
|
+
}
|
|
24518
|
+
else {
|
|
24519
|
+
expression = literal(value);
|
|
24520
|
+
}
|
|
24521
|
+
return expression;
|
|
24522
|
+
}
|
|
24523
|
+
// TODO: Can we populate Template binding kinds in ingest?
|
|
24524
|
+
const BINDING_KINDS = new Map([
|
|
24525
|
+
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
24526
|
+
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
24527
|
+
[2 /* e.BindingType.Class */, BindingKind.ClassName],
|
|
24528
|
+
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
24529
|
+
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
24530
|
+
]);
|
|
23877
24531
|
/**
|
|
23878
24532
|
* Checks whether the given template is a plain ng-template (as opposed to another kind of template
|
|
23879
24533
|
* such as a structural directive template or control flow template). This is checked based on the
|
|
@@ -23892,128 +24546,184 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23892
24546
|
* | `<ng-template *ngIf>` (structural) | null |
|
|
23893
24547
|
*/
|
|
23894
24548
|
function isPlainTemplate(tmpl) {
|
|
23895
|
-
return splitNsName(tmpl.tagName ?? '')[1] ===
|
|
24549
|
+
return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME$1;
|
|
23896
24550
|
}
|
|
23897
24551
|
/**
|
|
23898
|
-
*
|
|
23899
|
-
* to their IR representation.
|
|
24552
|
+
* Ensures that the i18nMeta, if provided, is an i18n.Message.
|
|
23900
24553
|
*/
|
|
23901
|
-
function
|
|
23902
|
-
|
|
23903
|
-
|
|
23904
|
-
flags |= BindingFlags.OnNgTemplateElement;
|
|
23905
|
-
if (element instanceof Template && isPlainTemplate(element)) {
|
|
23906
|
-
flags |= BindingFlags.BindingTargetsTemplate;
|
|
23907
|
-
}
|
|
23908
|
-
const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
|
|
23909
|
-
for (const attr of element.templateAttrs) {
|
|
23910
|
-
if (attr instanceof TextAttribute) {
|
|
23911
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue);
|
|
23912
|
-
}
|
|
23913
|
-
else {
|
|
23914
|
-
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags);
|
|
23915
|
-
}
|
|
23916
|
-
}
|
|
24554
|
+
function asMessage(i18nMeta) {
|
|
24555
|
+
if (i18nMeta == null) {
|
|
24556
|
+
return null;
|
|
23917
24557
|
}
|
|
24558
|
+
if (!(i18nMeta instanceof Message)) {
|
|
24559
|
+
throw Error(`Expected i18n meta to be a Message, but got: ${i18nMeta.constructor.name}`);
|
|
24560
|
+
}
|
|
24561
|
+
return i18nMeta;
|
|
24562
|
+
}
|
|
24563
|
+
/**
|
|
24564
|
+
* Process all of the bindings on an element in the template AST and convert them to their IR
|
|
24565
|
+
* representation.
|
|
24566
|
+
*/
|
|
24567
|
+
function ingestElementBindings(unit, op, element) {
|
|
24568
|
+
let bindings = new Array();
|
|
23918
24569
|
for (const attr of element.attributes) {
|
|
23919
|
-
//
|
|
23920
|
-
|
|
23921
|
-
|
|
23922
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue);
|
|
24570
|
+
// Attribute literal bindings, such as `attr.foo="bar"`.
|
|
24571
|
+
const securityContext = domSchema.securityContext(element.name, attr.name, true);
|
|
24572
|
+
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));
|
|
23923
24573
|
}
|
|
23924
24574
|
for (const input of element.inputs) {
|
|
23925
|
-
|
|
24575
|
+
// All dynamic bindings (both attribute and property bindings).
|
|
24576
|
+
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));
|
|
23926
24577
|
}
|
|
24578
|
+
unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
|
|
24579
|
+
unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
|
|
23927
24580
|
for (const output of element.outputs) {
|
|
23928
|
-
|
|
23929
|
-
|
|
23930
|
-
if (output.phase === null) {
|
|
23931
|
-
throw Error('Animation listener should have a phase');
|
|
23932
|
-
}
|
|
24581
|
+
if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
|
|
24582
|
+
throw Error('Animation listener should have a phase');
|
|
23933
24583
|
}
|
|
23934
|
-
|
|
23935
|
-
|
|
23936
|
-
|
|
23937
|
-
|
|
23938
|
-
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
|
|
23946
|
-
|
|
23947
|
-
|
|
24584
|
+
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));
|
|
24585
|
+
}
|
|
24586
|
+
// If any of the bindings on this element have an i18n message, then an i18n attrs configuration
|
|
24587
|
+
// op is also required.
|
|
24588
|
+
if (bindings.some(b => b?.i18nMessage) !== null) {
|
|
24589
|
+
unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
|
|
24590
|
+
}
|
|
24591
|
+
}
|
|
24592
|
+
/**
|
|
24593
|
+
* Process all of the bindings on a template in the template AST and convert them to their IR
|
|
24594
|
+
* representation.
|
|
24595
|
+
*/
|
|
24596
|
+
function ingestTemplateBindings(unit, op, template, templateKind) {
|
|
24597
|
+
let bindings = new Array();
|
|
24598
|
+
for (const attr of template.templateAttrs) {
|
|
24599
|
+
if (attr instanceof TextAttribute) {
|
|
24600
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
24601
|
+
bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
23948
24602
|
}
|
|
23949
24603
|
else {
|
|
23950
|
-
|
|
24604
|
+
bindings.push(createTemplateBinding(unit, op.xref, attr.type, attr.name, astOf(attr.value), attr.unit, attr.securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
23951
24605
|
}
|
|
23952
|
-
|
|
23953
|
-
|
|
24606
|
+
}
|
|
24607
|
+
for (const attr of template.attributes) {
|
|
24608
|
+
// Attribute literal bindings, such as `attr.foo="bar"`.
|
|
24609
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
24610
|
+
bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, false, templateKind, asMessage(attr.i18n), attr.sourceSpan));
|
|
24611
|
+
}
|
|
24612
|
+
for (const input of template.inputs) {
|
|
24613
|
+
// Dynamic bindings (both attribute and property bindings).
|
|
24614
|
+
bindings.push(createTemplateBinding(unit, op.xref, input.type, input.name, astOf(input.value), input.unit, input.securityContext, false, templateKind, asMessage(input.i18n), input.sourceSpan));
|
|
24615
|
+
}
|
|
24616
|
+
unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
|
|
24617
|
+
unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
|
|
24618
|
+
for (const output of template.outputs) {
|
|
24619
|
+
if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
|
|
24620
|
+
throw Error('Animation listener should have a phase');
|
|
23954
24621
|
}
|
|
23955
|
-
|
|
23956
|
-
|
|
23957
|
-
|
|
23958
|
-
|
|
23959
|
-
|
|
24622
|
+
if (templateKind === TemplateKind.NgTemplate) {
|
|
24623
|
+
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));
|
|
24624
|
+
}
|
|
24625
|
+
if (templateKind === TemplateKind.Structural &&
|
|
24626
|
+
output.type !== 1 /* e.ParsedEventType.Animation */) {
|
|
24627
|
+
// Animation bindings are excluded from the structural template's const array.
|
|
24628
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
|
|
24629
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null, null, securityContext));
|
|
23960
24630
|
}
|
|
23961
|
-
listenerOp.handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
23962
|
-
unit.create.push(listenerOp);
|
|
23963
|
-
}
|
|
23964
|
-
}
|
|
23965
|
-
const BINDING_KINDS = new Map([
|
|
23966
|
-
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
23967
|
-
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
23968
|
-
[2 /* e.BindingType.Class */, BindingKind.ClassName],
|
|
23969
|
-
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
23970
|
-
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
23971
|
-
]);
|
|
23972
|
-
var BindingFlags;
|
|
23973
|
-
(function (BindingFlags) {
|
|
23974
|
-
BindingFlags[BindingFlags["None"] = 0] = "None";
|
|
23975
|
-
/**
|
|
23976
|
-
* The binding is to a static text literal and not to an expression.
|
|
23977
|
-
*/
|
|
23978
|
-
BindingFlags[BindingFlags["TextValue"] = 1] = "TextValue";
|
|
23979
|
-
/**
|
|
23980
|
-
* The binding belongs to the `<ng-template>` side of a `t.Template`.
|
|
23981
|
-
*/
|
|
23982
|
-
BindingFlags[BindingFlags["BindingTargetsTemplate"] = 2] = "BindingTargetsTemplate";
|
|
23983
|
-
/**
|
|
23984
|
-
* The binding is on a structural directive.
|
|
23985
|
-
*/
|
|
23986
|
-
BindingFlags[BindingFlags["IsStructuralTemplateAttribute"] = 4] = "IsStructuralTemplateAttribute";
|
|
23987
|
-
/**
|
|
23988
|
-
* The binding is on a `t.Template`.
|
|
23989
|
-
*/
|
|
23990
|
-
BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
|
|
23991
|
-
})(BindingFlags || (BindingFlags = {}));
|
|
23992
|
-
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags) {
|
|
23993
|
-
if (value instanceof ASTWithSource) {
|
|
23994
|
-
value = value.ast;
|
|
23995
24631
|
}
|
|
23996
|
-
|
|
23997
|
-
|
|
23998
|
-
|
|
23999
|
-
// created.
|
|
24000
|
-
view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null));
|
|
24001
|
-
return;
|
|
24632
|
+
// TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
|
|
24633
|
+
if (bindings.some(b => b?.i18nMessage) !== null) {
|
|
24634
|
+
unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
|
|
24002
24635
|
}
|
|
24003
|
-
|
|
24004
|
-
|
|
24005
|
-
|
|
24006
|
-
|
|
24007
|
-
|
|
24636
|
+
}
|
|
24637
|
+
/**
|
|
24638
|
+
* Helper to ingest an individual binding on a template, either an explicit `ng-template`, or an
|
|
24639
|
+
* implicit template created via structural directive.
|
|
24640
|
+
*
|
|
24641
|
+
* Bindings on templates are *extremely* tricky. I have tried to isolate all of the confusing edge
|
|
24642
|
+
* cases into this function, and to comment it well to document the behavior.
|
|
24643
|
+
*
|
|
24644
|
+
* Some of this behavior is intuitively incorrect, and we should consider changing it in the future.
|
|
24645
|
+
*
|
|
24646
|
+
* @param view The compilation unit for the view containing the template.
|
|
24647
|
+
* @param xref The xref of the template op.
|
|
24648
|
+
* @param type The binding type, according to the parser. This is fairly reasonable, e.g. both
|
|
24649
|
+
* dynamic and static attributes have e.BindingType.Attribute.
|
|
24650
|
+
* @param name The binding's name.
|
|
24651
|
+
* @param value The bindings's value, which will either be an input AST expression, or a string
|
|
24652
|
+
* literal. Note that the input AST expression may or may not be const -- it will only be a
|
|
24653
|
+
* string literal if the parser considered it a text binding.
|
|
24654
|
+
* @param unit If the binding has a unit (e.g. `px` for style bindings), then this is the unit.
|
|
24655
|
+
* @param securityContext The security context of the binding.
|
|
24656
|
+
* @param isStructuralTemplateAttribute Whether this binding actually applies to the structural
|
|
24657
|
+
* ng-template. For example, an `ngFor` would actually apply to the structural template. (Most
|
|
24658
|
+
* bindings on structural elements target the inner element, not the template.)
|
|
24659
|
+
* @param templateKind Whether this is an explicit `ng-template` or an implicit template created by
|
|
24660
|
+
* a structural directive. This should never be a block template.
|
|
24661
|
+
* @param i18nMessage The i18n metadata for the binding, if any.
|
|
24662
|
+
* @param sourceSpan The source span of the binding.
|
|
24663
|
+
* @returns An IR binding op, or null if the binding should be skipped.
|
|
24664
|
+
*/
|
|
24665
|
+
function createTemplateBinding(view, xref, type, name, value, unit, securityContext, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
24666
|
+
const isTextBinding = typeof value === 'string';
|
|
24667
|
+
// If this is a structural template, then several kinds of bindings should not result in an
|
|
24668
|
+
// update instruction.
|
|
24669
|
+
if (templateKind === TemplateKind.Structural) {
|
|
24670
|
+
if (!isStructuralTemplateAttribute &&
|
|
24671
|
+
(type === 0 /* e.BindingType.Property */ || type === 2 /* e.BindingType.Class */ ||
|
|
24672
|
+
type === 3 /* e.BindingType.Style */)) {
|
|
24673
|
+
// Because this binding doesn't really target the ng-template, it must be a binding on an
|
|
24674
|
+
// inner node of a structural template. We can't skip it entirely, because we still need it on
|
|
24675
|
+
// the ng-template's consts (e.g. for the purposes of directive matching). However, we should
|
|
24676
|
+
// not generate an update instruction for it.
|
|
24677
|
+
return createExtractedAttributeOp(xref, BindingKind.Property, name, null, null, i18nMessage, securityContext);
|
|
24678
|
+
}
|
|
24679
|
+
if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
|
|
24680
|
+
// Again, this binding doesn't really target the ng-template; it actually targets the element
|
|
24681
|
+
// inside the structural template. In the case of non-text attribute or animation bindings,
|
|
24682
|
+
// the binding doesn't even show up on the ng-template const array, so we just skip it
|
|
24683
|
+
// entirely.
|
|
24684
|
+
return null;
|
|
24685
|
+
}
|
|
24008
24686
|
}
|
|
24009
|
-
|
|
24010
|
-
|
|
24687
|
+
let bindingType = BINDING_KINDS.get(type);
|
|
24688
|
+
if (templateKind === TemplateKind.NgTemplate) {
|
|
24689
|
+
// We know we are dealing with bindings directly on an explicit ng-template.
|
|
24690
|
+
// Static attribute bindings should be collected into the const array as k/v pairs. Property
|
|
24691
|
+
// bindings should result in a `property` instruction, and `AttributeMarker.Bindings` const
|
|
24692
|
+
// entries.
|
|
24693
|
+
//
|
|
24694
|
+
// The difficulty is with dynamic attribute, style, and class bindings. These don't really make
|
|
24695
|
+
// sense on an `ng-template` and should probably be parser errors. However,
|
|
24696
|
+
// TemplateDefinitionBuilder generates `property` instructions for them, and so we do that as
|
|
24697
|
+
// well.
|
|
24698
|
+
//
|
|
24699
|
+
// Note that we do have a slight behavior difference with TemplateDefinitionBuilder: although
|
|
24700
|
+
// TDB emits `property` instructions for dynamic attributes, styles, and classes, only styles
|
|
24701
|
+
// and classes also get const collected into the `AttributeMarker.Bindings` field. Dynamic
|
|
24702
|
+
// attribute bindings are missing from the consts entirely. We choose to emit them into the
|
|
24703
|
+
// consts field anyway, to avoid creating special cases for something so arcane and nonsensical.
|
|
24704
|
+
if (type === 2 /* e.BindingType.Class */ || type === 3 /* e.BindingType.Style */ ||
|
|
24705
|
+
(type === 1 /* e.BindingType.Attribute */ && !isTextBinding)) {
|
|
24706
|
+
// TODO: These cases should be parse errors.
|
|
24707
|
+
bindingType = BindingKind.Property;
|
|
24708
|
+
}
|
|
24011
24709
|
}
|
|
24012
|
-
|
|
24013
|
-
|
|
24710
|
+
return createBindingOp(xref, bindingType, name, convertAstWithInterpolation(view.job, value, i18nMessage), unit, securityContext, isTextBinding, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan);
|
|
24711
|
+
}
|
|
24712
|
+
function makeListenerHandlerOps(unit, handler, handlerSpan) {
|
|
24713
|
+
handler = astOf(handler);
|
|
24714
|
+
const handlerOps = new Array();
|
|
24715
|
+
let handlerExprs = handler instanceof Chain ? handler.expressions : [handler];
|
|
24716
|
+
if (handlerExprs.length === 0) {
|
|
24717
|
+
throw new Error('Expected listener to have non-empty expression list.');
|
|
24014
24718
|
}
|
|
24015
|
-
const
|
|
24016
|
-
|
|
24719
|
+
const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, handlerSpan));
|
|
24720
|
+
const returnExpr = expressions.pop();
|
|
24721
|
+
handlerOps.push(...expressions.map(e => createStatementOp(new ExpressionStatement(e, e.sourceSpan))));
|
|
24722
|
+
handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
24723
|
+
return handlerOps;
|
|
24724
|
+
}
|
|
24725
|
+
function astOf(ast) {
|
|
24726
|
+
return ast instanceof ASTWithSource ? ast.ast : ast;
|
|
24017
24727
|
}
|
|
24018
24728
|
/**
|
|
24019
24729
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -24101,11 +24811,12 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
|
|
|
24101
24811
|
// and they can be used in directive matching (in the case of `Template.templateAttrs`).
|
|
24102
24812
|
if (root !== null) {
|
|
24103
24813
|
for (const attr of root.attributes) {
|
|
24104
|
-
|
|
24814
|
+
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
|
|
24815
|
+
unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
24105
24816
|
}
|
|
24106
24817
|
const tagName = root instanceof Element$1 ? root.name : root.tagName;
|
|
24107
24818
|
// Don't pass along `ng-template` tag name since it enables directive matching.
|
|
24108
|
-
return tagName ===
|
|
24819
|
+
return tagName === NG_TEMPLATE_TAG_NAME$1 ? null : tagName;
|
|
24109
24820
|
}
|
|
24110
24821
|
return null;
|
|
24111
24822
|
}
|
|
@@ -27184,7 +27895,7 @@ class TemplateDefinitionBuilder {
|
|
|
27184
27895
|
else {
|
|
27185
27896
|
// ... otherwise we need to activate post-processing
|
|
27186
27897
|
// to replace ICU placeholders with proper values
|
|
27187
|
-
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
|
|
27898
|
+
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX$1}${key}`);
|
|
27188
27899
|
params[key] = literal(placeholder);
|
|
27189
27900
|
icuMapping[key] = literalArr(refs);
|
|
27190
27901
|
}
|
|
@@ -29459,14 +30170,16 @@ function createBaseDirectiveTypeParams(meta) {
|
|
|
29459
30170
|
function getInputsTypeExpression(meta) {
|
|
29460
30171
|
return literalMap(Object.keys(meta.inputs).map(key => {
|
|
29461
30172
|
const value = meta.inputs[key];
|
|
29462
|
-
|
|
29463
|
-
key,
|
|
29464
|
-
value:
|
|
29465
|
-
|
|
29466
|
-
|
|
29467
|
-
|
|
29468
|
-
|
|
29469
|
-
|
|
30173
|
+
const values = [
|
|
30174
|
+
{ key: 'alias', value: literal(value.bindingPropertyName), quoted: true },
|
|
30175
|
+
{ key: 'required', value: literal(value.required), quoted: true },
|
|
30176
|
+
];
|
|
30177
|
+
// TODO(legacy-partial-output-inputs): Consider always emitting this information,
|
|
30178
|
+
// or leaving it as is.
|
|
30179
|
+
if (value.isSignal) {
|
|
30180
|
+
values.push({ key: 'isSignal', value: literal(value.isSignal), quoted: true });
|
|
30181
|
+
}
|
|
30182
|
+
return { key, value: literalMap(values), quoted: true };
|
|
29470
30183
|
}));
|
|
29471
30184
|
}
|
|
29472
30185
|
/**
|
|
@@ -29532,6 +30245,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29532
30245
|
}
|
|
29533
30246
|
const hostJob = ingestHostBinding({
|
|
29534
30247
|
componentName: name,
|
|
30248
|
+
componentSelector: selector,
|
|
29535
30249
|
properties: bindings,
|
|
29536
30250
|
events: eventBindings,
|
|
29537
30251
|
attributes: hostBindingsMetadata.attributes,
|
|
@@ -29544,6 +30258,8 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29544
30258
|
}
|
|
29545
30259
|
return emitHostBindingFunction(hostJob);
|
|
29546
30260
|
}
|
|
30261
|
+
let bindingId = 0;
|
|
30262
|
+
const getNextBindingId = () => `${bindingId++}`;
|
|
29547
30263
|
const bindingContext = variable(CONTEXT_NAME);
|
|
29548
30264
|
const styleBuilder = new StylingBuilder(bindingContext);
|
|
29549
30265
|
const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
|
|
@@ -29596,7 +30312,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29596
30312
|
for (const binding of allOtherBindings) {
|
|
29597
30313
|
// resolve literal arrays and literal objects
|
|
29598
30314
|
const value = binding.expression.visit(getValueConverter());
|
|
29599
|
-
const bindingExpr = bindingFn(bindingContext, value);
|
|
30315
|
+
const bindingExpr = bindingFn(bindingContext, value, getNextBindingId);
|
|
29600
30316
|
const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
|
|
29601
30317
|
const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
|
|
29602
30318
|
.filter(context => context !== SecurityContext.NONE);
|
|
@@ -29675,10 +30391,12 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29675
30391
|
// at the top of this method when all the input bindings were counted.
|
|
29676
30392
|
totalHostVarsCount +=
|
|
29677
30393
|
Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
|
|
30394
|
+
const { params, stmts } = convertStylingCall(call, bindingContext, bindingFn, getNextBindingId);
|
|
30395
|
+
updateVariables.push(...stmts);
|
|
29678
30396
|
updateInstructions.push({
|
|
29679
30397
|
reference: instruction.reference,
|
|
29680
|
-
paramsOrFn:
|
|
29681
|
-
span: null
|
|
30398
|
+
paramsOrFn: params,
|
|
30399
|
+
span: null,
|
|
29682
30400
|
});
|
|
29683
30401
|
}
|
|
29684
30402
|
});
|
|
@@ -29699,11 +30417,19 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29699
30417
|
}
|
|
29700
30418
|
return null;
|
|
29701
30419
|
}
|
|
29702
|
-
function bindingFn(implicit, value) {
|
|
29703
|
-
return convertPropertyBinding(null, implicit, value,
|
|
30420
|
+
function bindingFn(implicit, value, getNextBindingIdFn) {
|
|
30421
|
+
return convertPropertyBinding(null, implicit, value, getNextBindingIdFn());
|
|
29704
30422
|
}
|
|
29705
|
-
function convertStylingCall(call, bindingContext, bindingFn) {
|
|
29706
|
-
|
|
30423
|
+
function convertStylingCall(call, bindingContext, bindingFn, getNextBindingIdFn) {
|
|
30424
|
+
const stmts = [];
|
|
30425
|
+
const params = call.params(value => {
|
|
30426
|
+
const result = bindingFn(bindingContext, value, getNextBindingIdFn);
|
|
30427
|
+
if (Array.isArray(result.stmts) && result.stmts.length > 0) {
|
|
30428
|
+
stmts.push(...result.stmts);
|
|
30429
|
+
}
|
|
30430
|
+
return result.currValExpr;
|
|
30431
|
+
});
|
|
30432
|
+
return { params, stmts };
|
|
29707
30433
|
}
|
|
29708
30434
|
function getBindingNameAndInstruction(binding) {
|
|
29709
30435
|
let bindingName = binding.name;
|
|
@@ -29830,6 +30556,18 @@ function compileStyles(styles, selector, hostSelector) {
|
|
|
29830
30556
|
return shadowCss.shimCssText(style, selector, hostSelector);
|
|
29831
30557
|
});
|
|
29832
30558
|
}
|
|
30559
|
+
/**
|
|
30560
|
+
* Encapsulates a CSS stylesheet with emulated view encapsulation.
|
|
30561
|
+
* This allows a stylesheet to be used with an Angular component that
|
|
30562
|
+
* is using the `ViewEncapsulation.Emulated` mode.
|
|
30563
|
+
*
|
|
30564
|
+
* @param style The content of a CSS stylesheet.
|
|
30565
|
+
* @returns The encapsulated content for the style.
|
|
30566
|
+
*/
|
|
30567
|
+
function encapsulateStyle(style) {
|
|
30568
|
+
const shadowCss = new ShadowCss();
|
|
30569
|
+
return shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR);
|
|
30570
|
+
}
|
|
29833
30571
|
function createHostDirectivesType(meta) {
|
|
29834
30572
|
if (!meta.hostDirectives?.length) {
|
|
29835
30573
|
return NONE_TYPE;
|
|
@@ -30895,6 +31633,8 @@ function convertDirectiveFacadeToMetadata(facade) {
|
|
|
30895
31633
|
bindingPropertyName: ann.alias || field,
|
|
30896
31634
|
classPropertyName: field,
|
|
30897
31635
|
required: ann.required || false,
|
|
31636
|
+
// TODO(signals): Support JIT signal inputs via decorator transform.
|
|
31637
|
+
isSignal: false,
|
|
30898
31638
|
transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null,
|
|
30899
31639
|
};
|
|
30900
31640
|
}
|
|
@@ -30926,7 +31666,7 @@ function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
|
|
|
30926
31666
|
type: wrapReference(declaration.type),
|
|
30927
31667
|
typeSourceSpan,
|
|
30928
31668
|
selector: declaration.selector ?? null,
|
|
30929
|
-
inputs: declaration.inputs ?
|
|
31669
|
+
inputs: declaration.inputs ? inputsPartialMetadataToInputMetadata(declaration.inputs) : {},
|
|
30930
31670
|
outputs: declaration.outputs ?? {},
|
|
30931
31671
|
host: convertHostDeclarationToMetadata(declaration.host),
|
|
30932
31672
|
queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata),
|
|
@@ -31189,28 +31929,51 @@ function isInput(value) {
|
|
|
31189
31929
|
function isOutput(value) {
|
|
31190
31930
|
return value.ngMetadataName === 'Output';
|
|
31191
31931
|
}
|
|
31192
|
-
function
|
|
31193
|
-
return Object.keys(inputs).reduce((result,
|
|
31194
|
-
const value = inputs[
|
|
31195
|
-
|
|
31196
|
-
|
|
31197
|
-
|
|
31198
|
-
classPropertyName: value,
|
|
31199
|
-
transformFunction: null,
|
|
31200
|
-
required: false,
|
|
31201
|
-
};
|
|
31932
|
+
function inputsPartialMetadataToInputMetadata(inputs) {
|
|
31933
|
+
return Object.keys(inputs).reduce((result, minifiedClassName) => {
|
|
31934
|
+
const value = inputs[minifiedClassName];
|
|
31935
|
+
// Handle legacy partial input output.
|
|
31936
|
+
if (typeof value === 'string' || Array.isArray(value)) {
|
|
31937
|
+
result[minifiedClassName] = parseLegacyInputPartialOutput(value);
|
|
31202
31938
|
}
|
|
31203
31939
|
else {
|
|
31204
|
-
result[
|
|
31205
|
-
bindingPropertyName: value
|
|
31206
|
-
classPropertyName:
|
|
31207
|
-
transformFunction: value
|
|
31208
|
-
|
|
31940
|
+
result[minifiedClassName] = {
|
|
31941
|
+
bindingPropertyName: value.publicName,
|
|
31942
|
+
classPropertyName: minifiedClassName,
|
|
31943
|
+
transformFunction: value.transformFunction !== null ?
|
|
31944
|
+
new WrappedNodeExpr(value.transformFunction) :
|
|
31945
|
+
null,
|
|
31946
|
+
required: value.isRequired,
|
|
31947
|
+
isSignal: value.isSignal,
|
|
31209
31948
|
};
|
|
31210
31949
|
}
|
|
31211
31950
|
return result;
|
|
31212
31951
|
}, {});
|
|
31213
31952
|
}
|
|
31953
|
+
/**
|
|
31954
|
+
* Parses the legacy input partial output. For more details see `partial/directive.ts`.
|
|
31955
|
+
* TODO(legacy-partial-output-inputs): Remove in v18.
|
|
31956
|
+
*/
|
|
31957
|
+
function parseLegacyInputPartialOutput(value) {
|
|
31958
|
+
if (typeof value === 'string') {
|
|
31959
|
+
return {
|
|
31960
|
+
bindingPropertyName: value,
|
|
31961
|
+
classPropertyName: value,
|
|
31962
|
+
transformFunction: null,
|
|
31963
|
+
required: false,
|
|
31964
|
+
// legacy partial output does not capture signal inputs.
|
|
31965
|
+
isSignal: false,
|
|
31966
|
+
};
|
|
31967
|
+
}
|
|
31968
|
+
return {
|
|
31969
|
+
bindingPropertyName: value[0],
|
|
31970
|
+
classPropertyName: value[1],
|
|
31971
|
+
transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
|
|
31972
|
+
required: false,
|
|
31973
|
+
// legacy partial output does not capture signal inputs.
|
|
31974
|
+
isSignal: false,
|
|
31975
|
+
};
|
|
31976
|
+
}
|
|
31214
31977
|
function parseInputsArray(values) {
|
|
31215
31978
|
return values.reduce((results, value) => {
|
|
31216
31979
|
if (typeof value === 'string') {
|
|
@@ -31219,6 +31982,8 @@ function parseInputsArray(values) {
|
|
|
31219
31982
|
bindingPropertyName,
|
|
31220
31983
|
classPropertyName,
|
|
31221
31984
|
required: false,
|
|
31985
|
+
// Signal inputs not supported for the inputs array.
|
|
31986
|
+
isSignal: false,
|
|
31222
31987
|
transformFunction: null,
|
|
31223
31988
|
};
|
|
31224
31989
|
}
|
|
@@ -31227,6 +31992,8 @@ function parseInputsArray(values) {
|
|
|
31227
31992
|
bindingPropertyName: value.alias || value.name,
|
|
31228
31993
|
classPropertyName: value.name,
|
|
31229
31994
|
required: value.required || false,
|
|
31995
|
+
// Signal inputs not supported for the inputs array.
|
|
31996
|
+
isSignal: false,
|
|
31230
31997
|
transformFunction: value.transform != null ? new WrappedNodeExpr(value.transform) : null,
|
|
31231
31998
|
};
|
|
31232
31999
|
}
|
|
@@ -31279,7 +32046,7 @@ function publishFacade(global) {
|
|
|
31279
32046
|
* @description
|
|
31280
32047
|
* Entry point for all public APIs of the compiler package.
|
|
31281
32048
|
*/
|
|
31282
|
-
const VERSION = new Version('17.1.0-next.
|
|
32049
|
+
const VERSION = new Version('17.1.0-next.4');
|
|
31283
32050
|
|
|
31284
32051
|
class CompilerConfig {
|
|
31285
32052
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -32841,11 +33608,11 @@ function compileClassDebugInfo(debugInfo) {
|
|
|
32841
33608
|
*
|
|
32842
33609
|
* Do not include any prerelease in these versions as they are ignored.
|
|
32843
33610
|
*/
|
|
32844
|
-
const MINIMUM_PARTIAL_LINKER_VERSION$
|
|
33611
|
+
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
|
|
32845
33612
|
function compileDeclareClassMetadata(metadata) {
|
|
32846
33613
|
const definitionMap = new DefinitionMap();
|
|
32847
|
-
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$
|
|
32848
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33614
|
+
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
33615
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
32849
33616
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32850
33617
|
definitionMap.set('type', metadata.type);
|
|
32851
33618
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -32924,14 +33691,6 @@ function compileDependency(dep) {
|
|
|
32924
33691
|
return depMeta.toLiteralMap();
|
|
32925
33692
|
}
|
|
32926
33693
|
|
|
32927
|
-
/**
|
|
32928
|
-
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
32929
|
-
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
32930
|
-
* declaration.
|
|
32931
|
-
*
|
|
32932
|
-
* Do not include any prerelease in these versions as they are ignored.
|
|
32933
|
-
*/
|
|
32934
|
-
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '16.1.0';
|
|
32935
33694
|
/**
|
|
32936
33695
|
* Compile a directive declaration defined by the `R3DirectiveMetadata`.
|
|
32937
33696
|
*/
|
|
@@ -32947,13 +33706,9 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
32947
33706
|
*/
|
|
32948
33707
|
function createDirectiveDefinitionMap(meta) {
|
|
32949
33708
|
const definitionMap = new DefinitionMap();
|
|
32950
|
-
const
|
|
32951
|
-
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
32952
|
-
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
32953
|
-
// in 16.1 is actually used.
|
|
32954
|
-
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
33709
|
+
const minVersion = getMinimumVersionForPartialOutput(meta);
|
|
32955
33710
|
definitionMap.set('minVersion', literal(minVersion));
|
|
32956
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33711
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
32957
33712
|
// e.g. `type: MyDirective`
|
|
32958
33713
|
definitionMap.set('type', meta.type.value);
|
|
32959
33714
|
if (meta.isStandalone) {
|
|
@@ -32966,7 +33721,8 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
32966
33721
|
if (meta.selector !== null) {
|
|
32967
33722
|
definitionMap.set('selector', literal(meta.selector));
|
|
32968
33723
|
}
|
|
32969
|
-
definitionMap.set('inputs',
|
|
33724
|
+
definitionMap.set('inputs', needsNewInputPartialOutput(meta) ? createInputsPartialMetadata(meta.inputs) :
|
|
33725
|
+
legacyInputsPartialMetadata(meta.inputs));
|
|
32970
33726
|
definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
|
|
32971
33727
|
definitionMap.set('host', compileHostMetadata(meta.host));
|
|
32972
33728
|
definitionMap.set('providers', meta.providers);
|
|
@@ -32991,6 +33747,44 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
32991
33747
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32992
33748
|
return definitionMap;
|
|
32993
33749
|
}
|
|
33750
|
+
/**
|
|
33751
|
+
* Determines the minimum linker version for the partial output
|
|
33752
|
+
* generated for this directive.
|
|
33753
|
+
*
|
|
33754
|
+
* Every time we make a breaking change to the declaration interface or partial-linker
|
|
33755
|
+
* behavior, we must update the minimum versions to prevent old partial-linkers from
|
|
33756
|
+
* incorrectly processing the declaration.
|
|
33757
|
+
*
|
|
33758
|
+
* NOTE: Do not include any prerelease in these versions as they are ignored.
|
|
33759
|
+
*/
|
|
33760
|
+
function getMinimumVersionForPartialOutput(meta) {
|
|
33761
|
+
// We are starting with the oldest minimum version that can work for common
|
|
33762
|
+
// directive partial compilation output. As we discover usages of new features
|
|
33763
|
+
// that require a newer partial output emit, we bump the `minVersion`. Our goal
|
|
33764
|
+
// is to keep libraries as much compatible with older linker versions as possible.
|
|
33765
|
+
let minVersion = '14.0.0';
|
|
33766
|
+
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
33767
|
+
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
33768
|
+
// in 16.1 is actually used.
|
|
33769
|
+
const hasTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
|
|
33770
|
+
if (hasTransformFunctions) {
|
|
33771
|
+
minVersion = '16.1.0';
|
|
33772
|
+
}
|
|
33773
|
+
// If there are input flags and we need the new emit, use the actual minimum version,
|
|
33774
|
+
// where this was introduced. i.e. in 17.1.0
|
|
33775
|
+
// TODO(legacy-partial-output-inputs): Remove in v18.
|
|
33776
|
+
if (needsNewInputPartialOutput(meta)) {
|
|
33777
|
+
minVersion = '17.1.0';
|
|
33778
|
+
}
|
|
33779
|
+
return minVersion;
|
|
33780
|
+
}
|
|
33781
|
+
/**
|
|
33782
|
+
* Gets whether the given directive needs the new input partial output structure
|
|
33783
|
+
* that can hold additional metadata like `isRequired`, `isSignal` etc.
|
|
33784
|
+
*/
|
|
33785
|
+
function needsNewInputPartialOutput(meta) {
|
|
33786
|
+
return Object.values(meta.inputs).some(input => input.isSignal);
|
|
33787
|
+
}
|
|
32994
33788
|
/**
|
|
32995
33789
|
* Compiles the metadata of a single query into its partial declaration form as declared
|
|
32996
33790
|
* by `R3DeclareQueryMetadata`.
|
|
@@ -33064,6 +33858,74 @@ function createHostDirectives(hostDirectives) {
|
|
|
33064
33858
|
// otherwise we can save some bytes by using a plain array, e.g. `[{directive: HostDir}]`.
|
|
33065
33859
|
return literalArr(expressions);
|
|
33066
33860
|
}
|
|
33861
|
+
/**
|
|
33862
|
+
* Generates partial output metadata for inputs of a directive.
|
|
33863
|
+
*
|
|
33864
|
+
* The generated structure is expected to match `R3DeclareDirectiveFacade['inputs']`.
|
|
33865
|
+
*/
|
|
33866
|
+
function createInputsPartialMetadata(inputs) {
|
|
33867
|
+
const keys = Object.getOwnPropertyNames(inputs);
|
|
33868
|
+
if (keys.length === 0) {
|
|
33869
|
+
return null;
|
|
33870
|
+
}
|
|
33871
|
+
return literalMap(keys.map(declaredName => {
|
|
33872
|
+
const value = inputs[declaredName];
|
|
33873
|
+
return {
|
|
33874
|
+
key: declaredName,
|
|
33875
|
+
// put quotes around keys that contain potentially unsafe characters
|
|
33876
|
+
quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
|
|
33877
|
+
value: literalMap([
|
|
33878
|
+
{ key: 'classPropertyName', quoted: false, value: asLiteral(value.classPropertyName) },
|
|
33879
|
+
{ key: 'publicName', quoted: false, value: asLiteral(value.bindingPropertyName) },
|
|
33880
|
+
{ key: 'isSignal', quoted: false, value: asLiteral(value.isSignal) },
|
|
33881
|
+
{ key: 'isRequired', quoted: false, value: asLiteral(value.required) },
|
|
33882
|
+
{ key: 'transformFunction', quoted: false, value: value.transformFunction ?? NULL_EXPR },
|
|
33883
|
+
])
|
|
33884
|
+
};
|
|
33885
|
+
}));
|
|
33886
|
+
}
|
|
33887
|
+
/**
|
|
33888
|
+
* Pre v18 legacy partial output for inputs.
|
|
33889
|
+
*
|
|
33890
|
+
* Previously, inputs did not capture metadata like `isSignal` in the partial compilation output.
|
|
33891
|
+
* To enable capturing such metadata, we restructured how input metadata is communicated in the
|
|
33892
|
+
* partial output. This would make libraries incompatible with older Angular FW versions where the
|
|
33893
|
+
* linker would not know how to handle this new "format". For this reason, if we know this metadata
|
|
33894
|
+
* does not need to be captured- we fall back to the old format. This is what this function
|
|
33895
|
+
* generates.
|
|
33896
|
+
*
|
|
33897
|
+
* See:
|
|
33898
|
+
* https://github.com/angular/angular/blob/d4b423690210872b5c32a322a6090beda30b05a3/packages/core/src/compiler/compiler_facade_interface.ts#L197-L199
|
|
33899
|
+
*/
|
|
33900
|
+
function legacyInputsPartialMetadata(inputs) {
|
|
33901
|
+
// TODO(legacy-partial-output-inputs): Remove function in v18.
|
|
33902
|
+
const keys = Object.getOwnPropertyNames(inputs);
|
|
33903
|
+
if (keys.length === 0) {
|
|
33904
|
+
return null;
|
|
33905
|
+
}
|
|
33906
|
+
return literalMap(keys.map(declaredName => {
|
|
33907
|
+
const value = inputs[declaredName];
|
|
33908
|
+
const publicName = value.bindingPropertyName;
|
|
33909
|
+
const differentDeclaringName = publicName !== declaredName;
|
|
33910
|
+
let result;
|
|
33911
|
+
if (differentDeclaringName || value.transformFunction !== null) {
|
|
33912
|
+
const values = [asLiteral(publicName), asLiteral(declaredName)];
|
|
33913
|
+
if (value.transformFunction !== null) {
|
|
33914
|
+
values.push(value.transformFunction);
|
|
33915
|
+
}
|
|
33916
|
+
result = literalArr(values);
|
|
33917
|
+
}
|
|
33918
|
+
else {
|
|
33919
|
+
result = asLiteral(publicName);
|
|
33920
|
+
}
|
|
33921
|
+
return {
|
|
33922
|
+
key: declaredName,
|
|
33923
|
+
// put quotes around keys that contain potentially unsafe characters
|
|
33924
|
+
quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
|
|
33925
|
+
value: result,
|
|
33926
|
+
};
|
|
33927
|
+
}));
|
|
33928
|
+
}
|
|
33067
33929
|
|
|
33068
33930
|
/**
|
|
33069
33931
|
* Compile a component declaration defined by the `R3ComponentMetadata`.
|
|
@@ -33230,7 +34092,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
33230
34092
|
function compileDeclareFactoryFunction(meta) {
|
|
33231
34093
|
const definitionMap = new DefinitionMap();
|
|
33232
34094
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
33233
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34095
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
33234
34096
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33235
34097
|
definitionMap.set('type', meta.type.value);
|
|
33236
34098
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -33265,7 +34127,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
33265
34127
|
function createInjectableDefinitionMap(meta) {
|
|
33266
34128
|
const definitionMap = new DefinitionMap();
|
|
33267
34129
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
33268
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34130
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
33269
34131
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33270
34132
|
definitionMap.set('type', meta.type.value);
|
|
33271
34133
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -33316,7 +34178,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
33316
34178
|
function createInjectorDefinitionMap(meta) {
|
|
33317
34179
|
const definitionMap = new DefinitionMap();
|
|
33318
34180
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
33319
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34181
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
33320
34182
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33321
34183
|
definitionMap.set('type', meta.type.value);
|
|
33322
34184
|
definitionMap.set('providers', meta.providers);
|
|
@@ -33349,7 +34211,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
33349
34211
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
33350
34212
|
}
|
|
33351
34213
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
33352
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34214
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
33353
34215
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33354
34216
|
definitionMap.set('type', meta.type.value);
|
|
33355
34217
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -33400,7 +34262,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
33400
34262
|
function createPipeDefinitionMap(meta) {
|
|
33401
34263
|
const definitionMap = new DefinitionMap();
|
|
33402
34264
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
33403
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
34265
|
+
definitionMap.set('version', literal('17.1.0-next.4'));
|
|
33404
34266
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33405
34267
|
// e.g. `type: MyPipe`
|
|
33406
34268
|
definitionMap.set('type', meta.type.value);
|
|
@@ -33433,5 +34295,5 @@ publishFacade(_global);
|
|
|
33433
34295
|
|
|
33434
34296
|
// This file is not used to build this module. It is only used during editing
|
|
33435
34297
|
|
|
33436
|
-
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 };
|
|
34298
|
+
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 };
|
|
33437
34299
|
//# sourceMappingURL=compiler.mjs.map
|