@angular/compiler 17.1.0-next.1 → 17.1.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler.mjs +2 -1
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +25 -11
- package/esm2022/src/render3/view/t2_api.mjs +1 -1
- package/esm2022/src/render3/view/t2_binder.mjs +6 -7
- package/esm2022/src/render3/view/template.mjs +1 -20
- package/esm2022/src/render3/view/util.mjs +24 -2
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +34 -1
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +8 -1
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +27 -8
- package/esm2022/src/template/pipeline/ir/src/ops/host.mjs +3 -2
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +23 -14
- package/esm2022/src/template/pipeline/src/emit.mjs +10 -8
- package/esm2022/src/template/pipeline/src/ingest.mjs +86 -36
- package/esm2022/src/template/pipeline/src/instruction.mjs +5 -1
- 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 +43 -10
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +19 -5
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/convert_i18n_bindings.mjs +52 -0
- package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +20 -6
- package/esm2022/src/template/pipeline/src/phases/extract_i18n_messages.mjs +67 -19
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +143 -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 +3 -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 +7 -2
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +7 -1
- 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 +169 -58
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +10 -5
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_icu_placeholders.mjs +5 -21
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +873 -358
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +21 -1
- package/package.json +2 -2
- package/esm2022/src/template/pipeline/src/phases/merge_i18n_contexts.mjs +0 -59
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.3
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -3679,6 +3679,41 @@ function getInjectFn(target) {
|
|
|
3679
3679
|
}
|
|
3680
3680
|
}
|
|
3681
3681
|
|
|
3682
|
+
var TagContentType;
|
|
3683
|
+
(function (TagContentType) {
|
|
3684
|
+
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
3685
|
+
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
3686
|
+
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
3687
|
+
})(TagContentType || (TagContentType = {}));
|
|
3688
|
+
function splitNsName(elementName) {
|
|
3689
|
+
if (elementName[0] != ':') {
|
|
3690
|
+
return [null, elementName];
|
|
3691
|
+
}
|
|
3692
|
+
const colonIndex = elementName.indexOf(':', 1);
|
|
3693
|
+
if (colonIndex === -1) {
|
|
3694
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
3695
|
+
}
|
|
3696
|
+
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
3697
|
+
}
|
|
3698
|
+
// `<ng-container>` tags work the same regardless the namespace
|
|
3699
|
+
function isNgContainer(tagName) {
|
|
3700
|
+
return splitNsName(tagName)[1] === 'ng-container';
|
|
3701
|
+
}
|
|
3702
|
+
// `<ng-content>` tags work the same regardless the namespace
|
|
3703
|
+
function isNgContent(tagName) {
|
|
3704
|
+
return splitNsName(tagName)[1] === 'ng-content';
|
|
3705
|
+
}
|
|
3706
|
+
// `<ng-template>` tags work the same regardless the namespace
|
|
3707
|
+
function isNgTemplate(tagName) {
|
|
3708
|
+
return splitNsName(tagName)[1] === 'ng-template';
|
|
3709
|
+
}
|
|
3710
|
+
function getNsPrefix(fullName) {
|
|
3711
|
+
return fullName === null ? null : splitNsName(fullName)[0];
|
|
3712
|
+
}
|
|
3713
|
+
function mergeNsAndName(prefix, localName) {
|
|
3714
|
+
return prefix ? `:${prefix}:${localName}` : localName;
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3682
3717
|
/**
|
|
3683
3718
|
* This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently
|
|
3684
3719
|
* require the implementation of a visitor for Comments as they are only collected at
|
|
@@ -4677,7 +4712,7 @@ const I18N_ATTR_PREFIX = 'i18n-';
|
|
|
4677
4712
|
/** Prefix of var expressions used in ICUs */
|
|
4678
4713
|
const I18N_ICU_VAR_PREFIX = 'VAR_';
|
|
4679
4714
|
/** Prefix of ICU expressions for post processing */
|
|
4680
|
-
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
4715
|
+
const I18N_ICU_MAPPING_PREFIX$1 = 'I18N_EXP_';
|
|
4681
4716
|
/** Placeholder wrapper for i18n expressions **/
|
|
4682
4717
|
const I18N_PLACEHOLDER_SYMBOL = '�';
|
|
4683
4718
|
function isI18nAttribute(name) {
|
|
@@ -5019,6 +5054,26 @@ class DefinitionMap {
|
|
|
5019
5054
|
return literalMap(this.values);
|
|
5020
5055
|
}
|
|
5021
5056
|
}
|
|
5057
|
+
/**
|
|
5058
|
+
* Creates a `CssSelector` from an AST node.
|
|
5059
|
+
*/
|
|
5060
|
+
function createCssSelectorFromNode(node) {
|
|
5061
|
+
const elementName = node instanceof Element$1 ? node.name : 'ng-template';
|
|
5062
|
+
const attributes = getAttrsForDirectiveMatching(node);
|
|
5063
|
+
const cssSelector = new CssSelector();
|
|
5064
|
+
const elementNameNoNs = splitNsName(elementName)[1];
|
|
5065
|
+
cssSelector.setElement(elementNameNoNs);
|
|
5066
|
+
Object.getOwnPropertyNames(attributes).forEach((name) => {
|
|
5067
|
+
const nameNoNs = splitNsName(name)[1];
|
|
5068
|
+
const value = attributes[name];
|
|
5069
|
+
cssSelector.addAttribute(nameNoNs, value);
|
|
5070
|
+
if (name.toLowerCase() === 'class') {
|
|
5071
|
+
const classes = value.trim().split(/\s+/);
|
|
5072
|
+
classes.forEach(className => cssSelector.addClassName(className));
|
|
5073
|
+
}
|
|
5074
|
+
});
|
|
5075
|
+
return cssSelector;
|
|
5076
|
+
}
|
|
5022
5077
|
/**
|
|
5023
5078
|
* Extract a map of properties to values for a given element or template node, which can be used
|
|
5024
5079
|
* by the directive matching machinery.
|
|
@@ -8915,6 +8970,10 @@ var OpKind;
|
|
|
8915
8970
|
* An i18n context containing information needed to generate an i18n message.
|
|
8916
8971
|
*/
|
|
8917
8972
|
OpKind[OpKind["I18nContext"] = 43] = "I18nContext";
|
|
8973
|
+
/**
|
|
8974
|
+
* A creation op that corresponds to i18n attributes on an element.
|
|
8975
|
+
*/
|
|
8976
|
+
OpKind[OpKind["I18nAttributes"] = 44] = "I18nAttributes";
|
|
8918
8977
|
})(OpKind || (OpKind = {}));
|
|
8919
8978
|
/**
|
|
8920
8979
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9136,6 +9195,20 @@ var I18nParamResolutionTime;
|
|
|
9136
9195
|
*/
|
|
9137
9196
|
I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
|
|
9138
9197
|
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
|
|
9198
|
+
/**
|
|
9199
|
+
* The contexts in which an i18n expression can be used.
|
|
9200
|
+
*/
|
|
9201
|
+
var I18nExpressionFor;
|
|
9202
|
+
(function (I18nExpressionFor) {
|
|
9203
|
+
/**
|
|
9204
|
+
* This expression is used as a value (i.e. inside an i18n block).
|
|
9205
|
+
*/
|
|
9206
|
+
I18nExpressionFor[I18nExpressionFor["I18nText"] = 0] = "I18nText";
|
|
9207
|
+
/**
|
|
9208
|
+
* This expression is used in a binding.
|
|
9209
|
+
*/
|
|
9210
|
+
I18nExpressionFor[I18nExpressionFor["I18nAttribute"] = 1] = "I18nAttribute";
|
|
9211
|
+
})(I18nExpressionFor || (I18nExpressionFor = {}));
|
|
9139
9212
|
/**
|
|
9140
9213
|
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
9141
9214
|
* the final map.
|
|
@@ -9195,6 +9268,21 @@ var DerivedRepeaterVarIdentity;
|
|
|
9195
9268
|
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
9196
9269
|
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
9197
9270
|
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
9271
|
+
/**
|
|
9272
|
+
* Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
|
|
9273
|
+
*/
|
|
9274
|
+
var I18nContextKind;
|
|
9275
|
+
(function (I18nContextKind) {
|
|
9276
|
+
I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
|
|
9277
|
+
I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
|
|
9278
|
+
I18nContextKind[I18nContextKind["Attr"] = 2] = "Attr";
|
|
9279
|
+
})(I18nContextKind || (I18nContextKind = {}));
|
|
9280
|
+
var TemplateKind;
|
|
9281
|
+
(function (TemplateKind) {
|
|
9282
|
+
TemplateKind[TemplateKind["NgTemplate"] = 0] = "NgTemplate";
|
|
9283
|
+
TemplateKind[TemplateKind["Structural"] = 1] = "Structural";
|
|
9284
|
+
TemplateKind[TemplateKind["Block"] = 2] = "Block";
|
|
9285
|
+
})(TemplateKind || (TemplateKind = {}));
|
|
9198
9286
|
|
|
9199
9287
|
/**
|
|
9200
9288
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9302,12 +9390,11 @@ const NEW_OP = {
|
|
|
9302
9390
|
/**
|
|
9303
9391
|
* Create an `InterpolationTextOp`.
|
|
9304
9392
|
*/
|
|
9305
|
-
function createInterpolateTextOp(xref, interpolation,
|
|
9393
|
+
function createInterpolateTextOp(xref, interpolation, sourceSpan) {
|
|
9306
9394
|
return {
|
|
9307
9395
|
kind: OpKind.InterpolateText,
|
|
9308
9396
|
target: xref,
|
|
9309
9397
|
interpolation,
|
|
9310
|
-
i18nPlaceholders,
|
|
9311
9398
|
sourceSpan,
|
|
9312
9399
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9313
9400
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9315,15 +9402,19 @@ function createInterpolateTextOp(xref, interpolation, i18nPlaceholders, sourceSp
|
|
|
9315
9402
|
};
|
|
9316
9403
|
}
|
|
9317
9404
|
class Interpolation {
|
|
9318
|
-
constructor(strings, expressions) {
|
|
9405
|
+
constructor(strings, expressions, i18nPlaceholders) {
|
|
9319
9406
|
this.strings = strings;
|
|
9320
9407
|
this.expressions = expressions;
|
|
9408
|
+
this.i18nPlaceholders = i18nPlaceholders;
|
|
9409
|
+
if (i18nPlaceholders.length !== 0 && i18nPlaceholders.length !== expressions.length) {
|
|
9410
|
+
throw new Error(`Expected ${expressions.length} placeholders to match interpolation expression count, but got ${i18nPlaceholders.length}`);
|
|
9411
|
+
}
|
|
9321
9412
|
}
|
|
9322
9413
|
}
|
|
9323
9414
|
/**
|
|
9324
9415
|
* Create a `BindingOp`, not yet transformed into a particular type of binding.
|
|
9325
9416
|
*/
|
|
9326
|
-
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute,
|
|
9417
|
+
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplate, i18nContext, sourceSpan) {
|
|
9327
9418
|
return {
|
|
9328
9419
|
kind: OpKind.Binding,
|
|
9329
9420
|
bindingKind: kind,
|
|
@@ -9333,7 +9424,8 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9333
9424
|
unit,
|
|
9334
9425
|
securityContext,
|
|
9335
9426
|
isTextAttribute,
|
|
9336
|
-
|
|
9427
|
+
isStructuralTemplate: isStructuralTemplate,
|
|
9428
|
+
i18nContext,
|
|
9337
9429
|
sourceSpan,
|
|
9338
9430
|
...NEW_OP,
|
|
9339
9431
|
};
|
|
@@ -9341,7 +9433,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
|
|
|
9341
9433
|
/**
|
|
9342
9434
|
* Create a `PropertyOp`.
|
|
9343
9435
|
*/
|
|
9344
|
-
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext,
|
|
9436
|
+
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplate, i18nContext, sourceSpan) {
|
|
9345
9437
|
return {
|
|
9346
9438
|
kind: OpKind.Property,
|
|
9347
9439
|
target,
|
|
@@ -9350,7 +9442,8 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
|
|
|
9350
9442
|
isAnimationTrigger,
|
|
9351
9443
|
securityContext,
|
|
9352
9444
|
sanitizer: null,
|
|
9353
|
-
|
|
9445
|
+
isStructuralTemplate,
|
|
9446
|
+
i18nContext,
|
|
9354
9447
|
sourceSpan,
|
|
9355
9448
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9356
9449
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9415,7 +9508,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9415
9508
|
/**
|
|
9416
9509
|
* Create an `AttributeOp`.
|
|
9417
9510
|
*/
|
|
9418
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute,
|
|
9511
|
+
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplate, i18nContext, sourceSpan) {
|
|
9419
9512
|
return {
|
|
9420
9513
|
kind: OpKind.Attribute,
|
|
9421
9514
|
target,
|
|
@@ -9424,7 +9517,8 @@ function createAttributeOp(target, name, expression, securityContext, isTextAttr
|
|
|
9424
9517
|
securityContext,
|
|
9425
9518
|
sanitizer: null,
|
|
9426
9519
|
isTextAttribute,
|
|
9427
|
-
|
|
9520
|
+
isStructuralTemplate,
|
|
9521
|
+
i18nContext,
|
|
9428
9522
|
sourceSpan,
|
|
9429
9523
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9430
9524
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9485,15 +9579,18 @@ function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
|
|
|
9485
9579
|
/**
|
|
9486
9580
|
* Create an i18n expression op.
|
|
9487
9581
|
*/
|
|
9488
|
-
function createI18nExpressionOp(context, target, handle, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9582
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9489
9583
|
return {
|
|
9490
9584
|
kind: OpKind.I18nExpression,
|
|
9491
9585
|
context,
|
|
9492
9586
|
target,
|
|
9587
|
+
i18nOwner,
|
|
9493
9588
|
handle,
|
|
9494
9589
|
expression,
|
|
9495
9590
|
i18nPlaceholder,
|
|
9496
9591
|
resolutionTime,
|
|
9592
|
+
usage,
|
|
9593
|
+
name,
|
|
9497
9594
|
sourceSpan,
|
|
9498
9595
|
...NEW_OP,
|
|
9499
9596
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9501,12 +9598,12 @@ function createI18nExpressionOp(context, target, handle, expression, i18nPlaceho
|
|
|
9501
9598
|
};
|
|
9502
9599
|
}
|
|
9503
9600
|
/**
|
|
9504
|
-
*Creates an op to apply i18n expression ops
|
|
9601
|
+
* Creates an op to apply i18n expression ops.
|
|
9505
9602
|
*/
|
|
9506
|
-
function createI18nApplyOp(
|
|
9603
|
+
function createI18nApplyOp(owner, handle, sourceSpan) {
|
|
9507
9604
|
return {
|
|
9508
9605
|
kind: OpKind.I18nApply,
|
|
9509
|
-
|
|
9606
|
+
owner,
|
|
9510
9607
|
handle,
|
|
9511
9608
|
sourceSpan,
|
|
9512
9609
|
...NEW_OP,
|
|
@@ -10310,6 +10407,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10310
10407
|
case OpKind.ProjectionDef:
|
|
10311
10408
|
case OpKind.Template:
|
|
10312
10409
|
case OpKind.Text:
|
|
10410
|
+
case OpKind.I18nAttributes:
|
|
10313
10411
|
// These operations contain no expressions.
|
|
10314
10412
|
break;
|
|
10315
10413
|
default:
|
|
@@ -10330,6 +10428,9 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10330
10428
|
expr.lhs = transformExpressionsInExpression(expr.lhs, transform, flags);
|
|
10331
10429
|
expr.rhs = transformExpressionsInExpression(expr.rhs, transform, flags);
|
|
10332
10430
|
}
|
|
10431
|
+
else if (expr instanceof UnaryOperatorExpr) {
|
|
10432
|
+
expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
|
|
10433
|
+
}
|
|
10333
10434
|
else if (expr instanceof ReadPropExpr) {
|
|
10334
10435
|
expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
|
|
10335
10436
|
}
|
|
@@ -10381,6 +10482,9 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10381
10482
|
expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
|
|
10382
10483
|
}
|
|
10383
10484
|
}
|
|
10485
|
+
else if (expr instanceof NotExpr) {
|
|
10486
|
+
expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
|
|
10487
|
+
}
|
|
10384
10488
|
else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
|
|
10385
10489
|
expr instanceof LiteralExpr) {
|
|
10386
10490
|
// No action for these types.
|
|
@@ -10722,10 +10826,11 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10722
10826
|
/**
|
|
10723
10827
|
* Create a `TemplateOp`.
|
|
10724
10828
|
*/
|
|
10725
|
-
function createTemplateOp(xref, tag, functionNameSuffix, namespace, i18nPlaceholder, sourceSpan) {
|
|
10829
|
+
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, sourceSpan) {
|
|
10726
10830
|
return {
|
|
10727
10831
|
kind: OpKind.Template,
|
|
10728
10832
|
xref,
|
|
10833
|
+
templateKind,
|
|
10729
10834
|
attributes: null,
|
|
10730
10835
|
tag,
|
|
10731
10836
|
handle: new SlotHandle(),
|
|
@@ -10848,14 +10953,15 @@ function createProjectionDefOp(def) {
|
|
|
10848
10953
|
...NEW_OP,
|
|
10849
10954
|
};
|
|
10850
10955
|
}
|
|
10851
|
-
function createProjectionOp(xref, selector, sourceSpan) {
|
|
10956
|
+
function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceSpan) {
|
|
10852
10957
|
return {
|
|
10853
10958
|
kind: OpKind.Projection,
|
|
10854
10959
|
xref,
|
|
10855
10960
|
handle: new SlotHandle(),
|
|
10856
10961
|
selector,
|
|
10962
|
+
i18nPlaceholder,
|
|
10857
10963
|
projectionSlotIndex: 0,
|
|
10858
|
-
attributes
|
|
10964
|
+
attributes,
|
|
10859
10965
|
localRefs: [],
|
|
10860
10966
|
sourceSpan,
|
|
10861
10967
|
...NEW_OP,
|
|
@@ -10865,13 +10971,14 @@ function createProjectionOp(xref, selector, sourceSpan) {
|
|
|
10865
10971
|
/**
|
|
10866
10972
|
* Create an `ExtractedAttributeOp`.
|
|
10867
10973
|
*/
|
|
10868
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
10974
|
+
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext) {
|
|
10869
10975
|
return {
|
|
10870
10976
|
kind: OpKind.ExtractedAttribute,
|
|
10871
10977
|
target,
|
|
10872
10978
|
bindingKind,
|
|
10873
10979
|
name,
|
|
10874
10980
|
expression,
|
|
10981
|
+
i18nContext,
|
|
10875
10982
|
...NEW_OP,
|
|
10876
10983
|
};
|
|
10877
10984
|
}
|
|
@@ -10914,10 +11021,11 @@ function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
|
|
|
10914
11021
|
/**
|
|
10915
11022
|
* Create an `ExtractedMessageOp`.
|
|
10916
11023
|
*/
|
|
10917
|
-
function createI18nMessageOp(xref, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
11024
|
+
function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
10918
11025
|
return {
|
|
10919
11026
|
kind: OpKind.I18nMessage,
|
|
10920
11027
|
xref,
|
|
11028
|
+
i18nContext,
|
|
10921
11029
|
i18nBlock,
|
|
10922
11030
|
message,
|
|
10923
11031
|
messagePlaceholder,
|
|
@@ -10979,9 +11087,13 @@ function createIcuEndOp(xref) {
|
|
|
10979
11087
|
...NEW_OP,
|
|
10980
11088
|
};
|
|
10981
11089
|
}
|
|
10982
|
-
function createI18nContextOp(xref, i18nBlock, message, sourceSpan) {
|
|
11090
|
+
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
11091
|
+
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
11092
|
+
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
11093
|
+
}
|
|
10983
11094
|
return {
|
|
10984
11095
|
kind: OpKind.I18nContext,
|
|
11096
|
+
contextKind,
|
|
10985
11097
|
xref,
|
|
10986
11098
|
i18nBlock,
|
|
10987
11099
|
message,
|
|
@@ -10991,6 +11103,17 @@ function createI18nContextOp(xref, i18nBlock, message, sourceSpan) {
|
|
|
10991
11103
|
...NEW_OP,
|
|
10992
11104
|
};
|
|
10993
11105
|
}
|
|
11106
|
+
function createI18nAttributesOp(xref, handle, target) {
|
|
11107
|
+
return {
|
|
11108
|
+
kind: OpKind.I18nAttributes,
|
|
11109
|
+
xref,
|
|
11110
|
+
handle,
|
|
11111
|
+
target,
|
|
11112
|
+
i18nAttributesConfig: null,
|
|
11113
|
+
...NEW_OP,
|
|
11114
|
+
...TRAIT_CONSUMES_SLOT,
|
|
11115
|
+
};
|
|
11116
|
+
}
|
|
10994
11117
|
function literalOrArrayLiteral$1(value) {
|
|
10995
11118
|
if (Array.isArray(value)) {
|
|
10996
11119
|
return literalArr(value.map(literalOrArrayLiteral$1));
|
|
@@ -10998,12 +11121,13 @@ function literalOrArrayLiteral$1(value) {
|
|
|
10998
11121
|
return literal(value, INFERRED_TYPE);
|
|
10999
11122
|
}
|
|
11000
11123
|
|
|
11001
|
-
function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan) {
|
|
11124
|
+
function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, sourceSpan) {
|
|
11002
11125
|
return {
|
|
11003
11126
|
kind: OpKind.HostProperty,
|
|
11004
11127
|
name,
|
|
11005
11128
|
expression,
|
|
11006
11129
|
isAnimationTrigger,
|
|
11130
|
+
i18nContext,
|
|
11007
11131
|
sourceSpan,
|
|
11008
11132
|
...TRAIT_CONSUMES_VARS,
|
|
11009
11133
|
...NEW_OP,
|
|
@@ -11240,7 +11364,7 @@ function applyI18nExpressions(job) {
|
|
|
11240
11364
|
// Only add apply after expressions that are not followed by more expressions.
|
|
11241
11365
|
if (op.kind === OpKind.I18nExpression && needsApplication(i18nContexts, op)) {
|
|
11242
11366
|
// TODO: what should be the source span for the apply op?
|
|
11243
|
-
OpList.insertAfter(createI18nApplyOp(op.
|
|
11367
|
+
OpList.insertAfter(createI18nApplyOp(op.i18nOwner, op.handle, null), op);
|
|
11244
11368
|
}
|
|
11245
11369
|
}
|
|
11246
11370
|
}
|
|
@@ -11253,21 +11377,37 @@ function needsApplication(i18nContexts, op) {
|
|
|
11253
11377
|
if (op.next?.kind !== OpKind.I18nExpression) {
|
|
11254
11378
|
return true;
|
|
11255
11379
|
}
|
|
11256
|
-
// If the next op is an expression targeting a different i18n block, we need to apply.
|
|
11257
11380
|
const context = i18nContexts.get(op.context);
|
|
11258
11381
|
const nextContext = i18nContexts.get(op.next.context);
|
|
11259
|
-
if (context
|
|
11382
|
+
if (context === undefined) {
|
|
11383
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the I18nExpressionOp\'s context');
|
|
11384
|
+
}
|
|
11385
|
+
if (nextContext === undefined) {
|
|
11386
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the next I18nExpressionOp\'s context');
|
|
11387
|
+
}
|
|
11388
|
+
// If the next op is an expression targeting a different i18n block (or different element, in the
|
|
11389
|
+
// case of i18n attributes), we need to apply.
|
|
11390
|
+
// First, handle the case of i18n blocks.
|
|
11391
|
+
if (context.i18nBlock !== null) {
|
|
11392
|
+
// This is a block context. Compare the blocks.
|
|
11393
|
+
if (context.i18nBlock !== nextContext.i18nBlock) {
|
|
11394
|
+
return true;
|
|
11395
|
+
}
|
|
11396
|
+
return false;
|
|
11397
|
+
}
|
|
11398
|
+
// Second, handle the case of i18n attributes.
|
|
11399
|
+
if (op.i18nOwner !== op.next.i18nOwner) {
|
|
11260
11400
|
return true;
|
|
11261
11401
|
}
|
|
11262
11402
|
return false;
|
|
11263
11403
|
}
|
|
11264
11404
|
|
|
11265
11405
|
/**
|
|
11266
|
-
* Updates i18n expression ops to
|
|
11406
|
+
* Updates i18n expression ops to target the last slot in their owning i18n block, and moves them
|
|
11407
|
+
* after the last update instruction that depends on that slot.
|
|
11267
11408
|
*/
|
|
11268
11409
|
function assignI18nSlotDependencies(job) {
|
|
11269
11410
|
const i18nLastSlotConsumers = new Map();
|
|
11270
|
-
const i18nContexts = new Map();
|
|
11271
11411
|
let lastSlotConsumer = null;
|
|
11272
11412
|
let currentI18nOp = null;
|
|
11273
11413
|
for (const unit of job.units) {
|
|
@@ -11281,21 +11421,54 @@ function assignI18nSlotDependencies(job) {
|
|
|
11281
11421
|
currentI18nOp = op;
|
|
11282
11422
|
break;
|
|
11283
11423
|
case OpKind.I18nEnd:
|
|
11424
|
+
if (currentI18nOp === null) {
|
|
11425
|
+
throw new Error('AssertionError: Expected an active I18n block while calculating last slot consumers');
|
|
11426
|
+
}
|
|
11427
|
+
if (lastSlotConsumer === null) {
|
|
11428
|
+
throw new Error('AssertionError: Expected a last slot consumer while calculating last slot consumers');
|
|
11429
|
+
}
|
|
11284
11430
|
i18nLastSlotConsumers.set(currentI18nOp.xref, lastSlotConsumer);
|
|
11285
11431
|
currentI18nOp = null;
|
|
11286
11432
|
break;
|
|
11287
|
-
case OpKind.I18nContext:
|
|
11288
|
-
i18nContexts.set(op.xref, op);
|
|
11289
|
-
break;
|
|
11290
11433
|
}
|
|
11291
11434
|
}
|
|
11292
|
-
//
|
|
11435
|
+
// Expresions that are currently being moved.
|
|
11436
|
+
let opsToMove = [];
|
|
11437
|
+
// Previously we found the last slot-consuming create mode op in the i18n block. That op will be
|
|
11438
|
+
// the new target for any moved i18n expresion inside the i18n block, and that op's slot is
|
|
11439
|
+
// stored here.
|
|
11440
|
+
let moveAfterTarget = null;
|
|
11441
|
+
// This is the last target in the create IR that we saw during iteration. Eventally, it will be
|
|
11442
|
+
// equal to moveAfterTarget. But wait! We need to find the *last* such op whose target is equal
|
|
11443
|
+
// to `moveAfterTarget`.
|
|
11444
|
+
let previousTarget = null;
|
|
11293
11445
|
for (const op of unit.update) {
|
|
11294
|
-
if (op
|
|
11295
|
-
|
|
11296
|
-
|
|
11446
|
+
if (hasDependsOnSlotContextTrait(op)) {
|
|
11447
|
+
// We've found an op that depends on another slot other than the one that we want to move
|
|
11448
|
+
// the expressions to, after previously having seen the one we want to move to.
|
|
11449
|
+
if (moveAfterTarget !== null && previousTarget === moveAfterTarget &&
|
|
11450
|
+
op.target !== previousTarget) {
|
|
11451
|
+
OpList.insertBefore(opsToMove, op);
|
|
11452
|
+
moveAfterTarget = null;
|
|
11453
|
+
opsToMove = [];
|
|
11454
|
+
}
|
|
11455
|
+
previousTarget = op.target;
|
|
11456
|
+
}
|
|
11457
|
+
if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nText) {
|
|
11458
|
+
// This is an I18nExpressionOps that is used for text (not attributes).
|
|
11459
|
+
OpList.remove(op);
|
|
11460
|
+
opsToMove.push(op);
|
|
11461
|
+
const target = i18nLastSlotConsumers.get(op.i18nOwner);
|
|
11462
|
+
if (target === undefined) {
|
|
11463
|
+
throw new Error('AssertionError: Expected to find a last slot consumer for an I18nExpressionOp');
|
|
11464
|
+
}
|
|
11465
|
+
op.target = target;
|
|
11466
|
+
moveAfterTarget = op.target;
|
|
11297
11467
|
}
|
|
11298
11468
|
}
|
|
11469
|
+
if (moveAfterTarget !== null) {
|
|
11470
|
+
unit.update.push(opsToMove);
|
|
11471
|
+
}
|
|
11299
11472
|
}
|
|
11300
11473
|
}
|
|
11301
11474
|
|
|
@@ -11327,22 +11500,36 @@ function extractAttributes(job) {
|
|
|
11327
11500
|
break;
|
|
11328
11501
|
case OpKind.Property:
|
|
11329
11502
|
if (!op.isAnimationTrigger) {
|
|
11330
|
-
|
|
11503
|
+
let bindingKind;
|
|
11504
|
+
if (op.i18nContext !== null) {
|
|
11505
|
+
// If the binding has an i18n context, it is an i18n attribute, and should have that
|
|
11506
|
+
// kind in the consts array.
|
|
11507
|
+
bindingKind = BindingKind.I18n;
|
|
11508
|
+
}
|
|
11509
|
+
else if (op.isStructuralTemplate) {
|
|
11510
|
+
// TODO: How do i18n attributes on templates work?!
|
|
11511
|
+
bindingKind = BindingKind.Template;
|
|
11512
|
+
}
|
|
11513
|
+
else {
|
|
11514
|
+
bindingKind = BindingKind.Property;
|
|
11515
|
+
}
|
|
11516
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, bindingKind, op.name, null, null), lookupElement$2(elements, op.target));
|
|
11331
11517
|
}
|
|
11332
11518
|
break;
|
|
11333
11519
|
case OpKind.StyleProp:
|
|
11334
11520
|
case OpKind.ClassProp:
|
|
11521
|
+
// TODO: Can style or class bindings be i18n attributes?
|
|
11335
11522
|
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
11336
11523
|
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
11337
11524
|
// mode.
|
|
11338
11525
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11339
11526
|
op.expression instanceof EmptyExpr) {
|
|
11340
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
|
|
11527
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null, null), lookupElement$2(elements, op.target));
|
|
11341
11528
|
}
|
|
11342
11529
|
break;
|
|
11343
11530
|
case OpKind.Listener:
|
|
11344
11531
|
if (!op.isAnimationListener) {
|
|
11345
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null);
|
|
11532
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null, null);
|
|
11346
11533
|
if (job.kind === CompilationJobKind.Host) {
|
|
11347
11534
|
// This attribute will apply to the enclosing host binding compilation unit, so order
|
|
11348
11535
|
// doesn't matter.
|
|
@@ -11391,7 +11578,7 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
11391
11578
|
}
|
|
11392
11579
|
}
|
|
11393
11580
|
if (extractable) {
|
|
11394
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.
|
|
11581
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext);
|
|
11395
11582
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11396
11583
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
11397
11584
|
// matter.
|
|
@@ -11438,16 +11625,16 @@ function specializeBindings(job) {
|
|
|
11438
11625
|
target.nonBindable = true;
|
|
11439
11626
|
}
|
|
11440
11627
|
else {
|
|
11441
|
-
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.
|
|
11628
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplate, op.i18nContext, op.sourceSpan));
|
|
11442
11629
|
}
|
|
11443
11630
|
break;
|
|
11444
11631
|
case BindingKind.Property:
|
|
11445
11632
|
case BindingKind.Animation:
|
|
11446
11633
|
if (job.kind === CompilationJobKind.Host) {
|
|
11447
|
-
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.sourceSpan));
|
|
11634
|
+
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.sourceSpan));
|
|
11448
11635
|
}
|
|
11449
11636
|
else {
|
|
11450
|
-
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.
|
|
11637
|
+
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplate, op.i18nContext, op.sourceSpan));
|
|
11451
11638
|
}
|
|
11452
11639
|
break;
|
|
11453
11640
|
case BindingKind.I18n:
|
|
@@ -11624,41 +11811,6 @@ function generateConditionalExpressions(job) {
|
|
|
11624
11811
|
}
|
|
11625
11812
|
}
|
|
11626
11813
|
|
|
11627
|
-
var TagContentType;
|
|
11628
|
-
(function (TagContentType) {
|
|
11629
|
-
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
11630
|
-
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
11631
|
-
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
11632
|
-
})(TagContentType || (TagContentType = {}));
|
|
11633
|
-
function splitNsName(elementName) {
|
|
11634
|
-
if (elementName[0] != ':') {
|
|
11635
|
-
return [null, elementName];
|
|
11636
|
-
}
|
|
11637
|
-
const colonIndex = elementName.indexOf(':', 1);
|
|
11638
|
-
if (colonIndex === -1) {
|
|
11639
|
-
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
11640
|
-
}
|
|
11641
|
-
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
11642
|
-
}
|
|
11643
|
-
// `<ng-container>` tags work the same regardless the namespace
|
|
11644
|
-
function isNgContainer(tagName) {
|
|
11645
|
-
return splitNsName(tagName)[1] === 'ng-container';
|
|
11646
|
-
}
|
|
11647
|
-
// `<ng-content>` tags work the same regardless the namespace
|
|
11648
|
-
function isNgContent(tagName) {
|
|
11649
|
-
return splitNsName(tagName)[1] === 'ng-content';
|
|
11650
|
-
}
|
|
11651
|
-
// `<ng-template>` tags work the same regardless the namespace
|
|
11652
|
-
function isNgTemplate(tagName) {
|
|
11653
|
-
return splitNsName(tagName)[1] === 'ng-template';
|
|
11654
|
-
}
|
|
11655
|
-
function getNsPrefix(fullName) {
|
|
11656
|
-
return fullName === null ? null : splitNsName(fullName)[0];
|
|
11657
|
-
}
|
|
11658
|
-
function mergeNsAndName(prefix, localName) {
|
|
11659
|
-
return prefix ? `:${prefix}:${localName}` : localName;
|
|
11660
|
-
}
|
|
11661
|
-
|
|
11662
11814
|
const BINARY_OPERATORS = new Map([
|
|
11663
11815
|
['&&', BinaryOperator.And],
|
|
11664
11816
|
['>', BinaryOperator.Bigger],
|
|
@@ -11803,7 +11955,7 @@ class ElementAttributes {
|
|
|
11803
11955
|
array.push(...getAttributeNameLiterals$1(name));
|
|
11804
11956
|
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11805
11957
|
if (value === null) {
|
|
11806
|
-
throw Error('Attribute & style element attributes must have a value');
|
|
11958
|
+
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
11807
11959
|
}
|
|
11808
11960
|
array.push(value);
|
|
11809
11961
|
}
|
|
@@ -11857,6 +12009,50 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
|
|
|
11857
12009
|
return literalArr(attrArray);
|
|
11858
12010
|
}
|
|
11859
12011
|
|
|
12012
|
+
/**
|
|
12013
|
+
* Some binding instructions in the update block may actually correspond to i18n bindings. In that
|
|
12014
|
+
* case, they should be replaced with i18nExp instructions for the dynamic portions.
|
|
12015
|
+
*/
|
|
12016
|
+
function convertI18nBindings(job) {
|
|
12017
|
+
const i18nAttributesByElem = new Map();
|
|
12018
|
+
for (const unit of job.units) {
|
|
12019
|
+
for (const op of unit.create) {
|
|
12020
|
+
if (op.kind === OpKind.I18nAttributes) {
|
|
12021
|
+
i18nAttributesByElem.set(op.target, op);
|
|
12022
|
+
}
|
|
12023
|
+
}
|
|
12024
|
+
for (const op of unit.update) {
|
|
12025
|
+
switch (op.kind) {
|
|
12026
|
+
case OpKind.Property:
|
|
12027
|
+
case OpKind.Attribute:
|
|
12028
|
+
if (op.i18nContext === null) {
|
|
12029
|
+
continue;
|
|
12030
|
+
}
|
|
12031
|
+
if (!(op.expression instanceof Interpolation)) {
|
|
12032
|
+
continue;
|
|
12033
|
+
}
|
|
12034
|
+
const i18nAttributesForElem = i18nAttributesByElem.get(op.target);
|
|
12035
|
+
if (i18nAttributesForElem === undefined) {
|
|
12036
|
+
throw new Error('AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction');
|
|
12037
|
+
}
|
|
12038
|
+
if (i18nAttributesForElem.target !== op.target) {
|
|
12039
|
+
throw new Error('AssertionError: Expected i18nAttributes target element to match binding target element');
|
|
12040
|
+
}
|
|
12041
|
+
const ops = [];
|
|
12042
|
+
for (let i = 0; i < op.expression.expressions.length; i++) {
|
|
12043
|
+
const expr = op.expression.expressions[i];
|
|
12044
|
+
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
12045
|
+
throw new Error(`AssertionError: An i18n attribute binding instruction requires the same number of expressions and placeholders, but found ${op.expression.i18nPlaceholders.length} placeholders and ${op.expression.expressions.length} expressions`);
|
|
12046
|
+
}
|
|
12047
|
+
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12048
|
+
}
|
|
12049
|
+
OpList.replaceWithMany(op, ops);
|
|
12050
|
+
break;
|
|
12051
|
+
}
|
|
12052
|
+
}
|
|
12053
|
+
}
|
|
12054
|
+
}
|
|
12055
|
+
|
|
11860
12056
|
/**
|
|
11861
12057
|
* Create extracted deps functions for defer ops.
|
|
11862
12058
|
*/
|
|
@@ -11902,17 +12098,22 @@ function createDeferDepsFns(job) {
|
|
|
11902
12098
|
* message.)
|
|
11903
12099
|
*/
|
|
11904
12100
|
function createI18nContexts(job) {
|
|
12101
|
+
const rootContexts = new Map();
|
|
11905
12102
|
let currentI18nOp = null;
|
|
11906
12103
|
let xref;
|
|
11907
12104
|
for (const unit of job.units) {
|
|
11908
12105
|
for (const op of unit.create) {
|
|
11909
12106
|
switch (op.kind) {
|
|
11910
12107
|
case OpKind.I18nStart:
|
|
11911
|
-
// Each i18n block gets its own context.
|
|
11912
|
-
xref = job.allocateXrefId();
|
|
11913
|
-
unit.create.push(createI18nContextOp(xref, op.xref, op.message, null));
|
|
11914
|
-
op.context = xref;
|
|
11915
12108
|
currentI18nOp = op;
|
|
12109
|
+
// Each root i18n block gets its own context, child ones refer to the context for their
|
|
12110
|
+
// root block.
|
|
12111
|
+
if (op.xref === op.root) {
|
|
12112
|
+
xref = job.allocateXrefId();
|
|
12113
|
+
unit.create.push(createI18nContextOp(I18nContextKind.RootI18n, xref, op.xref, op.message, null));
|
|
12114
|
+
op.context = xref;
|
|
12115
|
+
rootContexts.set(op.xref, xref);
|
|
12116
|
+
}
|
|
11916
12117
|
break;
|
|
11917
12118
|
case OpKind.I18nEnd:
|
|
11918
12119
|
currentI18nOp = null;
|
|
@@ -11926,7 +12127,7 @@ function createI18nContexts(job) {
|
|
|
11926
12127
|
if (op.message.id !== currentI18nOp.message.id) {
|
|
11927
12128
|
// There was an enclosing i18n block around this ICU somewhere.
|
|
11928
12129
|
xref = job.allocateXrefId();
|
|
11929
|
-
unit.create.push(createI18nContextOp(xref, currentI18nOp.xref, op.message, null));
|
|
12130
|
+
unit.create.push(createI18nContextOp(I18nContextKind.Icu, xref, currentI18nOp.xref, op.message, null));
|
|
11930
12131
|
op.context = xref;
|
|
11931
12132
|
}
|
|
11932
12133
|
else {
|
|
@@ -11938,6 +12139,15 @@ function createI18nContexts(job) {
|
|
|
11938
12139
|
}
|
|
11939
12140
|
}
|
|
11940
12141
|
}
|
|
12142
|
+
// Assign contexts to child i18n blocks, now that all root i18n blocks have their context
|
|
12143
|
+
// assigned.
|
|
12144
|
+
for (const unit of job.units) {
|
|
12145
|
+
for (const op of unit.create) {
|
|
12146
|
+
if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
|
|
12147
|
+
op.context = rootContexts.get(op.root);
|
|
12148
|
+
}
|
|
12149
|
+
}
|
|
12150
|
+
}
|
|
11941
12151
|
}
|
|
11942
12152
|
|
|
11943
12153
|
/**
|
|
@@ -12286,7 +12496,7 @@ function ternaryTransform(e) {
|
|
|
12286
12496
|
/**
|
|
12287
12497
|
* The escape sequence used indicate message param values.
|
|
12288
12498
|
*/
|
|
12289
|
-
const ESCAPE = '\uFFFD';
|
|
12499
|
+
const ESCAPE$1 = '\uFFFD';
|
|
12290
12500
|
/**
|
|
12291
12501
|
* Marker used to indicate an element tag.
|
|
12292
12502
|
*/
|
|
@@ -12320,11 +12530,9 @@ const LIST_DELIMITER = '|';
|
|
|
12320
12530
|
* used in the final output.
|
|
12321
12531
|
*/
|
|
12322
12532
|
function extractI18nMessages(job) {
|
|
12323
|
-
// Save the i18n context ops for later use.
|
|
12533
|
+
// Save the i18n start and i18n context ops for later use.
|
|
12324
12534
|
const i18nContexts = new Map();
|
|
12325
|
-
|
|
12326
|
-
// created from ICUs).
|
|
12327
|
-
const i18nBlockContexts = new Set();
|
|
12535
|
+
const i18nBlocks = new Map();
|
|
12328
12536
|
for (const unit of job.units) {
|
|
12329
12537
|
for (const op of unit.create) {
|
|
12330
12538
|
switch (op.kind) {
|
|
@@ -12332,11 +12540,23 @@ function extractI18nMessages(job) {
|
|
|
12332
12540
|
i18nContexts.set(op.xref, op);
|
|
12333
12541
|
break;
|
|
12334
12542
|
case OpKind.I18nStart:
|
|
12335
|
-
|
|
12543
|
+
i18nBlocks.set(op.xref, op);
|
|
12336
12544
|
break;
|
|
12337
12545
|
}
|
|
12338
12546
|
}
|
|
12339
12547
|
}
|
|
12548
|
+
// TODO: Miles and I think that contexts have a 1-to-1 correspondence with extracted messages, so
|
|
12549
|
+
// this phase can probably be simplified.
|
|
12550
|
+
// Extract messages from contexts of i18n attributes.
|
|
12551
|
+
for (const unit of job.units) {
|
|
12552
|
+
for (const op of unit.create) {
|
|
12553
|
+
if (op.kind !== OpKind.I18nContext || op.contextKind !== I18nContextKind.Attr) {
|
|
12554
|
+
continue;
|
|
12555
|
+
}
|
|
12556
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12557
|
+
unit.create.push(i18nMessageOp);
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12340
12560
|
// Extract messages from root i18n blocks.
|
|
12341
12561
|
const i18nBlockMessages = new Map();
|
|
12342
12562
|
for (const unit of job.units) {
|
|
@@ -12359,11 +12579,15 @@ function extractI18nMessages(job) {
|
|
|
12359
12579
|
if (!op.context) {
|
|
12360
12580
|
throw Error('ICU op should have its context set.');
|
|
12361
12581
|
}
|
|
12362
|
-
|
|
12363
|
-
|
|
12582
|
+
const i18nContext = i18nContexts.get(op.context);
|
|
12583
|
+
if (i18nContext.contextKind === I18nContextKind.Icu) {
|
|
12584
|
+
if (i18nContext.i18nBlock === null) {
|
|
12585
|
+
throw Error('ICU context should have its i18n block set.');
|
|
12586
|
+
}
|
|
12364
12587
|
const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
|
|
12365
12588
|
unit.create.push(subMessage);
|
|
12366
|
-
const
|
|
12589
|
+
const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
|
|
12590
|
+
const parentMessage = i18nBlockMessages.get(rootI18nId);
|
|
12367
12591
|
parentMessage?.subMessages.push(subMessage.xref);
|
|
12368
12592
|
}
|
|
12369
12593
|
OpList.remove(op);
|
|
@@ -12379,26 +12603,28 @@ function extractI18nMessages(job) {
|
|
|
12379
12603
|
* Create an i18n message op from an i18n context op.
|
|
12380
12604
|
*/
|
|
12381
12605
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
12382
|
-
let
|
|
12606
|
+
let formattedParams = formatParams(context.params);
|
|
12607
|
+
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12608
|
+
let needsPostprocessing = formattedPostprocessingParams.size > 0;
|
|
12383
12609
|
for (const values of context.params.values()) {
|
|
12384
12610
|
if (values.length > 1) {
|
|
12385
12611
|
needsPostprocessing = true;
|
|
12386
12612
|
}
|
|
12387
12613
|
}
|
|
12388
|
-
return createI18nMessageOp(job.allocateXrefId(), context.i18nBlock, context.message, messagePlaceholder ?? null,
|
|
12614
|
+
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12389
12615
|
}
|
|
12390
12616
|
/**
|
|
12391
12617
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12392
12618
|
*/
|
|
12393
12619
|
function formatParams(params) {
|
|
12394
|
-
const
|
|
12620
|
+
const formattedParams = new Map();
|
|
12395
12621
|
for (const [placeholder, placeholderValues] of params) {
|
|
12396
12622
|
const serializedValues = formatParamValues(placeholderValues);
|
|
12397
12623
|
if (serializedValues !== null) {
|
|
12398
|
-
|
|
12624
|
+
formattedParams.set(placeholder, literal(serializedValues));
|
|
12399
12625
|
}
|
|
12400
12626
|
}
|
|
12401
|
-
return
|
|
12627
|
+
return formattedParams;
|
|
12402
12628
|
}
|
|
12403
12629
|
/**
|
|
12404
12630
|
* Formats an `I18nParamValue[]` into a string (or null for empty array).
|
|
@@ -12416,10 +12642,47 @@ function formatParamValues(values) {
|
|
|
12416
12642
|
* Formats a single `I18nParamValue` into a string
|
|
12417
12643
|
*/
|
|
12418
12644
|
function formatValue(value) {
|
|
12645
|
+
// Element tags with a structural directive use a special form that concatenates the element and
|
|
12646
|
+
// template values.
|
|
12647
|
+
if ((value.flags & I18nParamValueFlags.ElementTag) &&
|
|
12648
|
+
(value.flags & I18nParamValueFlags.TemplateTag)) {
|
|
12649
|
+
if (typeof value.value !== 'object') {
|
|
12650
|
+
throw Error('AssertionError: Expected i18n param value to have an element and template slot');
|
|
12651
|
+
}
|
|
12652
|
+
const elementValue = formatValue({
|
|
12653
|
+
...value,
|
|
12654
|
+
value: value.value.element,
|
|
12655
|
+
flags: value.flags & ~I18nParamValueFlags.TemplateTag
|
|
12656
|
+
});
|
|
12657
|
+
const templateValue = formatValue({
|
|
12658
|
+
...value,
|
|
12659
|
+
value: value.value.template,
|
|
12660
|
+
flags: value.flags & ~I18nParamValueFlags.ElementTag
|
|
12661
|
+
});
|
|
12662
|
+
// TODO(mmalerba): This is likely a bug in TemplateDefinitionBuilder, we should not need to
|
|
12663
|
+
// record the template value twice. For now I'm re-implementing the behavior here to keep the
|
|
12664
|
+
// output consistent with TemplateDefinitionBuilder.
|
|
12665
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12666
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12667
|
+
return `${templateValue}${elementValue}${templateValue}`;
|
|
12668
|
+
}
|
|
12669
|
+
// To match the TemplateDefinitionBuilder output, flip the order depending on whether the
|
|
12670
|
+
// values represent a closing or opening tag (or both).
|
|
12671
|
+
// TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
|
|
12672
|
+
// or the resulting message ID. If not, we can remove the special-casing in the future.
|
|
12673
|
+
return value.flags & I18nParamValueFlags.CloseTag ? `${elementValue}${templateValue}` :
|
|
12674
|
+
`${templateValue}${elementValue}`;
|
|
12675
|
+
}
|
|
12676
|
+
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
12677
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12678
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12679
|
+
return `${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.CloseTag })}${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.OpenTag })}`;
|
|
12680
|
+
}
|
|
12419
12681
|
// If there are no special flags, just return the raw value.
|
|
12420
12682
|
if (value.flags === I18nParamValueFlags.None) {
|
|
12421
12683
|
return `${value.value}`;
|
|
12422
12684
|
}
|
|
12685
|
+
// Encode the remaining flags as part of the value.
|
|
12423
12686
|
let tagMarker = '';
|
|
12424
12687
|
let closeMarker = '';
|
|
12425
12688
|
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
@@ -12432,12 +12695,7 @@ function formatValue(value) {
|
|
|
12432
12695
|
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
12433
12696
|
}
|
|
12434
12697
|
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
12435
|
-
|
|
12436
|
-
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12437
|
-
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12438
|
-
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12439
|
-
}
|
|
12440
|
-
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12698
|
+
return `${ESCAPE$1}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE$1}`;
|
|
12441
12699
|
}
|
|
12442
12700
|
|
|
12443
12701
|
/**
|
|
@@ -12471,7 +12729,7 @@ function generateAdvance(job) {
|
|
|
12471
12729
|
else if (!slotMap.has(op.target)) {
|
|
12472
12730
|
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
12473
12731
|
// the `slotMap`.
|
|
12474
|
-
throw new Error(`AssertionError: reference to unknown slot for
|
|
12732
|
+
throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
|
|
12475
12733
|
}
|
|
12476
12734
|
const slot = slotMap.get(op.target);
|
|
12477
12735
|
// Does the slot counter need to be adjusted?
|
|
@@ -19681,35 +19939,132 @@ const NG_I18N_CLOSURE_MODE$1 = 'ngI18nClosureMode';
|
|
|
19681
19939
|
* considers variables like `I18N_0` as constants and throws an error when their value changes.
|
|
19682
19940
|
*/
|
|
19683
19941
|
const TRANSLATION_VAR_PREFIX = 'i18n_';
|
|
19942
|
+
/** Prefix of ICU expressions for post processing */
|
|
19943
|
+
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
19944
|
+
/**
|
|
19945
|
+
* The escape sequence used for message param values.
|
|
19946
|
+
*/
|
|
19947
|
+
const ESCAPE = '\uFFFD';
|
|
19684
19948
|
/**
|
|
19685
19949
|
* Lifts i18n properties into the consts array.
|
|
19686
19950
|
* TODO: Can we use `ConstCollectedExpr`?
|
|
19951
|
+
* TODO: The way the various attributes are linked together is very complex. Perhaps we could
|
|
19952
|
+
* simplify the process, maybe by combining the context and message ops?
|
|
19687
19953
|
*/
|
|
19688
19954
|
function collectI18nConsts(job) {
|
|
19689
19955
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
19690
|
-
|
|
19691
|
-
//
|
|
19956
|
+
// Step One: Build up various lookup maps we need to collect all the consts.
|
|
19957
|
+
// Context Xref -> Extracted Attribute Op
|
|
19958
|
+
const extractedAttributesByI18nContext = new Map();
|
|
19959
|
+
// Element/ElementStart Xref -> I18n Attributes config op
|
|
19960
|
+
const i18nAttributesByElement = new Map();
|
|
19961
|
+
// Element/ElementStart Xref -> All I18n Expression ops for attrs on that target
|
|
19962
|
+
const i18nExpressionsByElement = new Map();
|
|
19963
|
+
// I18n Message Xref -> I18n Message Op (TODO: use a central op map)
|
|
19692
19964
|
const messages = new Map();
|
|
19965
|
+
for (const unit of job.units) {
|
|
19966
|
+
for (const op of unit.ops()) {
|
|
19967
|
+
if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
|
|
19968
|
+
extractedAttributesByI18nContext.set(op.i18nContext, op);
|
|
19969
|
+
}
|
|
19970
|
+
else if (op.kind === OpKind.I18nAttributes) {
|
|
19971
|
+
i18nAttributesByElement.set(op.target, op);
|
|
19972
|
+
}
|
|
19973
|
+
else if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nAttribute) {
|
|
19974
|
+
const expressions = i18nExpressionsByElement.get(op.target) ?? [];
|
|
19975
|
+
expressions.push(op);
|
|
19976
|
+
i18nExpressionsByElement.set(op.target, expressions);
|
|
19977
|
+
}
|
|
19978
|
+
else if (op.kind === OpKind.I18nMessage) {
|
|
19979
|
+
messages.set(op.xref, op);
|
|
19980
|
+
}
|
|
19981
|
+
}
|
|
19982
|
+
}
|
|
19983
|
+
// Step Two: Serialize the extracted i18n messages for root i18n blocks and i18n attributes into
|
|
19984
|
+
// the const array.
|
|
19985
|
+
//
|
|
19986
|
+
// Also, each i18n message will have a variable expression that can refer to its
|
|
19987
|
+
// value. Store these expressions in the appropriate place:
|
|
19988
|
+
// 1. For normal i18n content, it also goes in the const array. We save the const index to use
|
|
19989
|
+
// later.
|
|
19990
|
+
// 2. For extracted attributes, it becomes the value of the extracted attribute instruction.
|
|
19991
|
+
// 3. For i18n bindings, it will go in a separate const array instruction below; for now, we just
|
|
19992
|
+
// save it.
|
|
19993
|
+
const i18nValuesByContext = new Map();
|
|
19994
|
+
const messageConstIndices = new Map();
|
|
19693
19995
|
for (const unit of job.units) {
|
|
19694
19996
|
for (const op of unit.create) {
|
|
19695
19997
|
if (op.kind === OpKind.I18nMessage) {
|
|
19696
|
-
|
|
19998
|
+
if (op.messagePlaceholder === null) {
|
|
19999
|
+
const { mainVar, statements } = collectMessage(job, fileBasedI18nSuffix, messages, op);
|
|
20000
|
+
if (op.i18nBlock !== null) {
|
|
20001
|
+
// This is a regular i18n message with a corresponding i18n block. Collect it into the
|
|
20002
|
+
// const array.
|
|
20003
|
+
const i18nConst = job.addConst(mainVar, statements);
|
|
20004
|
+
messageConstIndices.set(op.i18nBlock, i18nConst);
|
|
20005
|
+
}
|
|
20006
|
+
else {
|
|
20007
|
+
// This is an i18n attribute. Extract the initializers into the const pool.
|
|
20008
|
+
job.constsInitializers.push(...statements);
|
|
20009
|
+
// Save the i18n variable value for later.
|
|
20010
|
+
i18nValuesByContext.set(op.i18nContext, mainVar);
|
|
20011
|
+
// This i18n message may correspond to an individual extracted attribute. If so, The
|
|
20012
|
+
// value of that attribute is updated to read the extracted i18n variable.
|
|
20013
|
+
const attributeForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
|
|
20014
|
+
if (attributeForMessage !== undefined) {
|
|
20015
|
+
attributeForMessage.expression = mainVar;
|
|
20016
|
+
}
|
|
20017
|
+
}
|
|
20018
|
+
}
|
|
19697
20019
|
OpList.remove(op);
|
|
19698
20020
|
}
|
|
19699
20021
|
}
|
|
19700
20022
|
}
|
|
19701
|
-
//
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
20023
|
+
// Step Three: Serialize I18nAttributes configurations into the const array. Each I18nAttributes
|
|
20024
|
+
// instruction has a config array, which contains k-v pairs describing each binding name, and the
|
|
20025
|
+
// i18n variable that provides the value.
|
|
20026
|
+
for (const unit of job.units) {
|
|
20027
|
+
for (const elem of unit.create) {
|
|
20028
|
+
if (isElementOrContainerOp(elem)) {
|
|
20029
|
+
const i18nAttributes = i18nAttributesByElement.get(elem.xref);
|
|
20030
|
+
if (i18nAttributes === undefined) {
|
|
20031
|
+
// This element is not associated with an i18n attributes configuration instruction.
|
|
20032
|
+
continue;
|
|
20033
|
+
}
|
|
20034
|
+
let i18nExpressions = i18nExpressionsByElement.get(elem.xref);
|
|
20035
|
+
if (i18nExpressions === undefined) {
|
|
20036
|
+
// Unused i18nAttributes should have already been removed.
|
|
20037
|
+
// TODO: Should the removal of those dead instructions be merged with this phase?
|
|
20038
|
+
throw new Error('AssertionError: Could not find any i18n expressions associated with an I18nAttributes instruction');
|
|
20039
|
+
}
|
|
20040
|
+
// Find expressions for all the unique property names, removing duplicates.
|
|
20041
|
+
const seenPropertyNames = new Set();
|
|
20042
|
+
i18nExpressions = i18nExpressions.filter(i18nExpr => {
|
|
20043
|
+
const seen = (seenPropertyNames.has(i18nExpr.name));
|
|
20044
|
+
seenPropertyNames.add(i18nExpr.name);
|
|
20045
|
+
return !seen;
|
|
20046
|
+
});
|
|
20047
|
+
const i18nAttributeConfig = i18nExpressions.flatMap(i18nExpr => {
|
|
20048
|
+
const i18nExprValue = i18nValuesByContext.get(i18nExpr.context);
|
|
20049
|
+
if (i18nExprValue === undefined) {
|
|
20050
|
+
throw new Error('AssertionError: Could not find i18n expression\'s value');
|
|
20051
|
+
}
|
|
20052
|
+
return [literal(i18nExpr.name), i18nExprValue];
|
|
20053
|
+
});
|
|
20054
|
+
i18nAttributes.i18nAttributesConfig =
|
|
20055
|
+
job.addConst(new LiteralArrayExpr(i18nAttributeConfig));
|
|
20056
|
+
}
|
|
19706
20057
|
}
|
|
19707
20058
|
}
|
|
19708
|
-
//
|
|
20059
|
+
// Step Four: Propagate the extracted const index into i18n ops that messages were extracted from.
|
|
19709
20060
|
for (const unit of job.units) {
|
|
19710
20061
|
for (const op of unit.create) {
|
|
19711
20062
|
if (op.kind === OpKind.I18nStart) {
|
|
19712
|
-
|
|
20063
|
+
const msgIndex = messageConstIndices.get(op.root);
|
|
20064
|
+
if (msgIndex === undefined) {
|
|
20065
|
+
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?');
|
|
20066
|
+
}
|
|
20067
|
+
op.messageIndex = msgIndex;
|
|
19713
20068
|
}
|
|
19714
20069
|
}
|
|
19715
20070
|
}
|
|
@@ -19719,18 +20074,23 @@ function collectI18nConsts(job) {
|
|
|
19719
20074
|
* This will recursively collect any sub-messages referenced from the parent message as well.
|
|
19720
20075
|
*/
|
|
19721
20076
|
function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
19722
|
-
// Recursively collect any sub-messages,
|
|
20077
|
+
// Recursively collect any sub-messages, record each sub-message's main variable under its
|
|
20078
|
+
// placeholder so that we can add them to the params for the parent message. It is possible
|
|
20079
|
+
// that multiple sub-messages will share the same placeholder, so we need to track an array of
|
|
20080
|
+
// variables for each placeholder.
|
|
19723
20081
|
const statements = [];
|
|
20082
|
+
const subMessagePlaceholders = new Map();
|
|
19724
20083
|
for (const subMessageId of messageOp.subMessages) {
|
|
19725
20084
|
const subMessage = messages.get(subMessageId);
|
|
19726
20085
|
const { mainVar: subMessageVar, statements: subMessageStatements } = collectMessage(job, fileBasedI18nSuffix, messages, subMessage);
|
|
19727
20086
|
statements.push(...subMessageStatements);
|
|
19728
|
-
|
|
20087
|
+
const subMessages = subMessagePlaceholders.get(subMessage.messagePlaceholder) ?? [];
|
|
20088
|
+
subMessages.push(subMessageVar);
|
|
20089
|
+
subMessagePlaceholders.set(subMessage.messagePlaceholder, subMessages);
|
|
19729
20090
|
}
|
|
20091
|
+
addSubMessageParams(messageOp, subMessagePlaceholders);
|
|
19730
20092
|
// Sort the params for consistency with TemaplateDefinitionBuilder output.
|
|
19731
20093
|
messageOp.params = new Map([...messageOp.params.entries()].sort());
|
|
19732
|
-
// Check that the message has all of its parameters filled out.
|
|
19733
|
-
assertAllParamsResolved(messageOp);
|
|
19734
20094
|
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
19735
20095
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other
|
|
19736
20096
|
// const to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
@@ -19741,10 +20101,11 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19741
20101
|
// set in post-processing.
|
|
19742
20102
|
if (messageOp.needsPostprocessing) {
|
|
19743
20103
|
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
19744
|
-
|
|
20104
|
+
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
20105
|
+
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
19745
20106
|
const extraTransformFnParams = [];
|
|
19746
20107
|
if (messageOp.postprocessingParams.size > 0) {
|
|
19747
|
-
extraTransformFnParams.push(
|
|
20108
|
+
extraTransformFnParams.push(mapLiteral(formattedPostprocessingParams, /* quoted */ true));
|
|
19748
20109
|
}
|
|
19749
20110
|
transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
|
|
19750
20111
|
}
|
|
@@ -19752,6 +20113,26 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19752
20113
|
statements.push(...getTranslationDeclStmts$1(messageOp.message, mainVar, closureVar, messageOp.params, transformFn));
|
|
19753
20114
|
return { mainVar, statements };
|
|
19754
20115
|
}
|
|
20116
|
+
/**
|
|
20117
|
+
* Adds the given subMessage placeholders to the given message op.
|
|
20118
|
+
*
|
|
20119
|
+
* If a placeholder only corresponds to a single sub-message variable, we just set that variable
|
|
20120
|
+
* as the param value. However, if the placeholder corresponds to multiple sub-message
|
|
20121
|
+
* variables, we need to add a special placeholder value that is handled by the post-processing
|
|
20122
|
+
* step. We then add the array of variables as a post-processing param.
|
|
20123
|
+
*/
|
|
20124
|
+
function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
20125
|
+
for (const [placeholder, subMessages] of subMessagePlaceholders) {
|
|
20126
|
+
if (subMessages.length === 1) {
|
|
20127
|
+
messageOp.params.set(placeholder, subMessages[0]);
|
|
20128
|
+
}
|
|
20129
|
+
else {
|
|
20130
|
+
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
20131
|
+
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
20132
|
+
messageOp.needsPostprocessing = true;
|
|
20133
|
+
}
|
|
20134
|
+
}
|
|
20135
|
+
}
|
|
19755
20136
|
/**
|
|
19756
20137
|
* Generate statements that define a given translation message.
|
|
19757
20138
|
*
|
|
@@ -19774,7 +20155,8 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19774
20155
|
* @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
|
|
19775
20156
|
* @param params Object mapping placeholder names to their values (e.g.
|
|
19776
20157
|
* `{ "interpolation": "\uFFFD0\uFFFD" }`).
|
|
19777
|
-
* @param transformFn Optional transformation function that will be applied to the translation
|
|
20158
|
+
* @param transformFn Optional transformation function that will be applied to the translation
|
|
20159
|
+
* (e.g.
|
|
19778
20160
|
* post-processing).
|
|
19779
20161
|
* @returns An array of statements that defined a given translation.
|
|
19780
20162
|
*/
|
|
@@ -19819,28 +20201,13 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
|
|
|
19819
20201
|
}
|
|
19820
20202
|
return variable(name);
|
|
19821
20203
|
}
|
|
19822
|
-
/**
|
|
19823
|
-
* Asserts that all of the message's placeholders have values.
|
|
19824
|
-
*/
|
|
19825
|
-
function assertAllParamsResolved(op) {
|
|
19826
|
-
for (let placeholder in op.message.placeholders) {
|
|
19827
|
-
placeholder = placeholder.trimEnd();
|
|
19828
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19829
|
-
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
19830
|
-
}
|
|
19831
|
-
}
|
|
19832
|
-
for (let placeholder in op.message.placeholderToMessage) {
|
|
19833
|
-
placeholder = placeholder.trimEnd();
|
|
19834
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19835
|
-
throw Error(`Failed to resolve i18n message placeholder: ${placeholder}`);
|
|
19836
|
-
}
|
|
19837
|
-
}
|
|
19838
|
-
}
|
|
19839
20204
|
|
|
19840
20205
|
/**
|
|
19841
20206
|
* Removes text nodes within i18n blocks since they are already hardcoded into the i18n message.
|
|
20207
|
+
* Also, replaces interpolations on these text nodes with i18n expressions of the non-text portions,
|
|
20208
|
+
* which will be applied later.
|
|
19842
20209
|
*/
|
|
19843
|
-
function
|
|
20210
|
+
function convertI18nText(job) {
|
|
19844
20211
|
for (const unit of job.units) {
|
|
19845
20212
|
// Remove all text nodes within i18n blocks, their content is already captured in the i18n
|
|
19846
20213
|
// message.
|
|
@@ -19895,7 +20262,7 @@ function extractI18nText(job) {
|
|
|
19895
20262
|
const expr = op.interpolation.expressions[i];
|
|
19896
20263
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
19897
20264
|
// Later, we will modify this, and advance to a different point.
|
|
19898
|
-
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.handle, expr, op.i18nPlaceholders[i], resolutionTime, expr.sourceSpan ?? op.sourceSpan));
|
|
20265
|
+
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, op.interpolation.i18nPlaceholders[i], resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
19899
20266
|
}
|
|
19900
20267
|
OpList.replaceWithMany(op, ops);
|
|
19901
20268
|
break;
|
|
@@ -19938,57 +20305,6 @@ function serializeLocalRefs(refs) {
|
|
|
19938
20305
|
return literalArr(constRefs);
|
|
19939
20306
|
}
|
|
19940
20307
|
|
|
19941
|
-
/**
|
|
19942
|
-
* Merge i18n contexts for child i18n blocks into their ancestor root contexts.
|
|
19943
|
-
*/
|
|
19944
|
-
function mergeI18nContexts(job) {
|
|
19945
|
-
// Record all of the i18n and extracted message ops for use later.
|
|
19946
|
-
const i18nOps = new Map();
|
|
19947
|
-
const i18nContexts = new Map();
|
|
19948
|
-
for (const unit of job.units) {
|
|
19949
|
-
for (const op of unit.create) {
|
|
19950
|
-
switch (op.kind) {
|
|
19951
|
-
case OpKind.I18nStart:
|
|
19952
|
-
if (!op.context) {
|
|
19953
|
-
throw Error('I18n op should have its context set.');
|
|
19954
|
-
}
|
|
19955
|
-
i18nOps.set(op.xref, op);
|
|
19956
|
-
break;
|
|
19957
|
-
case OpKind.I18nContext:
|
|
19958
|
-
i18nContexts.set(op.xref, op);
|
|
19959
|
-
break;
|
|
19960
|
-
}
|
|
19961
|
-
}
|
|
19962
|
-
}
|
|
19963
|
-
// For each non-root i18n op, merge its context into the root i18n op's context.
|
|
19964
|
-
for (const childI18nOp of i18nOps.values()) {
|
|
19965
|
-
if (childI18nOp.xref !== childI18nOp.root) {
|
|
19966
|
-
const childContext = i18nContexts.get(childI18nOp.context);
|
|
19967
|
-
const rootI18nOp = i18nOps.get(childI18nOp.root);
|
|
19968
|
-
const rootContext = i18nContexts.get(rootI18nOp.context);
|
|
19969
|
-
mergeParams(rootContext.params, childContext.params);
|
|
19970
|
-
mergeParams(rootContext.postprocessingParams, childContext.postprocessingParams);
|
|
19971
|
-
}
|
|
19972
|
-
}
|
|
19973
|
-
}
|
|
19974
|
-
/**
|
|
19975
|
-
* Merges the params in the `from` map to into the `to` map.
|
|
19976
|
-
*/
|
|
19977
|
-
function mergeParams(to, from) {
|
|
19978
|
-
for (const [placeholder, fromValues] of from) {
|
|
19979
|
-
const toValues = to.get(placeholder) || [];
|
|
19980
|
-
// TODO(mmalerba): Child element close tag params should be prepended to maintain the same order
|
|
19981
|
-
// as TemplateDefinitionBuilder. Can be cleaned up when compatibility is no longer required.
|
|
19982
|
-
const flags = fromValues[0].flags;
|
|
19983
|
-
if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
|
|
19984
|
-
to.set(placeholder, [...fromValues, ...toValues]);
|
|
19985
|
-
}
|
|
19986
|
-
else {
|
|
19987
|
-
to.set(placeholder, [...toValues, ...fromValues]);
|
|
19988
|
-
}
|
|
19989
|
-
}
|
|
19990
|
-
}
|
|
19991
|
-
|
|
19992
20308
|
/**
|
|
19993
20309
|
* Change namespaces between HTML, SVG and MathML, depending on the next element.
|
|
19994
20310
|
*/
|
|
@@ -20484,14 +20800,14 @@ function parseExtractedStyles(job) {
|
|
|
20484
20800
|
if (op.name === 'style') {
|
|
20485
20801
|
const parsedStyles = parse(op.expression.value);
|
|
20486
20802
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
20487
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1])), op);
|
|
20803
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null), op);
|
|
20488
20804
|
}
|
|
20489
20805
|
OpList.remove(op);
|
|
20490
20806
|
}
|
|
20491
20807
|
else if (op.name === 'class') {
|
|
20492
20808
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
20493
20809
|
for (const parsedClass of parsedClasses) {
|
|
20494
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null), op);
|
|
20810
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null), op);
|
|
20495
20811
|
}
|
|
20496
20812
|
OpList.remove(op);
|
|
20497
20813
|
}
|
|
@@ -20507,18 +20823,30 @@ function parseExtractedStyles(job) {
|
|
|
20507
20823
|
function removeContentSelectors(job) {
|
|
20508
20824
|
for (const unit of job.units) {
|
|
20509
20825
|
const elements = createOpXrefMap(unit);
|
|
20510
|
-
for (const op of unit.
|
|
20826
|
+
for (const op of unit.ops()) {
|
|
20511
20827
|
switch (op.kind) {
|
|
20512
20828
|
case OpKind.Binding:
|
|
20513
20829
|
const target = lookupInXrefMap(elements, op.target);
|
|
20514
|
-
if (op.name
|
|
20830
|
+
if (isSelectAttribute(op.name) && target.kind === OpKind.Projection) {
|
|
20515
20831
|
OpList.remove(op);
|
|
20516
20832
|
}
|
|
20517
20833
|
break;
|
|
20834
|
+
case OpKind.Projection:
|
|
20835
|
+
// op.attributes is an array of [attr1-name, attr1-value, attr2-name, attr2-value, ...],
|
|
20836
|
+
// find the "select" attribute and remove its name and corresponding value.
|
|
20837
|
+
for (let i = op.attributes.length - 2; i >= 0; i -= 2) {
|
|
20838
|
+
if (isSelectAttribute(op.attributes[i])) {
|
|
20839
|
+
op.attributes.splice(i, 2);
|
|
20840
|
+
}
|
|
20841
|
+
}
|
|
20842
|
+
break;
|
|
20518
20843
|
}
|
|
20519
20844
|
}
|
|
20520
20845
|
}
|
|
20521
20846
|
}
|
|
20847
|
+
function isSelectAttribute(name) {
|
|
20848
|
+
return name.toLowerCase() === 'select';
|
|
20849
|
+
}
|
|
20522
20850
|
/**
|
|
20523
20851
|
* Looks up an element in the given map by xref ID.
|
|
20524
20852
|
*/
|
|
@@ -20638,6 +20966,10 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
|
20638
20966
|
i18nBlock = op;
|
|
20639
20967
|
break;
|
|
20640
20968
|
case OpKind.I18nEnd:
|
|
20969
|
+
// When we exit a root-level i18n block, reset the sub-template index counter.
|
|
20970
|
+
if (i18nBlock.subTemplateIndex === null) {
|
|
20971
|
+
subTemplateIndex = 0;
|
|
20972
|
+
}
|
|
20641
20973
|
i18nBlock = null;
|
|
20642
20974
|
break;
|
|
20643
20975
|
case OpKind.Template:
|
|
@@ -20652,9 +20984,10 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
|
20652
20984
|
wrapTemplateWithI18n(templateView, i18nBlock);
|
|
20653
20985
|
}
|
|
20654
20986
|
// Continue traversing inside the template's view.
|
|
20655
|
-
propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
|
|
20987
|
+
subTemplateIndex = propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
|
|
20656
20988
|
}
|
|
20657
20989
|
}
|
|
20990
|
+
return subTemplateIndex;
|
|
20658
20991
|
}
|
|
20659
20992
|
/**
|
|
20660
20993
|
* Wraps a template view with i18n start and end ops.
|
|
@@ -20978,6 +21311,10 @@ function i18n(slot, constIndex, subTemplateIndex) {
|
|
|
20978
21311
|
function i18nEnd() {
|
|
20979
21312
|
return call(Identifiers.i18nEnd, [], null);
|
|
20980
21313
|
}
|
|
21314
|
+
function i18nAttributes(slot, i18nAttributesConfig) {
|
|
21315
|
+
const args = [literal(slot), literal(i18nAttributesConfig)];
|
|
21316
|
+
return call(Identifiers.i18nAttributes, args, null);
|
|
21317
|
+
}
|
|
20981
21318
|
function property(name, expression, sanitizer, sourceSpan) {
|
|
20982
21319
|
const args = [literal(name), expression];
|
|
20983
21320
|
if (sanitizer !== null) {
|
|
@@ -21364,6 +21701,12 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21364
21701
|
case OpKind.I18n:
|
|
21365
21702
|
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21366
21703
|
break;
|
|
21704
|
+
case OpKind.I18nAttributes:
|
|
21705
|
+
if (op.i18nAttributesConfig === null) {
|
|
21706
|
+
throw new Error(`AssertionError: i18nAttributesConfig was not set`);
|
|
21707
|
+
}
|
|
21708
|
+
OpList.replace(op, i18nAttributes(op.handle.slot, op.i18nAttributesConfig));
|
|
21709
|
+
break;
|
|
21367
21710
|
case OpKind.Template:
|
|
21368
21711
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
21369
21712
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
@@ -21705,6 +22048,31 @@ function removeI18nContexts(job) {
|
|
|
21705
22048
|
}
|
|
21706
22049
|
}
|
|
21707
22050
|
|
|
22051
|
+
/**
|
|
22052
|
+
* i18nAttributes ops will be generated for each i18n attribute. However, not all i18n attribues
|
|
22053
|
+
* will contain dynamic content, and so some of these i18nAttributes ops may be unnecessary.
|
|
22054
|
+
*/
|
|
22055
|
+
function removeUnusedI18nAttributesOps(job) {
|
|
22056
|
+
for (const unit of job.units) {
|
|
22057
|
+
const ownersWithI18nExpressions = new Set();
|
|
22058
|
+
for (const op of unit.update) {
|
|
22059
|
+
switch (op.kind) {
|
|
22060
|
+
case OpKind.I18nExpression:
|
|
22061
|
+
ownersWithI18nExpressions.add(op.i18nOwner);
|
|
22062
|
+
}
|
|
22063
|
+
}
|
|
22064
|
+
for (const op of unit.create) {
|
|
22065
|
+
switch (op.kind) {
|
|
22066
|
+
case OpKind.I18nAttributes:
|
|
22067
|
+
if (ownersWithI18nExpressions.has(op.xref)) {
|
|
22068
|
+
continue;
|
|
22069
|
+
}
|
|
22070
|
+
OpList.remove(op);
|
|
22071
|
+
}
|
|
22072
|
+
}
|
|
22073
|
+
}
|
|
22074
|
+
}
|
|
22075
|
+
|
|
21708
22076
|
/**
|
|
21709
22077
|
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
21710
22078
|
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
@@ -21834,66 +22202,175 @@ function resolveI18nElementPlaceholders(job) {
|
|
|
21834
22202
|
}
|
|
21835
22203
|
}
|
|
21836
22204
|
}
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
22205
|
+
resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
|
|
22206
|
+
}
|
|
22207
|
+
/**
|
|
22208
|
+
* Recursively resolves element and template tag placeholders in the given view.
|
|
22209
|
+
*/
|
|
22210
|
+
function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingStructuralDirective) {
|
|
22211
|
+
// Track the current i18n op and corresponding i18n context op as we step through the creation
|
|
22212
|
+
// IR.
|
|
22213
|
+
let currentOps = null;
|
|
22214
|
+
let pendingStructuralDirectiveCloses = new Map();
|
|
22215
|
+
for (const op of unit.create) {
|
|
22216
|
+
switch (op.kind) {
|
|
22217
|
+
case OpKind.I18nStart:
|
|
22218
|
+
if (!op.context) {
|
|
22219
|
+
throw Error('Could not find i18n context for i18n op');
|
|
22220
|
+
}
|
|
22221
|
+
currentOps = { i18nBlock: op, i18nContext: i18nContexts.get(op.context) };
|
|
22222
|
+
break;
|
|
22223
|
+
case OpKind.I18nEnd:
|
|
22224
|
+
currentOps = null;
|
|
22225
|
+
break;
|
|
22226
|
+
case OpKind.ElementStart:
|
|
22227
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
22228
|
+
// corresponding tag start placeholder.
|
|
22229
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
22230
|
+
if (currentOps === null) {
|
|
22231
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21846
22232
|
}
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
case OpKind.ElementStart:
|
|
21853
|
-
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21854
|
-
// corresponding tag start placeholder.
|
|
21855
|
-
if (op.i18nPlaceholder !== undefined) {
|
|
21856
|
-
if (currentOps === null) {
|
|
21857
|
-
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21858
|
-
}
|
|
21859
|
-
const { startName, closeName } = op.i18nPlaceholder;
|
|
21860
|
-
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
21861
|
-
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
21862
|
-
// placeholder accounts for the start and close of the element.
|
|
21863
|
-
if (closeName === '') {
|
|
21864
|
-
flags |= I18nParamValueFlags.CloseTag;
|
|
21865
|
-
}
|
|
21866
|
-
addParam(currentOps.i18nContext.params, startName, op.handle.slot, currentOps.i18nBlock.subTemplateIndex, flags);
|
|
22233
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22234
|
+
// If there is a separate close tag placeholder for this element, save the pending
|
|
22235
|
+
// structural directive so we can pass it to the closing tag as well.
|
|
22236
|
+
if (pendingStructuralDirective && op.i18nPlaceholder.closeName) {
|
|
22237
|
+
pendingStructuralDirectiveCloses.set(op.xref, pendingStructuralDirective);
|
|
21867
22238
|
}
|
|
21868
|
-
|
|
21869
|
-
|
|
21870
|
-
|
|
21871
|
-
|
|
21872
|
-
|
|
21873
|
-
|
|
21874
|
-
|
|
21875
|
-
|
|
21876
|
-
|
|
21877
|
-
|
|
21878
|
-
|
|
21879
|
-
if (closeName !== '') {
|
|
21880
|
-
addParam(currentOps.i18nContext.params, closeName, startOp.handle.slot, currentOps.i18nBlock.subTemplateIndex, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
|
|
21881
|
-
}
|
|
22239
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
22240
|
+
pendingStructuralDirective = undefined;
|
|
22241
|
+
}
|
|
22242
|
+
break;
|
|
22243
|
+
case OpKind.ElementEnd:
|
|
22244
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
22245
|
+
// corresponding tag close placeholder.
|
|
22246
|
+
const startOp = elements.get(op.xref);
|
|
22247
|
+
if (startOp && startOp.i18nPlaceholder !== undefined) {
|
|
22248
|
+
if (currentOps === null) {
|
|
22249
|
+
throw Error('AssertionError: i18n tag placeholder should only occur inside an i18n block');
|
|
21882
22250
|
}
|
|
21883
|
-
|
|
21884
|
-
|
|
21885
|
-
|
|
21886
|
-
|
|
21887
|
-
|
|
21888
|
-
|
|
21889
|
-
|
|
21890
|
-
|
|
21891
|
-
|
|
21892
|
-
|
|
21893
|
-
|
|
22251
|
+
recordElementClose(startOp, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirectiveCloses.get(op.xref));
|
|
22252
|
+
// Clear out the pending structural directive close that was accounted for.
|
|
22253
|
+
pendingStructuralDirectiveCloses.delete(op.xref);
|
|
22254
|
+
}
|
|
22255
|
+
break;
|
|
22256
|
+
case OpKind.Projection:
|
|
22257
|
+
// For content projections with i18n placeholders, record its slot value in the params map
|
|
22258
|
+
// under the corresponding tag start and close placeholders.
|
|
22259
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
22260
|
+
if (currentOps === null) {
|
|
22261
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21894
22262
|
}
|
|
21895
|
-
|
|
21896
|
-
|
|
22263
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22264
|
+
recordElementClose(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22265
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
22266
|
+
pendingStructuralDirective = undefined;
|
|
22267
|
+
}
|
|
22268
|
+
break;
|
|
22269
|
+
case OpKind.Template:
|
|
22270
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22271
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22272
|
+
// blocks.
|
|
22273
|
+
resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
|
|
22274
|
+
}
|
|
22275
|
+
else {
|
|
22276
|
+
if (currentOps === null) {
|
|
22277
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22278
|
+
}
|
|
22279
|
+
if (op.templateKind === TemplateKind.Structural) {
|
|
22280
|
+
// If this is a structural directive template, don't record anything yet. Instead pass
|
|
22281
|
+
// the current template as a pending structural directive to be recorded when we find
|
|
22282
|
+
// the element, content, or template it belongs to. This allows us to create combined
|
|
22283
|
+
// values that represent, e.g. the start of a template and element at the same time.
|
|
22284
|
+
resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements, op);
|
|
22285
|
+
}
|
|
22286
|
+
else {
|
|
22287
|
+
// If this is some other kind of template, we can record its start, recurse into its
|
|
22288
|
+
// view, and then record its end.
|
|
22289
|
+
recordTemplateStart(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22290
|
+
resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
|
|
22291
|
+
recordTemplateClose(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22292
|
+
pendingStructuralDirective = undefined;
|
|
22293
|
+
}
|
|
22294
|
+
}
|
|
22295
|
+
break;
|
|
22296
|
+
}
|
|
22297
|
+
}
|
|
22298
|
+
}
|
|
22299
|
+
/**
|
|
22300
|
+
* Records an i18n param value for the start of an element.
|
|
22301
|
+
*/
|
|
22302
|
+
function recordElementStart(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22303
|
+
const { startName, closeName } = op.i18nPlaceholder;
|
|
22304
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
22305
|
+
let value = op.handle.slot;
|
|
22306
|
+
// If the element is associated with a structural directive, start it as well.
|
|
22307
|
+
if (structuralDirective !== undefined) {
|
|
22308
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22309
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22310
|
+
}
|
|
22311
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22312
|
+
// placeholder accounts for the start and close of the element.
|
|
22313
|
+
if (!closeName) {
|
|
22314
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22315
|
+
}
|
|
22316
|
+
addParam(i18nContext.params, startName, value, i18nBlock.subTemplateIndex, flags);
|
|
22317
|
+
}
|
|
22318
|
+
/**
|
|
22319
|
+
* Records an i18n param value for the closing of an element.
|
|
22320
|
+
*/
|
|
22321
|
+
function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22322
|
+
const { closeName } = op.i18nPlaceholder;
|
|
22323
|
+
// Self-closing tags don't have a closing tag placeholder, instead the element closing is
|
|
22324
|
+
// recorded via an additional flag on the element start value.
|
|
22325
|
+
if (closeName) {
|
|
22326
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag;
|
|
22327
|
+
let value = op.handle.slot;
|
|
22328
|
+
// If the element is associated with a structural directive, close it as well.
|
|
22329
|
+
if (structuralDirective !== undefined) {
|
|
22330
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22331
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22332
|
+
}
|
|
22333
|
+
addParam(i18nContext.params, closeName, value, i18nBlock.subTemplateIndex, flags);
|
|
22334
|
+
}
|
|
22335
|
+
}
|
|
22336
|
+
/**
|
|
22337
|
+
* Records an i18n param value for the start of a template.
|
|
22338
|
+
*/
|
|
22339
|
+
function recordTemplateStart(job, op, i18nContext, i18nBlock, structuralDirective) {
|
|
22340
|
+
let { startName, closeName } = op.i18nPlaceholder;
|
|
22341
|
+
let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
|
|
22342
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22343
|
+
// placeholder accounts for the start and close of the element.
|
|
22344
|
+
if (!closeName) {
|
|
22345
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22346
|
+
}
|
|
22347
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22348
|
+
// start first. Since this template must be in the structural directive's view, we can just
|
|
22349
|
+
// directly use the current i18n block's sub-template index.
|
|
22350
|
+
if (structuralDirective !== undefined) {
|
|
22351
|
+
addParam(i18nContext.params, startName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
22352
|
+
}
|
|
22353
|
+
// Record the start of the template. For the sub-template index, pass the index for the template's
|
|
22354
|
+
// view, rather than the current i18n block's index.
|
|
22355
|
+
addParam(i18nContext.params, startName, op.handle.slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, op), flags);
|
|
22356
|
+
}
|
|
22357
|
+
/**
|
|
22358
|
+
* Records an i18n param value for the closing of a template.
|
|
22359
|
+
*/
|
|
22360
|
+
function recordTemplateClose(job, op, i18nContext, i18nBlock, structuralDirective) {
|
|
22361
|
+
const { startName, closeName } = op.i18nPlaceholder;
|
|
22362
|
+
const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
|
|
22363
|
+
// Self-closing tags don't have a closing tag placeholder, instead the template's closing is
|
|
22364
|
+
// recorded via an additional flag on the template start value.
|
|
22365
|
+
if (closeName) {
|
|
22366
|
+
// Record the closing of the template. For the sub-template index, pass the index for the
|
|
22367
|
+
// template's view, rather than the current i18n block's index.
|
|
22368
|
+
addParam(i18nContext.params, closeName, op.handle.slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, op), flags);
|
|
22369
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22370
|
+
// closing after. Since this template must be in the structural directive's view, we can just
|
|
22371
|
+
// directly use the current i18n block's sub-template index.
|
|
22372
|
+
if (structuralDirective !== undefined) {
|
|
22373
|
+
addParam(i18nContext.params, closeName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
21897
22374
|
}
|
|
21898
22375
|
}
|
|
21899
22376
|
}
|
|
@@ -21909,7 +22386,9 @@ function getSubTemplateIndexForTemplateTag(job, i18nOp, op) {
|
|
|
21909
22386
|
}
|
|
21910
22387
|
return i18nOp.subTemplateIndex;
|
|
21911
22388
|
}
|
|
21912
|
-
/**
|
|
22389
|
+
/**
|
|
22390
|
+
* Add a param value to the given params map.
|
|
22391
|
+
*/
|
|
21913
22392
|
function addParam(params, placeholder, value, subTemplateIndex, flags) {
|
|
21914
22393
|
const values = params.get(placeholder) ?? [];
|
|
21915
22394
|
values.push({ value, subTemplateIndex, flags });
|
|
@@ -21935,14 +22414,19 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
21935
22414
|
}
|
|
21936
22415
|
}
|
|
21937
22416
|
}
|
|
21938
|
-
// Keep track of the next available expression index
|
|
22417
|
+
// Keep track of the next available expression index for each i18n message.
|
|
21939
22418
|
const expressionIndices = new Map();
|
|
22419
|
+
// Keep track of a reference index for each expression.
|
|
22420
|
+
// We use different references for normal i18n expressio and attribute i18n expressions. This is
|
|
22421
|
+
// because child i18n blocks in templates don't get their own context, since they're rolled into
|
|
22422
|
+
// the translated message of the parent, but they may target a different slot.
|
|
22423
|
+
const referenceIndex = (op) => op.usage === I18nExpressionFor.I18nText ? op.i18nOwner : op.context;
|
|
21940
22424
|
for (const unit of job.units) {
|
|
21941
22425
|
for (const op of unit.update) {
|
|
21942
22426
|
if (op.kind === OpKind.I18nExpression) {
|
|
21943
22427
|
const i18nContext = i18nContexts.get(op.context);
|
|
21944
|
-
const index = expressionIndices.get(
|
|
21945
|
-
const subTemplateIndex = subTemplateIndicies.get(
|
|
22428
|
+
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22429
|
+
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
21946
22430
|
// Add the expression index in the appropriate params map.
|
|
21947
22431
|
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
21948
22432
|
i18nContext.params :
|
|
@@ -21954,7 +22438,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
21954
22438
|
flags: I18nParamValueFlags.ExpressionIndex
|
|
21955
22439
|
});
|
|
21956
22440
|
params.set(op.i18nPlaceholder, values);
|
|
21957
|
-
expressionIndices.set(
|
|
22441
|
+
expressionIndices.set(referenceIndex(op), index + 1);
|
|
21958
22442
|
}
|
|
21959
22443
|
}
|
|
21960
22444
|
}
|
|
@@ -21964,28 +22448,12 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
21964
22448
|
* Resolves placeholders for element tags inside of an ICU.
|
|
21965
22449
|
*/
|
|
21966
22450
|
function resolveI18nIcuPlaceholders(job) {
|
|
21967
|
-
const contextOps = new Map();
|
|
21968
22451
|
for (const unit of job.units) {
|
|
21969
22452
|
for (const op of unit.create) {
|
|
21970
|
-
|
|
21971
|
-
|
|
21972
|
-
|
|
21973
|
-
|
|
21974
|
-
}
|
|
21975
|
-
}
|
|
21976
|
-
}
|
|
21977
|
-
for (const unit of job.units) {
|
|
21978
|
-
for (const op of unit.create) {
|
|
21979
|
-
switch (op.kind) {
|
|
21980
|
-
case OpKind.IcuStart:
|
|
21981
|
-
if (op.context === null) {
|
|
21982
|
-
throw Error('Icu should have its i18n context set.');
|
|
21983
|
-
}
|
|
21984
|
-
const i18nContext = contextOps.get(op.context);
|
|
21985
|
-
for (const node of op.message.nodes) {
|
|
21986
|
-
node.visit(new ResolveIcuPlaceholdersVisitor(i18nContext.postprocessingParams));
|
|
21987
|
-
}
|
|
21988
|
-
break;
|
|
22453
|
+
if (op.kind === OpKind.I18nContext && op.contextKind === I18nContextKind.Icu) {
|
|
22454
|
+
for (const node of op.message.nodes) {
|
|
22455
|
+
node.visit(new ResolveIcuPlaceholdersVisitor(op.postprocessingParams));
|
|
22456
|
+
}
|
|
21989
22457
|
}
|
|
21990
22458
|
}
|
|
21991
22459
|
}
|
|
@@ -23117,11 +23585,11 @@ const phases = [
|
|
|
23117
23585
|
{ kind: CompilationJobKind.Tmpl, fn: removeContentSelectors },
|
|
23118
23586
|
{ kind: CompilationJobKind.Host, fn: parseHostStyleProperties },
|
|
23119
23587
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
23120
|
-
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23121
|
-
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23122
23588
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
23123
23589
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
23124
23590
|
{ kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
|
|
23591
|
+
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23592
|
+
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23125
23593
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
23126
23594
|
{ kind: CompilationJobKind.Both, fn: parseExtractedStyles },
|
|
23127
23595
|
{ kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
|
|
@@ -23130,7 +23598,10 @@ const phases = [
|
|
|
23130
23598
|
{ kind: CompilationJobKind.Tmpl, fn: generateConditionalExpressions },
|
|
23131
23599
|
{ kind: CompilationJobKind.Tmpl, fn: createPipes },
|
|
23132
23600
|
{ kind: CompilationJobKind.Tmpl, fn: configureDeferInstructions },
|
|
23133
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
23601
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nText },
|
|
23602
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nBindings },
|
|
23603
|
+
{ kind: CompilationJobKind.Tmpl, fn: removeUnusedI18nAttributesOps },
|
|
23604
|
+
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
23134
23605
|
{ kind: CompilationJobKind.Tmpl, fn: applyI18nExpressions },
|
|
23135
23606
|
{ kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
|
|
23136
23607
|
{ kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
|
|
@@ -23155,13 +23626,11 @@ const phases = [
|
|
|
23155
23626
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
23156
23627
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
23157
23628
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nIcuPlaceholders },
|
|
23158
|
-
{ kind: CompilationJobKind.Tmpl, fn: mergeI18nContexts },
|
|
23159
23629
|
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
23160
23630
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
23161
23631
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
23162
23632
|
{ kind: CompilationJobKind.Tmpl, fn: collectConstExpressions },
|
|
23163
23633
|
{ kind: CompilationJobKind.Both, fn: collectElementConsts },
|
|
23164
|
-
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
23165
23634
|
{ kind: CompilationJobKind.Tmpl, fn: removeI18nContexts },
|
|
23166
23635
|
{ kind: CompilationJobKind.Both, fn: countVariables },
|
|
23167
23636
|
{ kind: CompilationJobKind.Tmpl, fn: generateAdvance },
|
|
@@ -23316,7 +23785,7 @@ function ingestHostProperty(job, property, isTextAttribute) {
|
|
|
23316
23785
|
let expression;
|
|
23317
23786
|
const ast = property.expression.ast;
|
|
23318
23787
|
if (ast instanceof Interpolation$1) {
|
|
23319
|
-
expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)));
|
|
23788
|
+
expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)), []);
|
|
23320
23789
|
}
|
|
23321
23790
|
else {
|
|
23322
23791
|
expression = convertAst(ast, job, property.sourceSpan);
|
|
@@ -23331,10 +23800,11 @@ function ingestHostProperty(job, property, isTextAttribute) {
|
|
|
23331
23800
|
bindingKind = BindingKind.Animation;
|
|
23332
23801
|
}
|
|
23333
23802
|
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
|
|
23334
|
-
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, property.sourceSpan));
|
|
23803
|
+
.NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
|
|
23335
23804
|
}
|
|
23336
23805
|
function ingestHostAttribute(job, name, value) {
|
|
23337
23806
|
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, SecurityContext.NONE, true, false,
|
|
23807
|
+
/* TODO */ null,
|
|
23338
23808
|
/* TODO: host attribute source spans */ null);
|
|
23339
23809
|
job.root.update.push(attrBinding);
|
|
23340
23810
|
}
|
|
@@ -23432,10 +23902,11 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23432
23902
|
const functionNameSuffix = tagNameWithoutNamespace === null ?
|
|
23433
23903
|
'' :
|
|
23434
23904
|
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
23435
|
-
const
|
|
23436
|
-
|
|
23437
|
-
|
|
23438
|
-
|
|
23905
|
+
const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
|
|
23906
|
+
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
23907
|
+
unit.create.push(templateOp);
|
|
23908
|
+
ingestBindings(unit, templateOp, tmpl);
|
|
23909
|
+
ingestReferences(templateOp, tmpl);
|
|
23439
23910
|
ingestNodes(childView, tmpl.children);
|
|
23440
23911
|
for (const { name, value } of tmpl.variables) {
|
|
23441
23912
|
childView.contextVariables.set(name, value !== '' ? value : '$implicit');
|
|
@@ -23443,7 +23914,7 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23443
23914
|
// If this is a plain template and there is an i18n message associated with it, insert i18n start
|
|
23444
23915
|
// and end ops. For structural directive templates, the i18n ops will be added when ingesting the
|
|
23445
23916
|
// element/template the directive is placed on.
|
|
23446
|
-
if (
|
|
23917
|
+
if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
|
|
23447
23918
|
const id = unit.job.allocateXrefId();
|
|
23448
23919
|
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
23449
23920
|
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
@@ -23453,9 +23924,13 @@ function ingestTemplate(unit, tmpl) {
|
|
|
23453
23924
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
23454
23925
|
*/
|
|
23455
23926
|
function ingestContent(unit, content) {
|
|
23456
|
-
|
|
23927
|
+
if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
|
|
23928
|
+
throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
|
|
23929
|
+
}
|
|
23930
|
+
const attrs = content.attributes.flatMap(a => [a.name, a.value]);
|
|
23931
|
+
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, attrs, content.sourceSpan);
|
|
23457
23932
|
for (const attr of content.attributes) {
|
|
23458
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue);
|
|
23933
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue, attr.i18n);
|
|
23459
23934
|
}
|
|
23460
23935
|
unit.create.push(op);
|
|
23461
23936
|
}
|
|
@@ -23480,6 +23955,7 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
23480
23955
|
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
23481
23956
|
}
|
|
23482
23957
|
if (i18nPlaceholders === undefined) {
|
|
23958
|
+
// TODO: We probably can just use the placeholders field, instead of walking the AST.
|
|
23483
23959
|
i18nPlaceholders = text.i18n instanceof Container ?
|
|
23484
23960
|
text.i18n.children
|
|
23485
23961
|
.filter((node) => node instanceof Placeholder)
|
|
@@ -23495,7 +23971,7 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
23495
23971
|
// interpolation. We copy that behavior in compatibility mode.
|
|
23496
23972
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
23497
23973
|
const baseSourceSpan = unit.job.compatibility ? null : text.sourceSpan;
|
|
23498
|
-
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))
|
|
23974
|
+
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan)), i18nPlaceholders), text.sourceSpan));
|
|
23499
23975
|
}
|
|
23500
23976
|
/**
|
|
23501
23977
|
* Ingest an `@if` block into the given `ViewCompilation`.
|
|
@@ -23516,14 +23992,21 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
23516
23992
|
if (ifCase.expressionAlias !== null) {
|
|
23517
23993
|
cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
|
|
23518
23994
|
}
|
|
23519
|
-
|
|
23520
|
-
|
|
23995
|
+
let ifCaseI18nMeta = undefined;
|
|
23996
|
+
if (ifCase.i18n !== undefined) {
|
|
23997
|
+
if (!(ifCase.i18n instanceof BlockPlaceholder)) {
|
|
23998
|
+
throw Error(`Unhandled i18n metadata type for if block: ${ifCase.i18n?.constructor.name}`);
|
|
23999
|
+
}
|
|
24000
|
+
ifCaseI18nMeta = ifCase.i18n;
|
|
24001
|
+
}
|
|
24002
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.sourceSpan);
|
|
24003
|
+
unit.create.push(templateOp);
|
|
23521
24004
|
if (firstXref === null) {
|
|
23522
24005
|
firstXref = cView.xref;
|
|
23523
|
-
firstSlotHandle =
|
|
24006
|
+
firstSlotHandle = templateOp.handle;
|
|
23524
24007
|
}
|
|
23525
24008
|
const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
|
|
23526
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
24009
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle, ifCase.expressionAlias);
|
|
23527
24010
|
conditions.push(conditionalCaseExpr);
|
|
23528
24011
|
ingestNodes(cView, ifCase.children);
|
|
23529
24012
|
}
|
|
@@ -23539,16 +24022,23 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
23539
24022
|
let conditions = [];
|
|
23540
24023
|
for (const switchCase of switchBlock.cases) {
|
|
23541
24024
|
const cView = unit.job.allocateView(unit.xref);
|
|
23542
|
-
|
|
23543
|
-
|
|
24025
|
+
let switchCaseI18nMeta = undefined;
|
|
24026
|
+
if (switchCase.i18n !== undefined) {
|
|
24027
|
+
if (!(switchCase.i18n instanceof BlockPlaceholder)) {
|
|
24028
|
+
throw Error(`Unhandled i18n metadata type for switch block: ${switchCase.i18n?.constructor.name}`);
|
|
24029
|
+
}
|
|
24030
|
+
switchCaseI18nMeta = switchCase.i18n;
|
|
24031
|
+
}
|
|
24032
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.sourceSpan);
|
|
24033
|
+
unit.create.push(templateOp);
|
|
23544
24034
|
if (firstXref === null) {
|
|
23545
24035
|
firstXref = cView.xref;
|
|
23546
|
-
firstSlotHandle =
|
|
24036
|
+
firstSlotHandle = templateOp.handle;
|
|
23547
24037
|
}
|
|
23548
24038
|
const caseExpr = switchCase.expression ?
|
|
23549
24039
|
convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
|
|
23550
24040
|
null;
|
|
23551
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
24041
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle);
|
|
23552
24042
|
conditions.push(conditionalCaseExpr);
|
|
23553
24043
|
ingestNodes(cView, switchCase.children);
|
|
23554
24044
|
}
|
|
@@ -23561,7 +24051,7 @@ function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
|
23561
24051
|
}
|
|
23562
24052
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
23563
24053
|
ingestNodes(secondaryView, children);
|
|
23564
|
-
const templateOp = createTemplateOp(secondaryView.xref, null, `Defer${suffix}`, Namespace.HTML, undefined, sourceSpan);
|
|
24054
|
+
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, undefined, sourceSpan);
|
|
23565
24055
|
unit.create.push(templateOp);
|
|
23566
24056
|
return templateOp;
|
|
23567
24057
|
}
|
|
@@ -23656,12 +24146,7 @@ function ingestIcu(unit, icu) {
|
|
|
23656
24146
|
const xref = unit.job.allocateXrefId();
|
|
23657
24147
|
const icuNode = icu.i18n.nodes[0];
|
|
23658
24148
|
unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
|
|
23659
|
-
const
|
|
23660
|
-
if (expressionPlaceholder === undefined || icu.vars[expressionPlaceholder] === undefined) {
|
|
23661
|
-
throw Error('ICU should have a text binding');
|
|
23662
|
-
}
|
|
23663
|
-
ingestBoundText(unit, icu.vars[expressionPlaceholder], [expressionPlaceholder]);
|
|
23664
|
-
for (const [placeholder, text] of Object.entries(icu.placeholders)) {
|
|
24149
|
+
for (const [placeholder, text] of Object.entries({ ...icu.vars, ...icu.placeholders })) {
|
|
23665
24150
|
if (text instanceof BoundText) {
|
|
23666
24151
|
ingestBoundText(unit, text, [placeholder]);
|
|
23667
24152
|
}
|
|
@@ -23757,6 +24242,16 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23757
24242
|
else if (ast instanceof LiteralPrimitive) {
|
|
23758
24243
|
return literal(ast.value, undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
23759
24244
|
}
|
|
24245
|
+
else if (ast instanceof Unary) {
|
|
24246
|
+
switch (ast.operator) {
|
|
24247
|
+
case '+':
|
|
24248
|
+
return new UnaryOperatorExpr(UnaryOperator.Plus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
24249
|
+
case '-':
|
|
24250
|
+
return new UnaryOperatorExpr(UnaryOperator.Minus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
|
|
24251
|
+
default:
|
|
24252
|
+
throw new Error(`AssertionError: unknown unary operator ${ast.operator}`);
|
|
24253
|
+
}
|
|
24254
|
+
}
|
|
23760
24255
|
else if (ast instanceof Binary) {
|
|
23761
24256
|
const operator = BINARY_OPERATORS.get(ast.operation);
|
|
23762
24257
|
if (operator === undefined) {
|
|
@@ -23815,6 +24310,9 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23815
24310
|
else if (ast instanceof EmptyExpr$1) {
|
|
23816
24311
|
return new EmptyExpr(convertSourceSpan(ast.span, baseSourceSpan));
|
|
23817
24312
|
}
|
|
24313
|
+
else if (ast instanceof PrefixNot) {
|
|
24314
|
+
return not(convertAst(ast.expression, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
|
|
24315
|
+
}
|
|
23818
24316
|
else {
|
|
23819
24317
|
throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
|
|
23820
24318
|
}
|
|
@@ -23845,6 +24343,7 @@ function isPlainTemplate(tmpl) {
|
|
|
23845
24343
|
*/
|
|
23846
24344
|
function ingestBindings(unit, op, element) {
|
|
23847
24345
|
let flags = BindingFlags.None;
|
|
24346
|
+
let hasI18nAttributes = false;
|
|
23848
24347
|
if (element instanceof Template) {
|
|
23849
24348
|
flags |= BindingFlags.OnNgTemplateElement;
|
|
23850
24349
|
if (element instanceof Template && isPlainTemplate(element)) {
|
|
@@ -23853,10 +24352,12 @@ function ingestBindings(unit, op, element) {
|
|
|
23853
24352
|
const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
|
|
23854
24353
|
for (const attr of element.templateAttrs) {
|
|
23855
24354
|
if (attr instanceof TextAttribute) {
|
|
23856
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue);
|
|
24355
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue, attr.i18n);
|
|
24356
|
+
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
23857
24357
|
}
|
|
23858
24358
|
else {
|
|
23859
|
-
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags);
|
|
24359
|
+
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags, attr.i18n);
|
|
24360
|
+
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
23860
24361
|
}
|
|
23861
24362
|
}
|
|
23862
24363
|
}
|
|
@@ -23864,10 +24365,12 @@ function ingestBindings(unit, op, element) {
|
|
|
23864
24365
|
// This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
|
|
23865
24366
|
// `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
|
|
23866
24367
|
// `BindingType.Attribute`.
|
|
23867
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue);
|
|
24368
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue, attr.i18n);
|
|
24369
|
+
hasI18nAttributes ||= attr.i18n !== undefined;
|
|
23868
24370
|
}
|
|
23869
24371
|
for (const input of element.inputs) {
|
|
23870
|
-
ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, flags);
|
|
24372
|
+
ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, flags, input.i18n);
|
|
24373
|
+
hasI18nAttributes ||= input.i18n !== undefined;
|
|
23871
24374
|
}
|
|
23872
24375
|
for (const output of element.outputs) {
|
|
23873
24376
|
let listenerOp;
|
|
@@ -23877,7 +24380,7 @@ function ingestBindings(unit, op, element) {
|
|
|
23877
24380
|
}
|
|
23878
24381
|
}
|
|
23879
24382
|
if (element instanceof Template && !isPlainTemplate(element)) {
|
|
23880
|
-
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
|
|
24383
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null));
|
|
23881
24384
|
continue;
|
|
23882
24385
|
}
|
|
23883
24386
|
listenerOp = createListenerOp(op.xref, op.handle, output.name, op.tag, output.phase, false, output.sourceSpan);
|
|
@@ -23906,6 +24409,10 @@ function ingestBindings(unit, op, element) {
|
|
|
23906
24409
|
listenerOp.handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
23907
24410
|
unit.create.push(listenerOp);
|
|
23908
24411
|
}
|
|
24412
|
+
// TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
|
|
24413
|
+
if (hasI18nAttributes) {
|
|
24414
|
+
unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
|
|
24415
|
+
}
|
|
23909
24416
|
}
|
|
23910
24417
|
const BINDING_KINDS = new Map([
|
|
23911
24418
|
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
@@ -23934,22 +24441,34 @@ var BindingFlags;
|
|
|
23934
24441
|
*/
|
|
23935
24442
|
BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
|
|
23936
24443
|
})(BindingFlags || (BindingFlags = {}));
|
|
23937
|
-
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags) {
|
|
24444
|
+
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags, i18nMeta) {
|
|
23938
24445
|
if (value instanceof ASTWithSource) {
|
|
23939
24446
|
value = value.ast;
|
|
23940
24447
|
}
|
|
24448
|
+
let i18nContext = null;
|
|
24449
|
+
if (i18nMeta !== undefined) {
|
|
24450
|
+
if (!(i18nMeta instanceof Message)) {
|
|
24451
|
+
throw Error(`Unhandled i18n metadata type for binding: ${i18nMeta.constructor.name}`);
|
|
24452
|
+
}
|
|
24453
|
+
i18nContext = view.job.allocateXrefId();
|
|
24454
|
+
view.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, i18nMeta, null));
|
|
24455
|
+
}
|
|
23941
24456
|
if (flags & BindingFlags.OnNgTemplateElement && !(flags & BindingFlags.BindingTargetsTemplate) &&
|
|
23942
24457
|
type === 0 /* e.BindingType.Property */) {
|
|
23943
24458
|
// This binding only exists for later const extraction, and is not an actual binding to be
|
|
23944
24459
|
// created.
|
|
23945
|
-
view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null));
|
|
24460
|
+
view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null, i18nContext));
|
|
23946
24461
|
return;
|
|
23947
24462
|
}
|
|
23948
24463
|
let expression;
|
|
23949
24464
|
// TODO: We could easily generate source maps for subexpressions in these cases, but
|
|
23950
24465
|
// TemplateDefinitionBuilder does not. Should we do so?
|
|
23951
24466
|
if (value instanceof Interpolation$1) {
|
|
23952
|
-
|
|
24467
|
+
let i18nPlaceholders = [];
|
|
24468
|
+
if (i18nMeta !== undefined) {
|
|
24469
|
+
i18nPlaceholders = Object.keys(i18nMeta.placeholders);
|
|
24470
|
+
}
|
|
24471
|
+
expression = new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, view.job, null)), i18nPlaceholders);
|
|
23953
24472
|
}
|
|
23954
24473
|
else if (value instanceof AST) {
|
|
23955
24474
|
expression = convertAst(value, view.job, null);
|
|
@@ -23958,7 +24477,7 @@ function ingestBinding(view, xref, name, value, type, unit, securityContext, sou
|
|
|
23958
24477
|
expression = value;
|
|
23959
24478
|
}
|
|
23960
24479
|
const kind = BINDING_KINDS.get(type);
|
|
23961
|
-
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, !!(flags & BindingFlags.TextValue), !!(flags & BindingFlags.IsStructuralTemplateAttribute), sourceSpan));
|
|
24480
|
+
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, !!(flags & BindingFlags.TextValue), !!(flags & BindingFlags.IsStructuralTemplateAttribute), i18nContext, sourceSpan));
|
|
23962
24481
|
}
|
|
23963
24482
|
/**
|
|
23964
24483
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -24046,7 +24565,7 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
|
|
|
24046
24565
|
// and they can be used in directive matching (in the case of `Template.templateAttrs`).
|
|
24047
24566
|
if (root !== null) {
|
|
24048
24567
|
for (const attr of root.attributes) {
|
|
24049
|
-
ingestBinding(unit, xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue);
|
|
24568
|
+
ingestBinding(unit, xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue, attr.i18n);
|
|
24050
24569
|
}
|
|
24051
24570
|
const tagName = root instanceof Element$1 ? root.name : root.tagName;
|
|
24052
24571
|
// Don't pass along `ng-template` tag name since it enables directive matching.
|
|
@@ -27129,7 +27648,7 @@ class TemplateDefinitionBuilder {
|
|
|
27129
27648
|
else {
|
|
27130
27649
|
// ... otherwise we need to activate post-processing
|
|
27131
27650
|
// to replace ICU placeholders with proper values
|
|
27132
|
-
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
|
|
27651
|
+
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX$1}${key}`);
|
|
27133
27652
|
params[key] = literal(placeholder);
|
|
27134
27653
|
icuMapping[key] = literalArr(refs);
|
|
27135
27654
|
}
|
|
@@ -28749,24 +29268,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
28749
29268
|
return this.componentAccessCount;
|
|
28750
29269
|
}
|
|
28751
29270
|
}
|
|
28752
|
-
/**
|
|
28753
|
-
* Creates a `CssSelector` given a tag name and a map of attributes
|
|
28754
|
-
*/
|
|
28755
|
-
function createCssSelector(elementName, attributes) {
|
|
28756
|
-
const cssSelector = new CssSelector();
|
|
28757
|
-
const elementNameNoNs = splitNsName(elementName)[1];
|
|
28758
|
-
cssSelector.setElement(elementNameNoNs);
|
|
28759
|
-
Object.getOwnPropertyNames(attributes).forEach((name) => {
|
|
28760
|
-
const nameNoNs = splitNsName(name)[1];
|
|
28761
|
-
const value = attributes[name];
|
|
28762
|
-
cssSelector.addAttribute(nameNoNs, value);
|
|
28763
|
-
if (name.toLowerCase() === 'class') {
|
|
28764
|
-
const classes = value.trim().split(/\s+/);
|
|
28765
|
-
classes.forEach(className => cssSelector.addClassName(className));
|
|
28766
|
-
}
|
|
28767
|
-
});
|
|
28768
|
-
return cssSelector;
|
|
28769
|
-
}
|
|
28770
29271
|
/**
|
|
28771
29272
|
* Creates an array of expressions out of an `ngProjectAs` attributes
|
|
28772
29273
|
* which can be added to the instruction parameters.
|
|
@@ -29127,6 +29628,11 @@ function addFeatures(definitionMap, meta) {
|
|
|
29127
29628
|
break;
|
|
29128
29629
|
}
|
|
29129
29630
|
}
|
|
29631
|
+
// Note: host directives feature needs to be inserted before the
|
|
29632
|
+
// inheritance feature to ensure the correct execution order.
|
|
29633
|
+
if (meta.hostDirectives?.length) {
|
|
29634
|
+
features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
|
|
29635
|
+
}
|
|
29130
29636
|
if (meta.usesInheritance) {
|
|
29131
29637
|
features.push(importExpr(Identifiers.InheritDefinitionFeature));
|
|
29132
29638
|
}
|
|
@@ -29140,9 +29646,6 @@ function addFeatures(definitionMap, meta) {
|
|
|
29140
29646
|
if (meta.hasOwnProperty('template') && meta.isStandalone) {
|
|
29141
29647
|
features.push(importExpr(Identifiers.StandaloneFeature));
|
|
29142
29648
|
}
|
|
29143
|
-
if (meta.hostDirectives?.length) {
|
|
29144
|
-
features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
|
|
29145
|
-
}
|
|
29146
29649
|
if (features.length) {
|
|
29147
29650
|
definitionMap.set('features', literalArr(features));
|
|
29148
29651
|
}
|
|
@@ -29505,6 +30008,8 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29505
30008
|
}
|
|
29506
30009
|
return emitHostBindingFunction(hostJob);
|
|
29507
30010
|
}
|
|
30011
|
+
let bindingId = 0;
|
|
30012
|
+
const getNextBindingId = () => `${bindingId++}`;
|
|
29508
30013
|
const bindingContext = variable(CONTEXT_NAME);
|
|
29509
30014
|
const styleBuilder = new StylingBuilder(bindingContext);
|
|
29510
30015
|
const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
|
|
@@ -29557,7 +30062,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29557
30062
|
for (const binding of allOtherBindings) {
|
|
29558
30063
|
// resolve literal arrays and literal objects
|
|
29559
30064
|
const value = binding.expression.visit(getValueConverter());
|
|
29560
|
-
const bindingExpr = bindingFn(bindingContext, value);
|
|
30065
|
+
const bindingExpr = bindingFn(bindingContext, value, getNextBindingId);
|
|
29561
30066
|
const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
|
|
29562
30067
|
const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
|
|
29563
30068
|
.filter(context => context !== SecurityContext.NONE);
|
|
@@ -29636,10 +30141,12 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29636
30141
|
// at the top of this method when all the input bindings were counted.
|
|
29637
30142
|
totalHostVarsCount +=
|
|
29638
30143
|
Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
|
|
30144
|
+
const { params, stmts } = convertStylingCall(call, bindingContext, bindingFn, getNextBindingId);
|
|
30145
|
+
updateVariables.push(...stmts);
|
|
29639
30146
|
updateInstructions.push({
|
|
29640
30147
|
reference: instruction.reference,
|
|
29641
|
-
paramsOrFn:
|
|
29642
|
-
span: null
|
|
30148
|
+
paramsOrFn: params,
|
|
30149
|
+
span: null,
|
|
29643
30150
|
});
|
|
29644
30151
|
}
|
|
29645
30152
|
});
|
|
@@ -29660,11 +30167,19 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
29660
30167
|
}
|
|
29661
30168
|
return null;
|
|
29662
30169
|
}
|
|
29663
|
-
function bindingFn(implicit, value) {
|
|
29664
|
-
return convertPropertyBinding(null, implicit, value,
|
|
30170
|
+
function bindingFn(implicit, value, getNextBindingIdFn) {
|
|
30171
|
+
return convertPropertyBinding(null, implicit, value, getNextBindingIdFn());
|
|
29665
30172
|
}
|
|
29666
|
-
function convertStylingCall(call, bindingContext, bindingFn) {
|
|
29667
|
-
|
|
30173
|
+
function convertStylingCall(call, bindingContext, bindingFn, getNextBindingIdFn) {
|
|
30174
|
+
const stmts = [];
|
|
30175
|
+
const params = call.params(value => {
|
|
30176
|
+
const result = bindingFn(bindingContext, value, getNextBindingIdFn);
|
|
30177
|
+
if (Array.isArray(result.stmts) && result.stmts.length > 0) {
|
|
30178
|
+
stmts.push(...result.stmts);
|
|
30179
|
+
}
|
|
30180
|
+
return result.currValExpr;
|
|
30181
|
+
});
|
|
30182
|
+
return { params, stmts };
|
|
29668
30183
|
}
|
|
29669
30184
|
function getBindingNameAndInstruction(binding) {
|
|
29670
30185
|
let bindingName = binding.name;
|
|
@@ -30103,15 +30618,15 @@ class DirectiveBinder {
|
|
|
30103
30618
|
template.forEach(node => node.visit(this));
|
|
30104
30619
|
}
|
|
30105
30620
|
visitElement(element) {
|
|
30106
|
-
this.visitElementOrTemplate(element
|
|
30621
|
+
this.visitElementOrTemplate(element);
|
|
30107
30622
|
}
|
|
30108
30623
|
visitTemplate(template) {
|
|
30109
|
-
this.visitElementOrTemplate(
|
|
30624
|
+
this.visitElementOrTemplate(template);
|
|
30110
30625
|
}
|
|
30111
|
-
visitElementOrTemplate(
|
|
30626
|
+
visitElementOrTemplate(node) {
|
|
30112
30627
|
// First, determine the HTML shape of the node for the purpose of directive matching.
|
|
30113
30628
|
// Do this by building up a `CssSelector` for the node.
|
|
30114
|
-
const cssSelector =
|
|
30629
|
+
const cssSelector = createCssSelectorFromNode(node);
|
|
30115
30630
|
// Next, use the `SelectorMatcher` to get the list of directives on the node.
|
|
30116
30631
|
const directives = [];
|
|
30117
30632
|
this.matcher.match(cssSelector, (_selector, results) => directives.push(...results));
|
|
@@ -31240,7 +31755,7 @@ function publishFacade(global) {
|
|
|
31240
31755
|
* @description
|
|
31241
31756
|
* Entry point for all public APIs of the compiler package.
|
|
31242
31757
|
*/
|
|
31243
|
-
const VERSION = new Version('17.1.0-next.
|
|
31758
|
+
const VERSION = new Version('17.1.0-next.3');
|
|
31244
31759
|
|
|
31245
31760
|
class CompilerConfig {
|
|
31246
31761
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -32806,7 +33321,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
32806
33321
|
function compileDeclareClassMetadata(metadata) {
|
|
32807
33322
|
const definitionMap = new DefinitionMap();
|
|
32808
33323
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
32809
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33324
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
32810
33325
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32811
33326
|
definitionMap.set('type', metadata.type);
|
|
32812
33327
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -32914,7 +33429,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
32914
33429
|
// in 16.1 is actually used.
|
|
32915
33430
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
32916
33431
|
definitionMap.set('minVersion', literal(minVersion));
|
|
32917
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33432
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
32918
33433
|
// e.g. `type: MyDirective`
|
|
32919
33434
|
definitionMap.set('type', meta.type.value);
|
|
32920
33435
|
if (meta.isStandalone) {
|
|
@@ -33191,7 +33706,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
33191
33706
|
function compileDeclareFactoryFunction(meta) {
|
|
33192
33707
|
const definitionMap = new DefinitionMap();
|
|
33193
33708
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
33194
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33709
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
33195
33710
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33196
33711
|
definitionMap.set('type', meta.type.value);
|
|
33197
33712
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -33226,7 +33741,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
33226
33741
|
function createInjectableDefinitionMap(meta) {
|
|
33227
33742
|
const definitionMap = new DefinitionMap();
|
|
33228
33743
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
33229
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33744
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
33230
33745
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33231
33746
|
definitionMap.set('type', meta.type.value);
|
|
33232
33747
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -33277,7 +33792,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
33277
33792
|
function createInjectorDefinitionMap(meta) {
|
|
33278
33793
|
const definitionMap = new DefinitionMap();
|
|
33279
33794
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
33280
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33795
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
33281
33796
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33282
33797
|
definitionMap.set('type', meta.type.value);
|
|
33283
33798
|
definitionMap.set('providers', meta.providers);
|
|
@@ -33310,7 +33825,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
33310
33825
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
33311
33826
|
}
|
|
33312
33827
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
33313
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33828
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
33314
33829
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33315
33830
|
definitionMap.set('type', meta.type.value);
|
|
33316
33831
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -33361,7 +33876,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
33361
33876
|
function createPipeDefinitionMap(meta) {
|
|
33362
33877
|
const definitionMap = new DefinitionMap();
|
|
33363
33878
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
33364
|
-
definitionMap.set('version', literal('17.1.0-next.
|
|
33879
|
+
definitionMap.set('version', literal('17.1.0-next.3'));
|
|
33365
33880
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33366
33881
|
// e.g. `type: MyPipe`
|
|
33367
33882
|
definitionMap.set('type', meta.type.value);
|
|
@@ -33394,5 +33909,5 @@ publishFacade(_global);
|
|
|
33394
33909
|
|
|
33395
33910
|
// This file is not used to build this module. It is only used during editing
|
|
33396
33911
|
|
|
33397
|
-
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, 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 };
|
|
33912
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, UnknownBlock as TmplAstUnknownBlock, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createCssSelectorFromNode, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
33398
33913
|
//# sourceMappingURL=compiler.mjs.map
|