@angular-eslint/bundled-angular-compiler 17.1.2-alpha.6 → 17.1.2-alpha.7
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/dist/index.js +1568 -622
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @license Angular v17.0.
|
|
4
|
+
* @license Angular v17.0.8
|
|
5
5
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
6
6
|
* License: MIT
|
|
7
7
|
*/
|
|
@@ -541,6 +541,9 @@ class _SerializerVisitor {
|
|
|
541
541
|
visitIcuPlaceholder(ph, context) {
|
|
542
542
|
return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
|
|
543
543
|
}
|
|
544
|
+
visitBlockPlaceholder(ph, context) {
|
|
545
|
+
return `<ph block name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
|
|
546
|
+
}
|
|
544
547
|
}
|
|
545
548
|
const serializerVisitor$1 = new _SerializerVisitor();
|
|
546
549
|
function serializeNodes(nodes) {
|
|
@@ -2307,7 +2310,9 @@ class ConstantPool {
|
|
|
2307
2310
|
}))));
|
|
2308
2311
|
}
|
|
2309
2312
|
}
|
|
2310
|
-
|
|
2313
|
+
// TODO: useUniqueName(false) is necessary for naming compatibility with
|
|
2314
|
+
// TemplateDefinitionBuilder, but should be removed once Template Pipeline is the default.
|
|
2315
|
+
getSharedFunctionReference(fn, prefix, useUniqueName = true) {
|
|
2311
2316
|
const isArrow = fn instanceof ArrowFunctionExpr;
|
|
2312
2317
|
for (const current of this.statements) {
|
|
2313
2318
|
// Arrow functions are saved as variables so we check if the
|
|
@@ -2322,7 +2327,7 @@ class ConstantPool {
|
|
|
2322
2327
|
}
|
|
2323
2328
|
}
|
|
2324
2329
|
// Otherwise declare the function.
|
|
2325
|
-
const name = this.uniqueName(prefix);
|
|
2330
|
+
const name = useUniqueName ? this.uniqueName(prefix) : prefix;
|
|
2326
2331
|
this.statements.push(fn.toDeclStmt(name, exports.StmtModifier.Final));
|
|
2327
2332
|
return variable(name);
|
|
2328
2333
|
}
|
|
@@ -3667,6 +3672,46 @@ function getInjectFn(target) {
|
|
|
3667
3672
|
}
|
|
3668
3673
|
}
|
|
3669
3674
|
|
|
3675
|
+
exports.TagContentType = void 0;
|
|
3676
|
+
(function (TagContentType) {
|
|
3677
|
+
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
3678
|
+
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
3679
|
+
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
3680
|
+
})(exports.TagContentType || (exports.TagContentType = {}));
|
|
3681
|
+
function splitNsName(elementName, fatal = true) {
|
|
3682
|
+
if (elementName[0] != ':') {
|
|
3683
|
+
return [null, elementName];
|
|
3684
|
+
}
|
|
3685
|
+
const colonIndex = elementName.indexOf(':', 1);
|
|
3686
|
+
if (colonIndex === -1) {
|
|
3687
|
+
if (fatal) {
|
|
3688
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
3689
|
+
}
|
|
3690
|
+
else {
|
|
3691
|
+
return [null, elementName];
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
3695
|
+
}
|
|
3696
|
+
// `<ng-container>` tags work the same regardless the namespace
|
|
3697
|
+
function isNgContainer(tagName) {
|
|
3698
|
+
return splitNsName(tagName)[1] === 'ng-container';
|
|
3699
|
+
}
|
|
3700
|
+
// `<ng-content>` tags work the same regardless the namespace
|
|
3701
|
+
function isNgContent(tagName) {
|
|
3702
|
+
return splitNsName(tagName)[1] === 'ng-content';
|
|
3703
|
+
}
|
|
3704
|
+
// `<ng-template>` tags work the same regardless the namespace
|
|
3705
|
+
function isNgTemplate(tagName) {
|
|
3706
|
+
return splitNsName(tagName)[1] === 'ng-template';
|
|
3707
|
+
}
|
|
3708
|
+
function getNsPrefix(fullName) {
|
|
3709
|
+
return fullName === null ? null : splitNsName(fullName)[0];
|
|
3710
|
+
}
|
|
3711
|
+
function mergeNsAndName(prefix, localName) {
|
|
3712
|
+
return prefix ? `:${prefix}:${localName}` : localName;
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3670
3715
|
/**
|
|
3671
3716
|
* This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently
|
|
3672
3717
|
* require the implementation of a visitor for Comments as they are only collected at
|
|
@@ -3838,43 +3883,47 @@ class BlockNode {
|
|
|
3838
3883
|
}
|
|
3839
3884
|
}
|
|
3840
3885
|
class DeferredBlockPlaceholder extends BlockNode {
|
|
3841
|
-
constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3886
|
+
constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
3842
3887
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3843
3888
|
this.children = children;
|
|
3844
3889
|
this.minimumTime = minimumTime;
|
|
3890
|
+
this.i18n = i18n;
|
|
3845
3891
|
}
|
|
3846
3892
|
visit(visitor) {
|
|
3847
3893
|
return visitor.visitDeferredBlockPlaceholder(this);
|
|
3848
3894
|
}
|
|
3849
3895
|
}
|
|
3850
3896
|
class DeferredBlockLoading extends BlockNode {
|
|
3851
|
-
constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3897
|
+
constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
3852
3898
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3853
3899
|
this.children = children;
|
|
3854
3900
|
this.afterTime = afterTime;
|
|
3855
3901
|
this.minimumTime = minimumTime;
|
|
3902
|
+
this.i18n = i18n;
|
|
3856
3903
|
}
|
|
3857
3904
|
visit(visitor) {
|
|
3858
3905
|
return visitor.visitDeferredBlockLoading(this);
|
|
3859
3906
|
}
|
|
3860
3907
|
}
|
|
3861
3908
|
class DeferredBlockError extends BlockNode {
|
|
3862
|
-
constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3909
|
+
constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
3863
3910
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3864
3911
|
this.children = children;
|
|
3912
|
+
this.i18n = i18n;
|
|
3865
3913
|
}
|
|
3866
3914
|
visit(visitor) {
|
|
3867
3915
|
return visitor.visitDeferredBlockError(this);
|
|
3868
3916
|
}
|
|
3869
3917
|
}
|
|
3870
3918
|
class DeferredBlock extends BlockNode {
|
|
3871
|
-
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3919
|
+
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
3872
3920
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3873
3921
|
this.children = children;
|
|
3874
3922
|
this.placeholder = placeholder;
|
|
3875
3923
|
this.loading = loading;
|
|
3876
3924
|
this.error = error;
|
|
3877
3925
|
this.mainBlockSpan = mainBlockSpan;
|
|
3926
|
+
this.i18n = i18n;
|
|
3878
3927
|
this.triggers = triggers;
|
|
3879
3928
|
this.prefetchTriggers = prefetchTriggers;
|
|
3880
3929
|
// We cache the keys since we know that they won't change and we
|
|
@@ -3913,17 +3962,18 @@ class SwitchBlock extends BlockNode {
|
|
|
3913
3962
|
}
|
|
3914
3963
|
}
|
|
3915
3964
|
class SwitchBlockCase extends BlockNode {
|
|
3916
|
-
constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3965
|
+
constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
|
|
3917
3966
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3918
3967
|
this.expression = expression;
|
|
3919
3968
|
this.children = children;
|
|
3969
|
+
this.i18n = i18n;
|
|
3920
3970
|
}
|
|
3921
3971
|
visit(visitor) {
|
|
3922
3972
|
return visitor.visitSwitchBlockCase(this);
|
|
3923
3973
|
}
|
|
3924
3974
|
}
|
|
3925
3975
|
class ForLoopBlock extends BlockNode {
|
|
3926
|
-
constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3976
|
+
constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
|
|
3927
3977
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3928
3978
|
this.item = item;
|
|
3929
3979
|
this.expression = expression;
|
|
@@ -3933,15 +3983,17 @@ class ForLoopBlock extends BlockNode {
|
|
|
3933
3983
|
this.children = children;
|
|
3934
3984
|
this.empty = empty;
|
|
3935
3985
|
this.mainBlockSpan = mainBlockSpan;
|
|
3986
|
+
this.i18n = i18n;
|
|
3936
3987
|
}
|
|
3937
3988
|
visit(visitor) {
|
|
3938
3989
|
return visitor.visitForLoopBlock(this);
|
|
3939
3990
|
}
|
|
3940
3991
|
}
|
|
3941
3992
|
class ForLoopBlockEmpty extends BlockNode {
|
|
3942
|
-
constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3993
|
+
constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
|
|
3943
3994
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3944
3995
|
this.children = children;
|
|
3996
|
+
this.i18n = i18n;
|
|
3945
3997
|
}
|
|
3946
3998
|
visit(visitor) {
|
|
3947
3999
|
return visitor.visitForLoopBlockEmpty(this);
|
|
@@ -3957,11 +4009,12 @@ class IfBlock extends BlockNode {
|
|
|
3957
4009
|
}
|
|
3958
4010
|
}
|
|
3959
4011
|
class IfBlockBranch extends BlockNode {
|
|
3960
|
-
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
4012
|
+
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
|
|
3961
4013
|
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3962
4014
|
this.expression = expression;
|
|
3963
4015
|
this.children = children;
|
|
3964
4016
|
this.expressionAlias = expressionAlias;
|
|
4017
|
+
this.i18n = i18n;
|
|
3965
4018
|
}
|
|
3966
4019
|
visit(visitor) {
|
|
3967
4020
|
return visitor.visitIfBlockBranch(this);
|
|
@@ -4231,6 +4284,21 @@ class IcuPlaceholder {
|
|
|
4231
4284
|
return visitor.visitIcuPlaceholder(this, context);
|
|
4232
4285
|
}
|
|
4233
4286
|
}
|
|
4287
|
+
class BlockPlaceholder {
|
|
4288
|
+
constructor(name, parameters, startName, closeName, children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4289
|
+
this.name = name;
|
|
4290
|
+
this.parameters = parameters;
|
|
4291
|
+
this.startName = startName;
|
|
4292
|
+
this.closeName = closeName;
|
|
4293
|
+
this.children = children;
|
|
4294
|
+
this.sourceSpan = sourceSpan;
|
|
4295
|
+
this.startSourceSpan = startSourceSpan;
|
|
4296
|
+
this.endSourceSpan = endSourceSpan;
|
|
4297
|
+
}
|
|
4298
|
+
visit(visitor, context) {
|
|
4299
|
+
return visitor.visitBlockPlaceholder(this, context);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4234
4302
|
// Clone the AST
|
|
4235
4303
|
class CloneVisitor {
|
|
4236
4304
|
visitText(text, context) {
|
|
@@ -4256,6 +4324,10 @@ class CloneVisitor {
|
|
|
4256
4324
|
visitIcuPlaceholder(ph, context) {
|
|
4257
4325
|
return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
|
|
4258
4326
|
}
|
|
4327
|
+
visitBlockPlaceholder(ph, context) {
|
|
4328
|
+
const children = ph.children.map(n => n.visit(this, context));
|
|
4329
|
+
return new BlockPlaceholder(ph.name, ph.parameters, ph.startName, ph.closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
|
|
4330
|
+
}
|
|
4259
4331
|
}
|
|
4260
4332
|
// Visit all the nodes recursively
|
|
4261
4333
|
class RecurseVisitor {
|
|
@@ -4273,6 +4345,9 @@ class RecurseVisitor {
|
|
|
4273
4345
|
}
|
|
4274
4346
|
visitPlaceholder(ph, context) { }
|
|
4275
4347
|
visitIcuPlaceholder(ph, context) { }
|
|
4348
|
+
visitBlockPlaceholder(ph, context) {
|
|
4349
|
+
ph.children.forEach(child => child.visit(this));
|
|
4350
|
+
}
|
|
4276
4351
|
}
|
|
4277
4352
|
/**
|
|
4278
4353
|
* Serialize the message to the Localize backtick string format that would appear in compiled code.
|
|
@@ -4303,6 +4378,10 @@ class LocalizeMessageStringVisitor {
|
|
|
4303
4378
|
visitIcuPlaceholder(ph) {
|
|
4304
4379
|
return `{$${ph.name}}`;
|
|
4305
4380
|
}
|
|
4381
|
+
visitBlockPlaceholder(ph) {
|
|
4382
|
+
const children = ph.children.map(child => child.visit(this)).join('');
|
|
4383
|
+
return `{$${ph.startName}}${children}{$${ph.closeName}}`;
|
|
4384
|
+
}
|
|
4306
4385
|
}
|
|
4307
4386
|
|
|
4308
4387
|
class Serializer {
|
|
@@ -4345,6 +4424,11 @@ class SimplePlaceholderMapper extends RecurseVisitor {
|
|
|
4345
4424
|
visitPlaceholder(ph, context) {
|
|
4346
4425
|
this.visitPlaceholderName(ph.name);
|
|
4347
4426
|
}
|
|
4427
|
+
visitBlockPlaceholder(ph, context) {
|
|
4428
|
+
this.visitPlaceholderName(ph.startName);
|
|
4429
|
+
super.visitBlockPlaceholder(ph, context);
|
|
4430
|
+
this.visitPlaceholderName(ph.closeName);
|
|
4431
|
+
}
|
|
4348
4432
|
visitIcuPlaceholder(ph, context) {
|
|
4349
4433
|
this.visitPlaceholderName(ph.name);
|
|
4350
4434
|
}
|
|
@@ -4557,6 +4641,17 @@ class _Visitor$1 {
|
|
|
4557
4641
|
new Tag(_PLACEHOLDER_TAG$3, { name: ph.name }, [exTag, interpolationAsText])
|
|
4558
4642
|
];
|
|
4559
4643
|
}
|
|
4644
|
+
visitBlockPlaceholder(ph, context) {
|
|
4645
|
+
const startAsText = new Text$1(`@${ph.name}`);
|
|
4646
|
+
const startEx = new Tag(_EXAMPLE_TAG, {}, [startAsText]);
|
|
4647
|
+
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
4648
|
+
const startTagPh = new Tag(_PLACEHOLDER_TAG$3, { name: ph.startName }, [startEx, startAsText]);
|
|
4649
|
+
const closeAsText = new Text$1(`}`);
|
|
4650
|
+
const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeAsText]);
|
|
4651
|
+
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
4652
|
+
const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, { name: ph.closeName }, [closeEx, closeAsText]);
|
|
4653
|
+
return [startTagPh, ...this.serialize(ph.children), closeTagPh];
|
|
4654
|
+
}
|
|
4560
4655
|
visitIcuPlaceholder(ph, context) {
|
|
4561
4656
|
const icuExpression = ph.value.expression;
|
|
4562
4657
|
const icuType = ph.value.type;
|
|
@@ -4615,7 +4710,7 @@ const I18N_ATTR_PREFIX = 'i18n-';
|
|
|
4615
4710
|
/** Prefix of var expressions used in ICUs */
|
|
4616
4711
|
const I18N_ICU_VAR_PREFIX = 'VAR_';
|
|
4617
4712
|
/** Prefix of ICU expressions for post processing */
|
|
4618
|
-
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
4713
|
+
const I18N_ICU_MAPPING_PREFIX$1 = 'I18N_EXP_';
|
|
4619
4714
|
/** Placeholder wrapper for i18n expressions **/
|
|
4620
4715
|
const I18N_PLACEHOLDER_SYMBOL = '�';
|
|
4621
4716
|
function isI18nAttribute(name) {
|
|
@@ -4957,6 +5052,26 @@ class DefinitionMap {
|
|
|
4957
5052
|
return literalMap(this.values);
|
|
4958
5053
|
}
|
|
4959
5054
|
}
|
|
5055
|
+
/**
|
|
5056
|
+
* Creates a `CssSelector` from an AST node.
|
|
5057
|
+
*/
|
|
5058
|
+
function createCssSelectorFromNode(node) {
|
|
5059
|
+
const elementName = node instanceof Element$1 ? node.name : 'ng-template';
|
|
5060
|
+
const attributes = getAttrsForDirectiveMatching(node);
|
|
5061
|
+
const cssSelector = new CssSelector();
|
|
5062
|
+
const elementNameNoNs = splitNsName(elementName)[1];
|
|
5063
|
+
cssSelector.setElement(elementNameNoNs);
|
|
5064
|
+
Object.getOwnPropertyNames(attributes).forEach((name) => {
|
|
5065
|
+
const nameNoNs = splitNsName(name)[1];
|
|
5066
|
+
const value = attributes[name];
|
|
5067
|
+
cssSelector.addAttribute(nameNoNs, value);
|
|
5068
|
+
if (name.toLowerCase() === 'class') {
|
|
5069
|
+
const classes = value.trim().split(/\s+/);
|
|
5070
|
+
classes.forEach(className => cssSelector.addClassName(className));
|
|
5071
|
+
}
|
|
5072
|
+
});
|
|
5073
|
+
return cssSelector;
|
|
5074
|
+
}
|
|
4960
5075
|
/**
|
|
4961
5076
|
* Extract a map of properties to values for a given element or template node, which can be used
|
|
4962
5077
|
* by the directive matching machinery.
|
|
@@ -5202,6 +5317,7 @@ class InterpolationConfig {
|
|
|
5202
5317
|
}
|
|
5203
5318
|
}
|
|
5204
5319
|
const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
|
|
5320
|
+
const DEFAULT_CONTAINER_BLOCKS = new Set(['switch']);
|
|
5205
5321
|
|
|
5206
5322
|
const $EOF = 0;
|
|
5207
5323
|
const $BSPACE = 8;
|
|
@@ -8800,15 +8916,23 @@ var OpKind;
|
|
|
8800
8916
|
/**
|
|
8801
8917
|
* An instruction to create an ICU expression.
|
|
8802
8918
|
*/
|
|
8803
|
-
OpKind[OpKind["
|
|
8919
|
+
OpKind[OpKind["IcuStart"] = 41] = "IcuStart";
|
|
8804
8920
|
/**
|
|
8805
8921
|
* An instruction to update an ICU expression.
|
|
8806
8922
|
*/
|
|
8807
|
-
OpKind[OpKind["
|
|
8923
|
+
OpKind[OpKind["IcuEnd"] = 42] = "IcuEnd";
|
|
8924
|
+
/**
|
|
8925
|
+
* An instruction representing a placeholder in an ICU expression.
|
|
8926
|
+
*/
|
|
8927
|
+
OpKind[OpKind["IcuPlaceholder"] = 43] = "IcuPlaceholder";
|
|
8808
8928
|
/**
|
|
8809
8929
|
* An i18n context containing information needed to generate an i18n message.
|
|
8810
8930
|
*/
|
|
8811
|
-
OpKind[OpKind["I18nContext"] =
|
|
8931
|
+
OpKind[OpKind["I18nContext"] = 44] = "I18nContext";
|
|
8932
|
+
/**
|
|
8933
|
+
* A creation op that corresponds to i18n attributes on an element.
|
|
8934
|
+
*/
|
|
8935
|
+
OpKind[OpKind["I18nAttributes"] = 45] = "I18nAttributes";
|
|
8812
8936
|
})(OpKind || (OpKind = {}));
|
|
8813
8937
|
/**
|
|
8814
8938
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -8899,23 +9023,27 @@ var ExpressionKind;
|
|
|
8899
9023
|
* An expression representing a sanitizer function.
|
|
8900
9024
|
*/
|
|
8901
9025
|
ExpressionKind[ExpressionKind["SanitizerExpr"] = 20] = "SanitizerExpr";
|
|
9026
|
+
/**
|
|
9027
|
+
* An expression representing a function to create trusted values.
|
|
9028
|
+
*/
|
|
9029
|
+
ExpressionKind[ExpressionKind["TrustedValueFnExpr"] = 21] = "TrustedValueFnExpr";
|
|
8902
9030
|
/**
|
|
8903
9031
|
* An expression that will cause a literal slot index to be emitted.
|
|
8904
9032
|
*/
|
|
8905
|
-
ExpressionKind[ExpressionKind["SlotLiteralExpr"] =
|
|
9033
|
+
ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
|
|
8906
9034
|
/**
|
|
8907
9035
|
* A test expression for a conditional op.
|
|
8908
9036
|
*/
|
|
8909
|
-
ExpressionKind[ExpressionKind["ConditionalCase"] =
|
|
9037
|
+
ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
|
|
8910
9038
|
/**
|
|
8911
9039
|
* A variable for use inside a repeater, providing one of the ambiently-available context
|
|
8912
9040
|
* properties ($even, $first, etc.).
|
|
8913
9041
|
*/
|
|
8914
|
-
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] =
|
|
9042
|
+
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 24] = "DerivedRepeaterVar";
|
|
8915
9043
|
/**
|
|
8916
9044
|
* An expression that will be automatically extracted to the component const array.
|
|
8917
9045
|
*/
|
|
8918
|
-
ExpressionKind[ExpressionKind["ConstCollected"] =
|
|
9046
|
+
ExpressionKind[ExpressionKind["ConstCollected"] = 25] = "ConstCollected";
|
|
8919
9047
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
8920
9048
|
var VariableFlags;
|
|
8921
9049
|
(function (VariableFlags) {
|
|
@@ -8959,18 +9087,6 @@ var CompatibilityMode;
|
|
|
8959
9087
|
CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
|
|
8960
9088
|
CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
|
|
8961
9089
|
})(CompatibilityMode || (CompatibilityMode = {}));
|
|
8962
|
-
/**
|
|
8963
|
-
* Represents functions used to sanitize different pieces of a template.
|
|
8964
|
-
*/
|
|
8965
|
-
var SanitizerFn;
|
|
8966
|
-
(function (SanitizerFn) {
|
|
8967
|
-
SanitizerFn[SanitizerFn["Html"] = 0] = "Html";
|
|
8968
|
-
SanitizerFn[SanitizerFn["Script"] = 1] = "Script";
|
|
8969
|
-
SanitizerFn[SanitizerFn["Style"] = 2] = "Style";
|
|
8970
|
-
SanitizerFn[SanitizerFn["Url"] = 3] = "Url";
|
|
8971
|
-
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
8972
|
-
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
8973
|
-
})(SanitizerFn || (SanitizerFn = {}));
|
|
8974
9090
|
/**
|
|
8975
9091
|
* Enumeration of the different kinds of `@defer` secondary blocks.
|
|
8976
9092
|
*/
|
|
@@ -9030,6 +9146,20 @@ var I18nParamResolutionTime;
|
|
|
9030
9146
|
*/
|
|
9031
9147
|
I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
|
|
9032
9148
|
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
|
|
9149
|
+
/**
|
|
9150
|
+
* The contexts in which an i18n expression can be used.
|
|
9151
|
+
*/
|
|
9152
|
+
var I18nExpressionFor;
|
|
9153
|
+
(function (I18nExpressionFor) {
|
|
9154
|
+
/**
|
|
9155
|
+
* This expression is used as a value (i.e. inside an i18n block).
|
|
9156
|
+
*/
|
|
9157
|
+
I18nExpressionFor[I18nExpressionFor["I18nText"] = 0] = "I18nText";
|
|
9158
|
+
/**
|
|
9159
|
+
* This expression is used in a binding.
|
|
9160
|
+
*/
|
|
9161
|
+
I18nExpressionFor[I18nExpressionFor["I18nAttribute"] = 1] = "I18nAttribute";
|
|
9162
|
+
})(I18nExpressionFor || (I18nExpressionFor = {}));
|
|
9033
9163
|
/**
|
|
9034
9164
|
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
9035
9165
|
* the final map.
|
|
@@ -9053,6 +9183,10 @@ var I18nParamValueFlags;
|
|
|
9053
9183
|
* This value represents the closing of a tag.
|
|
9054
9184
|
*/
|
|
9055
9185
|
I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
|
|
9186
|
+
/**
|
|
9187
|
+
* This value represents an i18n expression index.
|
|
9188
|
+
*/
|
|
9189
|
+
I18nParamValueFlags[I18nParamValueFlags["ExpressionIndex"] = 16] = "ExpressionIndex";
|
|
9056
9190
|
})(I18nParamValueFlags || (I18nParamValueFlags = {}));
|
|
9057
9191
|
/**
|
|
9058
9192
|
* Whether the active namespace is HTML, MathML, or SVG mode.
|
|
@@ -9085,6 +9219,21 @@ var DerivedRepeaterVarIdentity;
|
|
|
9085
9219
|
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
9086
9220
|
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
9087
9221
|
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
9222
|
+
/**
|
|
9223
|
+
* Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
|
|
9224
|
+
*/
|
|
9225
|
+
var I18nContextKind;
|
|
9226
|
+
(function (I18nContextKind) {
|
|
9227
|
+
I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
|
|
9228
|
+
I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
|
|
9229
|
+
I18nContextKind[I18nContextKind["Attr"] = 2] = "Attr";
|
|
9230
|
+
})(I18nContextKind || (I18nContextKind = {}));
|
|
9231
|
+
var TemplateKind;
|
|
9232
|
+
(function (TemplateKind) {
|
|
9233
|
+
TemplateKind[TemplateKind["NgTemplate"] = 0] = "NgTemplate";
|
|
9234
|
+
TemplateKind[TemplateKind["Structural"] = 1] = "Structural";
|
|
9235
|
+
TemplateKind[TemplateKind["Block"] = 2] = "Block";
|
|
9236
|
+
})(TemplateKind || (TemplateKind = {}));
|
|
9088
9237
|
|
|
9089
9238
|
/**
|
|
9090
9239
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9181,15 +9330,19 @@ const NEW_OP = {
|
|
|
9181
9330
|
next: null,
|
|
9182
9331
|
};
|
|
9183
9332
|
class Interpolation {
|
|
9184
|
-
constructor(strings, expressions) {
|
|
9333
|
+
constructor(strings, expressions, i18nPlaceholders) {
|
|
9185
9334
|
this.strings = strings;
|
|
9186
9335
|
this.expressions = expressions;
|
|
9336
|
+
this.i18nPlaceholders = i18nPlaceholders;
|
|
9337
|
+
if (i18nPlaceholders.length !== 0 && i18nPlaceholders.length !== expressions.length) {
|
|
9338
|
+
throw new Error(`Expected ${expressions.length} placeholders to match interpolation expression count, but got ${i18nPlaceholders.length}`);
|
|
9339
|
+
}
|
|
9187
9340
|
}
|
|
9188
9341
|
}
|
|
9189
9342
|
/**
|
|
9190
9343
|
* Create a `PropertyOp`.
|
|
9191
9344
|
*/
|
|
9192
|
-
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext,
|
|
9345
|
+
function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
|
|
9193
9346
|
return {
|
|
9194
9347
|
kind: OpKind.Property,
|
|
9195
9348
|
target,
|
|
@@ -9198,7 +9351,10 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
|
|
|
9198
9351
|
isAnimationTrigger,
|
|
9199
9352
|
securityContext,
|
|
9200
9353
|
sanitizer: null,
|
|
9201
|
-
|
|
9354
|
+
isStructuralTemplateAttribute,
|
|
9355
|
+
templateKind,
|
|
9356
|
+
i18nContext,
|
|
9357
|
+
i18nMessage,
|
|
9202
9358
|
sourceSpan,
|
|
9203
9359
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9204
9360
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9263,7 +9419,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9263
9419
|
/**
|
|
9264
9420
|
* Create an `AttributeOp`.
|
|
9265
9421
|
*/
|
|
9266
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute,
|
|
9422
|
+
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9267
9423
|
return {
|
|
9268
9424
|
kind: OpKind.Attribute,
|
|
9269
9425
|
target,
|
|
@@ -9272,7 +9428,10 @@ function createAttributeOp(target, name, expression, securityContext, isTextAttr
|
|
|
9272
9428
|
securityContext,
|
|
9273
9429
|
sanitizer: null,
|
|
9274
9430
|
isTextAttribute,
|
|
9275
|
-
|
|
9431
|
+
isStructuralTemplateAttribute,
|
|
9432
|
+
templateKind,
|
|
9433
|
+
i18nContext: null,
|
|
9434
|
+
i18nMessage,
|
|
9276
9435
|
sourceSpan,
|
|
9277
9436
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9278
9437
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9293,15 +9452,19 @@ function createAdvanceOp(delta, sourceSpan) {
|
|
|
9293
9452
|
/**
|
|
9294
9453
|
* Create an i18n expression op.
|
|
9295
9454
|
*/
|
|
9296
|
-
function createI18nExpressionOp(context, target, handle, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9455
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9297
9456
|
return {
|
|
9298
9457
|
kind: OpKind.I18nExpression,
|
|
9299
9458
|
context,
|
|
9300
9459
|
target,
|
|
9460
|
+
i18nOwner,
|
|
9301
9461
|
handle,
|
|
9302
9462
|
expression,
|
|
9463
|
+
icuPlaceholder,
|
|
9303
9464
|
i18nPlaceholder,
|
|
9304
9465
|
resolutionTime,
|
|
9466
|
+
usage,
|
|
9467
|
+
name,
|
|
9305
9468
|
sourceSpan,
|
|
9306
9469
|
...NEW_OP,
|
|
9307
9470
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9309,12 +9472,12 @@ function createI18nExpressionOp(context, target, handle, expression, i18nPlaceho
|
|
|
9309
9472
|
};
|
|
9310
9473
|
}
|
|
9311
9474
|
/**
|
|
9312
|
-
*Creates an op to apply i18n expression ops
|
|
9475
|
+
* Creates an op to apply i18n expression ops.
|
|
9313
9476
|
*/
|
|
9314
|
-
function createI18nApplyOp(
|
|
9477
|
+
function createI18nApplyOp(owner, handle, sourceSpan) {
|
|
9315
9478
|
return {
|
|
9316
9479
|
kind: OpKind.I18nApply,
|
|
9317
|
-
|
|
9480
|
+
owner,
|
|
9318
9481
|
handle,
|
|
9319
9482
|
sourceSpan,
|
|
9320
9483
|
...NEW_OP,
|
|
@@ -9863,24 +10026,6 @@ class ReadTemporaryExpr extends ExpressionBase {
|
|
|
9863
10026
|
return r;
|
|
9864
10027
|
}
|
|
9865
10028
|
}
|
|
9866
|
-
class SanitizerExpr extends ExpressionBase {
|
|
9867
|
-
constructor(fn) {
|
|
9868
|
-
super();
|
|
9869
|
-
this.fn = fn;
|
|
9870
|
-
this.kind = ExpressionKind.SanitizerExpr;
|
|
9871
|
-
}
|
|
9872
|
-
visitExpression(visitor, context) { }
|
|
9873
|
-
isEquivalent(e) {
|
|
9874
|
-
return e instanceof SanitizerExpr && e.fn === this.fn;
|
|
9875
|
-
}
|
|
9876
|
-
isConstant() {
|
|
9877
|
-
return true;
|
|
9878
|
-
}
|
|
9879
|
-
clone() {
|
|
9880
|
-
return new SanitizerExpr(this.fn);
|
|
9881
|
-
}
|
|
9882
|
-
transformInternalExpressions() { }
|
|
9883
|
-
}
|
|
9884
10029
|
class SlotLiteralExpr extends ExpressionBase {
|
|
9885
10030
|
constructor(slot) {
|
|
9886
10031
|
super();
|
|
@@ -9977,7 +10122,6 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9977
10122
|
case OpKind.ClassProp:
|
|
9978
10123
|
case OpKind.ClassMap:
|
|
9979
10124
|
case OpKind.Binding:
|
|
9980
|
-
case OpKind.HostProperty:
|
|
9981
10125
|
if (op.expression instanceof Interpolation) {
|
|
9982
10126
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
9983
10127
|
}
|
|
@@ -9986,6 +10130,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9986
10130
|
}
|
|
9987
10131
|
break;
|
|
9988
10132
|
case OpKind.Property:
|
|
10133
|
+
case OpKind.HostProperty:
|
|
9989
10134
|
case OpKind.Attribute:
|
|
9990
10135
|
if (op.expression instanceof Interpolation) {
|
|
9991
10136
|
transformExpressionsInInterpolation(op.expression, transform, flags);
|
|
@@ -10031,6 +10176,8 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10031
10176
|
case OpKind.ExtractedAttribute:
|
|
10032
10177
|
op.expression =
|
|
10033
10178
|
op.expression && transformExpressionsInExpression(op.expression, transform, flags);
|
|
10179
|
+
op.trustedValueFn = op.trustedValueFn &&
|
|
10180
|
+
transformExpressionsInExpression(op.trustedValueFn, transform, flags);
|
|
10034
10181
|
break;
|
|
10035
10182
|
case OpKind.RepeaterCreate:
|
|
10036
10183
|
op.track = transformExpressionsInExpression(op.track, transform, flags);
|
|
@@ -10049,6 +10196,9 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10049
10196
|
op.placeholderConfig =
|
|
10050
10197
|
transformExpressionsInExpression(op.placeholderConfig, transform, flags);
|
|
10051
10198
|
}
|
|
10199
|
+
if (op.resolverFn !== null) {
|
|
10200
|
+
op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
|
|
10201
|
+
}
|
|
10052
10202
|
break;
|
|
10053
10203
|
case OpKind.I18nMessage:
|
|
10054
10204
|
for (const [placeholder, expr] of op.params) {
|
|
@@ -10076,14 +10226,16 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10076
10226
|
case OpKind.I18nContext:
|
|
10077
10227
|
case OpKind.I18nEnd:
|
|
10078
10228
|
case OpKind.I18nStart:
|
|
10079
|
-
case OpKind.
|
|
10080
|
-
case OpKind.
|
|
10229
|
+
case OpKind.IcuEnd:
|
|
10230
|
+
case OpKind.IcuStart:
|
|
10081
10231
|
case OpKind.Namespace:
|
|
10082
10232
|
case OpKind.Pipe:
|
|
10083
10233
|
case OpKind.Projection:
|
|
10084
10234
|
case OpKind.ProjectionDef:
|
|
10085
10235
|
case OpKind.Template:
|
|
10086
10236
|
case OpKind.Text:
|
|
10237
|
+
case OpKind.I18nAttributes:
|
|
10238
|
+
case OpKind.IcuPlaceholder:
|
|
10087
10239
|
// These operations contain no expressions.
|
|
10088
10240
|
break;
|
|
10089
10241
|
default:
|
|
@@ -10104,6 +10256,9 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10104
10256
|
expr.lhs = transformExpressionsInExpression(expr.lhs, transform, flags);
|
|
10105
10257
|
expr.rhs = transformExpressionsInExpression(expr.rhs, transform, flags);
|
|
10106
10258
|
}
|
|
10259
|
+
else if (expr instanceof UnaryOperatorExpr) {
|
|
10260
|
+
expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
|
|
10261
|
+
}
|
|
10107
10262
|
else if (expr instanceof ReadPropExpr) {
|
|
10108
10263
|
expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
|
|
10109
10264
|
}
|
|
@@ -10155,6 +10310,15 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10155
10310
|
expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
|
|
10156
10311
|
}
|
|
10157
10312
|
}
|
|
10313
|
+
else if (expr instanceof NotExpr) {
|
|
10314
|
+
expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
|
|
10315
|
+
}
|
|
10316
|
+
else if (expr instanceof TaggedTemplateExpr) {
|
|
10317
|
+
expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
|
|
10318
|
+
expr.template.expressions =
|
|
10319
|
+
expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
|
|
10320
|
+
}
|
|
10321
|
+
else if (expr instanceof WrappedNodeExpr) ;
|
|
10158
10322
|
else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
|
|
10159
10323
|
expr instanceof LiteralExpr) ;
|
|
10160
10324
|
else {
|
|
@@ -10513,23 +10677,28 @@ function createProjectionDefOp(def) {
|
|
|
10513
10677
|
/**
|
|
10514
10678
|
* Create an `ExtractedAttributeOp`.
|
|
10515
10679
|
*/
|
|
10516
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
10680
|
+
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10517
10681
|
return {
|
|
10518
10682
|
kind: OpKind.ExtractedAttribute,
|
|
10519
10683
|
target,
|
|
10520
10684
|
bindingKind,
|
|
10521
10685
|
name,
|
|
10522
10686
|
expression,
|
|
10687
|
+
i18nContext,
|
|
10688
|
+
i18nMessage,
|
|
10689
|
+
securityContext,
|
|
10690
|
+
trustedValueFn: null,
|
|
10523
10691
|
...NEW_OP,
|
|
10524
10692
|
};
|
|
10525
10693
|
}
|
|
10526
10694
|
/**
|
|
10527
10695
|
* Create an `ExtractedMessageOp`.
|
|
10528
10696
|
*/
|
|
10529
|
-
function createI18nMessageOp(xref, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
10697
|
+
function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
|
|
10530
10698
|
return {
|
|
10531
10699
|
kind: OpKind.I18nMessage,
|
|
10532
10700
|
xref,
|
|
10701
|
+
i18nContext,
|
|
10533
10702
|
i18nBlock,
|
|
10534
10703
|
message,
|
|
10535
10704
|
messagePlaceholder,
|
|
@@ -10567,9 +10736,26 @@ function createI18nEndOp(xref) {
|
|
|
10567
10736
|
...NEW_OP,
|
|
10568
10737
|
};
|
|
10569
10738
|
}
|
|
10570
|
-
|
|
10739
|
+
/**
|
|
10740
|
+
* Creates an ICU placeholder op.
|
|
10741
|
+
*/
|
|
10742
|
+
function createIcuPlaceholderOp(xref, name, strings) {
|
|
10743
|
+
return {
|
|
10744
|
+
kind: OpKind.IcuPlaceholder,
|
|
10745
|
+
xref,
|
|
10746
|
+
name,
|
|
10747
|
+
strings,
|
|
10748
|
+
expressionPlaceholders: [],
|
|
10749
|
+
...NEW_OP,
|
|
10750
|
+
};
|
|
10751
|
+
}
|
|
10752
|
+
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
10753
|
+
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
10754
|
+
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
10755
|
+
}
|
|
10571
10756
|
return {
|
|
10572
10757
|
kind: OpKind.I18nContext,
|
|
10758
|
+
contextKind,
|
|
10573
10759
|
xref,
|
|
10574
10760
|
i18nBlock,
|
|
10575
10761
|
message,
|
|
@@ -10580,12 +10766,15 @@ function createI18nContextOp(xref, i18nBlock, message, sourceSpan) {
|
|
|
10580
10766
|
};
|
|
10581
10767
|
}
|
|
10582
10768
|
|
|
10583
|
-
function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan) {
|
|
10769
|
+
function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, securityContext, sourceSpan) {
|
|
10584
10770
|
return {
|
|
10585
10771
|
kind: OpKind.HostProperty,
|
|
10586
10772
|
name,
|
|
10587
10773
|
expression,
|
|
10588
10774
|
isAnimationTrigger,
|
|
10775
|
+
i18nContext,
|
|
10776
|
+
securityContext,
|
|
10777
|
+
sanitizer: null,
|
|
10589
10778
|
sourceSpan,
|
|
10590
10779
|
...TRAIT_CONSUMES_VARS,
|
|
10591
10780
|
...NEW_OP,
|
|
@@ -10809,12 +10998,20 @@ function removeAnys(e) {
|
|
|
10809
10998
|
* Adds apply operations after i18n expressions.
|
|
10810
10999
|
*/
|
|
10811
11000
|
function applyI18nExpressions(job) {
|
|
11001
|
+
const i18nContexts = new Map();
|
|
11002
|
+
for (const unit of job.units) {
|
|
11003
|
+
for (const op of unit.create) {
|
|
11004
|
+
if (op.kind === OpKind.I18nContext) {
|
|
11005
|
+
i18nContexts.set(op.xref, op);
|
|
11006
|
+
}
|
|
11007
|
+
}
|
|
11008
|
+
}
|
|
10812
11009
|
for (const unit of job.units) {
|
|
10813
11010
|
for (const op of unit.update) {
|
|
10814
11011
|
// Only add apply after expressions that are not followed by more expressions.
|
|
10815
|
-
if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
|
|
11012
|
+
if (op.kind === OpKind.I18nExpression && needsApplication(i18nContexts, op)) {
|
|
10816
11013
|
// TODO: what should be the source span for the apply op?
|
|
10817
|
-
OpList.insertAfter(createI18nApplyOp(op.
|
|
11014
|
+
OpList.insertAfter(createI18nApplyOp(op.i18nOwner, op.handle, null), op);
|
|
10818
11015
|
}
|
|
10819
11016
|
}
|
|
10820
11017
|
}
|
|
@@ -10822,50 +11019,85 @@ function applyI18nExpressions(job) {
|
|
|
10822
11019
|
/**
|
|
10823
11020
|
* Checks whether the given expression op needs to be followed with an apply op.
|
|
10824
11021
|
*/
|
|
10825
|
-
function needsApplication(op) {
|
|
11022
|
+
function needsApplication(i18nContexts, op) {
|
|
10826
11023
|
// If the next op is not another expression, we need to apply.
|
|
10827
11024
|
if (op.next?.kind !== OpKind.I18nExpression) {
|
|
10828
11025
|
return true;
|
|
10829
11026
|
}
|
|
10830
|
-
|
|
10831
|
-
|
|
11027
|
+
const context = i18nContexts.get(op.context);
|
|
11028
|
+
const nextContext = i18nContexts.get(op.next.context);
|
|
11029
|
+
if (context === undefined) {
|
|
11030
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the I18nExpressionOp\'s context');
|
|
11031
|
+
}
|
|
11032
|
+
if (nextContext === undefined) {
|
|
11033
|
+
throw new Error('AssertionError: expected an I18nContextOp to exist for the next I18nExpressionOp\'s context');
|
|
11034
|
+
}
|
|
11035
|
+
// If the next op is an expression targeting a different i18n block (or different element, in the
|
|
11036
|
+
// case of i18n attributes), we need to apply.
|
|
11037
|
+
// First, handle the case of i18n blocks.
|
|
11038
|
+
if (context.i18nBlock !== null) {
|
|
11039
|
+
// This is a block context. Compare the blocks.
|
|
11040
|
+
if (context.i18nBlock !== nextContext.i18nBlock) {
|
|
11041
|
+
return true;
|
|
11042
|
+
}
|
|
11043
|
+
return false;
|
|
11044
|
+
}
|
|
11045
|
+
// Second, handle the case of i18n attributes.
|
|
11046
|
+
if (op.i18nOwner !== op.next.i18nOwner) {
|
|
10832
11047
|
return true;
|
|
10833
11048
|
}
|
|
10834
11049
|
return false;
|
|
10835
11050
|
}
|
|
10836
11051
|
|
|
10837
11052
|
/**
|
|
10838
|
-
* Updates i18n expression ops to
|
|
11053
|
+
* Updates i18n expression ops to target the last slot in their owning i18n block, and moves them
|
|
11054
|
+
* after the last update instruction that depends on that slot.
|
|
10839
11055
|
*/
|
|
10840
11056
|
function assignI18nSlotDependencies(job) {
|
|
10841
|
-
const i18nLastSlotConsumers = new Map();
|
|
10842
|
-
const i18nContexts = new Map();
|
|
10843
|
-
let lastSlotConsumer = null;
|
|
10844
|
-
let currentI18nOp = null;
|
|
10845
11057
|
for (const unit of job.units) {
|
|
10846
|
-
//
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
11058
|
+
// The first update op.
|
|
11059
|
+
let updateOp = unit.update.head;
|
|
11060
|
+
// I18n expressions currently being moved during the iteration.
|
|
11061
|
+
let i18nExpressionsInProgress = [];
|
|
11062
|
+
// Non-null while we are iterating through an i18nStart/i18nEnd pair
|
|
11063
|
+
let state = null;
|
|
11064
|
+
for (const createOp of unit.create) {
|
|
11065
|
+
if (createOp.kind === OpKind.I18nStart) {
|
|
11066
|
+
state = {
|
|
11067
|
+
blockXref: createOp.xref,
|
|
11068
|
+
lastSlotConsumer: createOp.xref,
|
|
11069
|
+
};
|
|
10850
11070
|
}
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
break;
|
|
10859
|
-
case OpKind.I18nContext:
|
|
10860
|
-
i18nContexts.set(op.xref, op);
|
|
10861
|
-
break;
|
|
11071
|
+
else if (createOp.kind === OpKind.I18nEnd) {
|
|
11072
|
+
for (const op of i18nExpressionsInProgress) {
|
|
11073
|
+
op.target = state.lastSlotConsumer;
|
|
11074
|
+
OpList.insertBefore(op, updateOp);
|
|
11075
|
+
}
|
|
11076
|
+
i18nExpressionsInProgress.length = 0;
|
|
11077
|
+
state = null;
|
|
10862
11078
|
}
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
11079
|
+
if (hasConsumesSlotTrait(createOp)) {
|
|
11080
|
+
if (state !== null) {
|
|
11081
|
+
state.lastSlotConsumer = createOp.xref;
|
|
11082
|
+
}
|
|
11083
|
+
while (true) {
|
|
11084
|
+
if (updateOp.next === null) {
|
|
11085
|
+
break;
|
|
11086
|
+
}
|
|
11087
|
+
if (state !== null && updateOp.kind === OpKind.I18nExpression &&
|
|
11088
|
+
updateOp.usage === I18nExpressionFor.I18nText &&
|
|
11089
|
+
updateOp.i18nOwner === state.blockXref) {
|
|
11090
|
+
const opToRemove = updateOp;
|
|
11091
|
+
updateOp = updateOp.next;
|
|
11092
|
+
OpList.remove(opToRemove);
|
|
11093
|
+
i18nExpressionsInProgress.push(opToRemove);
|
|
11094
|
+
continue;
|
|
11095
|
+
}
|
|
11096
|
+
if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
|
|
11097
|
+
break;
|
|
11098
|
+
}
|
|
11099
|
+
updateOp = updateOp.next;
|
|
11100
|
+
}
|
|
10869
11101
|
}
|
|
10870
11102
|
}
|
|
10871
11103
|
}
|
|
@@ -10899,22 +11131,42 @@ function extractAttributes(job) {
|
|
|
10899
11131
|
break;
|
|
10900
11132
|
case OpKind.Property:
|
|
10901
11133
|
if (!op.isAnimationTrigger) {
|
|
10902
|
-
|
|
11134
|
+
let bindingKind;
|
|
11135
|
+
if (op.i18nMessage !== null && op.templateKind === null) {
|
|
11136
|
+
// If the binding has an i18n context, it is an i18n attribute, and should have that
|
|
11137
|
+
// kind in the consts array.
|
|
11138
|
+
bindingKind = BindingKind.I18n;
|
|
11139
|
+
}
|
|
11140
|
+
else if (op.isStructuralTemplateAttribute) {
|
|
11141
|
+
bindingKind = BindingKind.Template;
|
|
11142
|
+
}
|
|
11143
|
+
else {
|
|
11144
|
+
bindingKind = BindingKind.Property;
|
|
11145
|
+
}
|
|
11146
|
+
OpList.insertBefore(
|
|
11147
|
+
// Deliberaly null i18nMessage value
|
|
11148
|
+
createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null, /* i18nContext */ null,
|
|
11149
|
+
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
10903
11150
|
}
|
|
10904
11151
|
break;
|
|
10905
11152
|
case OpKind.StyleProp:
|
|
10906
11153
|
case OpKind.ClassProp:
|
|
11154
|
+
// TODO: Can style or class bindings be i18n attributes?
|
|
10907
11155
|
// The old compiler treated empty style bindings as regular bindings for the purpose of
|
|
10908
11156
|
// directive matching. That behavior is incorrect, but we emulate it in compatibility
|
|
10909
11157
|
// mode.
|
|
10910
11158
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
10911
11159
|
op.expression instanceof EmptyExpr) {
|
|
10912
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null
|
|
11160
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11161
|
+
/* i18nContext */ null,
|
|
11162
|
+
/* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
|
|
10913
11163
|
}
|
|
10914
11164
|
break;
|
|
10915
11165
|
case OpKind.Listener:
|
|
10916
11166
|
if (!op.isAnimationListener) {
|
|
10917
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null
|
|
11167
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11168
|
+
/* i18nContext */ null,
|
|
11169
|
+
/* i18nMessage */ null, SecurityContext.NONE);
|
|
10918
11170
|
if (job.kind === CompilationJobKind.Host) {
|
|
10919
11171
|
// This attribute will apply to the enclosing host binding compilation unit, so order
|
|
10920
11172
|
// doesn't matter.
|
|
@@ -10946,24 +11198,14 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
10946
11198
|
if (op.expression instanceof Interpolation) {
|
|
10947
11199
|
return;
|
|
10948
11200
|
}
|
|
10949
|
-
let extractable = op.expression.isConstant();
|
|
11201
|
+
let extractable = op.isTextAttribute || op.expression.isConstant();
|
|
10950
11202
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
10951
|
-
// TemplateDefinitionBuilder only
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
|
|
10955
|
-
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
|
|
10956
|
-
// string literal, because it is not a text attribute.
|
|
10957
|
-
extractable &&= op.isTextAttribute;
|
|
10958
|
-
}
|
|
10959
|
-
if (unit.job.kind === CompilationJobKind.Host) {
|
|
10960
|
-
// TemplateDefinitionBuilder also does not seem to extract string literals if they are part of
|
|
10961
|
-
// a host attribute.
|
|
10962
|
-
extractable &&= op.isTextAttribute;
|
|
10963
|
-
}
|
|
11203
|
+
// TemplateDefinitionBuilder only extracts text attributes. It does not extract attriibute
|
|
11204
|
+
// bindings, even if they are constants.
|
|
11205
|
+
extractable &&= op.isTextAttribute;
|
|
10964
11206
|
}
|
|
10965
11207
|
if (extractable) {
|
|
10966
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.
|
|
11208
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
10967
11209
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
10968
11210
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
10969
11211
|
// matter.
|
|
@@ -11010,16 +11252,16 @@ function specializeBindings(job) {
|
|
|
11010
11252
|
target.nonBindable = true;
|
|
11011
11253
|
}
|
|
11012
11254
|
else {
|
|
11013
|
-
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.
|
|
11255
|
+
OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
|
|
11014
11256
|
}
|
|
11015
11257
|
break;
|
|
11016
11258
|
case BindingKind.Property:
|
|
11017
11259
|
case BindingKind.Animation:
|
|
11018
11260
|
if (job.kind === CompilationJobKind.Host) {
|
|
11019
|
-
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.sourceSpan));
|
|
11261
|
+
OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.securityContext, op.sourceSpan));
|
|
11020
11262
|
}
|
|
11021
11263
|
else {
|
|
11022
|
-
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.
|
|
11264
|
+
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
|
|
11023
11265
|
}
|
|
11024
11266
|
break;
|
|
11025
11267
|
case BindingKind.I18n:
|
|
@@ -11196,41 +11438,6 @@ function generateConditionalExpressions(job) {
|
|
|
11196
11438
|
}
|
|
11197
11439
|
}
|
|
11198
11440
|
|
|
11199
|
-
exports.TagContentType = void 0;
|
|
11200
|
-
(function (TagContentType) {
|
|
11201
|
-
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
11202
|
-
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
11203
|
-
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
11204
|
-
})(exports.TagContentType || (exports.TagContentType = {}));
|
|
11205
|
-
function splitNsName(elementName) {
|
|
11206
|
-
if (elementName[0] != ':') {
|
|
11207
|
-
return [null, elementName];
|
|
11208
|
-
}
|
|
11209
|
-
const colonIndex = elementName.indexOf(':', 1);
|
|
11210
|
-
if (colonIndex === -1) {
|
|
11211
|
-
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
11212
|
-
}
|
|
11213
|
-
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
11214
|
-
}
|
|
11215
|
-
// `<ng-container>` tags work the same regardless the namespace
|
|
11216
|
-
function isNgContainer(tagName) {
|
|
11217
|
-
return splitNsName(tagName)[1] === 'ng-container';
|
|
11218
|
-
}
|
|
11219
|
-
// `<ng-content>` tags work the same regardless the namespace
|
|
11220
|
-
function isNgContent(tagName) {
|
|
11221
|
-
return splitNsName(tagName)[1] === 'ng-content';
|
|
11222
|
-
}
|
|
11223
|
-
// `<ng-template>` tags work the same regardless the namespace
|
|
11224
|
-
function isNgTemplate(tagName) {
|
|
11225
|
-
return splitNsName(tagName)[1] === 'ng-template';
|
|
11226
|
-
}
|
|
11227
|
-
function getNsPrefix(fullName) {
|
|
11228
|
-
return fullName === null ? null : splitNsName(fullName)[0];
|
|
11229
|
-
}
|
|
11230
|
-
function mergeNsAndName(prefix, localName) {
|
|
11231
|
-
return prefix ? `:${prefix}:${localName}` : localName;
|
|
11232
|
-
}
|
|
11233
|
-
|
|
11234
11441
|
new Map([
|
|
11235
11442
|
['&&', exports.BinaryOperator.And],
|
|
11236
11443
|
['>', exports.BinaryOperator.Bigger],
|
|
@@ -11267,9 +11474,9 @@ function collectElementConsts(job) {
|
|
|
11267
11474
|
for (const unit of job.units) {
|
|
11268
11475
|
for (const op of unit.create) {
|
|
11269
11476
|
if (op.kind === OpKind.ExtractedAttribute) {
|
|
11270
|
-
const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
|
|
11477
|
+
const attributes = allElementAttributes.get(op.target) || new ElementAttributes(job.compatibility);
|
|
11271
11478
|
allElementAttributes.set(op.target, attributes);
|
|
11272
|
-
attributes.add(op.bindingKind, op.name, op.expression);
|
|
11479
|
+
attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
|
|
11273
11480
|
OpList.remove(op);
|
|
11274
11481
|
}
|
|
11275
11482
|
}
|
|
@@ -11312,11 +11519,6 @@ const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
|
11312
11519
|
* Container for all of the various kinds of attributes which are applied on an element.
|
|
11313
11520
|
*/
|
|
11314
11521
|
class ElementAttributes {
|
|
11315
|
-
constructor() {
|
|
11316
|
-
this.known = new Set();
|
|
11317
|
-
this.byKind = new Map;
|
|
11318
|
-
this.projectAs = null;
|
|
11319
|
-
}
|
|
11320
11522
|
get attributes() {
|
|
11321
11523
|
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
11322
11524
|
}
|
|
@@ -11335,11 +11537,32 @@ class ElementAttributes {
|
|
|
11335
11537
|
get i18n() {
|
|
11336
11538
|
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11337
11539
|
}
|
|
11338
|
-
|
|
11339
|
-
|
|
11540
|
+
constructor(compatibility) {
|
|
11541
|
+
this.compatibility = compatibility;
|
|
11542
|
+
this.known = new Map();
|
|
11543
|
+
this.byKind = new Map;
|
|
11544
|
+
this.projectAs = null;
|
|
11545
|
+
}
|
|
11546
|
+
isKnown(kind, name, value) {
|
|
11547
|
+
const nameToValue = this.known.get(kind) ?? new Set();
|
|
11548
|
+
this.known.set(kind, nameToValue);
|
|
11549
|
+
if (nameToValue.has(name)) {
|
|
11550
|
+
return true;
|
|
11551
|
+
}
|
|
11552
|
+
nameToValue.add(name);
|
|
11553
|
+
return false;
|
|
11554
|
+
}
|
|
11555
|
+
add(kind, name, value, trustedValueFn) {
|
|
11556
|
+
// TemplateDefinitionBuilder puts duplicate attribute, class, and style values into the consts
|
|
11557
|
+
// array. This seems inefficient, we can probably keep just the first one or the last value
|
|
11558
|
+
// (whichever actually gets applied when multiple values are listed for the same attribute).
|
|
11559
|
+
const allowDuplicates = this.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11560
|
+
(kind === BindingKind.Attribute || kind === BindingKind.ClassName ||
|
|
11561
|
+
kind === BindingKind.StyleProperty);
|
|
11562
|
+
if (!allowDuplicates && this.isKnown(kind, name, value)) {
|
|
11340
11563
|
return;
|
|
11341
11564
|
}
|
|
11342
|
-
this
|
|
11565
|
+
// TODO: Can this be its own phase
|
|
11343
11566
|
if (name === 'ngProjectAs') {
|
|
11344
11567
|
if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
|
|
11345
11568
|
(typeof value.value?.toString() !== 'string')) {
|
|
@@ -11353,9 +11576,17 @@ class ElementAttributes {
|
|
|
11353
11576
|
array.push(...getAttributeNameLiterals$1(name));
|
|
11354
11577
|
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11355
11578
|
if (value === null) {
|
|
11356
|
-
throw Error('Attribute & style element attributes must have a value');
|
|
11579
|
+
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
11580
|
+
}
|
|
11581
|
+
if (trustedValueFn !== null) {
|
|
11582
|
+
if (!isStringLiteral(value)) {
|
|
11583
|
+
throw Error('AssertionError: extracted attribute value should be string literal');
|
|
11584
|
+
}
|
|
11585
|
+
array.push(taggedTemplate(trustedValueFn, new TemplateLiteral([new TemplateLiteralElement(value.value)], []), undefined, value.sourceSpan));
|
|
11586
|
+
}
|
|
11587
|
+
else {
|
|
11588
|
+
array.push(value);
|
|
11357
11589
|
}
|
|
11358
|
-
array.push(value);
|
|
11359
11590
|
}
|
|
11360
11591
|
}
|
|
11361
11592
|
arrayFor(kind) {
|
|
@@ -11369,7 +11600,7 @@ class ElementAttributes {
|
|
|
11369
11600
|
* Gets an array of literal expressions representing the attribute's namespaced name.
|
|
11370
11601
|
*/
|
|
11371
11602
|
function getAttributeNameLiterals$1(name) {
|
|
11372
|
-
const [attributeNamespace, attributeName] = splitNsName(name);
|
|
11603
|
+
const [attributeNamespace, attributeName] = splitNsName(name, false);
|
|
11373
11604
|
const nameLiteral = literal(attributeName);
|
|
11374
11605
|
if (attributeNamespace) {
|
|
11375
11606
|
return [
|
|
@@ -11407,6 +11638,50 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
|
|
|
11407
11638
|
return literalArr(attrArray);
|
|
11408
11639
|
}
|
|
11409
11640
|
|
|
11641
|
+
/**
|
|
11642
|
+
* Some binding instructions in the update block may actually correspond to i18n bindings. In that
|
|
11643
|
+
* case, they should be replaced with i18nExp instructions for the dynamic portions.
|
|
11644
|
+
*/
|
|
11645
|
+
function convertI18nBindings(job) {
|
|
11646
|
+
const i18nAttributesByElem = new Map();
|
|
11647
|
+
for (const unit of job.units) {
|
|
11648
|
+
for (const op of unit.create) {
|
|
11649
|
+
if (op.kind === OpKind.I18nAttributes) {
|
|
11650
|
+
i18nAttributesByElem.set(op.target, op);
|
|
11651
|
+
}
|
|
11652
|
+
}
|
|
11653
|
+
for (const op of unit.update) {
|
|
11654
|
+
switch (op.kind) {
|
|
11655
|
+
case OpKind.Property:
|
|
11656
|
+
case OpKind.Attribute:
|
|
11657
|
+
if (op.i18nContext === null) {
|
|
11658
|
+
continue;
|
|
11659
|
+
}
|
|
11660
|
+
if (!(op.expression instanceof Interpolation)) {
|
|
11661
|
+
continue;
|
|
11662
|
+
}
|
|
11663
|
+
const i18nAttributesForElem = i18nAttributesByElem.get(op.target);
|
|
11664
|
+
if (i18nAttributesForElem === undefined) {
|
|
11665
|
+
throw new Error('AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction');
|
|
11666
|
+
}
|
|
11667
|
+
if (i18nAttributesForElem.target !== op.target) {
|
|
11668
|
+
throw new Error('AssertionError: Expected i18nAttributes target element to match binding target element');
|
|
11669
|
+
}
|
|
11670
|
+
const ops = [];
|
|
11671
|
+
for (let i = 0; i < op.expression.expressions.length; i++) {
|
|
11672
|
+
const expr = op.expression.expressions[i];
|
|
11673
|
+
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
11674
|
+
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`);
|
|
11675
|
+
}
|
|
11676
|
+
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, null, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
11677
|
+
}
|
|
11678
|
+
OpList.replaceWithMany(op, ops);
|
|
11679
|
+
break;
|
|
11680
|
+
}
|
|
11681
|
+
}
|
|
11682
|
+
}
|
|
11683
|
+
}
|
|
11684
|
+
|
|
11410
11685
|
/**
|
|
11411
11686
|
* Create extracted deps functions for defer ops.
|
|
11412
11687
|
*/
|
|
@@ -11435,7 +11710,8 @@ function createDeferDepsFns(job) {
|
|
|
11435
11710
|
if (op.handle.slot === null) {
|
|
11436
11711
|
throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
|
|
11437
11712
|
}
|
|
11438
|
-
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn
|
|
11713
|
+
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn`,
|
|
11714
|
+
/* Don't use unique names for TDB compatibility */ false);
|
|
11439
11715
|
}
|
|
11440
11716
|
}
|
|
11441
11717
|
}
|
|
@@ -11452,37 +11728,85 @@ function createDeferDepsFns(job) {
|
|
|
11452
11728
|
* message.)
|
|
11453
11729
|
*/
|
|
11454
11730
|
function createI18nContexts(job) {
|
|
11731
|
+
// Create i18n context ops for i18n attrs.
|
|
11732
|
+
const attrContextByMessage = new Map();
|
|
11733
|
+
for (const unit of job.units) {
|
|
11734
|
+
for (const op of unit.ops()) {
|
|
11735
|
+
switch (op.kind) {
|
|
11736
|
+
case OpKind.Binding:
|
|
11737
|
+
case OpKind.Property:
|
|
11738
|
+
case OpKind.Attribute:
|
|
11739
|
+
case OpKind.ExtractedAttribute:
|
|
11740
|
+
if (op.i18nMessage === null) {
|
|
11741
|
+
continue;
|
|
11742
|
+
}
|
|
11743
|
+
if (!attrContextByMessage.has(op.i18nMessage)) {
|
|
11744
|
+
const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
|
|
11745
|
+
unit.create.push(i18nContext);
|
|
11746
|
+
attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
|
|
11747
|
+
}
|
|
11748
|
+
op.i18nContext = attrContextByMessage.get(op.i18nMessage);
|
|
11749
|
+
break;
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
// Create i18n context ops for root i18n blocks.
|
|
11754
|
+
const blockContextByI18nBlock = new Map();
|
|
11755
|
+
for (const unit of job.units) {
|
|
11756
|
+
for (const op of unit.create) {
|
|
11757
|
+
switch (op.kind) {
|
|
11758
|
+
case OpKind.I18nStart:
|
|
11759
|
+
if (op.xref === op.root) {
|
|
11760
|
+
const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
|
|
11761
|
+
unit.create.push(contextOp);
|
|
11762
|
+
op.context = contextOp.xref;
|
|
11763
|
+
blockContextByI18nBlock.set(op.xref, contextOp);
|
|
11764
|
+
}
|
|
11765
|
+
break;
|
|
11766
|
+
}
|
|
11767
|
+
}
|
|
11768
|
+
}
|
|
11769
|
+
// Assign i18n contexts for child i18n blocks. These don't need their own conext, instead they
|
|
11770
|
+
// should inherit from their root i18n block.
|
|
11771
|
+
for (const unit of job.units) {
|
|
11772
|
+
for (const op of unit.create) {
|
|
11773
|
+
if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
|
|
11774
|
+
const rootContext = blockContextByI18nBlock.get(op.root);
|
|
11775
|
+
if (rootContext === undefined) {
|
|
11776
|
+
throw Error('AssertionError: Root i18n block i18n context should have been created.');
|
|
11777
|
+
}
|
|
11778
|
+
op.context = rootContext.xref;
|
|
11779
|
+
blockContextByI18nBlock.set(op.xref, rootContext);
|
|
11780
|
+
}
|
|
11781
|
+
}
|
|
11782
|
+
}
|
|
11783
|
+
// Create or assign i18n contexts for ICUs.
|
|
11455
11784
|
let currentI18nOp = null;
|
|
11456
|
-
let xref;
|
|
11457
11785
|
for (const unit of job.units) {
|
|
11458
11786
|
for (const op of unit.create) {
|
|
11459
11787
|
switch (op.kind) {
|
|
11460
11788
|
case OpKind.I18nStart:
|
|
11461
|
-
// Each i18n block gets its own context.
|
|
11462
|
-
xref = job.allocateXrefId();
|
|
11463
|
-
unit.create.push(createI18nContextOp(xref, op.xref, op.message, null));
|
|
11464
|
-
op.context = xref;
|
|
11465
11789
|
currentI18nOp = op;
|
|
11466
11790
|
break;
|
|
11467
11791
|
case OpKind.I18nEnd:
|
|
11468
11792
|
currentI18nOp = null;
|
|
11469
11793
|
break;
|
|
11470
|
-
case OpKind.
|
|
11471
|
-
// If an ICU represents a different message than its containing block, we give it its own
|
|
11472
|
-
// i18n context.
|
|
11794
|
+
case OpKind.IcuStart:
|
|
11473
11795
|
if (currentI18nOp === null) {
|
|
11474
|
-
throw Error('Unexpected ICU outside of an i18n block.');
|
|
11796
|
+
throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
|
|
11475
11797
|
}
|
|
11476
11798
|
if (op.message.id !== currentI18nOp.message.id) {
|
|
11477
|
-
//
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11799
|
+
// This ICU is a sub-message inside its parent i18n block message. We need to give it
|
|
11800
|
+
// its own context.
|
|
11801
|
+
const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.xref, op.message, null);
|
|
11802
|
+
unit.create.push(contextOp);
|
|
11803
|
+
op.context = contextOp.xref;
|
|
11481
11804
|
}
|
|
11482
11805
|
else {
|
|
11483
|
-
//
|
|
11484
|
-
// the
|
|
11806
|
+
// This ICU is the only translatable content in its parent i18n block. We need to
|
|
11807
|
+
// convert the parent's context into an ICU context.
|
|
11485
11808
|
op.context = currentI18nOp.context;
|
|
11809
|
+
blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
|
|
11486
11810
|
}
|
|
11487
11811
|
break;
|
|
11488
11812
|
}
|
|
@@ -11491,44 +11815,27 @@ function createI18nContexts(job) {
|
|
|
11491
11815
|
}
|
|
11492
11816
|
|
|
11493
11817
|
/**
|
|
11494
|
-
*
|
|
11818
|
+
* Deduplicate text bindings, e.g. <div class="cls1" class="cls2">
|
|
11495
11819
|
*/
|
|
11496
|
-
function
|
|
11497
|
-
const
|
|
11498
|
-
const i18nContexts = new Map();
|
|
11499
|
-
const i18nBlocks = new Map();
|
|
11500
|
-
// Collect maps of ops that need to be referenced to create the I18nExpressionOps.
|
|
11820
|
+
function deduplicateTextBindings(job) {
|
|
11821
|
+
const seen = new Map();
|
|
11501
11822
|
for (const unit of job.units) {
|
|
11502
|
-
for (const op of unit.
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
}
|
|
11515
|
-
// Replace each IcuUpdateOp with an I18nExpressionOp.
|
|
11516
|
-
for (const op of unit.update) {
|
|
11517
|
-
switch (op.kind) {
|
|
11518
|
-
case OpKind.IcuUpdate:
|
|
11519
|
-
const icuOp = icus.get(op.xref);
|
|
11520
|
-
if (icuOp?.icu.expressionPlaceholder === undefined) {
|
|
11521
|
-
throw Error('ICU should have an i18n placeholder');
|
|
11522
|
-
}
|
|
11523
|
-
if (icuOp.context === null) {
|
|
11524
|
-
throw Error('ICU should have its i18n context set');
|
|
11823
|
+
for (const op of unit.update.reversed()) {
|
|
11824
|
+
if (op.kind === OpKind.Binding && op.isTextAttribute) {
|
|
11825
|
+
const seenForElement = seen.get(op.target) || new Set();
|
|
11826
|
+
if (seenForElement.has(op.name)) {
|
|
11827
|
+
if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
11828
|
+
// For most duplicated attributes, TemplateDefinitionBuilder lists all of the values in
|
|
11829
|
+
// the consts array. However, for style and class attributes it only keeps the last one.
|
|
11830
|
+
// We replicate that behavior here since it has actual consequences for apps with
|
|
11831
|
+
// duplicate class or style attrs.
|
|
11832
|
+
if (op.name === 'style' || op.name === 'class') {
|
|
11833
|
+
OpList.remove(op);
|
|
11834
|
+
}
|
|
11525
11835
|
}
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
// ICU-based i18n Expressions are resolved during post-processing.
|
|
11530
|
-
I18nParamResolutionTime.Postproccessing, null));
|
|
11531
|
-
break;
|
|
11836
|
+
}
|
|
11837
|
+
seenForElement.add(op.name);
|
|
11838
|
+
seen.set(op.target, seenForElement);
|
|
11532
11839
|
}
|
|
11533
11840
|
}
|
|
11534
11841
|
}
|
|
@@ -11880,7 +12187,7 @@ function ternaryTransform(e) {
|
|
|
11880
12187
|
/**
|
|
11881
12188
|
* The escape sequence used indicate message param values.
|
|
11882
12189
|
*/
|
|
11883
|
-
const ESCAPE = '\uFFFD';
|
|
12190
|
+
const ESCAPE$1 = '\uFFFD';
|
|
11884
12191
|
/**
|
|
11885
12192
|
* Marker used to indicate an element tag.
|
|
11886
12193
|
*/
|
|
@@ -11914,52 +12221,69 @@ const LIST_DELIMITER = '|';
|
|
|
11914
12221
|
* used in the final output.
|
|
11915
12222
|
*/
|
|
11916
12223
|
function extractI18nMessages(job) {
|
|
11917
|
-
//
|
|
12224
|
+
// Create an i18n message for each context.
|
|
12225
|
+
// TODO: Merge the context op with the message op since they're 1:1 anyways.
|
|
12226
|
+
const i18nMessagesByContext = new Map();
|
|
12227
|
+
const i18nBlocks = new Map();
|
|
11918
12228
|
const i18nContexts = new Map();
|
|
11919
|
-
// Record which contexts represent i18n blocks (any other contexts are assumed to have been
|
|
11920
|
-
// created from ICUs).
|
|
11921
|
-
const i18nBlockContexts = new Set();
|
|
11922
12229
|
for (const unit of job.units) {
|
|
11923
12230
|
for (const op of unit.create) {
|
|
11924
12231
|
switch (op.kind) {
|
|
11925
12232
|
case OpKind.I18nContext:
|
|
12233
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12234
|
+
unit.create.push(i18nMessageOp);
|
|
12235
|
+
i18nMessagesByContext.set(op.xref, i18nMessageOp);
|
|
11926
12236
|
i18nContexts.set(op.xref, op);
|
|
11927
12237
|
break;
|
|
11928
12238
|
case OpKind.I18nStart:
|
|
11929
|
-
|
|
12239
|
+
i18nBlocks.set(op.xref, op);
|
|
11930
12240
|
break;
|
|
11931
12241
|
}
|
|
11932
12242
|
}
|
|
11933
12243
|
}
|
|
11934
|
-
//
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
for (const op of unit.create) {
|
|
11938
|
-
if (op.kind === OpKind.I18nStart && op.xref === op.root) {
|
|
11939
|
-
if (!op.context) {
|
|
11940
|
-
throw Error('I18n start op should have its context set.');
|
|
11941
|
-
}
|
|
11942
|
-
const i18nMessageOp = createI18nMessage(job, i18nContexts.get(op.context));
|
|
11943
|
-
i18nBlockMessages.set(op.xref, i18nMessageOp);
|
|
11944
|
-
unit.create.push(i18nMessageOp);
|
|
11945
|
-
}
|
|
11946
|
-
}
|
|
11947
|
-
}
|
|
11948
|
-
// Extract messages from ICUs with their own sub-context.
|
|
12244
|
+
// Associate sub-messages for ICUs with their root message. At this point we can also remove the
|
|
12245
|
+
// ICU start/end ops, as they are no longer needed.
|
|
12246
|
+
let currentIcu = null;
|
|
11949
12247
|
for (const unit of job.units) {
|
|
11950
12248
|
for (const op of unit.create) {
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
const
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
12249
|
+
switch (op.kind) {
|
|
12250
|
+
case OpKind.IcuStart:
|
|
12251
|
+
currentIcu = op;
|
|
12252
|
+
OpList.remove(op);
|
|
12253
|
+
// Skip any contexts not associated with an ICU.
|
|
12254
|
+
const icuContext = i18nContexts.get(op.context);
|
|
12255
|
+
if (icuContext.contextKind !== I18nContextKind.Icu) {
|
|
12256
|
+
continue;
|
|
12257
|
+
}
|
|
12258
|
+
// Skip ICUs that share a context with their i18n message. These represent root-level
|
|
12259
|
+
// ICUs, not sub-messages.
|
|
12260
|
+
const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
|
|
12261
|
+
if (i18nBlock.context === icuContext.xref) {
|
|
12262
|
+
continue;
|
|
12263
|
+
}
|
|
12264
|
+
// Find the root message and push this ICUs message as a sub-message.
|
|
12265
|
+
const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
|
|
12266
|
+
const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
|
|
12267
|
+
if (rootMessage === undefined) {
|
|
12268
|
+
throw Error('AssertionError: ICU sub-message should belong to a root message.');
|
|
12269
|
+
}
|
|
12270
|
+
const subMessage = i18nMessagesByContext.get(icuContext.xref);
|
|
12271
|
+
subMessage.messagePlaceholder = op.messagePlaceholder;
|
|
12272
|
+
rootMessage.subMessages.push(subMessage.xref);
|
|
12273
|
+
break;
|
|
12274
|
+
case OpKind.IcuEnd:
|
|
12275
|
+
currentIcu = null;
|
|
12276
|
+
OpList.remove(op);
|
|
12277
|
+
break;
|
|
12278
|
+
case OpKind.IcuPlaceholder:
|
|
12279
|
+
// Add ICU placeholders to the message, then remove the ICU placeholder ops.
|
|
12280
|
+
if (currentIcu === null || currentIcu.context == null) {
|
|
12281
|
+
throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
|
|
12282
|
+
}
|
|
12283
|
+
const msg = i18nMessagesByContext.get(currentIcu.context);
|
|
12284
|
+
msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
|
|
12285
|
+
OpList.remove(op);
|
|
12286
|
+
break;
|
|
11963
12287
|
}
|
|
11964
12288
|
}
|
|
11965
12289
|
}
|
|
@@ -11968,26 +12292,33 @@ function extractI18nMessages(job) {
|
|
|
11968
12292
|
* Create an i18n message op from an i18n context op.
|
|
11969
12293
|
*/
|
|
11970
12294
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
11971
|
-
let
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
12295
|
+
let formattedParams = formatParams(context.params);
|
|
12296
|
+
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12297
|
+
let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
|
|
12298
|
+
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12299
|
+
}
|
|
12300
|
+
/**
|
|
12301
|
+
* Formats an ICU placeholder into a single string with expression placeholders.
|
|
12302
|
+
*/
|
|
12303
|
+
function formatIcuPlaceholder(op) {
|
|
12304
|
+
if (op.strings.length !== op.expressionPlaceholders.length + 1) {
|
|
12305
|
+
throw Error(`AsserionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
|
|
11976
12306
|
}
|
|
11977
|
-
|
|
12307
|
+
const values = op.expressionPlaceholders.map(formatValue);
|
|
12308
|
+
return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
|
|
11978
12309
|
}
|
|
11979
12310
|
/**
|
|
11980
12311
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
11981
12312
|
*/
|
|
11982
12313
|
function formatParams(params) {
|
|
11983
|
-
const
|
|
11984
|
-
for (const [placeholder, placeholderValues] of
|
|
12314
|
+
const formattedParams = new Map();
|
|
12315
|
+
for (const [placeholder, placeholderValues] of params) {
|
|
11985
12316
|
const serializedValues = formatParamValues(placeholderValues);
|
|
11986
12317
|
if (serializedValues !== null) {
|
|
11987
|
-
|
|
12318
|
+
formattedParams.set(placeholder, literal(serializedValues));
|
|
11988
12319
|
}
|
|
11989
12320
|
}
|
|
11990
|
-
return
|
|
12321
|
+
return formattedParams;
|
|
11991
12322
|
}
|
|
11992
12323
|
/**
|
|
11993
12324
|
* Formats an `I18nParamValue[]` into a string (or null for empty array).
|
|
@@ -12005,6 +12336,47 @@ function formatParamValues(values) {
|
|
|
12005
12336
|
* Formats a single `I18nParamValue` into a string
|
|
12006
12337
|
*/
|
|
12007
12338
|
function formatValue(value) {
|
|
12339
|
+
// Element tags with a structural directive use a special form that concatenates the element and
|
|
12340
|
+
// template values.
|
|
12341
|
+
if ((value.flags & I18nParamValueFlags.ElementTag) &&
|
|
12342
|
+
(value.flags & I18nParamValueFlags.TemplateTag)) {
|
|
12343
|
+
if (typeof value.value !== 'object') {
|
|
12344
|
+
throw Error('AssertionError: Expected i18n param value to have an element and template slot');
|
|
12345
|
+
}
|
|
12346
|
+
const elementValue = formatValue({
|
|
12347
|
+
...value,
|
|
12348
|
+
value: value.value.element,
|
|
12349
|
+
flags: value.flags & ~I18nParamValueFlags.TemplateTag
|
|
12350
|
+
});
|
|
12351
|
+
const templateValue = formatValue({
|
|
12352
|
+
...value,
|
|
12353
|
+
value: value.value.template,
|
|
12354
|
+
flags: value.flags & ~I18nParamValueFlags.ElementTag
|
|
12355
|
+
});
|
|
12356
|
+
// TODO(mmalerba): This is likely a bug in TemplateDefinitionBuilder, we should not need to
|
|
12357
|
+
// record the template value twice. For now I'm re-implementing the behavior here to keep the
|
|
12358
|
+
// output consistent with TemplateDefinitionBuilder.
|
|
12359
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12360
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12361
|
+
return `${templateValue}${elementValue}${templateValue}`;
|
|
12362
|
+
}
|
|
12363
|
+
// To match the TemplateDefinitionBuilder output, flip the order depending on whether the
|
|
12364
|
+
// values represent a closing or opening tag (or both).
|
|
12365
|
+
// TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
|
|
12366
|
+
// or the resulting message ID. If not, we can remove the special-casing in the future.
|
|
12367
|
+
return value.flags & I18nParamValueFlags.CloseTag ? `${elementValue}${templateValue}` :
|
|
12368
|
+
`${templateValue}${elementValue}`;
|
|
12369
|
+
}
|
|
12370
|
+
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
12371
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12372
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12373
|
+
return `${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.CloseTag })}${formatValue({ ...value, flags: value.flags & ~I18nParamValueFlags.OpenTag })}`;
|
|
12374
|
+
}
|
|
12375
|
+
// If there are no special flags, just return the raw value.
|
|
12376
|
+
if (value.flags === I18nParamValueFlags.None) {
|
|
12377
|
+
return `${value.value}`;
|
|
12378
|
+
}
|
|
12379
|
+
// Encode the remaining flags as part of the value.
|
|
12008
12380
|
let tagMarker = '';
|
|
12009
12381
|
let closeMarker = '';
|
|
12010
12382
|
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
@@ -12017,12 +12389,7 @@ function formatValue(value) {
|
|
|
12017
12389
|
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
12018
12390
|
}
|
|
12019
12391
|
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
12020
|
-
|
|
12021
|
-
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12022
|
-
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12023
|
-
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12024
|
-
}
|
|
12025
|
-
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12392
|
+
return `${ESCAPE$1}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE$1}`;
|
|
12026
12393
|
}
|
|
12027
12394
|
|
|
12028
12395
|
/**
|
|
@@ -12056,7 +12423,7 @@ function generateAdvance(job) {
|
|
|
12056
12423
|
else if (!slotMap.has(op.target)) {
|
|
12057
12424
|
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
12058
12425
|
// the `slotMap`.
|
|
12059
|
-
throw new Error(`AssertionError: reference to unknown slot for
|
|
12426
|
+
throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
|
|
12060
12427
|
}
|
|
12061
12428
|
const slot = slotMap.get(op.target);
|
|
12062
12429
|
// Does the slot counter need to be adjusted?
|
|
@@ -12139,9 +12506,15 @@ function recursivelyProcessView(view, parentScope) {
|
|
|
12139
12506
|
for (const op of view.create) {
|
|
12140
12507
|
switch (op.kind) {
|
|
12141
12508
|
case OpKind.Template:
|
|
12509
|
+
// Descend into child embedded views.
|
|
12510
|
+
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12511
|
+
break;
|
|
12142
12512
|
case OpKind.RepeaterCreate:
|
|
12143
12513
|
// Descend into child embedded views.
|
|
12144
12514
|
recursivelyProcessView(view.job.views.get(op.xref), scope);
|
|
12515
|
+
if (op.emptyView) {
|
|
12516
|
+
recursivelyProcessView(view.job.views.get(op.emptyView), scope);
|
|
12517
|
+
}
|
|
12145
12518
|
break;
|
|
12146
12519
|
case OpKind.Listener:
|
|
12147
12520
|
// Prepend variables to listener handler functions.
|
|
@@ -12272,7 +12645,7 @@ const BANG_IMPORTANT = '!important';
|
|
|
12272
12645
|
*/
|
|
12273
12646
|
function parseHostStyleProperties(job) {
|
|
12274
12647
|
for (const op of job.root.update) {
|
|
12275
|
-
if (op.kind
|
|
12648
|
+
if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
|
|
12276
12649
|
continue;
|
|
12277
12650
|
}
|
|
12278
12651
|
if (op.name.endsWith(BANG_IMPORTANT)) {
|
|
@@ -12359,6 +12732,9 @@ class IcuSerializerVisitor {
|
|
|
12359
12732
|
visitPlaceholder(ph) {
|
|
12360
12733
|
return this.formatPh(ph.name);
|
|
12361
12734
|
}
|
|
12735
|
+
visitBlockPlaceholder(ph) {
|
|
12736
|
+
return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
|
|
12737
|
+
}
|
|
12362
12738
|
visitIcuPlaceholder(ph, context) {
|
|
12363
12739
|
return this.formatPh(ph.name);
|
|
12364
12740
|
}
|
|
@@ -14080,12 +14456,12 @@ class Comment {
|
|
|
14080
14456
|
return visitor.visitComment(this, context);
|
|
14081
14457
|
}
|
|
14082
14458
|
}
|
|
14083
|
-
class Block {
|
|
14084
|
-
constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null) {
|
|
14459
|
+
class Block extends NodeWithI18n {
|
|
14460
|
+
constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null, i18n) {
|
|
14461
|
+
super(sourceSpan, i18n);
|
|
14085
14462
|
this.name = name;
|
|
14086
14463
|
this.parameters = parameters;
|
|
14087
14464
|
this.children = children;
|
|
14088
|
-
this.sourceSpan = sourceSpan;
|
|
14089
14465
|
this.nameSpan = nameSpan;
|
|
14090
14466
|
this.startSourceSpan = startSourceSpan;
|
|
14091
14467
|
this.endSourceSpan = endSourceSpan;
|
|
@@ -14771,6 +15147,24 @@ class PlaceholderRegistry {
|
|
|
14771
15147
|
getUniquePlaceholder(name) {
|
|
14772
15148
|
return this._generateUniqueName(name.toUpperCase());
|
|
14773
15149
|
}
|
|
15150
|
+
getStartBlockPlaceholderName(name, parameters) {
|
|
15151
|
+
const signature = this._hashBlock(name, parameters);
|
|
15152
|
+
if (this._signatureToName[signature]) {
|
|
15153
|
+
return this._signatureToName[signature];
|
|
15154
|
+
}
|
|
15155
|
+
const placeholder = this._generateUniqueName(`START_BLOCK_${this._toSnakeCase(name)}`);
|
|
15156
|
+
this._signatureToName[signature] = placeholder;
|
|
15157
|
+
return placeholder;
|
|
15158
|
+
}
|
|
15159
|
+
getCloseBlockPlaceholderName(name) {
|
|
15160
|
+
const signature = this._hashClosingBlock(name);
|
|
15161
|
+
if (this._signatureToName[signature]) {
|
|
15162
|
+
return this._signatureToName[signature];
|
|
15163
|
+
}
|
|
15164
|
+
const placeholder = this._generateUniqueName(`CLOSE_BLOCK_${this._toSnakeCase(name)}`);
|
|
15165
|
+
this._signatureToName[signature] = placeholder;
|
|
15166
|
+
return placeholder;
|
|
15167
|
+
}
|
|
14774
15168
|
// Generate a hash for a tag - does not take attribute order into account
|
|
14775
15169
|
_hashTag(tag, attrs, isVoid) {
|
|
14776
15170
|
const start = `<${tag}`;
|
|
@@ -14781,6 +15175,16 @@ class PlaceholderRegistry {
|
|
|
14781
15175
|
_hashClosingTag(tag) {
|
|
14782
15176
|
return this._hashTag(`/${tag}`, {}, false);
|
|
14783
15177
|
}
|
|
15178
|
+
_hashBlock(name, parameters) {
|
|
15179
|
+
const params = parameters.length === 0 ? '' : ` (${parameters.sort().join('; ')})`;
|
|
15180
|
+
return `@${name}${params} {}`;
|
|
15181
|
+
}
|
|
15182
|
+
_hashClosingBlock(name) {
|
|
15183
|
+
return this._hashBlock(`close_${name}`, []);
|
|
15184
|
+
}
|
|
15185
|
+
_toSnakeCase(name) {
|
|
15186
|
+
return name.toUpperCase().replace(/[^A-Z0-9]/g, '_');
|
|
15187
|
+
}
|
|
14784
15188
|
_generateUniqueName(base) {
|
|
14785
15189
|
const seen = this._placeHolderNameCounts.hasOwnProperty(base);
|
|
14786
15190
|
if (!seen) {
|
|
@@ -14797,17 +15201,18 @@ const _expParser = new Parser$1(new Lexer());
|
|
|
14797
15201
|
/**
|
|
14798
15202
|
* Returns a function converting html nodes to an i18n Message given an interpolationConfig
|
|
14799
15203
|
*/
|
|
14800
|
-
function createI18nMessageFactory(interpolationConfig) {
|
|
14801
|
-
const visitor = new _I18nVisitor(_expParser, interpolationConfig);
|
|
15204
|
+
function createI18nMessageFactory(interpolationConfig, containerBlocks) {
|
|
15205
|
+
const visitor = new _I18nVisitor(_expParser, interpolationConfig, containerBlocks);
|
|
14802
15206
|
return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
|
|
14803
15207
|
}
|
|
14804
15208
|
function noopVisitNodeFn(_html, i18n) {
|
|
14805
15209
|
return i18n;
|
|
14806
15210
|
}
|
|
14807
15211
|
class _I18nVisitor {
|
|
14808
|
-
constructor(_expressionParser, _interpolationConfig) {
|
|
15212
|
+
constructor(_expressionParser, _interpolationConfig, _containerBlocks) {
|
|
14809
15213
|
this._expressionParser = _expressionParser;
|
|
14810
15214
|
this._interpolationConfig = _interpolationConfig;
|
|
15215
|
+
this._containerBlocks = _containerBlocks;
|
|
14811
15216
|
}
|
|
14812
15217
|
toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
|
|
14813
15218
|
const context = {
|
|
@@ -14894,10 +15299,26 @@ class _I18nVisitor {
|
|
|
14894
15299
|
}
|
|
14895
15300
|
visitBlock(block, context) {
|
|
14896
15301
|
const children = visitAll(this, block.children, context);
|
|
14897
|
-
|
|
15302
|
+
if (this._containerBlocks.has(block.name)) {
|
|
15303
|
+
return new Container(children, block.sourceSpan);
|
|
15304
|
+
}
|
|
15305
|
+
const parameters = block.parameters.map(param => param.expression);
|
|
15306
|
+
const startPhName = context.placeholderRegistry.getStartBlockPlaceholderName(block.name, parameters);
|
|
15307
|
+
const closePhName = context.placeholderRegistry.getCloseBlockPlaceholderName(block.name);
|
|
15308
|
+
context.placeholderToContent[startPhName] = {
|
|
15309
|
+
text: block.startSourceSpan.toString(),
|
|
15310
|
+
sourceSpan: block.startSourceSpan,
|
|
15311
|
+
};
|
|
15312
|
+
context.placeholderToContent[closePhName] = {
|
|
15313
|
+
text: block.endSourceSpan ? block.endSourceSpan.toString() : '}',
|
|
15314
|
+
sourceSpan: block.endSourceSpan ?? block.sourceSpan,
|
|
15315
|
+
};
|
|
15316
|
+
const node = new BlockPlaceholder(block.name, parameters, startPhName, closePhName, children, block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
|
|
14898
15317
|
return context.visitNodeFn(block, node);
|
|
14899
15318
|
}
|
|
14900
|
-
visitBlockParameter(_parameter, _context) {
|
|
15319
|
+
visitBlockParameter(_parameter, _context) {
|
|
15320
|
+
throw new Error('Unreachable code');
|
|
15321
|
+
}
|
|
14901
15322
|
/**
|
|
14902
15323
|
* Convert, text and interpolated tokens up into text and placeholder pieces.
|
|
14903
15324
|
*
|
|
@@ -18766,17 +19187,18 @@ const setI18nRefs = (htmlNode, i18nNode) => {
|
|
|
18766
19187
|
* stored with other element's and attribute's information.
|
|
18767
19188
|
*/
|
|
18768
19189
|
class I18nMetaVisitor {
|
|
18769
|
-
constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false) {
|
|
19190
|
+
constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false, containerBlocks = DEFAULT_CONTAINER_BLOCKS) {
|
|
18770
19191
|
this.interpolationConfig = interpolationConfig;
|
|
18771
19192
|
this.keepI18nAttrs = keepI18nAttrs;
|
|
18772
19193
|
this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
|
|
19194
|
+
this.containerBlocks = containerBlocks;
|
|
18773
19195
|
// whether visited nodes contain i18n information
|
|
18774
19196
|
this.hasI18nMeta = false;
|
|
18775
19197
|
this._errors = [];
|
|
18776
19198
|
}
|
|
18777
19199
|
_generateI18nMessage(nodes, meta = '', visitNodeFn) {
|
|
18778
19200
|
const { meaning, description, customId } = this._parseMetadata(meta);
|
|
18779
|
-
const createI18nMessage = createI18nMessageFactory(this.interpolationConfig);
|
|
19201
|
+
const createI18nMessage = createI18nMessageFactory(this.interpolationConfig, this.containerBlocks);
|
|
18780
19202
|
const message = createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
|
|
18781
19203
|
this._setMessageId(message, meta);
|
|
18782
19204
|
this._setLegacyIds(message, meta);
|
|
@@ -19077,6 +19499,9 @@ class GetMsgSerializerVisitor {
|
|
|
19077
19499
|
visitPlaceholder(ph) {
|
|
19078
19500
|
return this.formatPh(ph.name);
|
|
19079
19501
|
}
|
|
19502
|
+
visitBlockPlaceholder(ph) {
|
|
19503
|
+
return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
|
|
19504
|
+
}
|
|
19080
19505
|
visitIcuPlaceholder(ph, context) {
|
|
19081
19506
|
return this.formatPh(ph.name);
|
|
19082
19507
|
}
|
|
@@ -19130,6 +19555,11 @@ class LocalizeSerializerVisitor {
|
|
|
19130
19555
|
visitPlaceholder(ph) {
|
|
19131
19556
|
this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
|
|
19132
19557
|
}
|
|
19558
|
+
visitBlockPlaceholder(ph) {
|
|
19559
|
+
this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
|
|
19560
|
+
ph.children.forEach(child => child.visit(this));
|
|
19561
|
+
this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
|
|
19562
|
+
}
|
|
19133
19563
|
visitIcuPlaceholder(ph) {
|
|
19134
19564
|
this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan, this.placeholderToMessage[ph.name]));
|
|
19135
19565
|
}
|
|
@@ -19203,35 +19633,136 @@ const NG_I18N_CLOSURE_MODE$1 = 'ngI18nClosureMode';
|
|
|
19203
19633
|
* considers variables like `I18N_0` as constants and throws an error when their value changes.
|
|
19204
19634
|
*/
|
|
19205
19635
|
const TRANSLATION_VAR_PREFIX = 'i18n_';
|
|
19636
|
+
/** Prefix of ICU expressions for post processing */
|
|
19637
|
+
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
19638
|
+
/**
|
|
19639
|
+
* The escape sequence used for message param values.
|
|
19640
|
+
*/
|
|
19641
|
+
const ESCAPE = '\uFFFD';
|
|
19206
19642
|
/**
|
|
19207
19643
|
* Lifts i18n properties into the consts array.
|
|
19208
19644
|
* TODO: Can we use `ConstCollectedExpr`?
|
|
19645
|
+
* TODO: The way the various attributes are linked together is very complex. Perhaps we could
|
|
19646
|
+
* simplify the process, maybe by combining the context and message ops?
|
|
19209
19647
|
*/
|
|
19210
19648
|
function collectI18nConsts(job) {
|
|
19211
19649
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
19212
|
-
|
|
19213
|
-
//
|
|
19650
|
+
// Step One: Build up various lookup maps we need to collect all the consts.
|
|
19651
|
+
// Context Xref -> Extracted Attribute Ops
|
|
19652
|
+
const extractedAttributesByI18nContext = new Map();
|
|
19653
|
+
// Element/ElementStart Xref -> I18n Attributes config op
|
|
19654
|
+
const i18nAttributesByElement = new Map();
|
|
19655
|
+
// Element/ElementStart Xref -> All I18n Expression ops for attrs on that target
|
|
19656
|
+
const i18nExpressionsByElement = new Map();
|
|
19657
|
+
// I18n Message Xref -> I18n Message Op (TODO: use a central op map)
|
|
19214
19658
|
const messages = new Map();
|
|
19659
|
+
for (const unit of job.units) {
|
|
19660
|
+
for (const op of unit.ops()) {
|
|
19661
|
+
if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
|
|
19662
|
+
const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
|
|
19663
|
+
attributes.push(op);
|
|
19664
|
+
extractedAttributesByI18nContext.set(op.i18nContext, attributes);
|
|
19665
|
+
}
|
|
19666
|
+
else if (op.kind === OpKind.I18nAttributes) {
|
|
19667
|
+
i18nAttributesByElement.set(op.target, op);
|
|
19668
|
+
}
|
|
19669
|
+
else if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nAttribute) {
|
|
19670
|
+
const expressions = i18nExpressionsByElement.get(op.target) ?? [];
|
|
19671
|
+
expressions.push(op);
|
|
19672
|
+
i18nExpressionsByElement.set(op.target, expressions);
|
|
19673
|
+
}
|
|
19674
|
+
else if (op.kind === OpKind.I18nMessage) {
|
|
19675
|
+
messages.set(op.xref, op);
|
|
19676
|
+
}
|
|
19677
|
+
}
|
|
19678
|
+
}
|
|
19679
|
+
// Step Two: Serialize the extracted i18n messages for root i18n blocks and i18n attributes into
|
|
19680
|
+
// the const array.
|
|
19681
|
+
//
|
|
19682
|
+
// Also, each i18n message will have a variable expression that can refer to its
|
|
19683
|
+
// value. Store these expressions in the appropriate place:
|
|
19684
|
+
// 1. For normal i18n content, it also goes in the const array. We save the const index to use
|
|
19685
|
+
// later.
|
|
19686
|
+
// 2. For extracted attributes, it becomes the value of the extracted attribute instruction.
|
|
19687
|
+
// 3. For i18n bindings, it will go in a separate const array instruction below; for now, we just
|
|
19688
|
+
// save it.
|
|
19689
|
+
const i18nValuesByContext = new Map();
|
|
19690
|
+
const messageConstIndices = new Map();
|
|
19215
19691
|
for (const unit of job.units) {
|
|
19216
19692
|
for (const op of unit.create) {
|
|
19217
19693
|
if (op.kind === OpKind.I18nMessage) {
|
|
19218
|
-
|
|
19694
|
+
if (op.messagePlaceholder === null) {
|
|
19695
|
+
const { mainVar, statements } = collectMessage(job, fileBasedI18nSuffix, messages, op);
|
|
19696
|
+
if (op.i18nBlock !== null) {
|
|
19697
|
+
// This is a regular i18n message with a corresponding i18n block. Collect it into the
|
|
19698
|
+
// const array.
|
|
19699
|
+
const i18nConst = job.addConst(mainVar, statements);
|
|
19700
|
+
messageConstIndices.set(op.i18nBlock, i18nConst);
|
|
19701
|
+
}
|
|
19702
|
+
else {
|
|
19703
|
+
// This is an i18n attribute. Extract the initializers into the const pool.
|
|
19704
|
+
job.constsInitializers.push(...statements);
|
|
19705
|
+
// Save the i18n variable value for later.
|
|
19706
|
+
i18nValuesByContext.set(op.i18nContext, mainVar);
|
|
19707
|
+
// This i18n message may correspond to an individual extracted attribute. If so, The
|
|
19708
|
+
// value of that attribute is updated to read the extracted i18n variable.
|
|
19709
|
+
const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
|
|
19710
|
+
if (attributesForMessage !== undefined) {
|
|
19711
|
+
for (const attr of attributesForMessage) {
|
|
19712
|
+
attr.expression = mainVar.clone();
|
|
19713
|
+
}
|
|
19714
|
+
}
|
|
19715
|
+
}
|
|
19716
|
+
}
|
|
19219
19717
|
OpList.remove(op);
|
|
19220
19718
|
}
|
|
19221
19719
|
}
|
|
19222
19720
|
}
|
|
19223
|
-
//
|
|
19224
|
-
|
|
19225
|
-
|
|
19226
|
-
|
|
19227
|
-
|
|
19721
|
+
// Step Three: Serialize I18nAttributes configurations into the const array. Each I18nAttributes
|
|
19722
|
+
// instruction has a config array, which contains k-v pairs describing each binding name, and the
|
|
19723
|
+
// i18n variable that provides the value.
|
|
19724
|
+
for (const unit of job.units) {
|
|
19725
|
+
for (const elem of unit.create) {
|
|
19726
|
+
if (isElementOrContainerOp(elem)) {
|
|
19727
|
+
const i18nAttributes = i18nAttributesByElement.get(elem.xref);
|
|
19728
|
+
if (i18nAttributes === undefined) {
|
|
19729
|
+
// This element is not associated with an i18n attributes configuration instruction.
|
|
19730
|
+
continue;
|
|
19731
|
+
}
|
|
19732
|
+
let i18nExpressions = i18nExpressionsByElement.get(elem.xref);
|
|
19733
|
+
if (i18nExpressions === undefined) {
|
|
19734
|
+
// Unused i18nAttributes should have already been removed.
|
|
19735
|
+
// TODO: Should the removal of those dead instructions be merged with this phase?
|
|
19736
|
+
throw new Error('AssertionError: Could not find any i18n expressions associated with an I18nAttributes instruction');
|
|
19737
|
+
}
|
|
19738
|
+
// Find expressions for all the unique property names, removing duplicates.
|
|
19739
|
+
const seenPropertyNames = new Set();
|
|
19740
|
+
i18nExpressions = i18nExpressions.filter(i18nExpr => {
|
|
19741
|
+
const seen = (seenPropertyNames.has(i18nExpr.name));
|
|
19742
|
+
seenPropertyNames.add(i18nExpr.name);
|
|
19743
|
+
return !seen;
|
|
19744
|
+
});
|
|
19745
|
+
const i18nAttributeConfig = i18nExpressions.flatMap(i18nExpr => {
|
|
19746
|
+
const i18nExprValue = i18nValuesByContext.get(i18nExpr.context);
|
|
19747
|
+
if (i18nExprValue === undefined) {
|
|
19748
|
+
throw new Error('AssertionError: Could not find i18n expression\'s value');
|
|
19749
|
+
}
|
|
19750
|
+
return [literal(i18nExpr.name), i18nExprValue];
|
|
19751
|
+
});
|
|
19752
|
+
i18nAttributes.i18nAttributesConfig =
|
|
19753
|
+
job.addConst(new LiteralArrayExpr(i18nAttributeConfig));
|
|
19754
|
+
}
|
|
19228
19755
|
}
|
|
19229
19756
|
}
|
|
19230
|
-
//
|
|
19757
|
+
// Step Four: Propagate the extracted const index into i18n ops that messages were extracted from.
|
|
19231
19758
|
for (const unit of job.units) {
|
|
19232
19759
|
for (const op of unit.create) {
|
|
19233
19760
|
if (op.kind === OpKind.I18nStart) {
|
|
19234
|
-
|
|
19761
|
+
const msgIndex = messageConstIndices.get(op.root);
|
|
19762
|
+
if (msgIndex === undefined) {
|
|
19763
|
+
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?');
|
|
19764
|
+
}
|
|
19765
|
+
op.messageIndex = msgIndex;
|
|
19235
19766
|
}
|
|
19236
19767
|
}
|
|
19237
19768
|
}
|
|
@@ -19241,16 +19772,23 @@ function collectI18nConsts(job) {
|
|
|
19241
19772
|
* This will recursively collect any sub-messages referenced from the parent message as well.
|
|
19242
19773
|
*/
|
|
19243
19774
|
function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
19244
|
-
// Recursively collect any sub-messages,
|
|
19775
|
+
// Recursively collect any sub-messages, record each sub-message's main variable under its
|
|
19776
|
+
// placeholder so that we can add them to the params for the parent message. It is possible
|
|
19777
|
+
// that multiple sub-messages will share the same placeholder, so we need to track an array of
|
|
19778
|
+
// variables for each placeholder.
|
|
19245
19779
|
const statements = [];
|
|
19780
|
+
const subMessagePlaceholders = new Map();
|
|
19246
19781
|
for (const subMessageId of messageOp.subMessages) {
|
|
19247
19782
|
const subMessage = messages.get(subMessageId);
|
|
19248
19783
|
const { mainVar: subMessageVar, statements: subMessageStatements } = collectMessage(job, fileBasedI18nSuffix, messages, subMessage);
|
|
19249
19784
|
statements.push(...subMessageStatements);
|
|
19250
|
-
|
|
19785
|
+
const subMessages = subMessagePlaceholders.get(subMessage.messagePlaceholder) ?? [];
|
|
19786
|
+
subMessages.push(subMessageVar);
|
|
19787
|
+
subMessagePlaceholders.set(subMessage.messagePlaceholder, subMessages);
|
|
19251
19788
|
}
|
|
19252
|
-
|
|
19253
|
-
|
|
19789
|
+
addSubMessageParams(messageOp, subMessagePlaceholders);
|
|
19790
|
+
// Sort the params for consistency with TemaplateDefinitionBuilder output.
|
|
19791
|
+
messageOp.params = new Map([...messageOp.params.entries()].sort());
|
|
19254
19792
|
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
19255
19793
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other
|
|
19256
19794
|
// const to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
@@ -19259,10 +19797,13 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19259
19797
|
let transformFn = undefined;
|
|
19260
19798
|
// If nescessary, add a post-processing step and resolve any placeholder params that are
|
|
19261
19799
|
// set in post-processing.
|
|
19262
|
-
if (messageOp.needsPostprocessing) {
|
|
19800
|
+
if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
|
|
19801
|
+
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
19802
|
+
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
19803
|
+
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
19263
19804
|
const extraTransformFnParams = [];
|
|
19264
19805
|
if (messageOp.postprocessingParams.size > 0) {
|
|
19265
|
-
extraTransformFnParams.push(
|
|
19806
|
+
extraTransformFnParams.push(mapLiteral(formattedPostprocessingParams, /* quoted */ true));
|
|
19266
19807
|
}
|
|
19267
19808
|
transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
|
|
19268
19809
|
}
|
|
@@ -19270,6 +19811,25 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19270
19811
|
statements.push(...getTranslationDeclStmts$1(messageOp.message, mainVar, closureVar, messageOp.params, transformFn));
|
|
19271
19812
|
return { mainVar, statements };
|
|
19272
19813
|
}
|
|
19814
|
+
/**
|
|
19815
|
+
* Adds the given subMessage placeholders to the given message op.
|
|
19816
|
+
*
|
|
19817
|
+
* If a placeholder only corresponds to a single sub-message variable, we just set that variable
|
|
19818
|
+
* as the param value. However, if the placeholder corresponds to multiple sub-message
|
|
19819
|
+
* variables, we need to add a special placeholder value that is handled by the post-processing
|
|
19820
|
+
* step. We then add the array of variables as a post-processing param.
|
|
19821
|
+
*/
|
|
19822
|
+
function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
19823
|
+
for (const [placeholder, subMessages] of subMessagePlaceholders) {
|
|
19824
|
+
if (subMessages.length === 1) {
|
|
19825
|
+
messageOp.params.set(placeholder, subMessages[0]);
|
|
19826
|
+
}
|
|
19827
|
+
else {
|
|
19828
|
+
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
19829
|
+
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
19830
|
+
}
|
|
19831
|
+
}
|
|
19832
|
+
}
|
|
19273
19833
|
/**
|
|
19274
19834
|
* Generate statements that define a given translation message.
|
|
19275
19835
|
*
|
|
@@ -19292,7 +19852,8 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
19292
19852
|
* @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
|
|
19293
19853
|
* @param params Object mapping placeholder names to their values (e.g.
|
|
19294
19854
|
* `{ "interpolation": "\uFFFD0\uFFFD" }`).
|
|
19295
|
-
* @param transformFn Optional transformation function that will be applied to the translation
|
|
19855
|
+
* @param transformFn Optional transformation function that will be applied to the translation
|
|
19856
|
+
* (e.g.
|
|
19296
19857
|
* post-processing).
|
|
19297
19858
|
* @returns An array of statements that defined a given translation.
|
|
19298
19859
|
*/
|
|
@@ -19337,31 +19898,21 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
|
|
|
19337
19898
|
}
|
|
19338
19899
|
return variable(name);
|
|
19339
19900
|
}
|
|
19340
|
-
/**
|
|
19341
|
-
* Asserts that all of the message's placeholders have values.
|
|
19342
|
-
*/
|
|
19343
|
-
function assertAllParamsResolved(op) {
|
|
19344
|
-
for (const placeholder in op.message.placeholders) {
|
|
19345
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19346
|
-
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
19347
|
-
}
|
|
19348
|
-
}
|
|
19349
|
-
for (const placeholder in op.message.placeholderToMessage) {
|
|
19350
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
19351
|
-
throw Error(`Failed to resolve i18n message placeholder: ${placeholder}`);
|
|
19352
|
-
}
|
|
19353
|
-
}
|
|
19354
|
-
}
|
|
19355
19901
|
|
|
19356
19902
|
/**
|
|
19357
19903
|
* Removes text nodes within i18n blocks since they are already hardcoded into the i18n message.
|
|
19904
|
+
* Also, replaces interpolations on these text nodes with i18n expressions of the non-text portions,
|
|
19905
|
+
* which will be applied later.
|
|
19358
19906
|
*/
|
|
19359
|
-
function
|
|
19907
|
+
function convertI18nText(job) {
|
|
19360
19908
|
for (const unit of job.units) {
|
|
19361
19909
|
// Remove all text nodes within i18n blocks, their content is already captured in the i18n
|
|
19362
19910
|
// message.
|
|
19363
19911
|
let currentI18n = null;
|
|
19912
|
+
let currentIcu = null;
|
|
19364
19913
|
const textNodeI18nBlocks = new Map();
|
|
19914
|
+
const textNodeIcus = new Map();
|
|
19915
|
+
const icuPlaceholderByText = new Map();
|
|
19365
19916
|
for (const op of unit.create) {
|
|
19366
19917
|
switch (op.kind) {
|
|
19367
19918
|
case OpKind.I18nStart:
|
|
@@ -19373,10 +19924,32 @@ function extractI18nText(job) {
|
|
|
19373
19924
|
case OpKind.I18nEnd:
|
|
19374
19925
|
currentI18n = null;
|
|
19375
19926
|
break;
|
|
19927
|
+
case OpKind.IcuStart:
|
|
19928
|
+
if (op.context === null) {
|
|
19929
|
+
throw Error('Icu op should have its context set.');
|
|
19930
|
+
}
|
|
19931
|
+
currentIcu = op;
|
|
19932
|
+
break;
|
|
19933
|
+
case OpKind.IcuEnd:
|
|
19934
|
+
currentIcu = null;
|
|
19935
|
+
break;
|
|
19376
19936
|
case OpKind.Text:
|
|
19377
19937
|
if (currentI18n !== null) {
|
|
19378
19938
|
textNodeI18nBlocks.set(op.xref, currentI18n);
|
|
19379
|
-
|
|
19939
|
+
textNodeIcus.set(op.xref, currentIcu);
|
|
19940
|
+
if (op.icuPlaceholder !== null) {
|
|
19941
|
+
// Create an op to represent the ICU placeholder. Initially set its static text to the
|
|
19942
|
+
// value of the text op, though this may be overwritten later if this text op is a
|
|
19943
|
+
// placeholder for an interpolation.
|
|
19944
|
+
const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
|
|
19945
|
+
OpList.replace(op, icuPlaceholderOp);
|
|
19946
|
+
icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
|
|
19947
|
+
}
|
|
19948
|
+
else {
|
|
19949
|
+
// Otherwise just remove the text op, since its value is already accounted for in the
|
|
19950
|
+
// translated message.
|
|
19951
|
+
OpList.remove(op);
|
|
19952
|
+
}
|
|
19380
19953
|
}
|
|
19381
19954
|
break;
|
|
19382
19955
|
}
|
|
@@ -19390,15 +19963,24 @@ function extractI18nText(job) {
|
|
|
19390
19963
|
continue;
|
|
19391
19964
|
}
|
|
19392
19965
|
const i18nOp = textNodeI18nBlocks.get(op.target);
|
|
19966
|
+
const icuOp = textNodeIcus.get(op.target);
|
|
19967
|
+
const icuPlaceholder = icuPlaceholderByText.get(op.target);
|
|
19968
|
+
const contextId = icuOp ? icuOp.context : i18nOp.context;
|
|
19969
|
+
const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing :
|
|
19970
|
+
I18nParamResolutionTime.Creation;
|
|
19393
19971
|
const ops = [];
|
|
19394
19972
|
for (let i = 0; i < op.interpolation.expressions.length; i++) {
|
|
19395
19973
|
const expr = op.interpolation.expressions[i];
|
|
19396
|
-
const placeholder = op.i18nPlaceholders[i];
|
|
19397
19974
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
19398
19975
|
// Later, we will modify this, and advance to a different point.
|
|
19399
|
-
ops.push(createI18nExpressionOp(i18nOp.
|
|
19976
|
+
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, icuPlaceholder?.xref ?? null, op.interpolation.i18nPlaceholders[i] ?? null, resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
19400
19977
|
}
|
|
19401
19978
|
OpList.replaceWithMany(op, ops);
|
|
19979
|
+
// If this interpolation is part of an ICU placeholder, add the strings and expressions to
|
|
19980
|
+
// the placeholder.
|
|
19981
|
+
if (icuPlaceholder !== undefined) {
|
|
19982
|
+
icuPlaceholder.strings = op.interpolation.strings;
|
|
19983
|
+
}
|
|
19402
19984
|
break;
|
|
19403
19985
|
}
|
|
19404
19986
|
}
|
|
@@ -19434,60 +20016,9 @@ function liftLocalRefs(job) {
|
|
|
19434
20016
|
function serializeLocalRefs(refs) {
|
|
19435
20017
|
const constRefs = [];
|
|
19436
20018
|
for (const ref of refs) {
|
|
19437
|
-
constRefs.push(literal(ref.name), literal(ref.target));
|
|
19438
|
-
}
|
|
19439
|
-
return literalArr(constRefs);
|
|
19440
|
-
}
|
|
19441
|
-
|
|
19442
|
-
/**
|
|
19443
|
-
* Merge i18n contexts for child i18n blocks into their ancestor root contexts.
|
|
19444
|
-
*/
|
|
19445
|
-
function mergeI18nContexts(job) {
|
|
19446
|
-
// Record all of the i18n and extracted message ops for use later.
|
|
19447
|
-
const i18nOps = new Map();
|
|
19448
|
-
const i18nContexts = new Map();
|
|
19449
|
-
for (const unit of job.units) {
|
|
19450
|
-
for (const op of unit.create) {
|
|
19451
|
-
switch (op.kind) {
|
|
19452
|
-
case OpKind.I18nStart:
|
|
19453
|
-
if (!op.context) {
|
|
19454
|
-
throw Error('I18n op should have its context set.');
|
|
19455
|
-
}
|
|
19456
|
-
i18nOps.set(op.xref, op);
|
|
19457
|
-
break;
|
|
19458
|
-
case OpKind.I18nContext:
|
|
19459
|
-
i18nContexts.set(op.xref, op);
|
|
19460
|
-
break;
|
|
19461
|
-
}
|
|
19462
|
-
}
|
|
19463
|
-
}
|
|
19464
|
-
// For each non-root i18n op, merge its context into the root i18n op's context.
|
|
19465
|
-
for (const childI18nOp of i18nOps.values()) {
|
|
19466
|
-
if (childI18nOp.xref !== childI18nOp.root) {
|
|
19467
|
-
const childContext = i18nContexts.get(childI18nOp.context);
|
|
19468
|
-
const rootI18nOp = i18nOps.get(childI18nOp.root);
|
|
19469
|
-
const rootContext = i18nContexts.get(rootI18nOp.context);
|
|
19470
|
-
mergeParams(rootContext.params, childContext.params);
|
|
19471
|
-
mergeParams(rootContext.postprocessingParams, childContext.postprocessingParams);
|
|
19472
|
-
}
|
|
19473
|
-
}
|
|
19474
|
-
}
|
|
19475
|
-
/**
|
|
19476
|
-
* Merges the params in the `from` map to into the `to` map.
|
|
19477
|
-
*/
|
|
19478
|
-
function mergeParams(to, from) {
|
|
19479
|
-
for (const [placeholder, fromValues] of from) {
|
|
19480
|
-
const toValues = to.get(placeholder) || [];
|
|
19481
|
-
// TODO(mmalerba): Child element close tag params should be prepended to maintain the same order
|
|
19482
|
-
// as TemplateDefinitionBuilder. Can be cleaned up when compatibility is no longer required.
|
|
19483
|
-
const flags = fromValues[0].flags;
|
|
19484
|
-
if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
|
|
19485
|
-
to.set(placeholder, [...fromValues, ...toValues]);
|
|
19486
|
-
}
|
|
19487
|
-
else {
|
|
19488
|
-
to.set(placeholder, [...toValues, ...fromValues]);
|
|
19489
|
-
}
|
|
20019
|
+
constRefs.push(literal(ref.name), literal(ref.target));
|
|
19490
20020
|
}
|
|
20021
|
+
return literalArr(constRefs);
|
|
19491
20022
|
}
|
|
19492
20023
|
|
|
19493
20024
|
/**
|
|
@@ -19978,21 +20509,39 @@ function keepLast(ops) {
|
|
|
19978
20509
|
* class property.
|
|
19979
20510
|
*/
|
|
19980
20511
|
function parseExtractedStyles(job) {
|
|
20512
|
+
const elements = new Map();
|
|
20513
|
+
for (const unit of job.units) {
|
|
20514
|
+
for (const op of unit.create) {
|
|
20515
|
+
if (isElementOrContainerOp(op)) {
|
|
20516
|
+
elements.set(op.xref, op);
|
|
20517
|
+
}
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
19981
20520
|
for (const unit of job.units) {
|
|
19982
20521
|
for (const op of unit.create) {
|
|
19983
20522
|
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
19984
20523
|
isStringLiteral(op.expression)) {
|
|
20524
|
+
const target = elements.get(op.target);
|
|
20525
|
+
if (target !== undefined && target.kind === OpKind.Template &&
|
|
20526
|
+
target.templateKind === TemplateKind.Structural) {
|
|
20527
|
+
// TemplateDefinitionBuilder will not apply class and style bindings to structural
|
|
20528
|
+
// directives; instead, it will leave them as attributes.
|
|
20529
|
+
// (It's not clear what that would mean, anyway -- classes and styles on a structural
|
|
20530
|
+
// element should probably be a parse error.)
|
|
20531
|
+
// TODO: We may be able to remove this once Template Pipeline is the default.
|
|
20532
|
+
continue;
|
|
20533
|
+
}
|
|
19985
20534
|
if (op.name === 'style') {
|
|
19986
20535
|
const parsedStyles = parse(op.expression.value);
|
|
19987
20536
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
19988
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1])), op);
|
|
20537
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
19989
20538
|
}
|
|
19990
20539
|
OpList.remove(op);
|
|
19991
20540
|
}
|
|
19992
20541
|
else if (op.name === 'class') {
|
|
19993
20542
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
19994
20543
|
for (const parsedClass of parsedClasses) {
|
|
19995
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null), op);
|
|
20544
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
19996
20545
|
}
|
|
19997
20546
|
OpList.remove(op);
|
|
19998
20547
|
}
|
|
@@ -20008,18 +20557,30 @@ function parseExtractedStyles(job) {
|
|
|
20008
20557
|
function removeContentSelectors(job) {
|
|
20009
20558
|
for (const unit of job.units) {
|
|
20010
20559
|
const elements = createOpXrefMap(unit);
|
|
20011
|
-
for (const op of unit.
|
|
20560
|
+
for (const op of unit.ops()) {
|
|
20012
20561
|
switch (op.kind) {
|
|
20013
20562
|
case OpKind.Binding:
|
|
20014
20563
|
const target = lookupInXrefMap(elements, op.target);
|
|
20015
|
-
if (op.name
|
|
20564
|
+
if (isSelectAttribute(op.name) && target.kind === OpKind.Projection) {
|
|
20016
20565
|
OpList.remove(op);
|
|
20017
20566
|
}
|
|
20018
20567
|
break;
|
|
20568
|
+
case OpKind.Projection:
|
|
20569
|
+
// op.attributes is an array of [attr1-name, attr1-value, attr2-name, attr2-value, ...],
|
|
20570
|
+
// find the "select" attribute and remove its name and corresponding value.
|
|
20571
|
+
for (let i = op.attributes.length - 2; i >= 0; i -= 2) {
|
|
20572
|
+
if (isSelectAttribute(op.attributes[i])) {
|
|
20573
|
+
op.attributes.splice(i, 2);
|
|
20574
|
+
}
|
|
20575
|
+
}
|
|
20576
|
+
break;
|
|
20019
20577
|
}
|
|
20020
20578
|
}
|
|
20021
20579
|
}
|
|
20022
20580
|
}
|
|
20581
|
+
function isSelectAttribute(name) {
|
|
20582
|
+
return name.toLowerCase() === 'select';
|
|
20583
|
+
}
|
|
20023
20584
|
/**
|
|
20024
20585
|
* Looks up an element in the given map by xref ID.
|
|
20025
20586
|
*/
|
|
@@ -20139,23 +20700,43 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
|
20139
20700
|
i18nBlock = op;
|
|
20140
20701
|
break;
|
|
20141
20702
|
case OpKind.I18nEnd:
|
|
20703
|
+
// When we exit a root-level i18n block, reset the sub-template index counter.
|
|
20704
|
+
if (i18nBlock.subTemplateIndex === null) {
|
|
20705
|
+
subTemplateIndex = 0;
|
|
20706
|
+
}
|
|
20142
20707
|
i18nBlock = null;
|
|
20143
20708
|
break;
|
|
20144
20709
|
case OpKind.Template:
|
|
20145
|
-
|
|
20146
|
-
|
|
20147
|
-
|
|
20148
|
-
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20710
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
20711
|
+
break;
|
|
20712
|
+
case OpKind.RepeaterCreate:
|
|
20713
|
+
// Propagate i18n blocks to the @for template.
|
|
20714
|
+
unit.job.views.get(op.xref);
|
|
20715
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
|
|
20716
|
+
// Then if there's an @empty template, propagate the i18n blocks for it as well.
|
|
20717
|
+
if (op.emptyView !== null) {
|
|
20718
|
+
subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
|
|
20154
20719
|
}
|
|
20155
|
-
|
|
20156
|
-
|
|
20720
|
+
break;
|
|
20721
|
+
}
|
|
20722
|
+
}
|
|
20723
|
+
return subTemplateIndex;
|
|
20724
|
+
}
|
|
20725
|
+
/**
|
|
20726
|
+
* Propagate i18n blocks for a view.
|
|
20727
|
+
*/
|
|
20728
|
+
function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
|
|
20729
|
+
// We found an <ng-template> inside an i18n block; increment the sub-template counter and
|
|
20730
|
+
// wrap the template's view in a child i18n block.
|
|
20731
|
+
if (i18nPlaceholder !== undefined) {
|
|
20732
|
+
if (i18nBlock === null) {
|
|
20733
|
+
throw Error('Expected template with i18n placeholder to be in an i18n block.');
|
|
20157
20734
|
}
|
|
20735
|
+
subTemplateIndex++;
|
|
20736
|
+
wrapTemplateWithI18n(view, i18nBlock);
|
|
20158
20737
|
}
|
|
20738
|
+
// Continue traversing inside the template's view.
|
|
20739
|
+
return propagateI18nBlocksToTemplates(view, subTemplateIndex);
|
|
20159
20740
|
}
|
|
20160
20741
|
/**
|
|
20161
20742
|
* Wraps a template view with i18n start and end ops.
|
|
@@ -20322,17 +20903,13 @@ function disableBindings() {
|
|
|
20322
20903
|
function enableBindings() {
|
|
20323
20904
|
return call(Identifiers.enableBindings, [], null);
|
|
20324
20905
|
}
|
|
20325
|
-
function listener(name, handlerFn, sourceSpan) {
|
|
20326
|
-
|
|
20327
|
-
|
|
20328
|
-
|
|
20329
|
-
|
|
20330
|
-
}
|
|
20331
|
-
|
|
20332
|
-
return call(Identifiers.syntheticHostListener, [
|
|
20333
|
-
literal(name),
|
|
20334
|
-
handlerFn,
|
|
20335
|
-
], sourceSpan);
|
|
20906
|
+
function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
|
|
20907
|
+
const args = [literal(name), handlerFn];
|
|
20908
|
+
if (eventTargetResolver !== null) {
|
|
20909
|
+
args.push(literal(false)); // `useCapture` flag, defaults to `false`
|
|
20910
|
+
args.push(importExpr(eventTargetResolver));
|
|
20911
|
+
}
|
|
20912
|
+
return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
|
|
20336
20913
|
}
|
|
20337
20914
|
function pipe(slot, name) {
|
|
20338
20915
|
return call(Identifiers.pipe, [
|
|
@@ -20463,8 +21040,8 @@ function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByF
|
|
|
20463
21040
|
}
|
|
20464
21041
|
return call(Identifiers.repeaterCreate, args, sourceSpan);
|
|
20465
21042
|
}
|
|
20466
|
-
function repeater(
|
|
20467
|
-
return call(Identifiers.repeater, [
|
|
21043
|
+
function repeater(collection, sourceSpan) {
|
|
21044
|
+
return call(Identifiers.repeater, [collection], sourceSpan);
|
|
20468
21045
|
}
|
|
20469
21046
|
function deferWhen(prefetch, expr, sourceSpan) {
|
|
20470
21047
|
return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
|
|
@@ -20479,6 +21056,10 @@ function i18n(slot, constIndex, subTemplateIndex) {
|
|
|
20479
21056
|
function i18nEnd() {
|
|
20480
21057
|
return call(Identifiers.i18nEnd, [], null);
|
|
20481
21058
|
}
|
|
21059
|
+
function i18nAttributes(slot, i18nAttributesConfig) {
|
|
21060
|
+
const args = [literal(slot), literal(i18nAttributesConfig)];
|
|
21061
|
+
return call(Identifiers.i18nAttributes, args, null);
|
|
21062
|
+
}
|
|
20482
21063
|
function property(name, expression, sanitizer, sourceSpan) {
|
|
20483
21064
|
const args = [literal(name), expression];
|
|
20484
21065
|
if (sanitizer !== null) {
|
|
@@ -20589,8 +21170,12 @@ function classMapInterpolate(strings, expressions, sourceSpan) {
|
|
|
20589
21170
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
20590
21171
|
return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
|
|
20591
21172
|
}
|
|
20592
|
-
function hostProperty(name, expression, sourceSpan) {
|
|
20593
|
-
|
|
21173
|
+
function hostProperty(name, expression, sanitizer, sourceSpan) {
|
|
21174
|
+
const args = [literal(name), expression];
|
|
21175
|
+
if (sanitizer !== null) {
|
|
21176
|
+
args.push(sanitizer);
|
|
21177
|
+
}
|
|
21178
|
+
return call(Identifiers.hostProperty, args, sourceSpan);
|
|
20594
21179
|
}
|
|
20595
21180
|
function syntheticHostProperty(name, expression, sourceSpan) {
|
|
20596
21181
|
return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
|
|
@@ -20808,14 +21393,12 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
|
|
|
20808
21393
|
}
|
|
20809
21394
|
|
|
20810
21395
|
/**
|
|
20811
|
-
* Map of
|
|
21396
|
+
* Map of target resolvers for event listeners.
|
|
20812
21397
|
*/
|
|
20813
|
-
const
|
|
20814
|
-
[
|
|
20815
|
-
[
|
|
20816
|
-
[
|
|
20817
|
-
[SanitizerFn.Script, Identifiers.sanitizeScript],
|
|
20818
|
-
[SanitizerFn.Style, Identifiers.sanitizeStyle], [SanitizerFn.Url, Identifiers.sanitizeUrl]
|
|
21398
|
+
const GLOBAL_TARGET_RESOLVERS$1 = new Map([
|
|
21399
|
+
['window', Identifiers.resolveWindow],
|
|
21400
|
+
['document', Identifiers.resolveDocument],
|
|
21401
|
+
['body', Identifiers.resolveBody],
|
|
20819
21402
|
]);
|
|
20820
21403
|
/**
|
|
20821
21404
|
* Compiles semantic operations across all views and generates output `o.Statement`s with actual
|
|
@@ -20839,19 +21422,19 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20839
21422
|
OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
|
|
20840
21423
|
break;
|
|
20841
21424
|
case OpKind.ElementStart:
|
|
20842
|
-
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21425
|
+
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
20843
21426
|
break;
|
|
20844
21427
|
case OpKind.Element:
|
|
20845
|
-
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21428
|
+
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
20846
21429
|
break;
|
|
20847
21430
|
case OpKind.ElementEnd:
|
|
20848
21431
|
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
20849
21432
|
break;
|
|
20850
21433
|
case OpKind.ContainerStart:
|
|
20851
|
-
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21434
|
+
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
|
|
20852
21435
|
break;
|
|
20853
21436
|
case OpKind.Container:
|
|
20854
|
-
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21437
|
+
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
20855
21438
|
break;
|
|
20856
21439
|
case OpKind.ContainerEnd:
|
|
20857
21440
|
OpList.replace(op, elementContainerEnd());
|
|
@@ -20865,6 +21448,12 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20865
21448
|
case OpKind.I18n:
|
|
20866
21449
|
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
20867
21450
|
break;
|
|
21451
|
+
case OpKind.I18nAttributes:
|
|
21452
|
+
if (op.i18nAttributesConfig === null) {
|
|
21453
|
+
throw new Error(`AssertionError: i18nAttributesConfig was not set`);
|
|
21454
|
+
}
|
|
21455
|
+
OpList.replace(op, i18nAttributes(op.handle.slot, op.i18nAttributesConfig));
|
|
21456
|
+
break;
|
|
20868
21457
|
case OpKind.Template:
|
|
20869
21458
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
20870
21459
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
@@ -20873,7 +21462,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20873
21462
|
throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
|
|
20874
21463
|
}
|
|
20875
21464
|
const childView = unit.job.views.get(op.xref);
|
|
20876
|
-
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.
|
|
21465
|
+
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
20877
21466
|
break;
|
|
20878
21467
|
case OpKind.DisableBindings:
|
|
20879
21468
|
OpList.replace(op, disableBindings());
|
|
@@ -20886,10 +21475,11 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20886
21475
|
break;
|
|
20887
21476
|
case OpKind.Listener:
|
|
20888
21477
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
20889
|
-
const
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
21478
|
+
const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
|
|
21479
|
+
if (eventTargetResolver === undefined) {
|
|
21480
|
+
throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
|
|
21481
|
+
}
|
|
21482
|
+
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
20893
21483
|
break;
|
|
20894
21484
|
case OpKind.Variable:
|
|
20895
21485
|
if (op.variable.name === null) {
|
|
@@ -20974,7 +21564,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20974
21564
|
emptyDecls = emptyView.decls;
|
|
20975
21565
|
emptyVars = emptyView.vars;
|
|
20976
21566
|
}
|
|
20977
|
-
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.
|
|
21567
|
+
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.wholeSourceSpan));
|
|
20978
21568
|
break;
|
|
20979
21569
|
case OpKind.Statement:
|
|
20980
21570
|
// Pass statement operations directly through.
|
|
@@ -21052,7 +21642,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21052
21642
|
OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
|
|
21053
21643
|
}
|
|
21054
21644
|
else {
|
|
21055
|
-
OpList.replace(op, hostProperty(op.name, op.expression, op.sourceSpan));
|
|
21645
|
+
OpList.replace(op, hostProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
21056
21646
|
}
|
|
21057
21647
|
}
|
|
21058
21648
|
break;
|
|
@@ -21072,7 +21662,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21072
21662
|
OpList.replace(op, conditional(op.targetSlot.slot, op.processed, op.contextValue, op.sourceSpan));
|
|
21073
21663
|
break;
|
|
21074
21664
|
case OpKind.Repeater:
|
|
21075
|
-
OpList.replace(op, repeater(op.
|
|
21665
|
+
OpList.replace(op, repeater(op.collection, op.sourceSpan));
|
|
21076
21666
|
break;
|
|
21077
21667
|
case OpKind.DeferWhen:
|
|
21078
21668
|
OpList.replace(op, deferWhen(op.prefetch, op.expr, op.sourceSpan));
|
|
@@ -21131,8 +21721,6 @@ function reifyIrExpression(expr) {
|
|
|
21131
21721
|
return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21132
21722
|
case ExpressionKind.PipeBindingVariadic:
|
|
21133
21723
|
return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
21134
|
-
case ExpressionKind.SanitizerExpr:
|
|
21135
|
-
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
21136
21724
|
case ExpressionKind.SlotLiteralExpr:
|
|
21137
21725
|
return literal(expr.slot.slot);
|
|
21138
21726
|
default:
|
|
@@ -21206,6 +21794,31 @@ function removeI18nContexts(job) {
|
|
|
21206
21794
|
}
|
|
21207
21795
|
}
|
|
21208
21796
|
|
|
21797
|
+
/**
|
|
21798
|
+
* i18nAttributes ops will be generated for each i18n attribute. However, not all i18n attribues
|
|
21799
|
+
* will contain dynamic content, and so some of these i18nAttributes ops may be unnecessary.
|
|
21800
|
+
*/
|
|
21801
|
+
function removeUnusedI18nAttributesOps(job) {
|
|
21802
|
+
for (const unit of job.units) {
|
|
21803
|
+
const ownersWithI18nExpressions = new Set();
|
|
21804
|
+
for (const op of unit.update) {
|
|
21805
|
+
switch (op.kind) {
|
|
21806
|
+
case OpKind.I18nExpression:
|
|
21807
|
+
ownersWithI18nExpressions.add(op.i18nOwner);
|
|
21808
|
+
}
|
|
21809
|
+
}
|
|
21810
|
+
for (const op of unit.create) {
|
|
21811
|
+
switch (op.kind) {
|
|
21812
|
+
case OpKind.I18nAttributes:
|
|
21813
|
+
if (ownersWithI18nExpressions.has(op.xref)) {
|
|
21814
|
+
continue;
|
|
21815
|
+
}
|
|
21816
|
+
OpList.remove(op);
|
|
21817
|
+
}
|
|
21818
|
+
}
|
|
21819
|
+
}
|
|
21820
|
+
}
|
|
21821
|
+
|
|
21209
21822
|
/**
|
|
21210
21823
|
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
21211
21824
|
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
@@ -21335,66 +21948,221 @@ function resolveI18nElementPlaceholders(job) {
|
|
|
21335
21948
|
}
|
|
21336
21949
|
}
|
|
21337
21950
|
}
|
|
21338
|
-
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
|
|
21342
|
-
|
|
21343
|
-
|
|
21344
|
-
|
|
21345
|
-
|
|
21346
|
-
|
|
21951
|
+
resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
|
|
21952
|
+
}
|
|
21953
|
+
/**
|
|
21954
|
+
* Recursively resolves element and template tag placeholders in the given view.
|
|
21955
|
+
*/
|
|
21956
|
+
function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingStructuralDirective) {
|
|
21957
|
+
// Track the current i18n op and corresponding i18n context op as we step through the creation
|
|
21958
|
+
// IR.
|
|
21959
|
+
let currentOps = null;
|
|
21960
|
+
let pendingStructuralDirectiveCloses = new Map();
|
|
21961
|
+
for (const op of unit.create) {
|
|
21962
|
+
switch (op.kind) {
|
|
21963
|
+
case OpKind.I18nStart:
|
|
21964
|
+
if (!op.context) {
|
|
21965
|
+
throw Error('Could not find i18n context for i18n op');
|
|
21966
|
+
}
|
|
21967
|
+
currentOps = { i18nBlock: op, i18nContext: i18nContexts.get(op.context) };
|
|
21968
|
+
break;
|
|
21969
|
+
case OpKind.I18nEnd:
|
|
21970
|
+
currentOps = null;
|
|
21971
|
+
break;
|
|
21972
|
+
case OpKind.ElementStart:
|
|
21973
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21974
|
+
// corresponding tag start placeholder.
|
|
21975
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
21976
|
+
if (currentOps === null) {
|
|
21977
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21347
21978
|
}
|
|
21348
|
-
|
|
21349
|
-
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21353
|
-
case OpKind.ElementStart:
|
|
21354
|
-
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21355
|
-
// corresponding tag start placeholder.
|
|
21356
|
-
if (op.i18nPlaceholder !== undefined) {
|
|
21357
|
-
if (currentOps === null) {
|
|
21358
|
-
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21359
|
-
}
|
|
21360
|
-
const { startName, closeName } = op.i18nPlaceholder;
|
|
21361
|
-
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
21362
|
-
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
21363
|
-
// placeholder accounts for the start and close of the element.
|
|
21364
|
-
if (closeName === '') {
|
|
21365
|
-
flags |= I18nParamValueFlags.CloseTag;
|
|
21366
|
-
}
|
|
21367
|
-
addParam(currentOps.i18nContext.params, startName, op.handle.slot, currentOps.i18nBlock.subTemplateIndex, flags);
|
|
21979
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
21980
|
+
// If there is a separate close tag placeholder for this element, save the pending
|
|
21981
|
+
// structural directive so we can pass it to the closing tag as well.
|
|
21982
|
+
if (pendingStructuralDirective && op.i18nPlaceholder.closeName) {
|
|
21983
|
+
pendingStructuralDirectiveCloses.set(op.xref, pendingStructuralDirective);
|
|
21368
21984
|
}
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
if (closeName !== '') {
|
|
21381
|
-
addParam(currentOps.i18nContext.params, closeName, startOp.handle.slot, currentOps.i18nBlock.subTemplateIndex, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
|
|
21382
|
-
}
|
|
21985
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
21986
|
+
pendingStructuralDirective = undefined;
|
|
21987
|
+
}
|
|
21988
|
+
break;
|
|
21989
|
+
case OpKind.ElementEnd:
|
|
21990
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21991
|
+
// corresponding tag close placeholder.
|
|
21992
|
+
const startOp = elements.get(op.xref);
|
|
21993
|
+
if (startOp && startOp.i18nPlaceholder !== undefined) {
|
|
21994
|
+
if (currentOps === null) {
|
|
21995
|
+
throw Error('AssertionError: i18n tag placeholder should only occur inside an i18n block');
|
|
21383
21996
|
}
|
|
21384
|
-
|
|
21385
|
-
|
|
21386
|
-
|
|
21387
|
-
|
|
21388
|
-
|
|
21997
|
+
recordElementClose(startOp, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirectiveCloses.get(op.xref));
|
|
21998
|
+
// Clear out the pending structural directive close that was accounted for.
|
|
21999
|
+
pendingStructuralDirectiveCloses.delete(op.xref);
|
|
22000
|
+
}
|
|
22001
|
+
break;
|
|
22002
|
+
case OpKind.Projection:
|
|
22003
|
+
// For content projections with i18n placeholders, record its slot value in the params map
|
|
22004
|
+
// under the corresponding tag start and close placeholders.
|
|
22005
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
22006
|
+
if (currentOps === null) {
|
|
22007
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22008
|
+
}
|
|
22009
|
+
recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22010
|
+
recordElementClose(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22011
|
+
// Clear out the pending structural directive now that its been accounted for.
|
|
22012
|
+
pendingStructuralDirective = undefined;
|
|
22013
|
+
}
|
|
22014
|
+
break;
|
|
22015
|
+
case OpKind.Template:
|
|
22016
|
+
const view = job.views.get(op.xref);
|
|
22017
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22018
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22019
|
+
// blocks.
|
|
22020
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22021
|
+
}
|
|
22022
|
+
else {
|
|
22023
|
+
if (currentOps === null) {
|
|
22024
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22025
|
+
}
|
|
22026
|
+
if (op.templateKind === TemplateKind.Structural) {
|
|
22027
|
+
// If this is a structural directive template, don't record anything yet. Instead pass
|
|
22028
|
+
// the current template as a pending structural directive to be recorded when we find
|
|
22029
|
+
// the element, content, or template it belongs to. This allows us to create combined
|
|
22030
|
+
// values that represent, e.g. the start of a template and element at the same time.
|
|
22031
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
|
|
22032
|
+
}
|
|
22033
|
+
else {
|
|
22034
|
+
// If this is some other kind of template, we can record its start, recurse into its
|
|
22035
|
+
// view, and then record its end.
|
|
22036
|
+
recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22037
|
+
resolvePlaceholdersForView(job, view, i18nContexts, elements);
|
|
22038
|
+
recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22039
|
+
pendingStructuralDirective = undefined;
|
|
22040
|
+
}
|
|
22041
|
+
}
|
|
22042
|
+
break;
|
|
22043
|
+
case OpKind.RepeaterCreate:
|
|
22044
|
+
if (pendingStructuralDirective !== undefined) {
|
|
22045
|
+
throw Error('AssertionError: Unexpected structural directive associated with @for block');
|
|
22046
|
+
}
|
|
22047
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22048
|
+
// template and the (optional) third is for the @empty template.
|
|
22049
|
+
const forSlot = op.handle.slot + 1;
|
|
22050
|
+
const forView = job.views.get(op.xref);
|
|
22051
|
+
// First record all of the placeholders for the @for template.
|
|
22052
|
+
if (op.i18nPlaceholder === undefined) {
|
|
22053
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22054
|
+
// blocks.
|
|
22055
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22056
|
+
}
|
|
22057
|
+
else {
|
|
22058
|
+
if (currentOps === null) {
|
|
22059
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
22060
|
+
}
|
|
22061
|
+
recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22062
|
+
resolvePlaceholdersForView(job, forView, i18nContexts, elements);
|
|
22063
|
+
recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22064
|
+
pendingStructuralDirective = undefined;
|
|
22065
|
+
}
|
|
22066
|
+
// Then if there's an @empty template, add its placeholders as well.
|
|
22067
|
+
if (op.emptyView !== null) {
|
|
22068
|
+
// RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
|
|
22069
|
+
// template and the (optional) third is for the @empty template.
|
|
22070
|
+
const emptySlot = op.handle.slot + 2;
|
|
22071
|
+
const emptyView = job.views.get(op.emptyView);
|
|
22072
|
+
if (op.emptyI18nPlaceholder === undefined) {
|
|
22073
|
+
// If there is no i18n placeholder, just recurse into the view in case it contains i18n
|
|
22074
|
+
// blocks.
|
|
22075
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22076
|
+
}
|
|
22077
|
+
else {
|
|
21389
22078
|
if (currentOps === null) {
|
|
21390
22079
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21391
22080
|
}
|
|
21392
|
-
|
|
21393
|
-
|
|
21394
|
-
|
|
22081
|
+
recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22082
|
+
resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
|
|
22083
|
+
recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
|
|
22084
|
+
pendingStructuralDirective = undefined;
|
|
21395
22085
|
}
|
|
21396
|
-
|
|
21397
|
-
|
|
22086
|
+
}
|
|
22087
|
+
break;
|
|
22088
|
+
}
|
|
22089
|
+
}
|
|
22090
|
+
}
|
|
22091
|
+
/**
|
|
22092
|
+
* Records an i18n param value for the start of an element.
|
|
22093
|
+
*/
|
|
22094
|
+
function recordElementStart(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22095
|
+
const { startName, closeName } = op.i18nPlaceholder;
|
|
22096
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
22097
|
+
let value = op.handle.slot;
|
|
22098
|
+
// If the element is associated with a structural directive, start it as well.
|
|
22099
|
+
if (structuralDirective !== undefined) {
|
|
22100
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22101
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22102
|
+
}
|
|
22103
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22104
|
+
// placeholder accounts for the start and close of the element.
|
|
22105
|
+
if (!closeName) {
|
|
22106
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22107
|
+
}
|
|
22108
|
+
addParam(i18nContext.params, startName, value, i18nBlock.subTemplateIndex, flags);
|
|
22109
|
+
}
|
|
22110
|
+
/**
|
|
22111
|
+
* Records an i18n param value for the closing of an element.
|
|
22112
|
+
*/
|
|
22113
|
+
function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
|
|
22114
|
+
const { closeName } = op.i18nPlaceholder;
|
|
22115
|
+
// Self-closing tags don't have a closing tag placeholder, instead the element closing is
|
|
22116
|
+
// recorded via an additional flag on the element start value.
|
|
22117
|
+
if (closeName) {
|
|
22118
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag;
|
|
22119
|
+
let value = op.handle.slot;
|
|
22120
|
+
// If the element is associated with a structural directive, close it as well.
|
|
22121
|
+
if (structuralDirective !== undefined) {
|
|
22122
|
+
flags |= I18nParamValueFlags.TemplateTag;
|
|
22123
|
+
value = { element: value, template: structuralDirective.handle.slot };
|
|
22124
|
+
}
|
|
22125
|
+
addParam(i18nContext.params, closeName, value, i18nBlock.subTemplateIndex, flags);
|
|
22126
|
+
}
|
|
22127
|
+
}
|
|
22128
|
+
/**
|
|
22129
|
+
* Records an i18n param value for the start of a template.
|
|
22130
|
+
*/
|
|
22131
|
+
function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22132
|
+
let { startName, closeName } = i18nPlaceholder;
|
|
22133
|
+
let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
|
|
22134
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
22135
|
+
// placeholder accounts for the start and close of the element.
|
|
22136
|
+
if (!closeName) {
|
|
22137
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
22138
|
+
}
|
|
22139
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22140
|
+
// start first. Since this template must be in the structural directive's view, we can just
|
|
22141
|
+
// directly use the current i18n block's sub-template index.
|
|
22142
|
+
if (structuralDirective !== undefined) {
|
|
22143
|
+
addParam(i18nContext.params, startName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
22144
|
+
}
|
|
22145
|
+
// Record the start of the template. For the sub-template index, pass the index for the template's
|
|
22146
|
+
// view, rather than the current i18n block's index.
|
|
22147
|
+
addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22148
|
+
}
|
|
22149
|
+
/**
|
|
22150
|
+
* Records an i18n param value for the closing of a template.
|
|
22151
|
+
*/
|
|
22152
|
+
function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
|
|
22153
|
+
const { startName, closeName } = i18nPlaceholder;
|
|
22154
|
+
const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
|
|
22155
|
+
// Self-closing tags don't have a closing tag placeholder, instead the template's closing is
|
|
22156
|
+
// recorded via an additional flag on the template start value.
|
|
22157
|
+
if (closeName) {
|
|
22158
|
+
// Record the closing of the template. For the sub-template index, pass the index for the
|
|
22159
|
+
// template's view, rather than the current i18n block's index.
|
|
22160
|
+
addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
|
|
22161
|
+
// If the template is associated with a structural directive, record the structural directive's
|
|
22162
|
+
// closing after. Since this template must be in the structural directive's view, we can just
|
|
22163
|
+
// directly use the current i18n block's sub-template index.
|
|
22164
|
+
if (structuralDirective !== undefined) {
|
|
22165
|
+
addParam(i18nContext.params, closeName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
|
|
21398
22166
|
}
|
|
21399
22167
|
}
|
|
21400
22168
|
}
|
|
@@ -21402,16 +22170,18 @@ function resolveI18nElementPlaceholders(job) {
|
|
|
21402
22170
|
* Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
|
|
21403
22171
|
* the child i18n block inside the template.
|
|
21404
22172
|
*/
|
|
21405
|
-
function getSubTemplateIndexForTemplateTag(job, i18nOp,
|
|
21406
|
-
for (const childOp of
|
|
22173
|
+
function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
|
|
22174
|
+
for (const childOp of view.create) {
|
|
21407
22175
|
if (childOp.kind === OpKind.I18nStart) {
|
|
21408
22176
|
return childOp.subTemplateIndex;
|
|
21409
22177
|
}
|
|
21410
22178
|
}
|
|
21411
22179
|
return i18nOp.subTemplateIndex;
|
|
21412
22180
|
}
|
|
21413
|
-
/**
|
|
21414
|
-
|
|
22181
|
+
/**
|
|
22182
|
+
* Add a param value to the given params map.
|
|
22183
|
+
*/
|
|
22184
|
+
function addParam(params, placeholder, value, subTemplateIndex, flags) {
|
|
21415
22185
|
const values = params.get(placeholder) ?? [];
|
|
21416
22186
|
values.push({ value, subTemplateIndex, flags });
|
|
21417
22187
|
params.set(placeholder, values);
|
|
@@ -21424,6 +22194,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
21424
22194
|
// Record all of the i18n context ops, and the sub-template index for each i18n op.
|
|
21425
22195
|
const subTemplateIndicies = new Map();
|
|
21426
22196
|
const i18nContexts = new Map();
|
|
22197
|
+
const icuPlaceholders = new Map();
|
|
21427
22198
|
for (const unit of job.units) {
|
|
21428
22199
|
for (const op of unit.create) {
|
|
21429
22200
|
switch (op.kind) {
|
|
@@ -21433,29 +22204,50 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
21433
22204
|
case OpKind.I18nContext:
|
|
21434
22205
|
i18nContexts.set(op.xref, op);
|
|
21435
22206
|
break;
|
|
22207
|
+
case OpKind.IcuPlaceholder:
|
|
22208
|
+
icuPlaceholders.set(op.xref, op);
|
|
22209
|
+
break;
|
|
21436
22210
|
}
|
|
21437
22211
|
}
|
|
21438
22212
|
}
|
|
21439
|
-
// Keep track of the next available expression index
|
|
22213
|
+
// Keep track of the next available expression index for each i18n message.
|
|
21440
22214
|
const expressionIndices = new Map();
|
|
22215
|
+
// Keep track of a reference index for each expression.
|
|
22216
|
+
// We use different references for normal i18n expressio and attribute i18n expressions. This is
|
|
22217
|
+
// because child i18n blocks in templates don't get their own context, since they're rolled into
|
|
22218
|
+
// the translated message of the parent, but they may target a different slot.
|
|
22219
|
+
const referenceIndex = (op) => op.usage === I18nExpressionFor.I18nText ? op.i18nOwner : op.context;
|
|
21441
22220
|
for (const unit of job.units) {
|
|
21442
22221
|
for (const op of unit.update) {
|
|
21443
22222
|
if (op.kind === OpKind.I18nExpression) {
|
|
21444
|
-
const index = expressionIndices.get(op
|
|
21445
|
-
const
|
|
21446
|
-
const
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
params.set(op.i18nPlaceholder, values);
|
|
21454
|
-
expressionIndices.set(op.context, index + 1);
|
|
22223
|
+
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22224
|
+
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
22225
|
+
const value = {
|
|
22226
|
+
value: index,
|
|
22227
|
+
subTemplateIndex: subTemplateIndex,
|
|
22228
|
+
flags: I18nParamValueFlags.ExpressionIndex
|
|
22229
|
+
};
|
|
22230
|
+
updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
|
|
22231
|
+
expressionIndices.set(referenceIndex(op), index + 1);
|
|
21455
22232
|
}
|
|
21456
22233
|
}
|
|
21457
22234
|
}
|
|
21458
22235
|
}
|
|
22236
|
+
function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
|
|
22237
|
+
if (op.i18nPlaceholder !== null) {
|
|
22238
|
+
const i18nContext = i18nContexts.get(op.context);
|
|
22239
|
+
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22240
|
+
i18nContext.params :
|
|
22241
|
+
i18nContext.postprocessingParams;
|
|
22242
|
+
const values = params.get(op.i18nPlaceholder) || [];
|
|
22243
|
+
values.push(value);
|
|
22244
|
+
params.set(op.i18nPlaceholder, values);
|
|
22245
|
+
}
|
|
22246
|
+
if (op.icuPlaceholder !== null) {
|
|
22247
|
+
const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
|
|
22248
|
+
icuPlaceholderOp?.expressionPlaceholders.push(value);
|
|
22249
|
+
}
|
|
22250
|
+
}
|
|
21459
22251
|
|
|
21460
22252
|
/**
|
|
21461
22253
|
* Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
|
|
@@ -21556,12 +22348,20 @@ function processLexicalScope(unit, ops, savedView) {
|
|
|
21556
22348
|
}
|
|
21557
22349
|
|
|
21558
22350
|
/**
|
|
21559
|
-
*
|
|
22351
|
+
* Map of security contexts to their sanitizer function.
|
|
22352
|
+
*/
|
|
22353
|
+
const sanitizerFns = new Map([
|
|
22354
|
+
[SecurityContext.HTML, Identifiers.sanitizeHtml],
|
|
22355
|
+
[SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl],
|
|
22356
|
+
[SecurityContext.SCRIPT, Identifiers.sanitizeScript],
|
|
22357
|
+
[SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl]
|
|
22358
|
+
]);
|
|
22359
|
+
/**
|
|
22360
|
+
* Map of security contexts to their trusted value function.
|
|
21560
22361
|
*/
|
|
21561
|
-
const
|
|
21562
|
-
[SecurityContext.HTML,
|
|
21563
|
-
[SecurityContext.
|
|
21564
|
-
[SecurityContext.RESOURCE_URL, SanitizerFn.ResourceUrl]
|
|
22362
|
+
const trustedValueFns = new Map([
|
|
22363
|
+
[SecurityContext.HTML, Identifiers.trustConstantHtml],
|
|
22364
|
+
[SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl],
|
|
21565
22365
|
]);
|
|
21566
22366
|
/**
|
|
21567
22367
|
* Resolves sanitization functions for ops that need them.
|
|
@@ -21569,24 +22369,61 @@ const sanitizers = new Map([
|
|
|
21569
22369
|
function resolveSanitizers(job) {
|
|
21570
22370
|
for (const unit of job.units) {
|
|
21571
22371
|
const elements = createOpXrefMap(unit);
|
|
21572
|
-
|
|
22372
|
+
// For normal element bindings we create trusted values for security sensitive constant
|
|
22373
|
+
// attributes. However, for host bindings we skip this step (this matches what
|
|
22374
|
+
// TemplateDefinitionBuilder does).
|
|
22375
|
+
// TODO: Is the TDB behavior correct here?
|
|
22376
|
+
if (job.kind !== CompilationJobKind.Host) {
|
|
22377
|
+
for (const op of unit.create) {
|
|
22378
|
+
if (op.kind === OpKind.ExtractedAttribute) {
|
|
22379
|
+
const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22380
|
+
op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
|
|
22381
|
+
}
|
|
22382
|
+
}
|
|
22383
|
+
}
|
|
21573
22384
|
for (const op of unit.update) {
|
|
21574
22385
|
switch (op.kind) {
|
|
21575
22386
|
case OpKind.Property:
|
|
21576
22387
|
case OpKind.Attribute:
|
|
21577
|
-
|
|
21578
|
-
|
|
22388
|
+
case OpKind.HostProperty:
|
|
22389
|
+
let sanitizerFn = null;
|
|
22390
|
+
if (Array.isArray(op.securityContext) && op.securityContext.length === 2 &&
|
|
22391
|
+
op.securityContext.indexOf(SecurityContext.URL) > -1 &&
|
|
22392
|
+
op.securityContext.indexOf(SecurityContext.RESOURCE_URL) > -1) {
|
|
22393
|
+
// When the host element isn't known, some URL attributes (such as "src" and "href") may
|
|
22394
|
+
// be part of multiple different security contexts. In this case we use special
|
|
22395
|
+
// sanitization function and select the actual sanitizer at runtime based on a tag name
|
|
22396
|
+
// that is provided while invoking sanitization function.
|
|
22397
|
+
sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
|
|
22398
|
+
}
|
|
22399
|
+
else {
|
|
22400
|
+
sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
|
|
22401
|
+
}
|
|
22402
|
+
op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
|
|
21579
22403
|
// If there was no sanitization function found based on the security context of an
|
|
21580
22404
|
// attribute/property, check whether this attribute/property is one of the
|
|
21581
22405
|
// security-sensitive <iframe> attributes (and that the current element is actually an
|
|
21582
22406
|
// <iframe>).
|
|
21583
22407
|
if (op.sanitizer === null) {
|
|
21584
|
-
|
|
21585
|
-
if (
|
|
21586
|
-
|
|
22408
|
+
let isIframe = false;
|
|
22409
|
+
if (job.kind === CompilationJobKind.Host || op.kind === OpKind.HostProperty) {
|
|
22410
|
+
// Note: for host bindings defined on a directive, we do not try to find all
|
|
22411
|
+
// possible places where it can be matched, so we can not determine whether
|
|
22412
|
+
// the host element is an <iframe>. In this case, we just assume it is and append a
|
|
22413
|
+
// validation function, which is invoked at runtime and would have access to the
|
|
22414
|
+
// underlying DOM element to check if it's an <iframe> and if so - run extra checks.
|
|
22415
|
+
isIframe = true;
|
|
22416
|
+
}
|
|
22417
|
+
else {
|
|
22418
|
+
// For a normal binding we can just check if the element its on is an iframe.
|
|
22419
|
+
const ownerOp = elements.get(op.target);
|
|
22420
|
+
if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
|
|
22421
|
+
throw Error('Property should have an element-like owner');
|
|
22422
|
+
}
|
|
22423
|
+
isIframe = isIframeElement$1(ownerOp);
|
|
21587
22424
|
}
|
|
21588
|
-
if (
|
|
21589
|
-
op.sanitizer =
|
|
22425
|
+
if (isIframe && isIframeSecuritySensitiveAttr(op.name)) {
|
|
22426
|
+
op.sanitizer = importExpr(Identifiers.validateIframeAttribute);
|
|
21590
22427
|
}
|
|
21591
22428
|
}
|
|
21592
22429
|
break;
|
|
@@ -21600,6 +22437,22 @@ function resolveSanitizers(job) {
|
|
|
21600
22437
|
function isIframeElement$1(op) {
|
|
21601
22438
|
return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
|
|
21602
22439
|
}
|
|
22440
|
+
/**
|
|
22441
|
+
* Asserts that there is only a single security context and returns it.
|
|
22442
|
+
*/
|
|
22443
|
+
function getOnlySecurityContext(securityContext) {
|
|
22444
|
+
if (Array.isArray(securityContext)) {
|
|
22445
|
+
if (securityContext.length > 1) {
|
|
22446
|
+
// TODO: What should we do here? TDB just took the first one, but this feels like something we
|
|
22447
|
+
// would want to know about and create a special case for like we did for Url/ResourceUrl. My
|
|
22448
|
+
// guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
|
|
22449
|
+
// do turn out to be other cases, throwing an error until we can address it feels safer.
|
|
22450
|
+
throw Error(`AssertionError: Ambiguous security context`);
|
|
22451
|
+
}
|
|
22452
|
+
return securityContext[0] || SecurityContext.NONE;
|
|
22453
|
+
}
|
|
22454
|
+
return securityContext;
|
|
22455
|
+
}
|
|
21603
22456
|
|
|
21604
22457
|
/**
|
|
21605
22458
|
* When inside of a listener, we may need access to one or more enclosing views. Therefore, each
|
|
@@ -21703,6 +22556,8 @@ function allocateSlots(job) {
|
|
|
21703
22556
|
// operation itself, so it can be emitted later.
|
|
21704
22557
|
const childView = job.views.get(op.xref);
|
|
21705
22558
|
op.decls = childView.decls;
|
|
22559
|
+
// TODO: currently we handle the decls for the RepeaterCreate empty template in the reify
|
|
22560
|
+
// phase. We should handle that here instead.
|
|
21706
22561
|
}
|
|
21707
22562
|
}
|
|
21708
22563
|
}
|
|
@@ -22026,6 +22881,8 @@ function countVariables(job) {
|
|
|
22026
22881
|
}
|
|
22027
22882
|
const childView = job.views.get(op.xref);
|
|
22028
22883
|
op.vars = childView.vars;
|
|
22884
|
+
// TODO: currently we handle the vars for the RepeaterCreate empty template in the reify
|
|
22885
|
+
// phase. We should handle that here instead.
|
|
22029
22886
|
}
|
|
22030
22887
|
}
|
|
22031
22888
|
}
|
|
@@ -22063,7 +22920,14 @@ function varsUsedByOp(op) {
|
|
|
22063
22920
|
return op.interpolation.expressions.length;
|
|
22064
22921
|
case OpKind.I18nExpression:
|
|
22065
22922
|
case OpKind.Conditional:
|
|
22923
|
+
case OpKind.DeferWhen:
|
|
22066
22924
|
return 1;
|
|
22925
|
+
case OpKind.RepeaterCreate:
|
|
22926
|
+
// Repeaters may require an extra variable binding slot, if they have an empty view, for the
|
|
22927
|
+
// empty block tracking.
|
|
22928
|
+
// TODO: It's a bit odd to have a create mode instruction consume variable slots. Maybe we can
|
|
22929
|
+
// find a way to use the Repeater update op instead.
|
|
22930
|
+
return op.emptyView ? 1 : 0;
|
|
22067
22931
|
default:
|
|
22068
22932
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
22069
22933
|
}
|
|
@@ -22507,6 +23371,7 @@ function allowConservativeInlining(decl, target) {
|
|
|
22507
23371
|
function wrapI18nIcus(job) {
|
|
22508
23372
|
for (const unit of job.units) {
|
|
22509
23373
|
let currentI18nOp = null;
|
|
23374
|
+
let addedI18nId = null;
|
|
22510
23375
|
for (const op of unit.create) {
|
|
22511
23376
|
switch (op.kind) {
|
|
22512
23377
|
case OpKind.I18nStart:
|
|
@@ -22515,11 +23380,16 @@ function wrapI18nIcus(job) {
|
|
|
22515
23380
|
case OpKind.I18nEnd:
|
|
22516
23381
|
currentI18nOp = null;
|
|
22517
23382
|
break;
|
|
22518
|
-
case OpKind.
|
|
23383
|
+
case OpKind.IcuStart:
|
|
22519
23384
|
if (currentI18nOp === null) {
|
|
22520
|
-
|
|
22521
|
-
OpList.insertBefore(createI18nStartOp(
|
|
22522
|
-
|
|
23385
|
+
addedI18nId = job.allocateXrefId();
|
|
23386
|
+
OpList.insertBefore(createI18nStartOp(addedI18nId, op.message), op);
|
|
23387
|
+
}
|
|
23388
|
+
break;
|
|
23389
|
+
case OpKind.IcuEnd:
|
|
23390
|
+
if (addedI18nId !== null) {
|
|
23391
|
+
OpList.insertAfter(createI18nEndOp(addedI18nId), op);
|
|
23392
|
+
addedI18nId = null;
|
|
22523
23393
|
}
|
|
22524
23394
|
break;
|
|
22525
23395
|
}
|
|
@@ -22539,12 +23409,13 @@ function wrapI18nIcus(job) {
|
|
|
22539
23409
|
{ kind: CompilationJobKind.Tmpl, fn: removeContentSelectors },
|
|
22540
23410
|
{ kind: CompilationJobKind.Host, fn: parseHostStyleProperties },
|
|
22541
23411
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
22542
|
-
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
22543
|
-
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
22544
23412
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
22545
23413
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
22546
|
-
{ kind: CompilationJobKind.
|
|
23414
|
+
{ kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
|
|
23415
|
+
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23416
|
+
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
22547
23417
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
23418
|
+
{ kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
|
|
22548
23419
|
{ kind: CompilationJobKind.Both, fn: parseExtractedStyles },
|
|
22549
23420
|
{ kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
|
|
22550
23421
|
{ kind: CompilationJobKind.Both, fn: collapseSingletonInterpolations },
|
|
@@ -22552,15 +23423,17 @@ function wrapI18nIcus(job) {
|
|
|
22552
23423
|
{ kind: CompilationJobKind.Tmpl, fn: generateConditionalExpressions },
|
|
22553
23424
|
{ kind: CompilationJobKind.Tmpl, fn: createPipes },
|
|
22554
23425
|
{ kind: CompilationJobKind.Tmpl, fn: configureDeferInstructions },
|
|
22555
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22556
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
23426
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nText },
|
|
23427
|
+
{ kind: CompilationJobKind.Tmpl, fn: convertI18nBindings },
|
|
23428
|
+
{ kind: CompilationJobKind.Tmpl, fn: removeUnusedI18nAttributesOps },
|
|
23429
|
+
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
22557
23430
|
{ kind: CompilationJobKind.Tmpl, fn: applyI18nExpressions },
|
|
22558
23431
|
{ kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
|
|
22559
23432
|
{ kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
|
|
22560
23433
|
{ kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
|
|
22561
23434
|
{ kind: CompilationJobKind.Tmpl, fn: generateVariables },
|
|
22562
23435
|
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
22563
|
-
{ kind: CompilationJobKind.
|
|
23436
|
+
{ kind: CompilationJobKind.Both, fn: deleteAnyCasts },
|
|
22564
23437
|
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
22565
23438
|
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
22566
23439
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
@@ -22568,7 +23441,7 @@ function wrapI18nIcus(job) {
|
|
|
22568
23441
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
22569
23442
|
{ kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
|
|
22570
23443
|
{ kind: CompilationJobKind.Both, fn: resolveContexts },
|
|
22571
|
-
{ kind: CompilationJobKind.
|
|
23444
|
+
{ kind: CompilationJobKind.Both, fn: resolveSanitizers },
|
|
22572
23445
|
{ kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
|
|
22573
23446
|
{ kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
|
|
22574
23447
|
{ kind: CompilationJobKind.Both, fn: expandSafeReads },
|
|
@@ -22577,13 +23450,11 @@ function wrapI18nIcus(job) {
|
|
|
22577
23450
|
{ kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
|
|
22578
23451
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
22579
23452
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
22580
|
-
{ kind: CompilationJobKind.Tmpl, fn: mergeI18nContexts },
|
|
22581
23453
|
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
22582
23454
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
22583
23455
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
22584
23456
|
{ kind: CompilationJobKind.Tmpl, fn: collectConstExpressions },
|
|
22585
23457
|
{ kind: CompilationJobKind.Both, fn: collectElementConsts },
|
|
22586
|
-
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
22587
23458
|
{ kind: CompilationJobKind.Tmpl, fn: removeI18nContexts },
|
|
22588
23459
|
{ kind: CompilationJobKind.Both, fn: countVariables },
|
|
22589
23460
|
{ kind: CompilationJobKind.Tmpl, fn: generateAdvance },
|
|
@@ -22599,6 +23470,9 @@ function wrapI18nIcus(job) {
|
|
|
22599
23470
|
];
|
|
22600
23471
|
|
|
22601
23472
|
CompatibilityMode.TemplateDefinitionBuilder;
|
|
23473
|
+
// Schema containing DOM elements and their properties.
|
|
23474
|
+
new DomElementSchemaRegistry();
|
|
23475
|
+
// TODO: Can we populate Template binding kinds in ingest?
|
|
22602
23476
|
new Map([
|
|
22603
23477
|
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
22604
23478
|
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
@@ -22606,26 +23480,6 @@ new Map([
|
|
|
22606
23480
|
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
22607
23481
|
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
22608
23482
|
]);
|
|
22609
|
-
var BindingFlags;
|
|
22610
|
-
(function (BindingFlags) {
|
|
22611
|
-
BindingFlags[BindingFlags["None"] = 0] = "None";
|
|
22612
|
-
/**
|
|
22613
|
-
* The binding is to a static text literal and not to an expression.
|
|
22614
|
-
*/
|
|
22615
|
-
BindingFlags[BindingFlags["TextValue"] = 1] = "TextValue";
|
|
22616
|
-
/**
|
|
22617
|
-
* The binding belongs to the `<ng-template>` side of a `t.Template`.
|
|
22618
|
-
*/
|
|
22619
|
-
BindingFlags[BindingFlags["BindingTargetsTemplate"] = 2] = "BindingTargetsTemplate";
|
|
22620
|
-
/**
|
|
22621
|
-
* The binding is on a structural directive.
|
|
22622
|
-
*/
|
|
22623
|
-
BindingFlags[BindingFlags["IsStructuralTemplateAttribute"] = 4] = "IsStructuralTemplateAttribute";
|
|
22624
|
-
/**
|
|
22625
|
-
* The binding is on a `t.Template`.
|
|
22626
|
-
*/
|
|
22627
|
-
BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
|
|
22628
|
-
})(BindingFlags || (BindingFlags = {}));
|
|
22629
23483
|
|
|
22630
23484
|
const IMPORTANT_FLAG = '!important';
|
|
22631
23485
|
/**
|
|
@@ -23776,19 +24630,19 @@ function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23776
24630
|
const branches = [];
|
|
23777
24631
|
const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
|
|
23778
24632
|
if (mainBlockParams !== null) {
|
|
23779
|
-
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan));
|
|
24633
|
+
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan, ast.i18n));
|
|
23780
24634
|
}
|
|
23781
24635
|
for (const block of connectedBlocks) {
|
|
23782
24636
|
if (ELSE_IF_PATTERN.test(block.name)) {
|
|
23783
24637
|
const params = parseConditionalBlockParameters(block, errors, bindingParser);
|
|
23784
24638
|
if (params !== null) {
|
|
23785
24639
|
const children = visitAll(visitor, block.children, block.children);
|
|
23786
|
-
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
|
|
24640
|
+
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
|
|
23787
24641
|
}
|
|
23788
24642
|
}
|
|
23789
24643
|
else if (block.name === 'else') {
|
|
23790
24644
|
const children = visitAll(visitor, block.children, block.children);
|
|
23791
|
-
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
|
|
24645
|
+
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
|
|
23792
24646
|
}
|
|
23793
24647
|
}
|
|
23794
24648
|
// The outer IfBlock should have a span that encapsulates all branches.
|
|
@@ -23819,7 +24673,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23819
24673
|
errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
|
|
23820
24674
|
}
|
|
23821
24675
|
else {
|
|
23822
|
-
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan);
|
|
24676
|
+
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n);
|
|
23823
24677
|
}
|
|
23824
24678
|
}
|
|
23825
24679
|
else {
|
|
@@ -23837,7 +24691,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23837
24691
|
// main `for` body, use `mainSourceSpan`.
|
|
23838
24692
|
const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
|
|
23839
24693
|
const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
|
|
23840
|
-
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan);
|
|
24694
|
+
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan, ast.i18n);
|
|
23841
24695
|
}
|
|
23842
24696
|
}
|
|
23843
24697
|
return { node, errors };
|
|
@@ -23863,7 +24717,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
|
|
|
23863
24717
|
const expression = node.name === 'case' ?
|
|
23864
24718
|
parseBlockParameterToBinding(node.parameters[0], bindingParser) :
|
|
23865
24719
|
null;
|
|
23866
|
-
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan);
|
|
24720
|
+
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan, node.i18n);
|
|
23867
24721
|
if (expression === null) {
|
|
23868
24722
|
defaultCase = ast;
|
|
23869
24723
|
}
|
|
@@ -24450,7 +25304,7 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24450
25304
|
endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
|
|
24451
25305
|
}
|
|
24452
25306
|
const sourceSpanWithConnectedBlocks = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
|
|
24453
|
-
const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
|
|
25307
|
+
const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan, ast.i18n);
|
|
24454
25308
|
return { node, errors };
|
|
24455
25309
|
}
|
|
24456
25310
|
function parseConnectedBlocks(connectedBlocks, errors, visitor) {
|
|
@@ -24513,7 +25367,7 @@ function parsePlaceholderBlock(ast, visitor) {
|
|
|
24513
25367
|
throw new Error(`Unrecognized parameter in @placeholder block: "${param.expression}"`);
|
|
24514
25368
|
}
|
|
24515
25369
|
}
|
|
24516
|
-
return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25370
|
+
return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
|
|
24517
25371
|
}
|
|
24518
25372
|
function parseLoadingBlock(ast, visitor) {
|
|
24519
25373
|
let afterTime = null;
|
|
@@ -24543,13 +25397,13 @@ function parseLoadingBlock(ast, visitor) {
|
|
|
24543
25397
|
throw new Error(`Unrecognized parameter in @loading block: "${param.expression}"`);
|
|
24544
25398
|
}
|
|
24545
25399
|
}
|
|
24546
|
-
return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25400
|
+
return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
|
|
24547
25401
|
}
|
|
24548
25402
|
function parseErrorBlock(ast, visitor) {
|
|
24549
25403
|
if (ast.parameters.length > 0) {
|
|
24550
25404
|
throw new Error(`@error block cannot have parameters`);
|
|
24551
25405
|
}
|
|
24552
|
-
return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25406
|
+
return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
|
|
24553
25407
|
}
|
|
24554
25408
|
function parsePrimaryTriggers(params, bindingParser, errors, placeholder) {
|
|
24555
25409
|
const triggers = {};
|
|
@@ -25149,6 +26003,11 @@ class I18nContext {
|
|
|
25149
26003
|
const content = { type, index, ctx: this.id, isVoid: node.isVoid, closed };
|
|
25150
26004
|
updatePlaceholderMap(this.placeholders, ph, content);
|
|
25151
26005
|
}
|
|
26006
|
+
appendBlockPart(node, index, closed) {
|
|
26007
|
+
const ph = closed ? node.closeName : node.startName;
|
|
26008
|
+
const content = { type: TagType.TEMPLATE, index, ctx: this.id, closed };
|
|
26009
|
+
updatePlaceholderMap(this.placeholders, ph, content);
|
|
26010
|
+
}
|
|
25152
26011
|
get icus() {
|
|
25153
26012
|
return this._registry.icus;
|
|
25154
26013
|
}
|
|
@@ -25181,6 +26040,13 @@ class I18nContext {
|
|
|
25181
26040
|
this.appendTag(TagType.TEMPLATE, node, index, true);
|
|
25182
26041
|
this._unresolvedCtxCount++;
|
|
25183
26042
|
}
|
|
26043
|
+
appendBlock(node, index) {
|
|
26044
|
+
// add open and close tags at the same time,
|
|
26045
|
+
// since we process nested templates separately
|
|
26046
|
+
this.appendBlockPart(node, index, false);
|
|
26047
|
+
this.appendBlockPart(node, index, true);
|
|
26048
|
+
this._unresolvedCtxCount++;
|
|
26049
|
+
}
|
|
25184
26050
|
appendElement(node, index, closed) {
|
|
25185
26051
|
this.appendTag(TagType.ELEMENT, node, index, closed);
|
|
25186
26052
|
}
|
|
@@ -25459,13 +26325,19 @@ class TemplateDefinitionBuilder {
|
|
|
25459
26325
|
this.creationInstruction(null, Identifiers.pipe, [literal(slot), literal(name)]);
|
|
25460
26326
|
});
|
|
25461
26327
|
}
|
|
25462
|
-
buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) {
|
|
26328
|
+
buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n, variableAliases) {
|
|
25463
26329
|
this._ngContentSelectorsOffset = ngContentSelectorsOffset;
|
|
25464
26330
|
if (this._namespace !== Identifiers.namespaceHTML) {
|
|
25465
26331
|
this.creationInstruction(null, this._namespace);
|
|
25466
26332
|
}
|
|
25467
26333
|
// Create variable bindings
|
|
25468
|
-
variables.forEach(v =>
|
|
26334
|
+
variables.forEach(v => {
|
|
26335
|
+
const alias = variableAliases?.[v.name];
|
|
26336
|
+
this.registerContextVariables(v.name, v.value);
|
|
26337
|
+
if (alias) {
|
|
26338
|
+
this.registerContextVariables(alias, v.value);
|
|
26339
|
+
}
|
|
26340
|
+
});
|
|
25469
26341
|
// Initiate i18n context in case:
|
|
25470
26342
|
// - this template has parent i18n context
|
|
25471
26343
|
// - or the template has i18n meta associated with it,
|
|
@@ -25559,12 +26431,12 @@ class TemplateDefinitionBuilder {
|
|
|
25559
26431
|
this._constants.prepareStatements.push(...statements);
|
|
25560
26432
|
return _ref;
|
|
25561
26433
|
}
|
|
25562
|
-
registerContextVariables(
|
|
26434
|
+
registerContextVariables(name, value) {
|
|
25563
26435
|
const scopedName = this._bindingScope.freshReferenceName();
|
|
25564
26436
|
const retrievalLevel = this.level;
|
|
25565
|
-
const isDirect =
|
|
25566
|
-
const lhs = variable(
|
|
25567
|
-
this._bindingScope.set(retrievalLevel,
|
|
26437
|
+
const isDirect = value === DIRECT_CONTEXT_REFERENCE;
|
|
26438
|
+
const lhs = variable(name + scopedName);
|
|
26439
|
+
this._bindingScope.set(retrievalLevel, name, scope => {
|
|
25568
26440
|
// If we're at the top level and we're referring to the context variable directly, we
|
|
25569
26441
|
// can do so through the implicit receiver, instead of renaming it. Note that this does
|
|
25570
26442
|
// not apply to listeners, because they need to restore the context.
|
|
@@ -25600,7 +26472,7 @@ class TemplateDefinitionBuilder {
|
|
|
25600
26472
|
return [
|
|
25601
26473
|
// e.g. const $items$ = x(2) for direct context references and
|
|
25602
26474
|
// const $item$ = x(2).$implicit for indirect ones.
|
|
25603
|
-
lhs.set(isDirect ? rhs : rhs.prop(
|
|
26475
|
+
lhs.set(isDirect ? rhs : rhs.prop(value || IMPLICIT_REFERENCE)).toConstDecl()
|
|
25604
26476
|
];
|
|
25605
26477
|
});
|
|
25606
26478
|
}
|
|
@@ -25666,7 +26538,7 @@ class TemplateDefinitionBuilder {
|
|
|
25666
26538
|
else {
|
|
25667
26539
|
// ... otherwise we need to activate post-processing
|
|
25668
26540
|
// to replace ICU placeholders with proper values
|
|
25669
|
-
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
|
|
26541
|
+
const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX$1}${key}`);
|
|
25670
26542
|
params[key] = literal(placeholder);
|
|
25671
26543
|
icuMapping[key] = literalArr(refs);
|
|
25672
26544
|
}
|
|
@@ -26023,10 +26895,15 @@ class TemplateDefinitionBuilder {
|
|
|
26023
26895
|
this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
|
|
26024
26896
|
}
|
|
26025
26897
|
}
|
|
26026
|
-
prepareEmbeddedTemplateFn(children, contextNameSuffix, variables = [],
|
|
26898
|
+
prepareEmbeddedTemplateFn(children, contextNameSuffix, variables = [], i18nMeta, variableAliases) {
|
|
26027
26899
|
const index = this.allocateDataSlot();
|
|
26028
|
-
if (this.i18n &&
|
|
26029
|
-
|
|
26900
|
+
if (this.i18n && i18nMeta) {
|
|
26901
|
+
if (i18nMeta instanceof BlockPlaceholder) {
|
|
26902
|
+
this.i18n.appendBlock(i18nMeta, index);
|
|
26903
|
+
}
|
|
26904
|
+
else {
|
|
26905
|
+
this.i18n.appendTemplate(i18nMeta, index);
|
|
26906
|
+
}
|
|
26030
26907
|
}
|
|
26031
26908
|
const contextName = `${this.contextName}${contextNameSuffix}_${index}`;
|
|
26032
26909
|
const name = `${contextName}_Template`;
|
|
@@ -26037,7 +26914,7 @@ class TemplateDefinitionBuilder {
|
|
|
26037
26914
|
// be able to support bindings in nested templates to local refs that occur after the
|
|
26038
26915
|
// template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
|
|
26039
26916
|
this._nestedTemplateFns.push(() => {
|
|
26040
|
-
const templateFunctionExpr = visitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset,
|
|
26917
|
+
const templateFunctionExpr = visitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18nMeta, variableAliases);
|
|
26041
26918
|
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(name));
|
|
26042
26919
|
if (visitor._ngContentReservedSlots.length) {
|
|
26043
26920
|
this._ngContentReservedSlots.push(...visitor._ngContentReservedSlots);
|
|
@@ -26145,7 +27022,9 @@ class TemplateDefinitionBuilder {
|
|
|
26145
27022
|
// inside ICUs)
|
|
26146
27023
|
// - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
|
|
26147
27024
|
const transformFn = (raw) => {
|
|
26148
|
-
|
|
27025
|
+
// Sort the map entries in the compiled output. This makes it easy to acheive identical output
|
|
27026
|
+
// in the template pipeline compiler.
|
|
27027
|
+
const params = Object.fromEntries(Object.entries({ ...vars, ...placeholders }).sort());
|
|
26149
27028
|
const formatted = formatI18nPlaceholderNamesInMap(params, /* useCamelCase */ false);
|
|
26150
27029
|
return invokeInstruction(null, Identifiers.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
|
|
26151
27030
|
};
|
|
@@ -26192,7 +27071,7 @@ class TemplateDefinitionBuilder {
|
|
|
26192
27071
|
}
|
|
26193
27072
|
// Note: the template needs to be created *before* we process the expression,
|
|
26194
27073
|
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26195
|
-
const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs);
|
|
27074
|
+
const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs, undefined, branch.i18n);
|
|
26196
27075
|
const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
|
|
26197
27076
|
return { index: templateIndex, expression: processedExpression, alias: expressionAlias };
|
|
26198
27077
|
});
|
|
@@ -26243,7 +27122,7 @@ class TemplateDefinitionBuilder {
|
|
|
26243
27122
|
// We have to process the block in two steps: once here and again in the update instruction
|
|
26244
27123
|
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
26245
27124
|
const caseData = block.cases.map(currentCase => {
|
|
26246
|
-
const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
|
|
27125
|
+
const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan, undefined, undefined, undefined, currentCase.i18n);
|
|
26247
27126
|
const expression = currentCase.expression === null ?
|
|
26248
27127
|
null :
|
|
26249
27128
|
currentCase.expression.visit(this._valueConverter);
|
|
@@ -26291,23 +27170,21 @@ class TemplateDefinitionBuilder {
|
|
|
26291
27170
|
if (!metadata) {
|
|
26292
27171
|
throw new Error('Could not resolve `defer` block metadata. Block may need to be analyzed.');
|
|
26293
27172
|
}
|
|
26294
|
-
const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan);
|
|
26295
|
-
const loadingIndex = loading ?
|
|
26296
|
-
this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan) :
|
|
27173
|
+
const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan, undefined, undefined, undefined, deferred.i18n);
|
|
27174
|
+
const loadingIndex = loading ? this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan, undefined, undefined, undefined, loading.i18n) :
|
|
26297
27175
|
null;
|
|
26298
27176
|
const loadingConsts = loading ?
|
|
26299
27177
|
trimTrailingNulls([literal(loading.minimumTime), literal(loading.afterTime)]) :
|
|
26300
27178
|
null;
|
|
26301
27179
|
const placeholderIndex = placeholder ?
|
|
26302
|
-
this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan) :
|
|
27180
|
+
this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan, undefined, undefined, undefined, placeholder.i18n) :
|
|
26303
27181
|
null;
|
|
26304
27182
|
const placeholderConsts = placeholder && placeholder.minimumTime !== null ?
|
|
26305
27183
|
// TODO(crisbeto): potentially pass the time directly instead of storing it in the `consts`
|
|
26306
27184
|
// since the placeholder block can only have one parameter?
|
|
26307
27185
|
literalArr([literal(placeholder.minimumTime)]) :
|
|
26308
27186
|
null;
|
|
26309
|
-
const errorIndex = error ?
|
|
26310
|
-
this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan) :
|
|
27187
|
+
const errorIndex = error ? this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan, undefined, undefined, undefined, error.i18n) :
|
|
26311
27188
|
null;
|
|
26312
27189
|
// Note: we generate this last so the index matches the instruction order.
|
|
26313
27190
|
const deferredIndex = this.allocateDataSlot();
|
|
@@ -26461,11 +27338,18 @@ class TemplateDefinitionBuilder {
|
|
|
26461
27338
|
// are implicitly inferred by the runtime to index + 1 and index + 2.
|
|
26462
27339
|
const blockIndex = this.allocateDataSlot();
|
|
26463
27340
|
const { tagName, attrsExprs } = this.inferProjectionDataFromInsertionPoint(block);
|
|
26464
|
-
const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]
|
|
27341
|
+
const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count], block.i18n, {
|
|
27342
|
+
// We need to provide level-specific versions of `$index` and `$count`, because
|
|
27343
|
+
// they're used when deriving the remaining variables (`$odd`, `$even` etc.) while at the
|
|
27344
|
+
// same time being available implicitly. Without these aliases, we wouldn't be able to
|
|
27345
|
+
// access the `$index` of a parent loop from inside of a nested loop.
|
|
27346
|
+
[block.contextVariables.$index.name]: this.getLevelSpecificVariableName('$index', this.level + 1),
|
|
27347
|
+
[block.contextVariables.$count.name]: this.getLevelSpecificVariableName('$count', this.level + 1),
|
|
27348
|
+
});
|
|
26465
27349
|
const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
|
|
26466
27350
|
let emptyData = null;
|
|
26467
27351
|
if (block.empty !== null) {
|
|
26468
|
-
emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
|
|
27352
|
+
emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty', undefined, block.empty.i18n);
|
|
26469
27353
|
// Allocate an extra slot for the empty block tracking.
|
|
26470
27354
|
this.allocateBindingSlots(null);
|
|
26471
27355
|
}
|
|
@@ -26495,17 +27379,44 @@ class TemplateDefinitionBuilder {
|
|
|
26495
27379
|
// Note: we don't allocate binding slots for this expression,
|
|
26496
27380
|
// because its value isn't stored in the LView.
|
|
26497
27381
|
const value = block.expression.visit(this._valueConverter);
|
|
26498
|
-
// `repeater(
|
|
26499
|
-
this.
|
|
27382
|
+
// `advance(x); repeater(iterable)`
|
|
27383
|
+
this.updateInstructionWithAdvance(blockIndex, block.sourceSpan, Identifiers.repeater, () => [this.convertPropertyBinding(value)]);
|
|
26500
27384
|
}
|
|
26501
27385
|
registerComputedLoopVariables(block, bindingScope) {
|
|
26502
|
-
const indexLocalName = block.contextVariables.$index.name;
|
|
26503
|
-
const countLocalName = block.contextVariables.$count.name;
|
|
26504
27386
|
const level = bindingScope.bindingLevel;
|
|
26505
|
-
bindingScope.set(level, block.contextVariables.$odd.name, scope =>
|
|
26506
|
-
|
|
26507
|
-
|
|
26508
|
-
|
|
27387
|
+
bindingScope.set(level, block.contextVariables.$odd.name, (scope, retrievalLevel) => {
|
|
27388
|
+
return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
|
|
27389
|
+
.modulo(literal(2))
|
|
27390
|
+
.notIdentical(literal(0));
|
|
27391
|
+
});
|
|
27392
|
+
bindingScope.set(level, block.contextVariables.$even.name, (scope, retrievalLevel) => {
|
|
27393
|
+
return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
|
|
27394
|
+
.modulo(literal(2))
|
|
27395
|
+
.identical(literal(0));
|
|
27396
|
+
});
|
|
27397
|
+
bindingScope.set(level, block.contextVariables.$first.name, (scope, retrievalLevel) => {
|
|
27398
|
+
return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
|
|
27399
|
+
.identical(literal(0));
|
|
27400
|
+
});
|
|
27401
|
+
bindingScope.set(level, block.contextVariables.$last.name, (scope, retrievalLevel) => {
|
|
27402
|
+
const index = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index');
|
|
27403
|
+
const count = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$count');
|
|
27404
|
+
return index.identical(count.minus(literal(1)));
|
|
27405
|
+
});
|
|
27406
|
+
}
|
|
27407
|
+
getLevelSpecificVariableName(name, level) {
|
|
27408
|
+
// We use the `ɵ` here to ensure that there are no name conflicts with user-defined variables.
|
|
27409
|
+
return `ɵ${name}_${level}`;
|
|
27410
|
+
}
|
|
27411
|
+
/**
|
|
27412
|
+
* Gets the name of a for loop variable at a specific binding level. This allows us to look
|
|
27413
|
+
* up implicitly shadowed variables like `$index` and `$count` at a specific level.
|
|
27414
|
+
*/
|
|
27415
|
+
getLevelSpecificForLoopVariable(block, scope, retrievalLevel, name) {
|
|
27416
|
+
const scopeName = scope.bindingLevel === retrievalLevel ?
|
|
27417
|
+
block.contextVariables[name].name :
|
|
27418
|
+
this.getLevelSpecificVariableName(name, retrievalLevel);
|
|
27419
|
+
return scope.get(scopeName);
|
|
26509
27420
|
}
|
|
26510
27421
|
optimizeTrackByFunction(block) {
|
|
26511
27422
|
const indexLocalName = block.contextVariables.$index.name;
|
|
@@ -27043,7 +27954,7 @@ class BindingScope {
|
|
|
27043
27954
|
if (value.declareLocalCallback && !value.declare) {
|
|
27044
27955
|
value.declare = true;
|
|
27045
27956
|
}
|
|
27046
|
-
return typeof value.lhs === 'function' ? value.lhs(this) : value.lhs;
|
|
27957
|
+
return typeof value.lhs === 'function' ? value.lhs(this, value.retrievalLevel) : value.lhs;
|
|
27047
27958
|
}
|
|
27048
27959
|
current = current.parent;
|
|
27049
27960
|
}
|
|
@@ -27151,7 +28062,9 @@ class BindingScope {
|
|
|
27151
28062
|
const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
|
|
27152
28063
|
componentValue.declare = true;
|
|
27153
28064
|
this.maybeRestoreView();
|
|
27154
|
-
const lhs = typeof componentValue.lhs === 'function' ?
|
|
28065
|
+
const lhs = typeof componentValue.lhs === 'function' ?
|
|
28066
|
+
componentValue.lhs(this, componentValue.retrievalLevel) :
|
|
28067
|
+
componentValue.lhs;
|
|
27155
28068
|
return name === DIRECT_CONTEXT_REFERENCE ? lhs : lhs.prop(name);
|
|
27156
28069
|
}
|
|
27157
28070
|
maybeRestoreView() {
|
|
@@ -27218,12 +28131,16 @@ class BindingScope {
|
|
|
27218
28131
|
}
|
|
27219
28132
|
/** Binding scope of a `track` function inside a `for` loop block. */
|
|
27220
28133
|
class TrackByBindingScope extends BindingScope {
|
|
27221
|
-
constructor(parentScope,
|
|
28134
|
+
constructor(parentScope, globalOverrides) {
|
|
27222
28135
|
super(parentScope.bindingLevel + 1, parentScope);
|
|
27223
|
-
this.
|
|
28136
|
+
this.globalOverrides = globalOverrides;
|
|
27224
28137
|
this.componentAccessCount = 0;
|
|
27225
28138
|
}
|
|
27226
28139
|
get(name) {
|
|
28140
|
+
// Intercept any overridden globals.
|
|
28141
|
+
if (this.globalOverrides.hasOwnProperty(name)) {
|
|
28142
|
+
return variable(this.globalOverrides[name]);
|
|
28143
|
+
}
|
|
27227
28144
|
let current = this.parent;
|
|
27228
28145
|
// Prevent accesses of template variables outside the `for` loop.
|
|
27229
28146
|
while (current) {
|
|
@@ -27232,10 +28149,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
27232
28149
|
}
|
|
27233
28150
|
current = current.parent;
|
|
27234
28151
|
}
|
|
27235
|
-
// Intercept any aliased globals.
|
|
27236
|
-
if (this.globalAliases[name]) {
|
|
27237
|
-
return variable(this.globalAliases[name]);
|
|
27238
|
-
}
|
|
27239
28152
|
// When the component scope is accessed, we redirect it through `this`.
|
|
27240
28153
|
this.componentAccessCount++;
|
|
27241
28154
|
return variable('this').prop(name);
|
|
@@ -27245,24 +28158,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
27245
28158
|
return this.componentAccessCount;
|
|
27246
28159
|
}
|
|
27247
28160
|
}
|
|
27248
|
-
/**
|
|
27249
|
-
* Creates a `CssSelector` given a tag name and a map of attributes
|
|
27250
|
-
*/
|
|
27251
|
-
function createCssSelector(elementName, attributes) {
|
|
27252
|
-
const cssSelector = new CssSelector();
|
|
27253
|
-
const elementNameNoNs = splitNsName(elementName)[1];
|
|
27254
|
-
cssSelector.setElement(elementNameNoNs);
|
|
27255
|
-
Object.getOwnPropertyNames(attributes).forEach((name) => {
|
|
27256
|
-
const nameNoNs = splitNsName(name)[1];
|
|
27257
|
-
const value = attributes[name];
|
|
27258
|
-
cssSelector.addAttribute(nameNoNs, value);
|
|
27259
|
-
if (name.toLowerCase() === 'class') {
|
|
27260
|
-
const classes = value.trim().split(/\s+/);
|
|
27261
|
-
classes.forEach(className => cssSelector.addClassName(className));
|
|
27262
|
-
}
|
|
27263
|
-
});
|
|
27264
|
-
return cssSelector;
|
|
27265
|
-
}
|
|
27266
28161
|
/**
|
|
27267
28162
|
* Creates an array of expressions out of an `ngProjectAs` attributes
|
|
27268
28163
|
* which can be added to the instruction parameters.
|
|
@@ -27623,6 +28518,11 @@ function addFeatures(definitionMap, meta) {
|
|
|
27623
28518
|
break;
|
|
27624
28519
|
}
|
|
27625
28520
|
}
|
|
28521
|
+
// Note: host directives feature needs to be inserted before the
|
|
28522
|
+
// inheritance feature to ensure the correct execution order.
|
|
28523
|
+
if (meta.hostDirectives?.length) {
|
|
28524
|
+
features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
|
|
28525
|
+
}
|
|
27626
28526
|
if (meta.usesInheritance) {
|
|
27627
28527
|
features.push(importExpr(Identifiers.InheritDefinitionFeature));
|
|
27628
28528
|
}
|
|
@@ -27636,9 +28536,6 @@ function addFeatures(definitionMap, meta) {
|
|
|
27636
28536
|
if (meta.hasOwnProperty('template') && meta.isStandalone) {
|
|
27637
28537
|
features.push(importExpr(Identifiers.StandaloneFeature));
|
|
27638
28538
|
}
|
|
27639
|
-
if (meta.hostDirectives?.length) {
|
|
27640
|
-
features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
|
|
27641
|
-
}
|
|
27642
28539
|
if (features.length) {
|
|
27643
28540
|
definitionMap.set('features', literalArr(features));
|
|
27644
28541
|
}
|
|
@@ -27949,6 +28846,8 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
27949
28846
|
const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, typeSourceSpan);
|
|
27950
28847
|
// Calculate host event bindings
|
|
27951
28848
|
const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, typeSourceSpan);
|
|
28849
|
+
let bindingId = 0;
|
|
28850
|
+
const getNextBindingId = () => `${bindingId++}`;
|
|
27952
28851
|
const bindingContext = variable(CONTEXT_NAME);
|
|
27953
28852
|
const styleBuilder = new StylingBuilder(bindingContext);
|
|
27954
28853
|
const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
|
|
@@ -28001,7 +28900,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
28001
28900
|
for (const binding of allOtherBindings) {
|
|
28002
28901
|
// resolve literal arrays and literal objects
|
|
28003
28902
|
const value = binding.expression.visit(getValueConverter());
|
|
28004
|
-
const bindingExpr = bindingFn(bindingContext, value);
|
|
28903
|
+
const bindingExpr = bindingFn(bindingContext, value, getNextBindingId);
|
|
28005
28904
|
const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
|
|
28006
28905
|
const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
|
|
28007
28906
|
.filter(context => context !== SecurityContext.NONE);
|
|
@@ -28080,10 +28979,12 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
28080
28979
|
// at the top of this method when all the input bindings were counted.
|
|
28081
28980
|
totalHostVarsCount +=
|
|
28082
28981
|
Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
|
|
28982
|
+
const { params, stmts } = convertStylingCall(call, bindingContext, bindingFn, getNextBindingId);
|
|
28983
|
+
updateVariables.push(...stmts);
|
|
28083
28984
|
updateInstructions.push({
|
|
28084
28985
|
reference: instruction.reference,
|
|
28085
|
-
paramsOrFn:
|
|
28086
|
-
span: null
|
|
28986
|
+
paramsOrFn: params,
|
|
28987
|
+
span: null,
|
|
28087
28988
|
});
|
|
28088
28989
|
}
|
|
28089
28990
|
});
|
|
@@ -28104,11 +29005,19 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
|
|
|
28104
29005
|
}
|
|
28105
29006
|
return null;
|
|
28106
29007
|
}
|
|
28107
|
-
function bindingFn(implicit, value) {
|
|
28108
|
-
return convertPropertyBinding(null, implicit, value,
|
|
29008
|
+
function bindingFn(implicit, value, getNextBindingIdFn) {
|
|
29009
|
+
return convertPropertyBinding(null, implicit, value, getNextBindingIdFn());
|
|
28109
29010
|
}
|
|
28110
|
-
function convertStylingCall(call, bindingContext, bindingFn) {
|
|
28111
|
-
|
|
29011
|
+
function convertStylingCall(call, bindingContext, bindingFn, getNextBindingIdFn) {
|
|
29012
|
+
const stmts = [];
|
|
29013
|
+
const params = call.params(value => {
|
|
29014
|
+
const result = bindingFn(bindingContext, value, getNextBindingIdFn);
|
|
29015
|
+
if (Array.isArray(result.stmts) && result.stmts.length > 0) {
|
|
29016
|
+
stmts.push(...result.stmts);
|
|
29017
|
+
}
|
|
29018
|
+
return result.currValExpr;
|
|
29019
|
+
});
|
|
29020
|
+
return { params, stmts };
|
|
28112
29021
|
}
|
|
28113
29022
|
function getBindingNameAndInstruction(binding) {
|
|
28114
29023
|
let bindingName = binding.name;
|
|
@@ -28547,15 +29456,15 @@ class DirectiveBinder {
|
|
|
28547
29456
|
template.forEach(node => node.visit(this));
|
|
28548
29457
|
}
|
|
28549
29458
|
visitElement(element) {
|
|
28550
|
-
this.visitElementOrTemplate(element
|
|
29459
|
+
this.visitElementOrTemplate(element);
|
|
28551
29460
|
}
|
|
28552
29461
|
visitTemplate(template) {
|
|
28553
|
-
this.visitElementOrTemplate(
|
|
29462
|
+
this.visitElementOrTemplate(template);
|
|
28554
29463
|
}
|
|
28555
|
-
visitElementOrTemplate(
|
|
29464
|
+
visitElementOrTemplate(node) {
|
|
28556
29465
|
// First, determine the HTML shape of the node for the purpose of directive matching.
|
|
28557
29466
|
// Do this by building up a `CssSelector` for the node.
|
|
28558
|
-
const cssSelector =
|
|
29467
|
+
const cssSelector = createCssSelectorFromNode(node);
|
|
28559
29468
|
// Next, use the `SelectorMatcher` to get the list of directives on the node.
|
|
28560
29469
|
const directives = [];
|
|
28561
29470
|
this.matcher.match(cssSelector, (_selector, results) => directives.push(...results));
|
|
@@ -29684,7 +30593,7 @@ function publishFacade(global) {
|
|
|
29684
30593
|
* @description
|
|
29685
30594
|
* Entry point for all public APIs of the compiler package.
|
|
29686
30595
|
*/
|
|
29687
|
-
const VERSION = new Version('17.0.
|
|
30596
|
+
const VERSION = new Version('17.0.8');
|
|
29688
30597
|
|
|
29689
30598
|
class CompilerConfig {
|
|
29690
30599
|
constructor({ defaultEncapsulation = exports.ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -29917,7 +30826,8 @@ class _Visitor {
|
|
|
29917
30826
|
this._errors = [];
|
|
29918
30827
|
this._messages = [];
|
|
29919
30828
|
this._inImplicitNode = false;
|
|
29920
|
-
this._createI18nMessage =
|
|
30829
|
+
this._createI18nMessage =
|
|
30830
|
+
createI18nMessageFactory(interpolationConfig, DEFAULT_CONTAINER_BLOCKS);
|
|
29921
30831
|
}
|
|
29922
30832
|
// looks for translatable attributes
|
|
29923
30833
|
_visitAttributesOf(el) {
|
|
@@ -30225,6 +31135,12 @@ class _WriteVisitor$1 {
|
|
|
30225
31135
|
visitPlaceholder(ph, context) {
|
|
30226
31136
|
return [new Tag(_PLACEHOLDER_TAG$2, { id: ph.name, 'equiv-text': `{{${ph.value}}}` })];
|
|
30227
31137
|
}
|
|
31138
|
+
visitBlockPlaceholder(ph, context) {
|
|
31139
|
+
const ctype = `x-${ph.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
|
|
31140
|
+
const startTagPh = new Tag(_PLACEHOLDER_TAG$2, { id: ph.startName, ctype, 'equiv-text': `@${ph.name}` });
|
|
31141
|
+
const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, { id: ph.closeName, ctype, 'equiv-text': `}` });
|
|
31142
|
+
return [startTagPh, ...this.serialize(ph.children), closeTagPh];
|
|
31143
|
+
}
|
|
30228
31144
|
visitIcuPlaceholder(ph, context) {
|
|
30229
31145
|
const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ')}}`;
|
|
30230
31146
|
return [new Tag(_PLACEHOLDER_TAG$2, { id: ph.name, 'equiv-text': equivText })];
|
|
@@ -30496,6 +31412,24 @@ class _WriteVisitor {
|
|
|
30496
31412
|
disp: `{{${ph.value}}}`,
|
|
30497
31413
|
})];
|
|
30498
31414
|
}
|
|
31415
|
+
visitBlockPlaceholder(ph, context) {
|
|
31416
|
+
const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
|
|
31417
|
+
id: (this._nextPlaceholderId++).toString(),
|
|
31418
|
+
equivStart: ph.startName,
|
|
31419
|
+
equivEnd: ph.closeName,
|
|
31420
|
+
type: 'other',
|
|
31421
|
+
dispStart: `@${ph.name}`,
|
|
31422
|
+
dispEnd: `}`,
|
|
31423
|
+
});
|
|
31424
|
+
const nodes = [].concat(...ph.children.map(node => node.visit(this)));
|
|
31425
|
+
if (nodes.length) {
|
|
31426
|
+
nodes.forEach((node) => tagPc.children.push(node));
|
|
31427
|
+
}
|
|
31428
|
+
else {
|
|
31429
|
+
tagPc.children.push(new Text$1(''));
|
|
31430
|
+
}
|
|
31431
|
+
return [tagPc];
|
|
31432
|
+
}
|
|
30499
31433
|
visitIcuPlaceholder(ph, context) {
|
|
30500
31434
|
const cases = Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ');
|
|
30501
31435
|
const idStr = (this._nextPlaceholderId++).toString();
|
|
@@ -30944,6 +31878,11 @@ class I18nToHtmlVisitor {
|
|
|
30944
31878
|
// An ICU placeholder references the source message to be serialized
|
|
30945
31879
|
return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
|
|
30946
31880
|
}
|
|
31881
|
+
visitBlockPlaceholder(ph, context) {
|
|
31882
|
+
const params = ph.parameters.length === 0 ? '' : ` (${ph.parameters.join('; ')})`;
|
|
31883
|
+
const children = ph.children.map((c) => c.visit(this)).join('');
|
|
31884
|
+
return `@${ph.name}${params} {${children}}`;
|
|
31885
|
+
}
|
|
30947
31886
|
/**
|
|
30948
31887
|
* Convert a source message to a translated text string:
|
|
30949
31888
|
* - text nodes are replaced with their translation,
|
|
@@ -31096,6 +32035,12 @@ class MapPlaceholderNames extends CloneVisitor {
|
|
|
31096
32035
|
const children = ph.children.map(n => n.visit(this, mapper));
|
|
31097
32036
|
return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
|
|
31098
32037
|
}
|
|
32038
|
+
visitBlockPlaceholder(ph, mapper) {
|
|
32039
|
+
const startName = mapper.toPublicName(ph.startName);
|
|
32040
|
+
const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
|
|
32041
|
+
const children = ph.children.map(n => n.visit(this, mapper));
|
|
32042
|
+
return new BlockPlaceholder(ph.name, ph.parameters, startName, closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
|
|
32043
|
+
}
|
|
31099
32044
|
visitPlaceholder(ph, mapper) {
|
|
31100
32045
|
return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
|
|
31101
32046
|
}
|
|
@@ -31214,7 +32159,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
31214
32159
|
function compileDeclareClassMetadata(metadata) {
|
|
31215
32160
|
const definitionMap = new DefinitionMap();
|
|
31216
32161
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
31217
|
-
definitionMap.set('version', literal('17.0.
|
|
32162
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31218
32163
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31219
32164
|
definitionMap.set('type', metadata.type);
|
|
31220
32165
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -31322,7 +32267,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
31322
32267
|
// in 16.1 is actually used.
|
|
31323
32268
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
31324
32269
|
definitionMap.set('minVersion', literal(minVersion));
|
|
31325
|
-
definitionMap.set('version', literal('17.0.
|
|
32270
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31326
32271
|
// e.g. `type: MyDirective`
|
|
31327
32272
|
definitionMap.set('type', meta.type.value);
|
|
31328
32273
|
if (meta.isStandalone) {
|
|
@@ -31596,7 +32541,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
31596
32541
|
function compileDeclareFactoryFunction(meta) {
|
|
31597
32542
|
const definitionMap = new DefinitionMap();
|
|
31598
32543
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
31599
|
-
definitionMap.set('version', literal('17.0.
|
|
32544
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31600
32545
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31601
32546
|
definitionMap.set('type', meta.type.value);
|
|
31602
32547
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -31631,7 +32576,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
31631
32576
|
function createInjectableDefinitionMap(meta) {
|
|
31632
32577
|
const definitionMap = new DefinitionMap();
|
|
31633
32578
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
31634
|
-
definitionMap.set('version', literal('17.0.
|
|
32579
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31635
32580
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31636
32581
|
definitionMap.set('type', meta.type.value);
|
|
31637
32582
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -31682,7 +32627,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
31682
32627
|
function createInjectorDefinitionMap(meta) {
|
|
31683
32628
|
const definitionMap = new DefinitionMap();
|
|
31684
32629
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
31685
|
-
definitionMap.set('version', literal('17.0.
|
|
32630
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31686
32631
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31687
32632
|
definitionMap.set('type', meta.type.value);
|
|
31688
32633
|
definitionMap.set('providers', meta.providers);
|
|
@@ -31715,7 +32660,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
31715
32660
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
31716
32661
|
}
|
|
31717
32662
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
31718
|
-
definitionMap.set('version', literal('17.0.
|
|
32663
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31719
32664
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31720
32665
|
definitionMap.set('type', meta.type.value);
|
|
31721
32666
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -31766,7 +32711,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
31766
32711
|
function createPipeDefinitionMap(meta) {
|
|
31767
32712
|
const definitionMap = new DefinitionMap();
|
|
31768
32713
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
31769
|
-
definitionMap.set('version', literal('17.0.
|
|
32714
|
+
definitionMap.set('version', literal('17.0.8'));
|
|
31770
32715
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31771
32716
|
// e.g. `type: MyPipe`
|
|
31772
32717
|
definitionMap.set('type', meta.type.value);
|
|
@@ -31974,6 +32919,7 @@ exports.compileNgModule = compileNgModule;
|
|
|
31974
32919
|
exports.compilePipeFromMetadata = compilePipeFromMetadata;
|
|
31975
32920
|
exports.computeMsgId = computeMsgId;
|
|
31976
32921
|
exports.core = core;
|
|
32922
|
+
exports.createCssSelectorFromNode = createCssSelectorFromNode;
|
|
31977
32923
|
exports.createInjectableType = createInjectableType;
|
|
31978
32924
|
exports.createMayBeForwardRefExpression = createMayBeForwardRefExpression;
|
|
31979
32925
|
exports.devOnlyGuardedExpression = devOnlyGuardedExpression;
|