@angular/compiler 17.0.7 → 17.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/constant_pool.mjs +5 -3
- package/esm2022/src/ml_parser/tags.mjs +8 -3
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/view/style_parser.mjs +2 -1
- package/esm2022/src/render3/view/template.mjs +11 -8
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +7 -13
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +5 -21
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +29 -10
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +6 -3
- package/esm2022/src/template/pipeline/src/emit.mjs +3 -5
- package/esm2022/src/template/pipeline/src/ingest.mjs +76 -48
- package/esm2022/src/template/pipeline/src/instruction.mjs +8 -7
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +10 -19
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -2
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +31 -20
- package/esm2022/src/template/pipeline/src/phases/convert_i18n_bindings.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/create_defer_deps_fns.mjs +3 -2
- package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +63 -51
- package/esm2022/src/template/pipeline/src/phases/deduplicate_text_bindings.mjs +40 -0
- package/esm2022/src/template/pipeline/src/phases/extract_i18n_messages.mjs +52 -49
- package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +2 -3
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +22 -3
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +21 -3
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +9 -9
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +23 -10
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +8 -1
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +419 -361
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +3 -3
- package/package.json +2 -2
- package/esm2022/src/template/pipeline/src/phases/repeater_derived_vars.mjs +0 -45
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_icu_placeholders.mjs +0 -62
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.
|
|
2
|
+
* @license Angular v17.0.9
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2308,7 +2308,9 @@ class ConstantPool {
|
|
|
2308
2308
|
}))));
|
|
2309
2309
|
}
|
|
2310
2310
|
}
|
|
2311
|
-
|
|
2311
|
+
// TODO: useUniqueName(false) is necessary for naming compatibility with
|
|
2312
|
+
// TemplateDefinitionBuilder, but should be removed once Template Pipeline is the default.
|
|
2313
|
+
getSharedFunctionReference(fn, prefix, useUniqueName = true) {
|
|
2312
2314
|
const isArrow = fn instanceof ArrowFunctionExpr;
|
|
2313
2315
|
for (const current of this.statements) {
|
|
2314
2316
|
// Arrow functions are saved as variables so we check if the
|
|
@@ -2323,7 +2325,7 @@ class ConstantPool {
|
|
|
2323
2325
|
}
|
|
2324
2326
|
}
|
|
2325
2327
|
// Otherwise declare the function.
|
|
2326
|
-
const name = this.uniqueName(prefix);
|
|
2328
|
+
const name = useUniqueName ? this.uniqueName(prefix) : prefix;
|
|
2327
2329
|
this.statements.push(fn.toDeclStmt(name, StmtModifier.Final));
|
|
2328
2330
|
return variable(name);
|
|
2329
2331
|
}
|
|
@@ -3685,13 +3687,18 @@ var TagContentType;
|
|
|
3685
3687
|
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
3686
3688
|
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
3687
3689
|
})(TagContentType || (TagContentType = {}));
|
|
3688
|
-
function splitNsName(elementName) {
|
|
3690
|
+
function splitNsName(elementName, fatal = true) {
|
|
3689
3691
|
if (elementName[0] != ':') {
|
|
3690
3692
|
return [null, elementName];
|
|
3691
3693
|
}
|
|
3692
3694
|
const colonIndex = elementName.indexOf(':', 1);
|
|
3693
3695
|
if (colonIndex === -1) {
|
|
3694
|
-
|
|
3696
|
+
if (fatal) {
|
|
3697
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
3698
|
+
}
|
|
3699
|
+
else {
|
|
3700
|
+
return [null, elementName];
|
|
3701
|
+
}
|
|
3695
3702
|
}
|
|
3696
3703
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
3697
3704
|
}
|
|
@@ -8966,14 +8973,18 @@ var OpKind;
|
|
|
8966
8973
|
* An instruction to update an ICU expression.
|
|
8967
8974
|
*/
|
|
8968
8975
|
OpKind[OpKind["IcuEnd"] = 42] = "IcuEnd";
|
|
8976
|
+
/**
|
|
8977
|
+
* An instruction representing a placeholder in an ICU expression.
|
|
8978
|
+
*/
|
|
8979
|
+
OpKind[OpKind["IcuPlaceholder"] = 43] = "IcuPlaceholder";
|
|
8969
8980
|
/**
|
|
8970
8981
|
* An i18n context containing information needed to generate an i18n message.
|
|
8971
8982
|
*/
|
|
8972
|
-
OpKind[OpKind["I18nContext"] =
|
|
8983
|
+
OpKind[OpKind["I18nContext"] = 44] = "I18nContext";
|
|
8973
8984
|
/**
|
|
8974
8985
|
* A creation op that corresponds to i18n attributes on an element.
|
|
8975
8986
|
*/
|
|
8976
|
-
OpKind[OpKind["I18nAttributes"] =
|
|
8987
|
+
OpKind[OpKind["I18nAttributes"] = 45] = "I18nAttributes";
|
|
8977
8988
|
})(OpKind || (OpKind = {}));
|
|
8978
8989
|
/**
|
|
8979
8990
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9250,16 +9261,6 @@ var DeferTriggerKind;
|
|
|
9250
9261
|
DeferTriggerKind[DeferTriggerKind["Interaction"] = 4] = "Interaction";
|
|
9251
9262
|
DeferTriggerKind[DeferTriggerKind["Viewport"] = 5] = "Viewport";
|
|
9252
9263
|
})(DeferTriggerKind || (DeferTriggerKind = {}));
|
|
9253
|
-
/**
|
|
9254
|
-
* Repeaters implicitly define these derived variables, and child nodes may read them.
|
|
9255
|
-
*/
|
|
9256
|
-
var DerivedRepeaterVarIdentity;
|
|
9257
|
-
(function (DerivedRepeaterVarIdentity) {
|
|
9258
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["First"] = 0] = "First";
|
|
9259
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Last"] = 1] = "Last";
|
|
9260
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
9261
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
9262
|
-
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
9263
9264
|
/**
|
|
9264
9265
|
* Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
|
|
9265
9266
|
*/
|
|
@@ -9504,10 +9505,11 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9504
9505
|
/**
|
|
9505
9506
|
* Create an `AttributeOp`.
|
|
9506
9507
|
*/
|
|
9507
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9508
|
+
function createAttributeOp(target, namespace, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9508
9509
|
return {
|
|
9509
9510
|
kind: OpKind.Attribute,
|
|
9510
9511
|
target,
|
|
9512
|
+
namespace,
|
|
9511
9513
|
name,
|
|
9512
9514
|
expression,
|
|
9513
9515
|
securityContext,
|
|
@@ -9572,12 +9574,13 @@ function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
|
|
|
9572
9574
|
sourceSpan,
|
|
9573
9575
|
...NEW_OP,
|
|
9574
9576
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9577
|
+
...TRAIT_CONSUMES_VARS,
|
|
9575
9578
|
};
|
|
9576
9579
|
}
|
|
9577
9580
|
/**
|
|
9578
9581
|
* Create an i18n expression op.
|
|
9579
9582
|
*/
|
|
9580
|
-
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9583
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9581
9584
|
return {
|
|
9582
9585
|
kind: OpKind.I18nExpression,
|
|
9583
9586
|
context,
|
|
@@ -9585,6 +9588,7 @@ function createI18nExpressionOp(context, target, i18nOwner, handle, expression,
|
|
|
9585
9588
|
i18nOwner,
|
|
9586
9589
|
handle,
|
|
9587
9590
|
expression,
|
|
9591
|
+
icuPlaceholder,
|
|
9588
9592
|
i18nPlaceholder,
|
|
9589
9593
|
resolutionTime,
|
|
9590
9594
|
usage,
|
|
@@ -10202,26 +10206,6 @@ class ConditionalCaseExpr extends ExpressionBase {
|
|
|
10202
10206
|
}
|
|
10203
10207
|
}
|
|
10204
10208
|
}
|
|
10205
|
-
class DerivedRepeaterVarExpr extends ExpressionBase {
|
|
10206
|
-
constructor(xref, identity) {
|
|
10207
|
-
super();
|
|
10208
|
-
this.xref = xref;
|
|
10209
|
-
this.identity = identity;
|
|
10210
|
-
this.kind = ExpressionKind.DerivedRepeaterVar;
|
|
10211
|
-
}
|
|
10212
|
-
transformInternalExpressions(transform, flags) { }
|
|
10213
|
-
visitExpression(visitor, context) { }
|
|
10214
|
-
isEquivalent(e) {
|
|
10215
|
-
return e instanceof DerivedRepeaterVarExpr && e.identity === this.identity &&
|
|
10216
|
-
e.xref === this.xref;
|
|
10217
|
-
}
|
|
10218
|
-
isConstant() {
|
|
10219
|
-
return false;
|
|
10220
|
-
}
|
|
10221
|
-
clone() {
|
|
10222
|
-
return new DerivedRepeaterVarExpr(this.xref, this.identity);
|
|
10223
|
-
}
|
|
10224
|
-
}
|
|
10225
10209
|
class ConstCollectedExpr extends ExpressionBase {
|
|
10226
10210
|
constructor(expr) {
|
|
10227
10211
|
super();
|
|
@@ -10354,6 +10338,9 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10354
10338
|
op.placeholderConfig =
|
|
10355
10339
|
transformExpressionsInExpression(op.placeholderConfig, transform, flags);
|
|
10356
10340
|
}
|
|
10341
|
+
if (op.resolverFn !== null) {
|
|
10342
|
+
op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
|
|
10343
|
+
}
|
|
10357
10344
|
break;
|
|
10358
10345
|
case OpKind.I18nMessage:
|
|
10359
10346
|
for (const [placeholder, expr] of op.params) {
|
|
@@ -10390,6 +10377,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10390
10377
|
case OpKind.Template:
|
|
10391
10378
|
case OpKind.Text:
|
|
10392
10379
|
case OpKind.I18nAttributes:
|
|
10380
|
+
case OpKind.IcuPlaceholder:
|
|
10393
10381
|
// These operations contain no expressions.
|
|
10394
10382
|
break;
|
|
10395
10383
|
default:
|
|
@@ -10797,7 +10785,7 @@ function isElementOrContainerOp(op) {
|
|
|
10797
10785
|
/**
|
|
10798
10786
|
* Create an `ElementStartOp`.
|
|
10799
10787
|
*/
|
|
10800
|
-
function createElementStartOp(tag, xref, namespace, i18nPlaceholder,
|
|
10788
|
+
function createElementStartOp(tag, xref, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10801
10789
|
return {
|
|
10802
10790
|
kind: OpKind.ElementStart,
|
|
10803
10791
|
xref,
|
|
@@ -10808,7 +10796,8 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10808
10796
|
nonBindable: false,
|
|
10809
10797
|
namespace,
|
|
10810
10798
|
i18nPlaceholder,
|
|
10811
|
-
|
|
10799
|
+
startSourceSpan,
|
|
10800
|
+
wholeSourceSpan,
|
|
10812
10801
|
...TRAIT_CONSUMES_SLOT,
|
|
10813
10802
|
...NEW_OP,
|
|
10814
10803
|
};
|
|
@@ -10816,7 +10805,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10816
10805
|
/**
|
|
10817
10806
|
* Create a `TemplateOp`.
|
|
10818
10807
|
*/
|
|
10819
|
-
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder,
|
|
10808
|
+
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10820
10809
|
return {
|
|
10821
10810
|
kind: OpKind.Template,
|
|
10822
10811
|
xref,
|
|
@@ -10831,12 +10820,13 @@ function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace
|
|
|
10831
10820
|
nonBindable: false,
|
|
10832
10821
|
namespace,
|
|
10833
10822
|
i18nPlaceholder,
|
|
10834
|
-
|
|
10823
|
+
startSourceSpan,
|
|
10824
|
+
wholeSourceSpan,
|
|
10835
10825
|
...TRAIT_CONSUMES_SLOT,
|
|
10836
10826
|
...NEW_OP,
|
|
10837
10827
|
};
|
|
10838
10828
|
}
|
|
10839
|
-
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i18nPlaceholder, emptyI18nPlaceholder,
|
|
10829
|
+
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10840
10830
|
return {
|
|
10841
10831
|
kind: OpKind.RepeaterCreate,
|
|
10842
10832
|
attributes: null,
|
|
@@ -10856,9 +10846,11 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i1
|
|
|
10856
10846
|
usesComponentInstance: false,
|
|
10857
10847
|
i18nPlaceholder,
|
|
10858
10848
|
emptyI18nPlaceholder,
|
|
10859
|
-
|
|
10849
|
+
startSourceSpan,
|
|
10850
|
+
wholeSourceSpan,
|
|
10860
10851
|
...TRAIT_CONSUMES_SLOT,
|
|
10861
10852
|
...NEW_OP,
|
|
10853
|
+
...TRAIT_CONSUMES_VARS,
|
|
10862
10854
|
numSlotsUsed: emptyView === null ? 2 : 3,
|
|
10863
10855
|
};
|
|
10864
10856
|
}
|
|
@@ -10890,12 +10882,13 @@ function createEnableBindingsOp(xref) {
|
|
|
10890
10882
|
/**
|
|
10891
10883
|
* Create a `TextOp`.
|
|
10892
10884
|
*/
|
|
10893
|
-
function createTextOp(xref, initialValue, sourceSpan) {
|
|
10885
|
+
function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
|
|
10894
10886
|
return {
|
|
10895
10887
|
kind: OpKind.Text,
|
|
10896
10888
|
xref,
|
|
10897
10889
|
handle: new SlotHandle(),
|
|
10898
10890
|
initialValue,
|
|
10891
|
+
icuPlaceholder,
|
|
10899
10892
|
sourceSpan,
|
|
10900
10893
|
...TRAIT_CONSUMES_SLOT,
|
|
10901
10894
|
...NEW_OP,
|
|
@@ -10966,11 +10959,12 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
|
|
|
10966
10959
|
/**
|
|
10967
10960
|
* Create an `ExtractedAttributeOp`.
|
|
10968
10961
|
*/
|
|
10969
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10962
|
+
function createExtractedAttributeOp(target, bindingKind, namespace, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10970
10963
|
return {
|
|
10971
10964
|
kind: OpKind.ExtractedAttribute,
|
|
10972
10965
|
target,
|
|
10973
10966
|
bindingKind,
|
|
10967
|
+
namespace,
|
|
10974
10968
|
name,
|
|
10975
10969
|
expression,
|
|
10976
10970
|
i18nContext,
|
|
@@ -11085,6 +11079,19 @@ function createIcuEndOp(xref) {
|
|
|
11085
11079
|
...NEW_OP,
|
|
11086
11080
|
};
|
|
11087
11081
|
}
|
|
11082
|
+
/**
|
|
11083
|
+
* Creates an ICU placeholder op.
|
|
11084
|
+
*/
|
|
11085
|
+
function createIcuPlaceholderOp(xref, name, strings) {
|
|
11086
|
+
return {
|
|
11087
|
+
kind: OpKind.IcuPlaceholder,
|
|
11088
|
+
xref,
|
|
11089
|
+
name,
|
|
11090
|
+
strings,
|
|
11091
|
+
expressionPlaceholders: [],
|
|
11092
|
+
...NEW_OP,
|
|
11093
|
+
};
|
|
11094
|
+
}
|
|
11088
11095
|
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
11089
11096
|
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
11090
11097
|
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
@@ -11498,7 +11505,8 @@ function extractAttributes(job) {
|
|
|
11498
11505
|
}
|
|
11499
11506
|
OpList.insertBefore(
|
|
11500
11507
|
// Deliberaly null i18nMessage value
|
|
11501
|
-
createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null,
|
|
11508
|
+
createExtractedAttributeOp(op.target, bindingKind, null, op.name, /* expression */ null,
|
|
11509
|
+
/* i18nContext */ null,
|
|
11502
11510
|
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11503
11511
|
}
|
|
11504
11512
|
break;
|
|
@@ -11510,14 +11518,14 @@ function extractAttributes(job) {
|
|
|
11510
11518
|
// mode.
|
|
11511
11519
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11512
11520
|
op.expression instanceof EmptyExpr) {
|
|
11513
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11521
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */ null,
|
|
11514
11522
|
/* i18nContext */ null,
|
|
11515
11523
|
/* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
|
|
11516
11524
|
}
|
|
11517
11525
|
break;
|
|
11518
11526
|
case OpKind.Listener:
|
|
11519
11527
|
if (!op.isAnimationListener) {
|
|
11520
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11528
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */ null,
|
|
11521
11529
|
/* i18nContext */ null,
|
|
11522
11530
|
/* i18nMessage */ null, SecurityContext.NONE);
|
|
11523
11531
|
if (job.kind === CompilationJobKind.Host) {
|
|
@@ -11551,24 +11559,14 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
11551
11559
|
if (op.expression instanceof Interpolation) {
|
|
11552
11560
|
return;
|
|
11553
11561
|
}
|
|
11554
|
-
let extractable = op.expression.isConstant();
|
|
11562
|
+
let extractable = op.isTextAttribute || op.expression.isConstant();
|
|
11555
11563
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
11556
|
-
// TemplateDefinitionBuilder only
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
|
|
11560
|
-
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
|
|
11561
|
-
// string literal, because it is not a text attribute.
|
|
11562
|
-
extractable &&= op.isTextAttribute;
|
|
11563
|
-
}
|
|
11564
|
-
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11565
|
-
// TemplateDefinitionBuilder also does not seem to extract string literals if they are part of
|
|
11566
|
-
// a host attribute.
|
|
11567
|
-
extractable &&= op.isTextAttribute;
|
|
11568
|
-
}
|
|
11564
|
+
// TemplateDefinitionBuilder only extracts text attributes. It does not extract attriibute
|
|
11565
|
+
// bindings, even if they are constants.
|
|
11566
|
+
extractable &&= op.isTextAttribute;
|
|
11569
11567
|
}
|
|
11570
11568
|
if (extractable) {
|
|
11571
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11569
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.namespace, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11572
11570
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11573
11571
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
11574
11572
|
// matter.
|
|
@@ -11615,7 +11613,8 @@ function specializeBindings(job) {
|
|
|
11615
11613
|
target.nonBindable = true;
|
|
11616
11614
|
}
|
|
11617
11615
|
else {
|
|
11618
|
-
|
|
11616
|
+
const [namespace, name] = splitNsName(op.name);
|
|
11617
|
+
OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
|
|
11619
11618
|
}
|
|
11620
11619
|
break;
|
|
11621
11620
|
case BindingKind.Property:
|
|
@@ -11859,9 +11858,9 @@ function collectElementConsts(job) {
|
|
|
11859
11858
|
for (const unit of job.units) {
|
|
11860
11859
|
for (const op of unit.create) {
|
|
11861
11860
|
if (op.kind === OpKind.ExtractedAttribute) {
|
|
11862
|
-
const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
|
|
11861
|
+
const attributes = allElementAttributes.get(op.target) || new ElementAttributes(job.compatibility);
|
|
11863
11862
|
allElementAttributes.set(op.target, attributes);
|
|
11864
|
-
attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
|
|
11863
|
+
attributes.add(op.bindingKind, op.name, op.expression, op.namespace, op.trustedValueFn);
|
|
11865
11864
|
OpList.remove(op);
|
|
11866
11865
|
}
|
|
11867
11866
|
}
|
|
@@ -11904,11 +11903,6 @@ const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
|
11904
11903
|
* Container for all of the various kinds of attributes which are applied on an element.
|
|
11905
11904
|
*/
|
|
11906
11905
|
class ElementAttributes {
|
|
11907
|
-
constructor() {
|
|
11908
|
-
this.known = new Set();
|
|
11909
|
-
this.byKind = new Map;
|
|
11910
|
-
this.projectAs = null;
|
|
11911
|
-
}
|
|
11912
11906
|
get attributes() {
|
|
11913
11907
|
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
11914
11908
|
}
|
|
@@ -11927,11 +11921,31 @@ class ElementAttributes {
|
|
|
11927
11921
|
get i18n() {
|
|
11928
11922
|
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11929
11923
|
}
|
|
11930
|
-
|
|
11931
|
-
|
|
11924
|
+
constructor(compatibility) {
|
|
11925
|
+
this.compatibility = compatibility;
|
|
11926
|
+
this.known = new Map();
|
|
11927
|
+
this.byKind = new Map;
|
|
11928
|
+
this.projectAs = null;
|
|
11929
|
+
}
|
|
11930
|
+
isKnown(kind, name, value) {
|
|
11931
|
+
const nameToValue = this.known.get(kind) ?? new Set();
|
|
11932
|
+
this.known.set(kind, nameToValue);
|
|
11933
|
+
if (nameToValue.has(name)) {
|
|
11934
|
+
return true;
|
|
11935
|
+
}
|
|
11936
|
+
nameToValue.add(name);
|
|
11937
|
+
return false;
|
|
11938
|
+
}
|
|
11939
|
+
add(kind, name, value, namespace, trustedValueFn) {
|
|
11940
|
+
// TemplateDefinitionBuilder puts duplicate attribute, class, and style values into the consts
|
|
11941
|
+
// array. This seems inefficient, we can probably keep just the first one or the last value
|
|
11942
|
+
// (whichever actually gets applied when multiple values are listed for the same attribute).
|
|
11943
|
+
const allowDuplicates = this.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11944
|
+
(kind === BindingKind.Attribute || kind === BindingKind.ClassName ||
|
|
11945
|
+
kind === BindingKind.StyleProperty);
|
|
11946
|
+
if (!allowDuplicates && this.isKnown(kind, name, value)) {
|
|
11932
11947
|
return;
|
|
11933
11948
|
}
|
|
11934
|
-
this.known.add(name);
|
|
11935
11949
|
// TODO: Can this be its own phase
|
|
11936
11950
|
if (name === 'ngProjectAs') {
|
|
11937
11951
|
if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
|
|
@@ -11943,7 +11957,7 @@ class ElementAttributes {
|
|
|
11943
11957
|
// attribute. Is this sane?
|
|
11944
11958
|
}
|
|
11945
11959
|
const array = this.arrayFor(kind);
|
|
11946
|
-
array.push(...getAttributeNameLiterals$1(name));
|
|
11960
|
+
array.push(...getAttributeNameLiterals$1(namespace, name));
|
|
11947
11961
|
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11948
11962
|
if (value === null) {
|
|
11949
11963
|
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
@@ -11969,13 +11983,10 @@ class ElementAttributes {
|
|
|
11969
11983
|
/**
|
|
11970
11984
|
* Gets an array of literal expressions representing the attribute's namespaced name.
|
|
11971
11985
|
*/
|
|
11972
|
-
function getAttributeNameLiterals$1(name) {
|
|
11973
|
-
const
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
return [
|
|
11977
|
-
literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
11978
|
-
];
|
|
11986
|
+
function getAttributeNameLiterals$1(namespace, name) {
|
|
11987
|
+
const nameLiteral = literal(name);
|
|
11988
|
+
if (namespace) {
|
|
11989
|
+
return [literal(0 /* core.AttributeMarker.NamespaceURI */), literal(namespace), nameLiteral];
|
|
11979
11990
|
}
|
|
11980
11991
|
return [nameLiteral];
|
|
11981
11992
|
}
|
|
@@ -12043,7 +12054,7 @@ function convertI18nBindings(job) {
|
|
|
12043
12054
|
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
12044
12055
|
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`);
|
|
12045
12056
|
}
|
|
12046
|
-
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12057
|
+
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));
|
|
12047
12058
|
}
|
|
12048
12059
|
OpList.replaceWithMany(op, ops);
|
|
12049
12060
|
break;
|
|
@@ -12080,7 +12091,8 @@ function createDeferDepsFns(job) {
|
|
|
12080
12091
|
if (op.handle.slot === null) {
|
|
12081
12092
|
throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
|
|
12082
12093
|
}
|
|
12083
|
-
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn
|
|
12094
|
+
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn`,
|
|
12095
|
+
/* Don't use unique names for TDB compatibility */ false);
|
|
12084
12096
|
}
|
|
12085
12097
|
}
|
|
12086
12098
|
}
|
|
@@ -12097,75 +12109,119 @@ function createDeferDepsFns(job) {
|
|
|
12097
12109
|
* message.)
|
|
12098
12110
|
*/
|
|
12099
12111
|
function createI18nContexts(job) {
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12112
|
+
// Create i18n context ops for i18n attrs.
|
|
12113
|
+
const attrContextByMessage = new Map();
|
|
12114
|
+
for (const unit of job.units) {
|
|
12115
|
+
for (const op of unit.ops()) {
|
|
12116
|
+
switch (op.kind) {
|
|
12117
|
+
case OpKind.Binding:
|
|
12118
|
+
case OpKind.Property:
|
|
12119
|
+
case OpKind.Attribute:
|
|
12120
|
+
case OpKind.ExtractedAttribute:
|
|
12121
|
+
if (op.i18nMessage === null) {
|
|
12122
|
+
continue;
|
|
12123
|
+
}
|
|
12124
|
+
if (!attrContextByMessage.has(op.i18nMessage)) {
|
|
12125
|
+
const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
|
|
12126
|
+
unit.create.push(i18nContext);
|
|
12127
|
+
attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
|
|
12128
|
+
}
|
|
12129
|
+
op.i18nContext = attrContextByMessage.get(op.i18nMessage);
|
|
12130
|
+
break;
|
|
12131
|
+
}
|
|
12132
|
+
}
|
|
12133
|
+
}
|
|
12134
|
+
// Create i18n context ops for root i18n blocks.
|
|
12135
|
+
const blockContextByI18nBlock = new Map();
|
|
12106
12136
|
for (const unit of job.units) {
|
|
12107
12137
|
for (const op of unit.create) {
|
|
12108
12138
|
switch (op.kind) {
|
|
12109
12139
|
case OpKind.I18nStart:
|
|
12110
|
-
currentI18nOp = op;
|
|
12111
|
-
// Each root i18n block gets its own context, child ones refer to the context for their
|
|
12112
|
-
// root block.
|
|
12113
12140
|
if (op.xref === op.root) {
|
|
12114
|
-
|
|
12115
|
-
unit.create.push(
|
|
12116
|
-
op.context = xref;
|
|
12117
|
-
|
|
12141
|
+
const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
|
|
12142
|
+
unit.create.push(contextOp);
|
|
12143
|
+
op.context = contextOp.xref;
|
|
12144
|
+
blockContextByI18nBlock.set(op.xref, contextOp);
|
|
12118
12145
|
}
|
|
12119
12146
|
break;
|
|
12147
|
+
}
|
|
12148
|
+
}
|
|
12149
|
+
}
|
|
12150
|
+
// Assign i18n contexts for child i18n blocks. These don't need their own conext, instead they
|
|
12151
|
+
// should inherit from their root i18n block.
|
|
12152
|
+
for (const unit of job.units) {
|
|
12153
|
+
for (const op of unit.create) {
|
|
12154
|
+
if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
|
|
12155
|
+
const rootContext = blockContextByI18nBlock.get(op.root);
|
|
12156
|
+
if (rootContext === undefined) {
|
|
12157
|
+
throw Error('AssertionError: Root i18n block i18n context should have been created.');
|
|
12158
|
+
}
|
|
12159
|
+
op.context = rootContext.xref;
|
|
12160
|
+
blockContextByI18nBlock.set(op.xref, rootContext);
|
|
12161
|
+
}
|
|
12162
|
+
}
|
|
12163
|
+
}
|
|
12164
|
+
// Create or assign i18n contexts for ICUs.
|
|
12165
|
+
let currentI18nOp = null;
|
|
12166
|
+
for (const unit of job.units) {
|
|
12167
|
+
for (const op of unit.create) {
|
|
12168
|
+
switch (op.kind) {
|
|
12169
|
+
case OpKind.I18nStart:
|
|
12170
|
+
currentI18nOp = op;
|
|
12171
|
+
break;
|
|
12120
12172
|
case OpKind.I18nEnd:
|
|
12121
12173
|
currentI18nOp = null;
|
|
12122
12174
|
break;
|
|
12123
12175
|
case OpKind.IcuStart:
|
|
12124
|
-
// If an ICU represents a different message than its containing block, we give it its own
|
|
12125
|
-
// i18n context.
|
|
12126
12176
|
if (currentI18nOp === null) {
|
|
12127
|
-
throw Error('Unexpected ICU outside of an i18n block.');
|
|
12177
|
+
throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
|
|
12128
12178
|
}
|
|
12129
12179
|
if (op.message.id !== currentI18nOp.message.id) {
|
|
12130
|
-
//
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12180
|
+
// This ICU is a sub-message inside its parent i18n block message. We need to give it
|
|
12181
|
+
// its own context.
|
|
12182
|
+
const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.xref, op.message, null);
|
|
12183
|
+
unit.create.push(contextOp);
|
|
12184
|
+
op.context = contextOp.xref;
|
|
12134
12185
|
}
|
|
12135
12186
|
else {
|
|
12136
|
-
//
|
|
12137
|
-
// the
|
|
12187
|
+
// This ICU is the only translatable content in its parent i18n block. We need to
|
|
12188
|
+
// convert the parent's context into an ICU context.
|
|
12138
12189
|
op.context = currentI18nOp.context;
|
|
12190
|
+
blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
|
|
12139
12191
|
}
|
|
12140
12192
|
break;
|
|
12141
12193
|
}
|
|
12142
12194
|
}
|
|
12143
|
-
for (const op of unit.ops()) {
|
|
12144
|
-
switch (op.kind) {
|
|
12145
|
-
case OpKind.Binding:
|
|
12146
|
-
case OpKind.Property:
|
|
12147
|
-
case OpKind.Attribute:
|
|
12148
|
-
case OpKind.ExtractedAttribute:
|
|
12149
|
-
if (!op.i18nMessage) {
|
|
12150
|
-
continue;
|
|
12151
|
-
}
|
|
12152
|
-
if (!messageToContext.has(op.i18nMessage)) {
|
|
12153
|
-
// create the context
|
|
12154
|
-
const i18nContext = job.allocateXrefId();
|
|
12155
|
-
unit.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, op.i18nMessage, null));
|
|
12156
|
-
messageToContext.set(op.i18nMessage, i18nContext);
|
|
12157
|
-
}
|
|
12158
|
-
op.i18nContext = messageToContext.get(op.i18nMessage);
|
|
12159
|
-
break;
|
|
12160
|
-
}
|
|
12161
|
-
}
|
|
12162
12195
|
}
|
|
12163
|
-
|
|
12164
|
-
|
|
12196
|
+
}
|
|
12197
|
+
|
|
12198
|
+
/**
|
|
12199
|
+
* Deduplicate text bindings, e.g. <div class="cls1" class="cls2">
|
|
12200
|
+
*/
|
|
12201
|
+
function deduplicateTextBindings(job) {
|
|
12202
|
+
const seen = new Map();
|
|
12165
12203
|
for (const unit of job.units) {
|
|
12166
|
-
for (const op of unit.
|
|
12167
|
-
if (op.kind === OpKind.
|
|
12168
|
-
|
|
12204
|
+
for (const op of unit.update.reversed()) {
|
|
12205
|
+
if (op.kind === OpKind.Binding && op.isTextAttribute) {
|
|
12206
|
+
const seenForElement = seen.get(op.target) || new Set();
|
|
12207
|
+
if (seenForElement.has(op.name)) {
|
|
12208
|
+
if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
12209
|
+
// For most duplicated attributes, TemplateDefinitionBuilder lists all of the values in
|
|
12210
|
+
// the consts array. However, for style and class attributes it only keeps the last one.
|
|
12211
|
+
// We replicate that behavior here since it has actual consequences for apps with
|
|
12212
|
+
// duplicate class or style attrs.
|
|
12213
|
+
if (op.name === 'style' || op.name === 'class') {
|
|
12214
|
+
OpList.remove(op);
|
|
12215
|
+
}
|
|
12216
|
+
}
|
|
12217
|
+
else {
|
|
12218
|
+
// TODO: Determine the correct behavior. It would probably make sense to merge multiple
|
|
12219
|
+
// style and class attributes. Alternatively we could just throw an error, as HTML
|
|
12220
|
+
// doesn't permit duplicate attributes.
|
|
12221
|
+
}
|
|
12222
|
+
}
|
|
12223
|
+
seenForElement.add(op.name);
|
|
12224
|
+
seen.set(op.target, seenForElement);
|
|
12169
12225
|
}
|
|
12170
12226
|
}
|
|
12171
12227
|
}
|
|
@@ -12551,13 +12607,18 @@ const LIST_DELIMITER = '|';
|
|
|
12551
12607
|
* used in the final output.
|
|
12552
12608
|
*/
|
|
12553
12609
|
function extractI18nMessages(job) {
|
|
12554
|
-
//
|
|
12555
|
-
|
|
12610
|
+
// Create an i18n message for each context.
|
|
12611
|
+
// TODO: Merge the context op with the message op since they're 1:1 anyways.
|
|
12612
|
+
const i18nMessagesByContext = new Map();
|
|
12556
12613
|
const i18nBlocks = new Map();
|
|
12614
|
+
const i18nContexts = new Map();
|
|
12557
12615
|
for (const unit of job.units) {
|
|
12558
12616
|
for (const op of unit.create) {
|
|
12559
12617
|
switch (op.kind) {
|
|
12560
12618
|
case OpKind.I18nContext:
|
|
12619
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12620
|
+
unit.create.push(i18nMessageOp);
|
|
12621
|
+
i18nMessagesByContext.set(op.xref, i18nMessageOp);
|
|
12561
12622
|
i18nContexts.set(op.xref, op);
|
|
12562
12623
|
break;
|
|
12563
12624
|
case OpKind.I18nStart:
|
|
@@ -12566,54 +12627,47 @@ function extractI18nMessages(job) {
|
|
|
12566
12627
|
}
|
|
12567
12628
|
}
|
|
12568
12629
|
}
|
|
12569
|
-
//
|
|
12570
|
-
//
|
|
12571
|
-
|
|
12572
|
-
for (const unit of job.units) {
|
|
12573
|
-
for (const op of unit.create) {
|
|
12574
|
-
if (op.kind !== OpKind.I18nContext || op.contextKind !== I18nContextKind.Attr) {
|
|
12575
|
-
continue;
|
|
12576
|
-
}
|
|
12577
|
-
const i18nMessageOp = createI18nMessage(job, op);
|
|
12578
|
-
unit.create.push(i18nMessageOp);
|
|
12579
|
-
}
|
|
12580
|
-
}
|
|
12581
|
-
// Extract messages from root i18n blocks.
|
|
12582
|
-
const i18nBlockMessages = new Map();
|
|
12583
|
-
for (const unit of job.units) {
|
|
12584
|
-
for (const op of unit.create) {
|
|
12585
|
-
if (op.kind === OpKind.I18nStart && op.xref === op.root) {
|
|
12586
|
-
if (!op.context) {
|
|
12587
|
-
throw Error('I18n start op should have its context set.');
|
|
12588
|
-
}
|
|
12589
|
-
const i18nMessageOp = createI18nMessage(job, i18nContexts.get(op.context));
|
|
12590
|
-
i18nBlockMessages.set(op.xref, i18nMessageOp);
|
|
12591
|
-
unit.create.push(i18nMessageOp);
|
|
12592
|
-
}
|
|
12593
|
-
}
|
|
12594
|
-
}
|
|
12595
|
-
// Extract messages from ICUs with their own sub-context.
|
|
12630
|
+
// Associate sub-messages for ICUs with their root message. At this point we can also remove the
|
|
12631
|
+
// ICU start/end ops, as they are no longer needed.
|
|
12632
|
+
let currentIcu = null;
|
|
12596
12633
|
for (const unit of job.units) {
|
|
12597
12634
|
for (const op of unit.create) {
|
|
12598
12635
|
switch (op.kind) {
|
|
12599
12636
|
case OpKind.IcuStart:
|
|
12600
|
-
|
|
12601
|
-
|
|
12637
|
+
currentIcu = op;
|
|
12638
|
+
OpList.remove(op);
|
|
12639
|
+
// Skip any contexts not associated with an ICU.
|
|
12640
|
+
const icuContext = i18nContexts.get(op.context);
|
|
12641
|
+
if (icuContext.contextKind !== I18nContextKind.Icu) {
|
|
12642
|
+
continue;
|
|
12602
12643
|
}
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
12607
|
-
|
|
12608
|
-
const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
|
|
12609
|
-
unit.create.push(subMessage);
|
|
12610
|
-
const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
|
|
12611
|
-
const parentMessage = i18nBlockMessages.get(rootI18nId);
|
|
12612
|
-
parentMessage?.subMessages.push(subMessage.xref);
|
|
12644
|
+
// Skip ICUs that share a context with their i18n message. These represent root-level
|
|
12645
|
+
// ICUs, not sub-messages.
|
|
12646
|
+
const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
|
|
12647
|
+
if (i18nBlock.context === icuContext.xref) {
|
|
12648
|
+
continue;
|
|
12613
12649
|
}
|
|
12614
|
-
|
|
12650
|
+
// Find the root message and push this ICUs message as a sub-message.
|
|
12651
|
+
const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
|
|
12652
|
+
const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
|
|
12653
|
+
if (rootMessage === undefined) {
|
|
12654
|
+
throw Error('AssertionError: ICU sub-message should belong to a root message.');
|
|
12655
|
+
}
|
|
12656
|
+
const subMessage = i18nMessagesByContext.get(icuContext.xref);
|
|
12657
|
+
subMessage.messagePlaceholder = op.messagePlaceholder;
|
|
12658
|
+
rootMessage.subMessages.push(subMessage.xref);
|
|
12615
12659
|
break;
|
|
12616
12660
|
case OpKind.IcuEnd:
|
|
12661
|
+
currentIcu = null;
|
|
12662
|
+
OpList.remove(op);
|
|
12663
|
+
break;
|
|
12664
|
+
case OpKind.IcuPlaceholder:
|
|
12665
|
+
// Add ICU placeholders to the message, then remove the ICU placeholder ops.
|
|
12666
|
+
if (currentIcu === null || currentIcu.context == null) {
|
|
12667
|
+
throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
|
|
12668
|
+
}
|
|
12669
|
+
const msg = i18nMessagesByContext.get(currentIcu.context);
|
|
12670
|
+
msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
|
|
12617
12671
|
OpList.remove(op);
|
|
12618
12672
|
break;
|
|
12619
12673
|
}
|
|
@@ -12626,14 +12680,19 @@ function extractI18nMessages(job) {
|
|
|
12626
12680
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
12627
12681
|
let formattedParams = formatParams(context.params);
|
|
12628
12682
|
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12629
|
-
let needsPostprocessing =
|
|
12630
|
-
for (const values of context.params.values()) {
|
|
12631
|
-
if (values.length > 1) {
|
|
12632
|
-
needsPostprocessing = true;
|
|
12633
|
-
}
|
|
12634
|
-
}
|
|
12683
|
+
let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
|
|
12635
12684
|
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12636
12685
|
}
|
|
12686
|
+
/**
|
|
12687
|
+
* Formats an ICU placeholder into a single string with expression placeholders.
|
|
12688
|
+
*/
|
|
12689
|
+
function formatIcuPlaceholder(op) {
|
|
12690
|
+
if (op.strings.length !== op.expressionPlaceholders.length + 1) {
|
|
12691
|
+
throw Error(`AsserionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
|
|
12692
|
+
}
|
|
12693
|
+
const values = op.expressionPlaceholders.map(formatValue);
|
|
12694
|
+
return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
|
|
12695
|
+
}
|
|
12637
12696
|
/**
|
|
12638
12697
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12639
12698
|
*/
|
|
@@ -12972,7 +13031,7 @@ const BANG_IMPORTANT = '!important';
|
|
|
12972
13031
|
*/
|
|
12973
13032
|
function parseHostStyleProperties(job) {
|
|
12974
13033
|
for (const op of job.root.update) {
|
|
12975
|
-
if (op.kind
|
|
13034
|
+
if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
|
|
12976
13035
|
continue;
|
|
12977
13036
|
}
|
|
12978
13037
|
if (op.name.endsWith(BANG_IMPORTANT)) {
|
|
@@ -12982,7 +13041,7 @@ function parseHostStyleProperties(job) {
|
|
|
12982
13041
|
if (op.name.startsWith(STYLE_DOT)) {
|
|
12983
13042
|
op.bindingKind = BindingKind.StyleProperty;
|
|
12984
13043
|
op.name = op.name.substring(STYLE_DOT.length);
|
|
12985
|
-
if (isCssCustomProperty$1(op.name)) {
|
|
13044
|
+
if (!isCssCustomProperty$1(op.name)) {
|
|
12986
13045
|
op.name = hyphenate$1(op.name);
|
|
12987
13046
|
}
|
|
12988
13047
|
const { property, suffix } = parseProperty$1(op.name);
|
|
@@ -20130,7 +20189,7 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
20130
20189
|
let transformFn = undefined;
|
|
20131
20190
|
// If nescessary, add a post-processing step and resolve any placeholder params that are
|
|
20132
20191
|
// set in post-processing.
|
|
20133
|
-
if (messageOp.needsPostprocessing) {
|
|
20192
|
+
if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
|
|
20134
20193
|
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
20135
20194
|
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
20136
20195
|
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
@@ -20160,7 +20219,6 @@ function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
|
20160
20219
|
else {
|
|
20161
20220
|
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
20162
20221
|
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
20163
|
-
messageOp.needsPostprocessing = true;
|
|
20164
20222
|
}
|
|
20165
20223
|
}
|
|
20166
20224
|
}
|
|
@@ -20246,6 +20304,7 @@ function convertI18nText(job) {
|
|
|
20246
20304
|
let currentIcu = null;
|
|
20247
20305
|
const textNodeI18nBlocks = new Map();
|
|
20248
20306
|
const textNodeIcus = new Map();
|
|
20307
|
+
const icuPlaceholderByText = new Map();
|
|
20249
20308
|
for (const op of unit.create) {
|
|
20250
20309
|
switch (op.kind) {
|
|
20251
20310
|
case OpKind.I18nStart:
|
|
@@ -20270,7 +20329,19 @@ function convertI18nText(job) {
|
|
|
20270
20329
|
if (currentI18n !== null) {
|
|
20271
20330
|
textNodeI18nBlocks.set(op.xref, currentI18n);
|
|
20272
20331
|
textNodeIcus.set(op.xref, currentIcu);
|
|
20273
|
-
|
|
20332
|
+
if (op.icuPlaceholder !== null) {
|
|
20333
|
+
// Create an op to represent the ICU placeholder. Initially set its static text to the
|
|
20334
|
+
// value of the text op, though this may be overwritten later if this text op is a
|
|
20335
|
+
// placeholder for an interpolation.
|
|
20336
|
+
const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
|
|
20337
|
+
OpList.replace(op, icuPlaceholderOp);
|
|
20338
|
+
icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
|
|
20339
|
+
}
|
|
20340
|
+
else {
|
|
20341
|
+
// Otherwise just remove the text op, since its value is already accounted for in the
|
|
20342
|
+
// translated message.
|
|
20343
|
+
OpList.remove(op);
|
|
20344
|
+
}
|
|
20274
20345
|
}
|
|
20275
20346
|
break;
|
|
20276
20347
|
}
|
|
@@ -20285,6 +20356,7 @@ function convertI18nText(job) {
|
|
|
20285
20356
|
}
|
|
20286
20357
|
const i18nOp = textNodeI18nBlocks.get(op.target);
|
|
20287
20358
|
const icuOp = textNodeIcus.get(op.target);
|
|
20359
|
+
const icuPlaceholder = icuPlaceholderByText.get(op.target);
|
|
20288
20360
|
const contextId = icuOp ? icuOp.context : i18nOp.context;
|
|
20289
20361
|
const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing :
|
|
20290
20362
|
I18nParamResolutionTime.Creation;
|
|
@@ -20293,9 +20365,14 @@ function convertI18nText(job) {
|
|
|
20293
20365
|
const expr = op.interpolation.expressions[i];
|
|
20294
20366
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
20295
20367
|
// Later, we will modify this, and advance to a different point.
|
|
20296
|
-
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, op.interpolation.i18nPlaceholders[i], resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
20368
|
+
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));
|
|
20297
20369
|
}
|
|
20298
20370
|
OpList.replaceWithMany(op, ops);
|
|
20371
|
+
// If this interpolation is part of an ICU placeholder, add the strings and expressions to
|
|
20372
|
+
// the placeholder.
|
|
20373
|
+
if (icuPlaceholder !== undefined) {
|
|
20374
|
+
icuPlaceholder.strings = op.interpolation.strings;
|
|
20375
|
+
}
|
|
20299
20376
|
break;
|
|
20300
20377
|
}
|
|
20301
20378
|
}
|
|
@@ -20404,6 +20481,7 @@ function parse(value) {
|
|
|
20404
20481
|
break;
|
|
20405
20482
|
case 58 /* Char.Colon */:
|
|
20406
20483
|
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
20484
|
+
// TODO: Do not hyphenate CSS custom property names like: `--intentionallyCamelCase`
|
|
20407
20485
|
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
20408
20486
|
valueStart = i;
|
|
20409
20487
|
}
|
|
@@ -20824,21 +20902,39 @@ function keepLast(ops) {
|
|
|
20824
20902
|
* class property.
|
|
20825
20903
|
*/
|
|
20826
20904
|
function parseExtractedStyles(job) {
|
|
20905
|
+
const elements = new Map();
|
|
20906
|
+
for (const unit of job.units) {
|
|
20907
|
+
for (const op of unit.create) {
|
|
20908
|
+
if (isElementOrContainerOp(op)) {
|
|
20909
|
+
elements.set(op.xref, op);
|
|
20910
|
+
}
|
|
20911
|
+
}
|
|
20912
|
+
}
|
|
20827
20913
|
for (const unit of job.units) {
|
|
20828
20914
|
for (const op of unit.create) {
|
|
20829
20915
|
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
20830
20916
|
isStringLiteral(op.expression)) {
|
|
20917
|
+
const target = elements.get(op.target);
|
|
20918
|
+
if (target !== undefined && target.kind === OpKind.Template &&
|
|
20919
|
+
target.templateKind === TemplateKind.Structural) {
|
|
20920
|
+
// TemplateDefinitionBuilder will not apply class and style bindings to structural
|
|
20921
|
+
// directives; instead, it will leave them as attributes.
|
|
20922
|
+
// (It's not clear what that would mean, anyway -- classes and styles on a structural
|
|
20923
|
+
// element should probably be a parse error.)
|
|
20924
|
+
// TODO: We may be able to remove this once Template Pipeline is the default.
|
|
20925
|
+
continue;
|
|
20926
|
+
}
|
|
20831
20927
|
if (op.name === 'style') {
|
|
20832
20928
|
const parsedStyles = parse(op.expression.value);
|
|
20833
20929
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
20834
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
20930
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, null, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
20835
20931
|
}
|
|
20836
20932
|
OpList.remove(op);
|
|
20837
20933
|
}
|
|
20838
20934
|
else if (op.name === 'class') {
|
|
20839
20935
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
20840
20936
|
for (const parsedClass of parsedClasses) {
|
|
20841
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
20937
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, null, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
20842
20938
|
}
|
|
20843
20939
|
OpList.remove(op);
|
|
20844
20940
|
}
|
|
@@ -21224,9 +21320,7 @@ function namespaceMath() {
|
|
|
21224
21320
|
return call(Identifiers.namespaceMathML, [], null);
|
|
21225
21321
|
}
|
|
21226
21322
|
function advance(delta, sourceSpan) {
|
|
21227
|
-
return call(Identifiers.advance, [
|
|
21228
|
-
literal(delta),
|
|
21229
|
-
], sourceSpan);
|
|
21323
|
+
return call(Identifiers.advance, delta > 1 ? [literal(delta)] : [], sourceSpan);
|
|
21230
21324
|
}
|
|
21231
21325
|
function reference(slot) {
|
|
21232
21326
|
return importExpr(Identifiers.reference).callFn([
|
|
@@ -21364,10 +21458,13 @@ function property(name, expression, sanitizer, sourceSpan) {
|
|
|
21364
21458
|
}
|
|
21365
21459
|
return call(Identifiers.property, args, sourceSpan);
|
|
21366
21460
|
}
|
|
21367
|
-
function attribute(name, expression, sanitizer) {
|
|
21461
|
+
function attribute(name, expression, sanitizer, namespace) {
|
|
21368
21462
|
const args = [literal(name), expression];
|
|
21369
|
-
if (sanitizer !== null) {
|
|
21370
|
-
args.push(sanitizer);
|
|
21463
|
+
if (sanitizer !== null || namespace !== null) {
|
|
21464
|
+
args.push(sanitizer ?? literal(null));
|
|
21465
|
+
}
|
|
21466
|
+
if (namespace !== null) {
|
|
21467
|
+
args.push(literal(namespace));
|
|
21371
21468
|
}
|
|
21372
21469
|
return call(Identifiers.attribute, args, null);
|
|
21373
21470
|
}
|
|
@@ -21719,19 +21816,19 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21719
21816
|
OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
|
|
21720
21817
|
break;
|
|
21721
21818
|
case OpKind.ElementStart:
|
|
21722
|
-
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21819
|
+
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21723
21820
|
break;
|
|
21724
21821
|
case OpKind.Element:
|
|
21725
|
-
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21822
|
+
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21726
21823
|
break;
|
|
21727
21824
|
case OpKind.ElementEnd:
|
|
21728
21825
|
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
21729
21826
|
break;
|
|
21730
21827
|
case OpKind.ContainerStart:
|
|
21731
|
-
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21828
|
+
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21732
21829
|
break;
|
|
21733
21830
|
case OpKind.Container:
|
|
21734
|
-
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21831
|
+
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21735
21832
|
break;
|
|
21736
21833
|
case OpKind.ContainerEnd:
|
|
21737
21834
|
OpList.replace(op, elementContainerEnd());
|
|
@@ -21759,7 +21856,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21759
21856
|
throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
|
|
21760
21857
|
}
|
|
21761
21858
|
const childView = unit.job.views.get(op.xref);
|
|
21762
|
-
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.
|
|
21859
|
+
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21763
21860
|
break;
|
|
21764
21861
|
case OpKind.DisableBindings:
|
|
21765
21862
|
OpList.replace(op, disableBindings());
|
|
@@ -21774,7 +21871,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21774
21871
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
21775
21872
|
const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
|
|
21776
21873
|
if (eventTargetResolver === undefined) {
|
|
21777
|
-
throw new Error(`
|
|
21874
|
+
throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
|
|
21778
21875
|
}
|
|
21779
21876
|
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
21780
21877
|
break;
|
|
@@ -21861,7 +21958,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21861
21958
|
emptyDecls = emptyView.decls;
|
|
21862
21959
|
emptyVars = emptyView.vars;
|
|
21863
21960
|
}
|
|
21864
|
-
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.
|
|
21961
|
+
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));
|
|
21865
21962
|
break;
|
|
21866
21963
|
case OpKind.Statement:
|
|
21867
21964
|
// Pass statement operations directly through.
|
|
@@ -21927,7 +22024,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21927
22024
|
OpList.replace(op, attributeInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer, op.sourceSpan));
|
|
21928
22025
|
}
|
|
21929
22026
|
else {
|
|
21930
|
-
OpList.replace(op, attribute(op.name, op.expression, op.sanitizer));
|
|
22027
|
+
OpList.replace(op, attribute(op.name, op.expression, op.sanitizer, op.namespace));
|
|
21931
22028
|
}
|
|
21932
22029
|
break;
|
|
21933
22030
|
case OpKind.HostProperty:
|
|
@@ -22116,42 +22213,6 @@ function removeUnusedI18nAttributesOps(job) {
|
|
|
22116
22213
|
}
|
|
22117
22214
|
}
|
|
22118
22215
|
|
|
22119
|
-
/**
|
|
22120
|
-
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
22121
|
-
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
22122
|
-
* expression.
|
|
22123
|
-
*/
|
|
22124
|
-
function generateRepeaterDerivedVars(job) {
|
|
22125
|
-
const repeaters = new Map();
|
|
22126
|
-
for (const unit of job.units) {
|
|
22127
|
-
for (const op of unit.ops()) {
|
|
22128
|
-
if (op.kind === OpKind.RepeaterCreate) {
|
|
22129
|
-
repeaters.set(op.xref, op);
|
|
22130
|
-
}
|
|
22131
|
-
}
|
|
22132
|
-
}
|
|
22133
|
-
for (const unit of job.units) {
|
|
22134
|
-
for (const op of unit.ops()) {
|
|
22135
|
-
transformExpressionsInOp(op, expr => {
|
|
22136
|
-
if (!(expr instanceof DerivedRepeaterVarExpr)) {
|
|
22137
|
-
return expr;
|
|
22138
|
-
}
|
|
22139
|
-
const repeaterOp = repeaters.get(expr.xref);
|
|
22140
|
-
switch (expr.identity) {
|
|
22141
|
-
case DerivedRepeaterVarIdentity.First:
|
|
22142
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), literal(0));
|
|
22143
|
-
case DerivedRepeaterVarIdentity.Last:
|
|
22144
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), new BinaryOperatorExpr(BinaryOperator.Minus, new LexicalReadExpr(repeaterOp.varNames.$count), literal(1)));
|
|
22145
|
-
case DerivedRepeaterVarIdentity.Even:
|
|
22146
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
22147
|
-
case DerivedRepeaterVarIdentity.Odd:
|
|
22148
|
-
return new BinaryOperatorExpr(BinaryOperator.NotIdentical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
22149
|
-
}
|
|
22150
|
-
}, VisitorContextFlag.None);
|
|
22151
|
-
}
|
|
22152
|
-
}
|
|
22153
|
-
}
|
|
22154
|
-
|
|
22155
22216
|
/**
|
|
22156
22217
|
* Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
|
|
22157
22218
|
* either the `ctx` parameter to component functions (for the current view context) or to variables
|
|
@@ -22491,6 +22552,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22491
22552
|
// Record all of the i18n context ops, and the sub-template index for each i18n op.
|
|
22492
22553
|
const subTemplateIndicies = new Map();
|
|
22493
22554
|
const i18nContexts = new Map();
|
|
22555
|
+
const icuPlaceholders = new Map();
|
|
22494
22556
|
for (const unit of job.units) {
|
|
22495
22557
|
for (const op of unit.create) {
|
|
22496
22558
|
switch (op.kind) {
|
|
@@ -22500,6 +22562,9 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22500
22562
|
case OpKind.I18nContext:
|
|
22501
22563
|
i18nContexts.set(op.xref, op);
|
|
22502
22564
|
break;
|
|
22565
|
+
case OpKind.IcuPlaceholder:
|
|
22566
|
+
icuPlaceholders.set(op.xref, op);
|
|
22567
|
+
break;
|
|
22503
22568
|
}
|
|
22504
22569
|
}
|
|
22505
22570
|
}
|
|
@@ -22513,76 +22578,32 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22513
22578
|
for (const unit of job.units) {
|
|
22514
22579
|
for (const op of unit.update) {
|
|
22515
22580
|
if (op.kind === OpKind.I18nExpression) {
|
|
22516
|
-
const i18nContext = i18nContexts.get(op.context);
|
|
22517
22581
|
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22518
22582
|
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
22519
|
-
|
|
22520
|
-
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22521
|
-
i18nContext.params :
|
|
22522
|
-
i18nContext.postprocessingParams;
|
|
22523
|
-
const values = params.get(op.i18nPlaceholder) || [];
|
|
22524
|
-
values.push({
|
|
22583
|
+
const value = {
|
|
22525
22584
|
value: index,
|
|
22526
22585
|
subTemplateIndex: subTemplateIndex,
|
|
22527
22586
|
flags: I18nParamValueFlags.ExpressionIndex
|
|
22528
|
-
}
|
|
22529
|
-
|
|
22587
|
+
};
|
|
22588
|
+
updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
|
|
22530
22589
|
expressionIndices.set(referenceIndex(op), index + 1);
|
|
22531
22590
|
}
|
|
22532
22591
|
}
|
|
22533
22592
|
}
|
|
22534
22593
|
}
|
|
22535
|
-
|
|
22536
|
-
|
|
22537
|
-
|
|
22538
|
-
|
|
22539
|
-
|
|
22540
|
-
|
|
22541
|
-
|
|
22542
|
-
|
|
22543
|
-
|
|
22544
|
-
node.visit(new ResolveIcuPlaceholdersVisitor(op.postprocessingParams));
|
|
22545
|
-
}
|
|
22546
|
-
}
|
|
22547
|
-
}
|
|
22594
|
+
function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
|
|
22595
|
+
if (op.i18nPlaceholder !== null) {
|
|
22596
|
+
const i18nContext = i18nContexts.get(op.context);
|
|
22597
|
+
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22598
|
+
i18nContext.params :
|
|
22599
|
+
i18nContext.postprocessingParams;
|
|
22600
|
+
const values = params.get(op.i18nPlaceholder) || [];
|
|
22601
|
+
values.push(value);
|
|
22602
|
+
params.set(op.i18nPlaceholder, values);
|
|
22548
22603
|
}
|
|
22549
|
-
|
|
22550
|
-
|
|
22551
|
-
|
|
22552
|
-
*/
|
|
22553
|
-
class ResolveIcuPlaceholdersVisitor extends RecurseVisitor {
|
|
22554
|
-
constructor(params) {
|
|
22555
|
-
super();
|
|
22556
|
-
this.params = params;
|
|
22557
|
-
}
|
|
22558
|
-
visitContainerPlaceholder(placeholder) {
|
|
22559
|
-
// Add the start and end source span for container placeholders. These need to be recorded for
|
|
22560
|
-
// elements inside ICUs. The slots for the nodes were recorded separately under the i18n
|
|
22561
|
-
// block's context as part of the `resolveI18nElementPlaceholders` phase.
|
|
22562
|
-
if (placeholder.startName && placeholder.startSourceSpan &&
|
|
22563
|
-
!this.params.has(placeholder.startName)) {
|
|
22564
|
-
this.params.set(placeholder.startName, [{
|
|
22565
|
-
value: placeholder.startSourceSpan?.toString(),
|
|
22566
|
-
subTemplateIndex: null,
|
|
22567
|
-
flags: I18nParamValueFlags.None
|
|
22568
|
-
}]);
|
|
22569
|
-
}
|
|
22570
|
-
if (placeholder.closeName && placeholder.endSourceSpan &&
|
|
22571
|
-
!this.params.has(placeholder.closeName)) {
|
|
22572
|
-
this.params.set(placeholder.closeName, [{
|
|
22573
|
-
value: placeholder.endSourceSpan?.toString(),
|
|
22574
|
-
subTemplateIndex: null,
|
|
22575
|
-
flags: I18nParamValueFlags.None
|
|
22576
|
-
}]);
|
|
22577
|
-
}
|
|
22578
|
-
}
|
|
22579
|
-
visitTagPlaceholder(placeholder) {
|
|
22580
|
-
super.visitTagPlaceholder(placeholder);
|
|
22581
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22582
|
-
}
|
|
22583
|
-
visitBlockPlaceholder(placeholder) {
|
|
22584
|
-
super.visitBlockPlaceholder(placeholder);
|
|
22585
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22604
|
+
if (op.icuPlaceholder !== null) {
|
|
22605
|
+
const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
|
|
22606
|
+
icuPlaceholderOp?.expressionPlaceholders.push(value);
|
|
22586
22607
|
}
|
|
22587
22608
|
}
|
|
22588
22609
|
|
|
@@ -23257,7 +23278,14 @@ function varsUsedByOp(op) {
|
|
|
23257
23278
|
return op.interpolation.expressions.length;
|
|
23258
23279
|
case OpKind.I18nExpression:
|
|
23259
23280
|
case OpKind.Conditional:
|
|
23281
|
+
case OpKind.DeferWhen:
|
|
23260
23282
|
return 1;
|
|
23283
|
+
case OpKind.RepeaterCreate:
|
|
23284
|
+
// Repeaters may require an extra variable binding slot, if they have an empty view, for the
|
|
23285
|
+
// empty block tracking.
|
|
23286
|
+
// TODO: It's a bit odd to have a create mode instruction consume variable slots. Maybe we can
|
|
23287
|
+
// find a way to use the Repeater update op instead.
|
|
23288
|
+
return op.emptyView ? 1 : 0;
|
|
23261
23289
|
default:
|
|
23262
23290
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
23263
23291
|
}
|
|
@@ -23741,6 +23769,7 @@ const phases = [
|
|
|
23741
23769
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
23742
23770
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
23743
23771
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
23772
|
+
{ kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
|
|
23744
23773
|
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23745
23774
|
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23746
23775
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
@@ -23764,7 +23793,6 @@ const phases = [
|
|
|
23764
23793
|
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
23765
23794
|
{ kind: CompilationJobKind.Both, fn: deleteAnyCasts },
|
|
23766
23795
|
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
23767
|
-
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
23768
23796
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
23769
23797
|
{ kind: CompilationJobKind.Both, fn: resolveNames },
|
|
23770
23798
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
@@ -23779,7 +23807,6 @@ const phases = [
|
|
|
23779
23807
|
{ kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
|
|
23780
23808
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
23781
23809
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
23782
|
-
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nIcuPlaceholders },
|
|
23783
23810
|
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
23784
23811
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
23785
23812
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
@@ -23939,7 +23966,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23939
23966
|
const securityContexts = bindingParser
|
|
23940
23967
|
.calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
|
|
23941
23968
|
.filter(context => context !== SecurityContext.NONE);
|
|
23942
|
-
ingestHostProperty(job, property, bindingKind,
|
|
23969
|
+
ingestHostProperty(job, property, bindingKind, securityContexts);
|
|
23943
23970
|
}
|
|
23944
23971
|
for (const [name, expr] of Object.entries(input.attributes) ?? []) {
|
|
23945
23972
|
const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true)
|
|
@@ -23953,7 +23980,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23953
23980
|
}
|
|
23954
23981
|
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
23955
23982
|
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
23956
|
-
function ingestHostProperty(job, property, bindingKind,
|
|
23983
|
+
function ingestHostProperty(job, property, bindingKind, securityContexts) {
|
|
23957
23984
|
let expression;
|
|
23958
23985
|
const ast = property.expression.ast;
|
|
23959
23986
|
if (ast instanceof Interpolation$1) {
|
|
@@ -23962,20 +23989,21 @@ function ingestHostProperty(job, property, bindingKind, isTextAttribute, securit
|
|
|
23962
23989
|
else {
|
|
23963
23990
|
expression = convertAst(ast, job, property.sourceSpan);
|
|
23964
23991
|
}
|
|
23965
|
-
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts,
|
|
23992
|
+
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
|
|
23966
23993
|
}
|
|
23967
23994
|
function ingestHostAttribute(job, name, value, securityContexts) {
|
|
23968
|
-
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
|
|
23995
|
+
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
|
|
23996
|
+
/* Host attributes should always be extracted to const hostAttrs, even if they are not
|
|
23997
|
+
*strictly* text literals */
|
|
23998
|
+
true, false, null,
|
|
23969
23999
|
/* TODO */ null,
|
|
23970
|
-
|
|
24000
|
+
/** TODO: May be null? */ value.sourceSpan);
|
|
23971
24001
|
job.root.update.push(attrBinding);
|
|
23972
24002
|
}
|
|
23973
24003
|
function ingestHostEvent(job, event) {
|
|
23974
24004
|
const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
|
|
23975
24005
|
[event.targetOrPhase, null];
|
|
23976
|
-
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null,
|
|
23977
|
-
// TODO: Can this be a chain?
|
|
23978
|
-
eventBinding.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(event.handler.ast, job, event.sourceSpan), event.handlerSpan)));
|
|
24006
|
+
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
|
|
23979
24007
|
job.root.create.push(eventBinding);
|
|
23980
24008
|
}
|
|
23981
24009
|
/**
|
|
@@ -23993,10 +24021,10 @@ function ingestNodes(unit, template) {
|
|
|
23993
24021
|
ingestContent(unit, node);
|
|
23994
24022
|
}
|
|
23995
24023
|
else if (node instanceof Text$3) {
|
|
23996
|
-
ingestText(unit, node);
|
|
24024
|
+
ingestText(unit, node, null);
|
|
23997
24025
|
}
|
|
23998
24026
|
else if (node instanceof BoundText) {
|
|
23999
|
-
ingestBoundText(unit, node);
|
|
24027
|
+
ingestBoundText(unit, node, null);
|
|
24000
24028
|
}
|
|
24001
24029
|
else if (node instanceof IfBlock) {
|
|
24002
24030
|
ingestIfBlock(unit, node);
|
|
@@ -24028,7 +24056,7 @@ function ingestElement(unit, element) {
|
|
|
24028
24056
|
}
|
|
24029
24057
|
const id = unit.job.allocateXrefId();
|
|
24030
24058
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
24031
|
-
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
24059
|
+
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
|
|
24032
24060
|
unit.create.push(startOp);
|
|
24033
24061
|
ingestElementBindings(unit, startOp, element);
|
|
24034
24062
|
ingestReferences(startOp, element);
|
|
@@ -24071,7 +24099,7 @@ function ingestTemplate(unit, tmpl) {
|
|
|
24071
24099
|
'' :
|
|
24072
24100
|
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
24073
24101
|
const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
|
|
24074
|
-
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
24102
|
+
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
|
|
24075
24103
|
unit.create.push(templateOp);
|
|
24076
24104
|
ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
|
|
24077
24105
|
ingestReferences(templateOp, tmpl);
|
|
@@ -24106,13 +24134,13 @@ function ingestContent(unit, content) {
|
|
|
24106
24134
|
/**
|
|
24107
24135
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
24108
24136
|
*/
|
|
24109
|
-
function ingestText(unit, text) {
|
|
24110
|
-
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, text.sourceSpan));
|
|
24137
|
+
function ingestText(unit, text, icuPlaceholder) {
|
|
24138
|
+
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, icuPlaceholder, text.sourceSpan));
|
|
24111
24139
|
}
|
|
24112
24140
|
/**
|
|
24113
24141
|
* Ingest an interpolated text node from the AST into the given `ViewCompilation`.
|
|
24114
24142
|
*/
|
|
24115
|
-
function ingestBoundText(unit, text,
|
|
24143
|
+
function ingestBoundText(unit, text, icuPlaceholder) {
|
|
24116
24144
|
let value = text.value;
|
|
24117
24145
|
if (value instanceof ASTWithSource) {
|
|
24118
24146
|
value = value.ast;
|
|
@@ -24123,19 +24151,16 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
24123
24151
|
if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
|
|
24124
24152
|
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
24125
24153
|
}
|
|
24126
|
-
|
|
24127
|
-
|
|
24128
|
-
|
|
24129
|
-
|
|
24130
|
-
|
|
24131
|
-
.map(placeholder => placeholder.name) :
|
|
24132
|
-
[];
|
|
24133
|
-
}
|
|
24154
|
+
const i18nPlaceholders = text.i18n instanceof Container ?
|
|
24155
|
+
text.i18n.children
|
|
24156
|
+
.filter((node) => node instanceof Placeholder)
|
|
24157
|
+
.map(placeholder => placeholder.name) :
|
|
24158
|
+
[];
|
|
24134
24159
|
if (i18nPlaceholders.length > 0 && i18nPlaceholders.length !== value.expressions.length) {
|
|
24135
24160
|
throw Error(`Unexpected number of i18n placeholders (${value.expressions.length}) for BoundText with ${value.expressions.length} expressions`);
|
|
24136
24161
|
}
|
|
24137
24162
|
const textXref = unit.job.allocateXrefId();
|
|
24138
|
-
unit.create.push(createTextOp(textXref, '', text.sourceSpan));
|
|
24163
|
+
unit.create.push(createTextOp(textXref, '', icuPlaceholder, text.sourceSpan));
|
|
24139
24164
|
// TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
|
|
24140
24165
|
// interpolation. We copy that behavior in compatibility mode.
|
|
24141
24166
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
@@ -24168,7 +24193,7 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
24168
24193
|
}
|
|
24169
24194
|
ifCaseI18nMeta = ifCase.i18n;
|
|
24170
24195
|
}
|
|
24171
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.sourceSpan);
|
|
24196
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
|
|
24172
24197
|
unit.create.push(templateOp);
|
|
24173
24198
|
if (firstXref === null) {
|
|
24174
24199
|
firstXref = cView.xref;
|
|
@@ -24186,6 +24211,10 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
24186
24211
|
* Ingest an `@switch` block into the given `ViewCompilation`.
|
|
24187
24212
|
*/
|
|
24188
24213
|
function ingestSwitchBlock(unit, switchBlock) {
|
|
24214
|
+
// Don't ingest empty switches since they won't render anything.
|
|
24215
|
+
if (switchBlock.cases.length === 0) {
|
|
24216
|
+
return;
|
|
24217
|
+
}
|
|
24189
24218
|
let firstXref = null;
|
|
24190
24219
|
let firstSlotHandle = null;
|
|
24191
24220
|
let conditions = [];
|
|
@@ -24198,7 +24227,7 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
24198
24227
|
}
|
|
24199
24228
|
switchCaseI18nMeta = switchCase.i18n;
|
|
24200
24229
|
}
|
|
24201
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.sourceSpan);
|
|
24230
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
|
|
24202
24231
|
unit.create.push(templateOp);
|
|
24203
24232
|
if (firstXref === null) {
|
|
24204
24233
|
firstXref = cView.xref;
|
|
@@ -24223,7 +24252,7 @@ function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
|
|
|
24223
24252
|
}
|
|
24224
24253
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
24225
24254
|
ingestNodes(secondaryView, children);
|
|
24226
|
-
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan);
|
|
24255
|
+
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan, sourceSpan);
|
|
24227
24256
|
unit.create.push(templateOp);
|
|
24228
24257
|
return templateOp;
|
|
24229
24258
|
}
|
|
@@ -24301,6 +24330,11 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
24301
24330
|
deferOnOps.push(deferOnOp);
|
|
24302
24331
|
}
|
|
24303
24332
|
if (triggers.when !== undefined) {
|
|
24333
|
+
if (triggers.when.value instanceof Interpolation$1) {
|
|
24334
|
+
// TemplateDefinitionBuilder supports this case, but it's very strange to me. What would it
|
|
24335
|
+
// even mean?
|
|
24336
|
+
throw new Error(`Unexpected interpolation in defer block when trigger`);
|
|
24337
|
+
}
|
|
24304
24338
|
const deferOnOp = createDeferWhenOp(deferXref, convertAst(triggers.when.value, unit.job, triggers.when.sourceSpan), prefetch, triggers.when.sourceSpan);
|
|
24305
24339
|
deferWhenOps.push(deferOnOp);
|
|
24306
24340
|
}
|
|
@@ -24320,10 +24354,10 @@ function ingestIcu(unit, icu) {
|
|
|
24320
24354
|
unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
|
|
24321
24355
|
for (const [placeholder, text] of Object.entries({ ...icu.vars, ...icu.placeholders })) {
|
|
24322
24356
|
if (text instanceof BoundText) {
|
|
24323
|
-
ingestBoundText(unit, text,
|
|
24357
|
+
ingestBoundText(unit, text, placeholder);
|
|
24324
24358
|
}
|
|
24325
24359
|
else {
|
|
24326
|
-
ingestText(unit, text);
|
|
24360
|
+
ingestText(unit, text, placeholder);
|
|
24327
24361
|
}
|
|
24328
24362
|
}
|
|
24329
24363
|
unit.create.push(createIcuEndOp(xref));
|
|
@@ -24337,22 +24371,43 @@ function ingestIcu(unit, icu) {
|
|
|
24337
24371
|
*/
|
|
24338
24372
|
function ingestForBlock(unit, forBlock) {
|
|
24339
24373
|
const repeaterView = unit.job.allocateView(unit.xref);
|
|
24340
|
-
const createRepeaterAlias = (ident, repeaterVar) => {
|
|
24341
|
-
repeaterView.aliases.add({
|
|
24342
|
-
kind: SemanticVariableKind.Alias,
|
|
24343
|
-
name: null,
|
|
24344
|
-
identifier: ident,
|
|
24345
|
-
expression: new DerivedRepeaterVarExpr(repeaterView.xref, repeaterVar),
|
|
24346
|
-
});
|
|
24347
|
-
};
|
|
24348
24374
|
// Set all the context variables and aliases available in the repeater.
|
|
24349
24375
|
repeaterView.contextVariables.set(forBlock.item.name, forBlock.item.value);
|
|
24350
24376
|
repeaterView.contextVariables.set(forBlock.contextVariables.$index.name, forBlock.contextVariables.$index.value);
|
|
24351
24377
|
repeaterView.contextVariables.set(forBlock.contextVariables.$count.name, forBlock.contextVariables.$count.value);
|
|
24352
|
-
|
|
24353
|
-
|
|
24354
|
-
|
|
24355
|
-
|
|
24378
|
+
// We copy TemplateDefinitionBuilder's scheme of creating names for `$count` and `$index` that are
|
|
24379
|
+
// suffixed with special information, to disambiguate which level of nested loop the below aliases
|
|
24380
|
+
// refer to.
|
|
24381
|
+
// TODO: We should refactor Template Pipeline's variable phases to gracefully handle shadowing,
|
|
24382
|
+
// and arbitrarily many levels of variables depending on each other.
|
|
24383
|
+
const indexName = `ɵ${forBlock.contextVariables.$index.name}_${repeaterView.xref}`;
|
|
24384
|
+
const countName = `ɵ${forBlock.contextVariables.$count.name}_${repeaterView.xref}`;
|
|
24385
|
+
repeaterView.contextVariables.set(indexName, forBlock.contextVariables.$index.value);
|
|
24386
|
+
repeaterView.contextVariables.set(countName, forBlock.contextVariables.$count.value);
|
|
24387
|
+
repeaterView.aliases.add({
|
|
24388
|
+
kind: SemanticVariableKind.Alias,
|
|
24389
|
+
name: null,
|
|
24390
|
+
identifier: forBlock.contextVariables.$first.name,
|
|
24391
|
+
expression: new LexicalReadExpr(indexName).identical(literal(0))
|
|
24392
|
+
});
|
|
24393
|
+
repeaterView.aliases.add({
|
|
24394
|
+
kind: SemanticVariableKind.Alias,
|
|
24395
|
+
name: null,
|
|
24396
|
+
identifier: forBlock.contextVariables.$last.name,
|
|
24397
|
+
expression: new LexicalReadExpr(indexName).identical(new LexicalReadExpr(countName).minus(literal(1)))
|
|
24398
|
+
});
|
|
24399
|
+
repeaterView.aliases.add({
|
|
24400
|
+
kind: SemanticVariableKind.Alias,
|
|
24401
|
+
name: null,
|
|
24402
|
+
identifier: forBlock.contextVariables.$even.name,
|
|
24403
|
+
expression: new LexicalReadExpr(indexName).modulo(literal(2)).identical(literal(0))
|
|
24404
|
+
});
|
|
24405
|
+
repeaterView.aliases.add({
|
|
24406
|
+
kind: SemanticVariableKind.Alias,
|
|
24407
|
+
name: null,
|
|
24408
|
+
identifier: forBlock.contextVariables.$odd.name,
|
|
24409
|
+
expression: new LexicalReadExpr(indexName).modulo(literal(2)).notIdentical(literal(0))
|
|
24410
|
+
});
|
|
24356
24411
|
const sourceSpan = convertSourceSpan(forBlock.trackBy.span, forBlock.sourceSpan);
|
|
24357
24412
|
const track = convertAst(forBlock.trackBy, unit.job, sourceSpan);
|
|
24358
24413
|
ingestNodes(repeaterView, forBlock.children);
|
|
@@ -24380,7 +24435,7 @@ function ingestForBlock(unit, forBlock) {
|
|
|
24380
24435
|
const i18nPlaceholder = forBlock.i18n;
|
|
24381
24436
|
const emptyI18nPlaceholder = forBlock.empty?.i18n;
|
|
24382
24437
|
const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
|
|
24383
|
-
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, forBlock.sourceSpan);
|
|
24438
|
+
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, forBlock.startSourceSpan, forBlock.sourceSpan);
|
|
24384
24439
|
unit.create.push(repeaterCreate);
|
|
24385
24440
|
const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
|
|
24386
24441
|
const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
|
|
@@ -24498,13 +24553,13 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24498
24553
|
throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
|
|
24499
24554
|
}
|
|
24500
24555
|
}
|
|
24501
|
-
function convertAstWithInterpolation(job, value, i18nMeta) {
|
|
24556
|
+
function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
|
|
24502
24557
|
let expression;
|
|
24503
24558
|
if (value instanceof Interpolation$1) {
|
|
24504
|
-
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24559
|
+
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, sourceSpan ?? null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24505
24560
|
}
|
|
24506
24561
|
else if (value instanceof AST) {
|
|
24507
|
-
expression = convertAst(value, job, null);
|
|
24562
|
+
expression = convertAst(value, job, sourceSpan ?? null);
|
|
24508
24563
|
}
|
|
24509
24564
|
else {
|
|
24510
24565
|
expression = literal(value);
|
|
@@ -24617,7 +24672,7 @@ function ingestTemplateBindings(unit, op, template, templateKind) {
|
|
|
24617
24672
|
output.type !== 1 /* e.ParsedEventType.Animation */) {
|
|
24618
24673
|
// Animation bindings are excluded from the structural template's const array.
|
|
24619
24674
|
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
|
|
24620
|
-
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null, null, securityContext));
|
|
24675
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, null, output.name, null, null, null, securityContext));
|
|
24621
24676
|
}
|
|
24622
24677
|
}
|
|
24623
24678
|
// TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
|
|
@@ -24665,7 +24720,7 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
|
|
|
24665
24720
|
// inner node of a structural template. We can't skip it entirely, because we still need it on
|
|
24666
24721
|
// the ng-template's consts (e.g. for the purposes of directive matching). However, we should
|
|
24667
24722
|
// not generate an update instruction for it.
|
|
24668
|
-
return createExtractedAttributeOp(xref, BindingKind.Property, name, null, null, i18nMessage, securityContext);
|
|
24723
|
+
return createExtractedAttributeOp(xref, BindingKind.Property, null, name, null, null, i18nMessage, securityContext);
|
|
24669
24724
|
}
|
|
24670
24725
|
if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
|
|
24671
24726
|
// Again, this binding doesn't really target the ng-template; it actually targets the element
|
|
@@ -28467,6 +28522,9 @@ class TemplateDefinitionBuilder {
|
|
|
28467
28522
|
this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
|
|
28468
28523
|
}
|
|
28469
28524
|
visitSwitchBlock(block) {
|
|
28525
|
+
if (block.cases.length === 0) {
|
|
28526
|
+
return;
|
|
28527
|
+
}
|
|
28470
28528
|
// We have to process the block in two steps: once here and again in the update instruction
|
|
28471
28529
|
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
28472
28530
|
const caseData = block.cases.map(currentCase => {
|
|
@@ -28925,7 +28983,7 @@ class TemplateDefinitionBuilder {
|
|
|
28925
28983
|
if (delta < 1) {
|
|
28926
28984
|
throw new Error('advance instruction can only go forwards');
|
|
28927
28985
|
}
|
|
28928
|
-
this.instructionFn(this._updateCodeFns, span, Identifiers.advance, [literal(delta)]);
|
|
28986
|
+
this.instructionFn(this._updateCodeFns, span, Identifiers.advance, delta > 1 ? [literal(delta)] : []);
|
|
28929
28987
|
this._currentIndex = nodeIndex;
|
|
28930
28988
|
}
|
|
28931
28989
|
}
|
|
@@ -29479,12 +29537,16 @@ class BindingScope {
|
|
|
29479
29537
|
}
|
|
29480
29538
|
/** Binding scope of a `track` function inside a `for` loop block. */
|
|
29481
29539
|
class TrackByBindingScope extends BindingScope {
|
|
29482
|
-
constructor(parentScope,
|
|
29540
|
+
constructor(parentScope, globalOverrides) {
|
|
29483
29541
|
super(parentScope.bindingLevel + 1, parentScope);
|
|
29484
|
-
this.
|
|
29542
|
+
this.globalOverrides = globalOverrides;
|
|
29485
29543
|
this.componentAccessCount = 0;
|
|
29486
29544
|
}
|
|
29487
29545
|
get(name) {
|
|
29546
|
+
// Intercept any overridden globals.
|
|
29547
|
+
if (this.globalOverrides.hasOwnProperty(name)) {
|
|
29548
|
+
return variable(this.globalOverrides[name]);
|
|
29549
|
+
}
|
|
29488
29550
|
let current = this.parent;
|
|
29489
29551
|
// Prevent accesses of template variables outside the `for` loop.
|
|
29490
29552
|
while (current) {
|
|
@@ -29493,10 +29555,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
29493
29555
|
}
|
|
29494
29556
|
current = current.parent;
|
|
29495
29557
|
}
|
|
29496
|
-
// Intercept any aliased globals.
|
|
29497
|
-
if (this.globalAliases[name]) {
|
|
29498
|
-
return variable(this.globalAliases[name]);
|
|
29499
|
-
}
|
|
29500
29558
|
// When the component scope is accessed, we redirect it through `this`.
|
|
29501
29559
|
this.componentAccessCount++;
|
|
29502
29560
|
return variable('this').prop(name);
|
|
@@ -31994,7 +32052,7 @@ function publishFacade(global) {
|
|
|
31994
32052
|
* @description
|
|
31995
32053
|
* Entry point for all public APIs of the compiler package.
|
|
31996
32054
|
*/
|
|
31997
|
-
const VERSION = new Version('17.0.
|
|
32055
|
+
const VERSION = new Version('17.0.9');
|
|
31998
32056
|
|
|
31999
32057
|
class CompilerConfig {
|
|
32000
32058
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -33560,7 +33618,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
33560
33618
|
function compileDeclareClassMetadata(metadata) {
|
|
33561
33619
|
const definitionMap = new DefinitionMap();
|
|
33562
33620
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
33563
|
-
definitionMap.set('version', literal('17.0.
|
|
33621
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
33564
33622
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33565
33623
|
definitionMap.set('type', metadata.type);
|
|
33566
33624
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -33668,7 +33726,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
33668
33726
|
// in 16.1 is actually used.
|
|
33669
33727
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
33670
33728
|
definitionMap.set('minVersion', literal(minVersion));
|
|
33671
|
-
definitionMap.set('version', literal('17.0.
|
|
33729
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
33672
33730
|
// e.g. `type: MyDirective`
|
|
33673
33731
|
definitionMap.set('type', meta.type.value);
|
|
33674
33732
|
if (meta.isStandalone) {
|
|
@@ -33945,7 +34003,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
33945
34003
|
function compileDeclareFactoryFunction(meta) {
|
|
33946
34004
|
const definitionMap = new DefinitionMap();
|
|
33947
34005
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
33948
|
-
definitionMap.set('version', literal('17.0.
|
|
34006
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
33949
34007
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33950
34008
|
definitionMap.set('type', meta.type.value);
|
|
33951
34009
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -33980,7 +34038,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
33980
34038
|
function createInjectableDefinitionMap(meta) {
|
|
33981
34039
|
const definitionMap = new DefinitionMap();
|
|
33982
34040
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
33983
|
-
definitionMap.set('version', literal('17.0.
|
|
34041
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
33984
34042
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33985
34043
|
definitionMap.set('type', meta.type.value);
|
|
33986
34044
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -34031,7 +34089,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
34031
34089
|
function createInjectorDefinitionMap(meta) {
|
|
34032
34090
|
const definitionMap = new DefinitionMap();
|
|
34033
34091
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
34034
|
-
definitionMap.set('version', literal('17.0.
|
|
34092
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
34035
34093
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34036
34094
|
definitionMap.set('type', meta.type.value);
|
|
34037
34095
|
definitionMap.set('providers', meta.providers);
|
|
@@ -34064,7 +34122,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
34064
34122
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
34065
34123
|
}
|
|
34066
34124
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
34067
|
-
definitionMap.set('version', literal('17.0.
|
|
34125
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
34068
34126
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34069
34127
|
definitionMap.set('type', meta.type.value);
|
|
34070
34128
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -34115,7 +34173,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
34115
34173
|
function createPipeDefinitionMap(meta) {
|
|
34116
34174
|
const definitionMap = new DefinitionMap();
|
|
34117
34175
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
34118
|
-
definitionMap.set('version', literal('17.0.
|
|
34176
|
+
definitionMap.set('version', literal('17.0.9'));
|
|
34119
34177
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34120
34178
|
// e.g. `type: MyPipe`
|
|
34121
34179
|
definitionMap.set('type', meta.type.value);
|