@angular/compiler 17.1.0-next.4 → 17.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler_facade_interface.mjs +1 -1
- package/esm2022/src/constant_pool.mjs +5 -3
- package/esm2022/src/core.mjs +8 -1
- package/esm2022/src/jit_compiler_facade.mjs +5 -3
- package/esm2022/src/ml_parser/tags.mjs +8 -3
- package/esm2022/src/output/abstract_emitter.mjs +4 -1
- package/esm2022/src/output/output_ast.mjs +11 -7
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +4 -4
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_identifiers.mjs +5 -1
- package/esm2022/src/render3/view/style_parser.mjs +2 -1
- package/esm2022/src/render3/view/template.mjs +18 -10
- package/esm2022/src/render3/view/util.mjs +35 -7
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +7 -13
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +15 -21
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +37 -14
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +6 -3
- package/esm2022/src/template/pipeline/src/conversion.mjs +2 -1
- package/esm2022/src/template/pipeline/src/emit.mjs +3 -5
- package/esm2022/src/template/pipeline/src/ingest.mjs +106 -55
- package/esm2022/src/template/pipeline/src/instruction.mjs +24 -17
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +15 -19
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -2
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +54 -22
- 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/naming.mjs +13 -5
- package/esm2022/src/template/pipeline/src/phases/ordering.mjs +17 -5
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +21 -3
- package/esm2022/src/template/pipeline/src/phases/phase_remove_content_selectors.mjs +1 -10
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +5 -3
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +37 -12
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +23 -10
- package/esm2022/src/template/pipeline/src/phases/track_fn_generation.mjs +4 -1
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +8 -1
- package/esm2022/src/template/pipeline/src/phases/wrap_icus.mjs +4 -3
- package/esm2022/src/template/pipeline/src/util/elements.mjs +8 -1
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +655 -426
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +21 -9
- 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.1.0-
|
|
2
|
+
* @license Angular v17.1.0-rc.0
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -409,6 +409,13 @@ var ChangeDetectionStrategy;
|
|
|
409
409
|
ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
|
|
410
410
|
ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
|
|
411
411
|
})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
|
|
412
|
+
/** Flags describing an input for a directive. */
|
|
413
|
+
var InputFlags;
|
|
414
|
+
(function (InputFlags) {
|
|
415
|
+
InputFlags[InputFlags["None"] = 0] = "None";
|
|
416
|
+
InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
|
|
417
|
+
InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
|
|
418
|
+
})(InputFlags || (InputFlags = {}));
|
|
412
419
|
const CUSTOM_ELEMENTS_SCHEMA = {
|
|
413
420
|
name: 'custom-elements'
|
|
414
421
|
};
|
|
@@ -472,6 +479,7 @@ var core = /*#__PURE__*/Object.freeze({
|
|
|
472
479
|
emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue,
|
|
473
480
|
get ViewEncapsulation () { return ViewEncapsulation; },
|
|
474
481
|
get ChangeDetectionStrategy () { return ChangeDetectionStrategy; },
|
|
482
|
+
get InputFlags () { return InputFlags; },
|
|
475
483
|
CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
|
|
476
484
|
NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA,
|
|
477
485
|
Type: Type$1,
|
|
@@ -890,12 +898,13 @@ var BinaryOperator;
|
|
|
890
898
|
BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo";
|
|
891
899
|
BinaryOperator[BinaryOperator["And"] = 9] = "And";
|
|
892
900
|
BinaryOperator[BinaryOperator["Or"] = 10] = "Or";
|
|
893
|
-
BinaryOperator[BinaryOperator["
|
|
894
|
-
BinaryOperator[BinaryOperator["
|
|
895
|
-
BinaryOperator[BinaryOperator["
|
|
896
|
-
BinaryOperator[BinaryOperator["
|
|
897
|
-
BinaryOperator[BinaryOperator["
|
|
898
|
-
BinaryOperator[BinaryOperator["
|
|
901
|
+
BinaryOperator[BinaryOperator["BitwiseOr"] = 11] = "BitwiseOr";
|
|
902
|
+
BinaryOperator[BinaryOperator["BitwiseAnd"] = 12] = "BitwiseAnd";
|
|
903
|
+
BinaryOperator[BinaryOperator["Lower"] = 13] = "Lower";
|
|
904
|
+
BinaryOperator[BinaryOperator["LowerEquals"] = 14] = "LowerEquals";
|
|
905
|
+
BinaryOperator[BinaryOperator["Bigger"] = 15] = "Bigger";
|
|
906
|
+
BinaryOperator[BinaryOperator["BiggerEquals"] = 16] = "BiggerEquals";
|
|
907
|
+
BinaryOperator[BinaryOperator["NullishCoalesce"] = 17] = "NullishCoalesce";
|
|
899
908
|
})(BinaryOperator || (BinaryOperator = {}));
|
|
900
909
|
function nullSafeIsEquivalent(base, other) {
|
|
901
910
|
if (base == null || other == null) {
|
|
@@ -968,6 +977,9 @@ class Expression {
|
|
|
968
977
|
and(rhs, sourceSpan) {
|
|
969
978
|
return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
|
|
970
979
|
}
|
|
980
|
+
bitwiseOr(rhs, sourceSpan, parens = true) {
|
|
981
|
+
return new BinaryOperatorExpr(BinaryOperator.BitwiseOr, this, rhs, null, sourceSpan, parens);
|
|
982
|
+
}
|
|
971
983
|
bitwiseAnd(rhs, sourceSpan, parens = true) {
|
|
972
984
|
return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
|
|
973
985
|
}
|
|
@@ -2308,7 +2320,9 @@ class ConstantPool {
|
|
|
2308
2320
|
}))));
|
|
2309
2321
|
}
|
|
2310
2322
|
}
|
|
2311
|
-
|
|
2323
|
+
// TODO: useUniqueName(false) is necessary for naming compatibility with
|
|
2324
|
+
// TemplateDefinitionBuilder, but should be removed once Template Pipeline is the default.
|
|
2325
|
+
getSharedFunctionReference(fn, prefix, useUniqueName = true) {
|
|
2312
2326
|
const isArrow = fn instanceof ArrowFunctionExpr;
|
|
2313
2327
|
for (const current of this.statements) {
|
|
2314
2328
|
// Arrow functions are saved as variables so we check if the
|
|
@@ -2323,7 +2337,7 @@ class ConstantPool {
|
|
|
2323
2337
|
}
|
|
2324
2338
|
}
|
|
2325
2339
|
// Otherwise declare the function.
|
|
2326
|
-
const name = this.uniqueName(prefix);
|
|
2340
|
+
const name = useUniqueName ? this.uniqueName(prefix) : prefix;
|
|
2327
2341
|
this.statements.push(fn.toDeclStmt(name, StmtModifier.Final));
|
|
2328
2342
|
return variable(name);
|
|
2329
2343
|
}
|
|
@@ -2626,6 +2640,10 @@ class Identifiers {
|
|
|
2626
2640
|
name: 'ɵɵgetInheritedFactory',
|
|
2627
2641
|
moduleName: CORE,
|
|
2628
2642
|
}; }
|
|
2643
|
+
static { this.InputFlags = {
|
|
2644
|
+
name: 'ɵɵInputFlags',
|
|
2645
|
+
moduleName: CORE,
|
|
2646
|
+
}; }
|
|
2629
2647
|
// sanitization-related functions
|
|
2630
2648
|
static { this.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE }; }
|
|
2631
2649
|
static { this.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE }; }
|
|
@@ -3267,6 +3285,9 @@ class AbstractEmitterVisitor {
|
|
|
3267
3285
|
case BinaryOperator.And:
|
|
3268
3286
|
opStr = '&&';
|
|
3269
3287
|
break;
|
|
3288
|
+
case BinaryOperator.BitwiseOr:
|
|
3289
|
+
opStr = '|';
|
|
3290
|
+
break;
|
|
3270
3291
|
case BinaryOperator.BitwiseAnd:
|
|
3271
3292
|
opStr = '&';
|
|
3272
3293
|
break;
|
|
@@ -3688,13 +3709,18 @@ var TagContentType;
|
|
|
3688
3709
|
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
3689
3710
|
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
3690
3711
|
})(TagContentType || (TagContentType = {}));
|
|
3691
|
-
function splitNsName(elementName) {
|
|
3712
|
+
function splitNsName(elementName, fatal = true) {
|
|
3692
3713
|
if (elementName[0] != ':') {
|
|
3693
3714
|
return [null, elementName];
|
|
3694
3715
|
}
|
|
3695
3716
|
const colonIndex = elementName.indexOf(':', 1);
|
|
3696
3717
|
if (colonIndex === -1) {
|
|
3697
|
-
|
|
3718
|
+
if (fatal) {
|
|
3719
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
3720
|
+
}
|
|
3721
|
+
else {
|
|
3722
|
+
return [null, elementName];
|
|
3723
|
+
}
|
|
3698
3724
|
}
|
|
3699
3725
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
3700
3726
|
}
|
|
@@ -4966,7 +4992,7 @@ function asLiteral(value) {
|
|
|
4966
4992
|
* This will attempt to generate optimized data structures to minimize memory or
|
|
4967
4993
|
* file size of fully compiled applications.
|
|
4968
4994
|
*/
|
|
4969
|
-
function conditionallyCreateDirectiveBindingLiteral(map,
|
|
4995
|
+
function conditionallyCreateDirectiveBindingLiteral(map, forInputs) {
|
|
4970
4996
|
const keys = Object.getOwnPropertyNames(map);
|
|
4971
4997
|
if (keys.length === 0) {
|
|
4972
4998
|
return null;
|
|
@@ -4988,12 +5014,28 @@ function conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) {
|
|
|
4988
5014
|
minifiedName = key;
|
|
4989
5015
|
declaredName = value.classPropertyName;
|
|
4990
5016
|
publicName = value.bindingPropertyName;
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
5017
|
+
const differentDeclaringName = publicName !== declaredName;
|
|
5018
|
+
const hasDecoratorInputTransform = value.transformFunction !== null;
|
|
5019
|
+
// Build up input flags
|
|
5020
|
+
let flags = null;
|
|
5021
|
+
if (value.isSignal) {
|
|
5022
|
+
flags = bitwiseOrInputFlagsExpr(InputFlags.SignalBased, flags);
|
|
5023
|
+
}
|
|
5024
|
+
if (hasDecoratorInputTransform) {
|
|
5025
|
+
flags = bitwiseOrInputFlagsExpr(InputFlags.HasDecoratorInputTransform, flags);
|
|
5026
|
+
}
|
|
5027
|
+
// Inputs, compared to outputs, will track their declared name (for `ngOnChanges`), support
|
|
5028
|
+
// decorator input transform functions, or store flag information if there is any.
|
|
5029
|
+
if (forInputs && (differentDeclaringName || hasDecoratorInputTransform || flags !== null)) {
|
|
5030
|
+
const flagsExpr = flags ?? importExpr(Identifiers.InputFlags).prop(InputFlags[InputFlags.None]);
|
|
5031
|
+
const result = [flagsExpr, asLiteral(publicName)];
|
|
5032
|
+
if (differentDeclaringName || hasDecoratorInputTransform) {
|
|
5033
|
+
result.push(asLiteral(declaredName));
|
|
5034
|
+
if (hasDecoratorInputTransform) {
|
|
5035
|
+
result.push(value.transformFunction);
|
|
5036
|
+
}
|
|
4995
5037
|
}
|
|
4996
|
-
expressionValue = literalArr(
|
|
5038
|
+
expressionValue = literalArr(result);
|
|
4997
5039
|
}
|
|
4998
5040
|
else {
|
|
4999
5041
|
expressionValue = asLiteral(publicName);
|
|
@@ -5007,6 +5049,17 @@ function conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) {
|
|
|
5007
5049
|
};
|
|
5008
5050
|
}));
|
|
5009
5051
|
}
|
|
5052
|
+
/** Gets an output AST expression referencing the given flag. */
|
|
5053
|
+
function getInputFlagExpr(flag) {
|
|
5054
|
+
return importExpr(Identifiers.InputFlags).prop(InputFlags[flag]);
|
|
5055
|
+
}
|
|
5056
|
+
/** Combines a given input flag with an existing flag expression, if present. */
|
|
5057
|
+
function bitwiseOrInputFlagsExpr(flag, expr) {
|
|
5058
|
+
if (expr === null) {
|
|
5059
|
+
return getInputFlagExpr(flag);
|
|
5060
|
+
}
|
|
5061
|
+
return getInputFlagExpr(flag).bitwiseOr(expr);
|
|
5062
|
+
}
|
|
5010
5063
|
/**
|
|
5011
5064
|
* Remove trailing null nodes as they are implied.
|
|
5012
5065
|
*/
|
|
@@ -8975,14 +9028,18 @@ var OpKind;
|
|
|
8975
9028
|
* An instruction to update an ICU expression.
|
|
8976
9029
|
*/
|
|
8977
9030
|
OpKind[OpKind["IcuEnd"] = 42] = "IcuEnd";
|
|
9031
|
+
/**
|
|
9032
|
+
* An instruction representing a placeholder in an ICU expression.
|
|
9033
|
+
*/
|
|
9034
|
+
OpKind[OpKind["IcuPlaceholder"] = 43] = "IcuPlaceholder";
|
|
8978
9035
|
/**
|
|
8979
9036
|
* An i18n context containing information needed to generate an i18n message.
|
|
8980
9037
|
*/
|
|
8981
|
-
OpKind[OpKind["I18nContext"] =
|
|
9038
|
+
OpKind[OpKind["I18nContext"] = 44] = "I18nContext";
|
|
8982
9039
|
/**
|
|
8983
9040
|
* A creation op that corresponds to i18n attributes on an element.
|
|
8984
9041
|
*/
|
|
8985
|
-
OpKind[OpKind["I18nAttributes"] =
|
|
9042
|
+
OpKind[OpKind["I18nAttributes"] = 45] = "I18nAttributes";
|
|
8986
9043
|
})(OpKind || (OpKind = {}));
|
|
8987
9044
|
/**
|
|
8988
9045
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9259,16 +9316,6 @@ var DeferTriggerKind;
|
|
|
9259
9316
|
DeferTriggerKind[DeferTriggerKind["Interaction"] = 4] = "Interaction";
|
|
9260
9317
|
DeferTriggerKind[DeferTriggerKind["Viewport"] = 5] = "Viewport";
|
|
9261
9318
|
})(DeferTriggerKind || (DeferTriggerKind = {}));
|
|
9262
|
-
/**
|
|
9263
|
-
* Repeaters implicitly define these derived variables, and child nodes may read them.
|
|
9264
|
-
*/
|
|
9265
|
-
var DerivedRepeaterVarIdentity;
|
|
9266
|
-
(function (DerivedRepeaterVarIdentity) {
|
|
9267
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["First"] = 0] = "First";
|
|
9268
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Last"] = 1] = "Last";
|
|
9269
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
9270
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
9271
|
-
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
9272
9319
|
/**
|
|
9273
9320
|
* Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
|
|
9274
9321
|
*/
|
|
@@ -9513,10 +9560,11 @@ function createClassMapOp(xref, expression, sourceSpan) {
|
|
|
9513
9560
|
/**
|
|
9514
9561
|
* Create an `AttributeOp`.
|
|
9515
9562
|
*/
|
|
9516
|
-
function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9563
|
+
function createAttributeOp(target, namespace, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
|
|
9517
9564
|
return {
|
|
9518
9565
|
kind: OpKind.Attribute,
|
|
9519
9566
|
target,
|
|
9567
|
+
namespace,
|
|
9520
9568
|
name,
|
|
9521
9569
|
expression,
|
|
9522
9570
|
securityContext,
|
|
@@ -9581,12 +9629,13 @@ function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
|
|
|
9581
9629
|
sourceSpan,
|
|
9582
9630
|
...NEW_OP,
|
|
9583
9631
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9632
|
+
...TRAIT_CONSUMES_VARS,
|
|
9584
9633
|
};
|
|
9585
9634
|
}
|
|
9586
9635
|
/**
|
|
9587
9636
|
* Create an i18n expression op.
|
|
9588
9637
|
*/
|
|
9589
|
-
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9638
|
+
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
|
|
9590
9639
|
return {
|
|
9591
9640
|
kind: OpKind.I18nExpression,
|
|
9592
9641
|
context,
|
|
@@ -9594,6 +9643,7 @@ function createI18nExpressionOp(context, target, i18nOwner, handle, expression,
|
|
|
9594
9643
|
i18nOwner,
|
|
9595
9644
|
handle,
|
|
9596
9645
|
expression,
|
|
9646
|
+
icuPlaceholder,
|
|
9597
9647
|
i18nPlaceholder,
|
|
9598
9648
|
resolutionTime,
|
|
9599
9649
|
usage,
|
|
@@ -10211,26 +10261,6 @@ class ConditionalCaseExpr extends ExpressionBase {
|
|
|
10211
10261
|
}
|
|
10212
10262
|
}
|
|
10213
10263
|
}
|
|
10214
|
-
class DerivedRepeaterVarExpr extends ExpressionBase {
|
|
10215
|
-
constructor(xref, identity) {
|
|
10216
|
-
super();
|
|
10217
|
-
this.xref = xref;
|
|
10218
|
-
this.identity = identity;
|
|
10219
|
-
this.kind = ExpressionKind.DerivedRepeaterVar;
|
|
10220
|
-
}
|
|
10221
|
-
transformInternalExpressions(transform, flags) { }
|
|
10222
|
-
visitExpression(visitor, context) { }
|
|
10223
|
-
isEquivalent(e) {
|
|
10224
|
-
return e instanceof DerivedRepeaterVarExpr && e.identity === this.identity &&
|
|
10225
|
-
e.xref === this.xref;
|
|
10226
|
-
}
|
|
10227
|
-
isConstant() {
|
|
10228
|
-
return false;
|
|
10229
|
-
}
|
|
10230
|
-
clone() {
|
|
10231
|
-
return new DerivedRepeaterVarExpr(this.xref, this.identity);
|
|
10232
|
-
}
|
|
10233
|
-
}
|
|
10234
10264
|
class ConstCollectedExpr extends ExpressionBase {
|
|
10235
10265
|
constructor(expr) {
|
|
10236
10266
|
super();
|
|
@@ -10363,6 +10393,9 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10363
10393
|
op.placeholderConfig =
|
|
10364
10394
|
transformExpressionsInExpression(op.placeholderConfig, transform, flags);
|
|
10365
10395
|
}
|
|
10396
|
+
if (op.resolverFn !== null) {
|
|
10397
|
+
op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
|
|
10398
|
+
}
|
|
10366
10399
|
break;
|
|
10367
10400
|
case OpKind.I18nMessage:
|
|
10368
10401
|
for (const [placeholder, expr] of op.params) {
|
|
@@ -10399,6 +10432,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10399
10432
|
case OpKind.Template:
|
|
10400
10433
|
case OpKind.Text:
|
|
10401
10434
|
case OpKind.I18nAttributes:
|
|
10435
|
+
case OpKind.IcuPlaceholder:
|
|
10402
10436
|
// These operations contain no expressions.
|
|
10403
10437
|
break;
|
|
10404
10438
|
default:
|
|
@@ -10481,6 +10515,16 @@ function transformExpressionsInExpression(expr, transform, flags) {
|
|
|
10481
10515
|
expr.template.expressions =
|
|
10482
10516
|
expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
|
|
10483
10517
|
}
|
|
10518
|
+
else if (expr instanceof ArrowFunctionExpr) {
|
|
10519
|
+
if (Array.isArray(expr.body)) {
|
|
10520
|
+
for (let i = 0; i < expr.body.length; i++) {
|
|
10521
|
+
transformExpressionsInStatement(expr.body[i], transform, flags);
|
|
10522
|
+
}
|
|
10523
|
+
}
|
|
10524
|
+
else {
|
|
10525
|
+
expr.body = transformExpressionsInExpression(expr.body, transform, flags);
|
|
10526
|
+
}
|
|
10527
|
+
}
|
|
10484
10528
|
else if (expr instanceof WrappedNodeExpr) {
|
|
10485
10529
|
// TODO: Do we need to transform any TS nodes nested inside of this expression?
|
|
10486
10530
|
}
|
|
@@ -10806,7 +10850,7 @@ function isElementOrContainerOp(op) {
|
|
|
10806
10850
|
/**
|
|
10807
10851
|
* Create an `ElementStartOp`.
|
|
10808
10852
|
*/
|
|
10809
|
-
function createElementStartOp(tag, xref, namespace, i18nPlaceholder,
|
|
10853
|
+
function createElementStartOp(tag, xref, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10810
10854
|
return {
|
|
10811
10855
|
kind: OpKind.ElementStart,
|
|
10812
10856
|
xref,
|
|
@@ -10817,7 +10861,8 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10817
10861
|
nonBindable: false,
|
|
10818
10862
|
namespace,
|
|
10819
10863
|
i18nPlaceholder,
|
|
10820
|
-
|
|
10864
|
+
startSourceSpan,
|
|
10865
|
+
wholeSourceSpan,
|
|
10821
10866
|
...TRAIT_CONSUMES_SLOT,
|
|
10822
10867
|
...NEW_OP,
|
|
10823
10868
|
};
|
|
@@ -10825,7 +10870,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10825
10870
|
/**
|
|
10826
10871
|
* Create a `TemplateOp`.
|
|
10827
10872
|
*/
|
|
10828
|
-
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder,
|
|
10873
|
+
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10829
10874
|
return {
|
|
10830
10875
|
kind: OpKind.Template,
|
|
10831
10876
|
xref,
|
|
@@ -10840,12 +10885,13 @@ function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace
|
|
|
10840
10885
|
nonBindable: false,
|
|
10841
10886
|
namespace,
|
|
10842
10887
|
i18nPlaceholder,
|
|
10843
|
-
|
|
10888
|
+
startSourceSpan,
|
|
10889
|
+
wholeSourceSpan,
|
|
10844
10890
|
...TRAIT_CONSUMES_SLOT,
|
|
10845
10891
|
...NEW_OP,
|
|
10846
10892
|
};
|
|
10847
10893
|
}
|
|
10848
|
-
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i18nPlaceholder, emptyI18nPlaceholder,
|
|
10894
|
+
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, emptyTag, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
|
|
10849
10895
|
return {
|
|
10850
10896
|
kind: OpKind.RepeaterCreate,
|
|
10851
10897
|
attributes: null,
|
|
@@ -10855,6 +10901,8 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i1
|
|
|
10855
10901
|
track,
|
|
10856
10902
|
trackByFn: null,
|
|
10857
10903
|
tag,
|
|
10904
|
+
emptyTag,
|
|
10905
|
+
emptyAttributes: null,
|
|
10858
10906
|
functionNameSuffix: 'For',
|
|
10859
10907
|
namespace: Namespace.HTML,
|
|
10860
10908
|
nonBindable: false,
|
|
@@ -10865,9 +10913,11 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i1
|
|
|
10865
10913
|
usesComponentInstance: false,
|
|
10866
10914
|
i18nPlaceholder,
|
|
10867
10915
|
emptyI18nPlaceholder,
|
|
10868
|
-
|
|
10916
|
+
startSourceSpan,
|
|
10917
|
+
wholeSourceSpan,
|
|
10869
10918
|
...TRAIT_CONSUMES_SLOT,
|
|
10870
10919
|
...NEW_OP,
|
|
10920
|
+
...TRAIT_CONSUMES_VARS,
|
|
10871
10921
|
numSlotsUsed: emptyView === null ? 2 : 3,
|
|
10872
10922
|
};
|
|
10873
10923
|
}
|
|
@@ -10899,12 +10949,13 @@ function createEnableBindingsOp(xref) {
|
|
|
10899
10949
|
/**
|
|
10900
10950
|
* Create a `TextOp`.
|
|
10901
10951
|
*/
|
|
10902
|
-
function createTextOp(xref, initialValue, sourceSpan) {
|
|
10952
|
+
function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
|
|
10903
10953
|
return {
|
|
10904
10954
|
kind: OpKind.Text,
|
|
10905
10955
|
xref,
|
|
10906
10956
|
handle: new SlotHandle(),
|
|
10907
10957
|
initialValue,
|
|
10958
|
+
icuPlaceholder,
|
|
10908
10959
|
sourceSpan,
|
|
10909
10960
|
...TRAIT_CONSUMES_SLOT,
|
|
10910
10961
|
...NEW_OP,
|
|
@@ -10957,7 +11008,7 @@ function createProjectionDefOp(def) {
|
|
|
10957
11008
|
...NEW_OP,
|
|
10958
11009
|
};
|
|
10959
11010
|
}
|
|
10960
|
-
function createProjectionOp(xref, selector, i18nPlaceholder,
|
|
11011
|
+
function createProjectionOp(xref, selector, i18nPlaceholder, sourceSpan) {
|
|
10961
11012
|
return {
|
|
10962
11013
|
kind: OpKind.Projection,
|
|
10963
11014
|
xref,
|
|
@@ -10965,7 +11016,7 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
|
|
|
10965
11016
|
selector,
|
|
10966
11017
|
i18nPlaceholder,
|
|
10967
11018
|
projectionSlotIndex: 0,
|
|
10968
|
-
attributes,
|
|
11019
|
+
attributes: null,
|
|
10969
11020
|
localRefs: [],
|
|
10970
11021
|
sourceSpan,
|
|
10971
11022
|
...NEW_OP,
|
|
@@ -10975,11 +11026,12 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
|
|
|
10975
11026
|
/**
|
|
10976
11027
|
* Create an `ExtractedAttributeOp`.
|
|
10977
11028
|
*/
|
|
10978
|
-
function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
11029
|
+
function createExtractedAttributeOp(target, bindingKind, namespace, name, expression, i18nContext, i18nMessage, securityContext) {
|
|
10979
11030
|
return {
|
|
10980
11031
|
kind: OpKind.ExtractedAttribute,
|
|
10981
11032
|
target,
|
|
10982
11033
|
bindingKind,
|
|
11034
|
+
namespace,
|
|
10983
11035
|
name,
|
|
10984
11036
|
expression,
|
|
10985
11037
|
i18nContext,
|
|
@@ -11046,7 +11098,7 @@ function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlace
|
|
|
11046
11098
|
/**
|
|
11047
11099
|
* Create an `I18nStartOp`.
|
|
11048
11100
|
*/
|
|
11049
|
-
function createI18nStartOp(xref, message, root) {
|
|
11101
|
+
function createI18nStartOp(xref, message, root, sourceSpan) {
|
|
11050
11102
|
return {
|
|
11051
11103
|
kind: OpKind.I18nStart,
|
|
11052
11104
|
xref,
|
|
@@ -11056,6 +11108,7 @@ function createI18nStartOp(xref, message, root) {
|
|
|
11056
11108
|
messageIndex: null,
|
|
11057
11109
|
subTemplateIndex: null,
|
|
11058
11110
|
context: null,
|
|
11111
|
+
sourceSpan,
|
|
11059
11112
|
...NEW_OP,
|
|
11060
11113
|
...TRAIT_CONSUMES_SLOT,
|
|
11061
11114
|
};
|
|
@@ -11063,10 +11116,11 @@ function createI18nStartOp(xref, message, root) {
|
|
|
11063
11116
|
/**
|
|
11064
11117
|
* Create an `I18nEndOp`.
|
|
11065
11118
|
*/
|
|
11066
|
-
function createI18nEndOp(xref) {
|
|
11119
|
+
function createI18nEndOp(xref, sourceSpan) {
|
|
11067
11120
|
return {
|
|
11068
11121
|
kind: OpKind.I18nEnd,
|
|
11069
11122
|
xref,
|
|
11123
|
+
sourceSpan,
|
|
11070
11124
|
...NEW_OP,
|
|
11071
11125
|
};
|
|
11072
11126
|
}
|
|
@@ -11094,6 +11148,19 @@ function createIcuEndOp(xref) {
|
|
|
11094
11148
|
...NEW_OP,
|
|
11095
11149
|
};
|
|
11096
11150
|
}
|
|
11151
|
+
/**
|
|
11152
|
+
* Creates an ICU placeholder op.
|
|
11153
|
+
*/
|
|
11154
|
+
function createIcuPlaceholderOp(xref, name, strings) {
|
|
11155
|
+
return {
|
|
11156
|
+
kind: OpKind.IcuPlaceholder,
|
|
11157
|
+
xref,
|
|
11158
|
+
name,
|
|
11159
|
+
strings,
|
|
11160
|
+
expressionPlaceholders: [],
|
|
11161
|
+
...NEW_OP,
|
|
11162
|
+
};
|
|
11163
|
+
}
|
|
11097
11164
|
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
|
|
11098
11165
|
if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
|
|
11099
11166
|
throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
|
|
@@ -11475,6 +11542,13 @@ function createOpXrefMap(unit) {
|
|
|
11475
11542
|
continue;
|
|
11476
11543
|
}
|
|
11477
11544
|
map.set(op.xref, op);
|
|
11545
|
+
// TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
|
|
11546
|
+
// because the slot consumer trait currently only supports one slot per consumer and we
|
|
11547
|
+
// need two. This should be revisited when making the refactors mentioned in:
|
|
11548
|
+
// https://github.com/angular/angular/pull/53620#discussion_r1430918822
|
|
11549
|
+
if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
|
|
11550
|
+
map.set(op.emptyView, op);
|
|
11551
|
+
}
|
|
11478
11552
|
}
|
|
11479
11553
|
return map;
|
|
11480
11554
|
}
|
|
@@ -11507,7 +11581,8 @@ function extractAttributes(job) {
|
|
|
11507
11581
|
}
|
|
11508
11582
|
OpList.insertBefore(
|
|
11509
11583
|
// Deliberaly null i18nMessage value
|
|
11510
|
-
createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null,
|
|
11584
|
+
createExtractedAttributeOp(op.target, bindingKind, null, op.name, /* expression */ null,
|
|
11585
|
+
/* i18nContext */ null,
|
|
11511
11586
|
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11512
11587
|
}
|
|
11513
11588
|
break;
|
|
@@ -11519,17 +11594,22 @@ function extractAttributes(job) {
|
|
|
11519
11594
|
// mode.
|
|
11520
11595
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
11521
11596
|
op.expression instanceof EmptyExpr) {
|
|
11522
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11597
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */ null,
|
|
11523
11598
|
/* i18nContext */ null,
|
|
11524
11599
|
/* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
|
|
11525
11600
|
}
|
|
11526
11601
|
break;
|
|
11527
11602
|
case OpKind.Listener:
|
|
11528
11603
|
if (!op.isAnimationListener) {
|
|
11529
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
|
|
11604
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */ null,
|
|
11530
11605
|
/* i18nContext */ null,
|
|
11531
11606
|
/* i18nMessage */ null, SecurityContext.NONE);
|
|
11532
11607
|
if (job.kind === CompilationJobKind.Host) {
|
|
11608
|
+
if (job.compatibility) {
|
|
11609
|
+
// TemplateDefinitionBuilder does not extract listener bindings to the const array
|
|
11610
|
+
// (which is honestly pretty inconsistent).
|
|
11611
|
+
break;
|
|
11612
|
+
}
|
|
11533
11613
|
// This attribute will apply to the enclosing host binding compilation unit, so order
|
|
11534
11614
|
// doesn't matter.
|
|
11535
11615
|
unit.create.push(extractedAttributeOp);
|
|
@@ -11560,24 +11640,14 @@ function extractAttributeOp(unit, op, elements) {
|
|
|
11560
11640
|
if (op.expression instanceof Interpolation) {
|
|
11561
11641
|
return;
|
|
11562
11642
|
}
|
|
11563
|
-
let extractable = op.expression.isConstant();
|
|
11643
|
+
let extractable = op.isTextAttribute || op.expression.isConstant();
|
|
11564
11644
|
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
11565
|
-
// TemplateDefinitionBuilder only
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
|
|
11569
|
-
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
|
|
11570
|
-
// string literal, because it is not a text attribute.
|
|
11571
|
-
extractable &&= op.isTextAttribute;
|
|
11572
|
-
}
|
|
11573
|
-
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11574
|
-
// TemplateDefinitionBuilder also does not seem to extract string literals if they are part of
|
|
11575
|
-
// a host attribute.
|
|
11576
|
-
extractable &&= op.isTextAttribute;
|
|
11577
|
-
}
|
|
11645
|
+
// TemplateDefinitionBuilder only extracts text attributes. It does not extract attriibute
|
|
11646
|
+
// bindings, even if they are constants.
|
|
11647
|
+
extractable &&= op.isTextAttribute;
|
|
11578
11648
|
}
|
|
11579
11649
|
if (extractable) {
|
|
11580
|
-
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11650
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.namespace, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
|
|
11581
11651
|
if (unit.job.kind === CompilationJobKind.Host) {
|
|
11582
11652
|
// This attribute will apply to the enclosing host binding compilation unit, so order doesn't
|
|
11583
11653
|
// matter.
|
|
@@ -11624,7 +11694,8 @@ function specializeBindings(job) {
|
|
|
11624
11694
|
target.nonBindable = true;
|
|
11625
11695
|
}
|
|
11626
11696
|
else {
|
|
11627
|
-
|
|
11697
|
+
const [namespace, name] = splitNsName(op.name);
|
|
11698
|
+
OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
|
|
11628
11699
|
}
|
|
11629
11700
|
break;
|
|
11630
11701
|
case BindingKind.Property:
|
|
@@ -11814,6 +11885,7 @@ const BINARY_OPERATORS = new Map([
|
|
|
11814
11885
|
['&&', BinaryOperator.And],
|
|
11815
11886
|
['>', BinaryOperator.Bigger],
|
|
11816
11887
|
['>=', BinaryOperator.BiggerEquals],
|
|
11888
|
+
['|', BinaryOperator.BitwiseOr],
|
|
11817
11889
|
['&', BinaryOperator.BitwiseAnd],
|
|
11818
11890
|
['/', BinaryOperator.Divide],
|
|
11819
11891
|
['==', BinaryOperator.Equals],
|
|
@@ -11868,9 +11940,9 @@ function collectElementConsts(job) {
|
|
|
11868
11940
|
for (const unit of job.units) {
|
|
11869
11941
|
for (const op of unit.create) {
|
|
11870
11942
|
if (op.kind === OpKind.ExtractedAttribute) {
|
|
11871
|
-
const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
|
|
11943
|
+
const attributes = allElementAttributes.get(op.target) || new ElementAttributes(job.compatibility);
|
|
11872
11944
|
allElementAttributes.set(op.target, attributes);
|
|
11873
|
-
attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
|
|
11945
|
+
attributes.add(op.bindingKind, op.name, op.expression, op.namespace, op.trustedValueFn);
|
|
11874
11946
|
OpList.remove(op);
|
|
11875
11947
|
}
|
|
11876
11948
|
}
|
|
@@ -11879,15 +11951,26 @@ function collectElementConsts(job) {
|
|
|
11879
11951
|
if (job instanceof ComponentCompilationJob) {
|
|
11880
11952
|
for (const unit of job.units) {
|
|
11881
11953
|
for (const op of unit.create) {
|
|
11882
|
-
|
|
11954
|
+
// TODO: Simplify and combine these cases.
|
|
11955
|
+
if (op.kind == OpKind.Projection) {
|
|
11883
11956
|
const attributes = allElementAttributes.get(op.xref);
|
|
11884
11957
|
if (attributes !== undefined) {
|
|
11885
11958
|
const attrArray = serializeAttributes(attributes);
|
|
11886
11959
|
if (attrArray.entries.length > 0) {
|
|
11887
|
-
op.attributes =
|
|
11960
|
+
op.attributes = attrArray;
|
|
11888
11961
|
}
|
|
11889
11962
|
}
|
|
11890
11963
|
}
|
|
11964
|
+
else if (isElementOrContainerOp(op)) {
|
|
11965
|
+
op.attributes = getConstIndex(job, allElementAttributes, op.xref);
|
|
11966
|
+
// TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
|
|
11967
|
+
// because the slot consumer trait currently only supports one slot per consumer and we
|
|
11968
|
+
// need two. This should be revisited when making the refactors mentioned in:
|
|
11969
|
+
// https://github.com/angular/angular/pull/53620#discussion_r1430918822
|
|
11970
|
+
if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
|
|
11971
|
+
op.emptyAttributes = getConstIndex(job, allElementAttributes, op.emptyView);
|
|
11972
|
+
}
|
|
11973
|
+
}
|
|
11891
11974
|
}
|
|
11892
11975
|
}
|
|
11893
11976
|
}
|
|
@@ -11905,6 +11988,16 @@ function collectElementConsts(job) {
|
|
|
11905
11988
|
}
|
|
11906
11989
|
}
|
|
11907
11990
|
}
|
|
11991
|
+
function getConstIndex(job, allElementAttributes, xref) {
|
|
11992
|
+
const attributes = allElementAttributes.get(xref);
|
|
11993
|
+
if (attributes !== undefined) {
|
|
11994
|
+
const attrArray = serializeAttributes(attributes);
|
|
11995
|
+
if (attrArray.entries.length > 0) {
|
|
11996
|
+
return job.addConst(attrArray);
|
|
11997
|
+
}
|
|
11998
|
+
}
|
|
11999
|
+
return null;
|
|
12000
|
+
}
|
|
11908
12001
|
/**
|
|
11909
12002
|
* Shared instance of an empty array to avoid unnecessary array allocations.
|
|
11910
12003
|
*/
|
|
@@ -11913,11 +12006,6 @@ const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
|
11913
12006
|
* Container for all of the various kinds of attributes which are applied on an element.
|
|
11914
12007
|
*/
|
|
11915
12008
|
class ElementAttributes {
|
|
11916
|
-
constructor() {
|
|
11917
|
-
this.known = new Set();
|
|
11918
|
-
this.byKind = new Map;
|
|
11919
|
-
this.projectAs = null;
|
|
11920
|
-
}
|
|
11921
12009
|
get attributes() {
|
|
11922
12010
|
return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
11923
12011
|
}
|
|
@@ -11936,11 +12024,31 @@ class ElementAttributes {
|
|
|
11936
12024
|
get i18n() {
|
|
11937
12025
|
return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
11938
12026
|
}
|
|
11939
|
-
|
|
11940
|
-
|
|
12027
|
+
constructor(compatibility) {
|
|
12028
|
+
this.compatibility = compatibility;
|
|
12029
|
+
this.known = new Map();
|
|
12030
|
+
this.byKind = new Map;
|
|
12031
|
+
this.projectAs = null;
|
|
12032
|
+
}
|
|
12033
|
+
isKnown(kind, name, value) {
|
|
12034
|
+
const nameToValue = this.known.get(kind) ?? new Set();
|
|
12035
|
+
this.known.set(kind, nameToValue);
|
|
12036
|
+
if (nameToValue.has(name)) {
|
|
12037
|
+
return true;
|
|
12038
|
+
}
|
|
12039
|
+
nameToValue.add(name);
|
|
12040
|
+
return false;
|
|
12041
|
+
}
|
|
12042
|
+
add(kind, name, value, namespace, trustedValueFn) {
|
|
12043
|
+
// TemplateDefinitionBuilder puts duplicate attribute, class, and style values into the consts
|
|
12044
|
+
// array. This seems inefficient, we can probably keep just the first one or the last value
|
|
12045
|
+
// (whichever actually gets applied when multiple values are listed for the same attribute).
|
|
12046
|
+
const allowDuplicates = this.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
|
|
12047
|
+
(kind === BindingKind.Attribute || kind === BindingKind.ClassName ||
|
|
12048
|
+
kind === BindingKind.StyleProperty);
|
|
12049
|
+
if (!allowDuplicates && this.isKnown(kind, name, value)) {
|
|
11941
12050
|
return;
|
|
11942
12051
|
}
|
|
11943
|
-
this.known.add(name);
|
|
11944
12052
|
// TODO: Can this be its own phase
|
|
11945
12053
|
if (name === 'ngProjectAs') {
|
|
11946
12054
|
if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
|
|
@@ -11952,7 +12060,7 @@ class ElementAttributes {
|
|
|
11952
12060
|
// attribute. Is this sane?
|
|
11953
12061
|
}
|
|
11954
12062
|
const array = this.arrayFor(kind);
|
|
11955
|
-
array.push(...getAttributeNameLiterals$1(name));
|
|
12063
|
+
array.push(...getAttributeNameLiterals$1(namespace, name));
|
|
11956
12064
|
if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
|
|
11957
12065
|
if (value === null) {
|
|
11958
12066
|
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
|
|
@@ -11978,13 +12086,10 @@ class ElementAttributes {
|
|
|
11978
12086
|
/**
|
|
11979
12087
|
* Gets an array of literal expressions representing the attribute's namespaced name.
|
|
11980
12088
|
*/
|
|
11981
|
-
function getAttributeNameLiterals$1(name) {
|
|
11982
|
-
const
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
return [
|
|
11986
|
-
literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
11987
|
-
];
|
|
12089
|
+
function getAttributeNameLiterals$1(namespace, name) {
|
|
12090
|
+
const nameLiteral = literal(name);
|
|
12091
|
+
if (namespace) {
|
|
12092
|
+
return [literal(0 /* core.AttributeMarker.NamespaceURI */), literal(namespace), nameLiteral];
|
|
11988
12093
|
}
|
|
11989
12094
|
return [nameLiteral];
|
|
11990
12095
|
}
|
|
@@ -12052,7 +12157,7 @@ function convertI18nBindings(job) {
|
|
|
12052
12157
|
if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
|
|
12053
12158
|
throw new Error(`AssertionError: An i18n attribute binding instruction requires the same number of expressions and placeholders, but found ${op.expression.i18nPlaceholders.length} placeholders and ${op.expression.expressions.length} expressions`);
|
|
12054
12159
|
}
|
|
12055
|
-
ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
|
|
12160
|
+
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));
|
|
12056
12161
|
}
|
|
12057
12162
|
OpList.replaceWithMany(op, ops);
|
|
12058
12163
|
break;
|
|
@@ -12089,7 +12194,8 @@ function createDeferDepsFns(job) {
|
|
|
12089
12194
|
if (op.handle.slot === null) {
|
|
12090
12195
|
throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
|
|
12091
12196
|
}
|
|
12092
|
-
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn
|
|
12197
|
+
op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn`,
|
|
12198
|
+
/* Don't use unique names for TDB compatibility */ false);
|
|
12093
12199
|
}
|
|
12094
12200
|
}
|
|
12095
12201
|
}
|
|
@@ -12106,75 +12212,119 @@ function createDeferDepsFns(job) {
|
|
|
12106
12212
|
* message.)
|
|
12107
12213
|
*/
|
|
12108
12214
|
function createI18nContexts(job) {
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12215
|
+
// Create i18n context ops for i18n attrs.
|
|
12216
|
+
const attrContextByMessage = new Map();
|
|
12217
|
+
for (const unit of job.units) {
|
|
12218
|
+
for (const op of unit.ops()) {
|
|
12219
|
+
switch (op.kind) {
|
|
12220
|
+
case OpKind.Binding:
|
|
12221
|
+
case OpKind.Property:
|
|
12222
|
+
case OpKind.Attribute:
|
|
12223
|
+
case OpKind.ExtractedAttribute:
|
|
12224
|
+
if (op.i18nMessage === null) {
|
|
12225
|
+
continue;
|
|
12226
|
+
}
|
|
12227
|
+
if (!attrContextByMessage.has(op.i18nMessage)) {
|
|
12228
|
+
const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
|
|
12229
|
+
unit.create.push(i18nContext);
|
|
12230
|
+
attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
|
|
12231
|
+
}
|
|
12232
|
+
op.i18nContext = attrContextByMessage.get(op.i18nMessage);
|
|
12233
|
+
break;
|
|
12234
|
+
}
|
|
12235
|
+
}
|
|
12236
|
+
}
|
|
12237
|
+
// Create i18n context ops for root i18n blocks.
|
|
12238
|
+
const blockContextByI18nBlock = new Map();
|
|
12115
12239
|
for (const unit of job.units) {
|
|
12116
12240
|
for (const op of unit.create) {
|
|
12117
12241
|
switch (op.kind) {
|
|
12118
12242
|
case OpKind.I18nStart:
|
|
12119
|
-
currentI18nOp = op;
|
|
12120
|
-
// Each root i18n block gets its own context, child ones refer to the context for their
|
|
12121
|
-
// root block.
|
|
12122
12243
|
if (op.xref === op.root) {
|
|
12123
|
-
|
|
12124
|
-
unit.create.push(
|
|
12125
|
-
op.context = xref;
|
|
12126
|
-
|
|
12244
|
+
const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
|
|
12245
|
+
unit.create.push(contextOp);
|
|
12246
|
+
op.context = contextOp.xref;
|
|
12247
|
+
blockContextByI18nBlock.set(op.xref, contextOp);
|
|
12127
12248
|
}
|
|
12128
12249
|
break;
|
|
12250
|
+
}
|
|
12251
|
+
}
|
|
12252
|
+
}
|
|
12253
|
+
// Assign i18n contexts for child i18n blocks. These don't need their own conext, instead they
|
|
12254
|
+
// should inherit from their root i18n block.
|
|
12255
|
+
for (const unit of job.units) {
|
|
12256
|
+
for (const op of unit.create) {
|
|
12257
|
+
if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
|
|
12258
|
+
const rootContext = blockContextByI18nBlock.get(op.root);
|
|
12259
|
+
if (rootContext === undefined) {
|
|
12260
|
+
throw Error('AssertionError: Root i18n block i18n context should have been created.');
|
|
12261
|
+
}
|
|
12262
|
+
op.context = rootContext.xref;
|
|
12263
|
+
blockContextByI18nBlock.set(op.xref, rootContext);
|
|
12264
|
+
}
|
|
12265
|
+
}
|
|
12266
|
+
}
|
|
12267
|
+
// Create or assign i18n contexts for ICUs.
|
|
12268
|
+
let currentI18nOp = null;
|
|
12269
|
+
for (const unit of job.units) {
|
|
12270
|
+
for (const op of unit.create) {
|
|
12271
|
+
switch (op.kind) {
|
|
12272
|
+
case OpKind.I18nStart:
|
|
12273
|
+
currentI18nOp = op;
|
|
12274
|
+
break;
|
|
12129
12275
|
case OpKind.I18nEnd:
|
|
12130
12276
|
currentI18nOp = null;
|
|
12131
12277
|
break;
|
|
12132
12278
|
case OpKind.IcuStart:
|
|
12133
|
-
// If an ICU represents a different message than its containing block, we give it its own
|
|
12134
|
-
// i18n context.
|
|
12135
12279
|
if (currentI18nOp === null) {
|
|
12136
|
-
throw Error('Unexpected ICU outside of an i18n block.');
|
|
12280
|
+
throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
|
|
12137
12281
|
}
|
|
12138
12282
|
if (op.message.id !== currentI18nOp.message.id) {
|
|
12139
|
-
//
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12283
|
+
// This ICU is a sub-message inside its parent i18n block message. We need to give it
|
|
12284
|
+
// its own context.
|
|
12285
|
+
const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.xref, op.message, null);
|
|
12286
|
+
unit.create.push(contextOp);
|
|
12287
|
+
op.context = contextOp.xref;
|
|
12143
12288
|
}
|
|
12144
12289
|
else {
|
|
12145
|
-
//
|
|
12146
|
-
// the
|
|
12290
|
+
// This ICU is the only translatable content in its parent i18n block. We need to
|
|
12291
|
+
// convert the parent's context into an ICU context.
|
|
12147
12292
|
op.context = currentI18nOp.context;
|
|
12293
|
+
blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
|
|
12148
12294
|
}
|
|
12149
12295
|
break;
|
|
12150
12296
|
}
|
|
12151
12297
|
}
|
|
12152
|
-
for (const op of unit.ops()) {
|
|
12153
|
-
switch (op.kind) {
|
|
12154
|
-
case OpKind.Binding:
|
|
12155
|
-
case OpKind.Property:
|
|
12156
|
-
case OpKind.Attribute:
|
|
12157
|
-
case OpKind.ExtractedAttribute:
|
|
12158
|
-
if (!op.i18nMessage) {
|
|
12159
|
-
continue;
|
|
12160
|
-
}
|
|
12161
|
-
if (!messageToContext.has(op.i18nMessage)) {
|
|
12162
|
-
// create the context
|
|
12163
|
-
const i18nContext = job.allocateXrefId();
|
|
12164
|
-
unit.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, op.i18nMessage, null));
|
|
12165
|
-
messageToContext.set(op.i18nMessage, i18nContext);
|
|
12166
|
-
}
|
|
12167
|
-
op.i18nContext = messageToContext.get(op.i18nMessage);
|
|
12168
|
-
break;
|
|
12169
|
-
}
|
|
12170
|
-
}
|
|
12171
12298
|
}
|
|
12172
|
-
|
|
12173
|
-
|
|
12299
|
+
}
|
|
12300
|
+
|
|
12301
|
+
/**
|
|
12302
|
+
* Deduplicate text bindings, e.g. <div class="cls1" class="cls2">
|
|
12303
|
+
*/
|
|
12304
|
+
function deduplicateTextBindings(job) {
|
|
12305
|
+
const seen = new Map();
|
|
12174
12306
|
for (const unit of job.units) {
|
|
12175
|
-
for (const op of unit.
|
|
12176
|
-
if (op.kind === OpKind.
|
|
12177
|
-
|
|
12307
|
+
for (const op of unit.update.reversed()) {
|
|
12308
|
+
if (op.kind === OpKind.Binding && op.isTextAttribute) {
|
|
12309
|
+
const seenForElement = seen.get(op.target) || new Set();
|
|
12310
|
+
if (seenForElement.has(op.name)) {
|
|
12311
|
+
if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
12312
|
+
// For most duplicated attributes, TemplateDefinitionBuilder lists all of the values in
|
|
12313
|
+
// the consts array. However, for style and class attributes it only keeps the last one.
|
|
12314
|
+
// We replicate that behavior here since it has actual consequences for apps with
|
|
12315
|
+
// duplicate class or style attrs.
|
|
12316
|
+
if (op.name === 'style' || op.name === 'class') {
|
|
12317
|
+
OpList.remove(op);
|
|
12318
|
+
}
|
|
12319
|
+
}
|
|
12320
|
+
else {
|
|
12321
|
+
// TODO: Determine the correct behavior. It would probably make sense to merge multiple
|
|
12322
|
+
// style and class attributes. Alternatively we could just throw an error, as HTML
|
|
12323
|
+
// doesn't permit duplicate attributes.
|
|
12324
|
+
}
|
|
12325
|
+
}
|
|
12326
|
+
seenForElement.add(op.name);
|
|
12327
|
+
seen.set(op.target, seenForElement);
|
|
12178
12328
|
}
|
|
12179
12329
|
}
|
|
12180
12330
|
}
|
|
@@ -12560,13 +12710,18 @@ const LIST_DELIMITER = '|';
|
|
|
12560
12710
|
* used in the final output.
|
|
12561
12711
|
*/
|
|
12562
12712
|
function extractI18nMessages(job) {
|
|
12563
|
-
//
|
|
12564
|
-
|
|
12713
|
+
// Create an i18n message for each context.
|
|
12714
|
+
// TODO: Merge the context op with the message op since they're 1:1 anyways.
|
|
12715
|
+
const i18nMessagesByContext = new Map();
|
|
12565
12716
|
const i18nBlocks = new Map();
|
|
12717
|
+
const i18nContexts = new Map();
|
|
12566
12718
|
for (const unit of job.units) {
|
|
12567
12719
|
for (const op of unit.create) {
|
|
12568
12720
|
switch (op.kind) {
|
|
12569
12721
|
case OpKind.I18nContext:
|
|
12722
|
+
const i18nMessageOp = createI18nMessage(job, op);
|
|
12723
|
+
unit.create.push(i18nMessageOp);
|
|
12724
|
+
i18nMessagesByContext.set(op.xref, i18nMessageOp);
|
|
12570
12725
|
i18nContexts.set(op.xref, op);
|
|
12571
12726
|
break;
|
|
12572
12727
|
case OpKind.I18nStart:
|
|
@@ -12575,54 +12730,47 @@ function extractI18nMessages(job) {
|
|
|
12575
12730
|
}
|
|
12576
12731
|
}
|
|
12577
12732
|
}
|
|
12578
|
-
//
|
|
12579
|
-
//
|
|
12580
|
-
|
|
12581
|
-
for (const unit of job.units) {
|
|
12582
|
-
for (const op of unit.create) {
|
|
12583
|
-
if (op.kind !== OpKind.I18nContext || op.contextKind !== I18nContextKind.Attr) {
|
|
12584
|
-
continue;
|
|
12585
|
-
}
|
|
12586
|
-
const i18nMessageOp = createI18nMessage(job, op);
|
|
12587
|
-
unit.create.push(i18nMessageOp);
|
|
12588
|
-
}
|
|
12589
|
-
}
|
|
12590
|
-
// Extract messages from root i18n blocks.
|
|
12591
|
-
const i18nBlockMessages = new Map();
|
|
12592
|
-
for (const unit of job.units) {
|
|
12593
|
-
for (const op of unit.create) {
|
|
12594
|
-
if (op.kind === OpKind.I18nStart && op.xref === op.root) {
|
|
12595
|
-
if (!op.context) {
|
|
12596
|
-
throw Error('I18n start op should have its context set.');
|
|
12597
|
-
}
|
|
12598
|
-
const i18nMessageOp = createI18nMessage(job, i18nContexts.get(op.context));
|
|
12599
|
-
i18nBlockMessages.set(op.xref, i18nMessageOp);
|
|
12600
|
-
unit.create.push(i18nMessageOp);
|
|
12601
|
-
}
|
|
12602
|
-
}
|
|
12603
|
-
}
|
|
12604
|
-
// Extract messages from ICUs with their own sub-context.
|
|
12733
|
+
// Associate sub-messages for ICUs with their root message. At this point we can also remove the
|
|
12734
|
+
// ICU start/end ops, as they are no longer needed.
|
|
12735
|
+
let currentIcu = null;
|
|
12605
12736
|
for (const unit of job.units) {
|
|
12606
12737
|
for (const op of unit.create) {
|
|
12607
12738
|
switch (op.kind) {
|
|
12608
12739
|
case OpKind.IcuStart:
|
|
12609
|
-
|
|
12610
|
-
|
|
12740
|
+
currentIcu = op;
|
|
12741
|
+
OpList.remove(op);
|
|
12742
|
+
// Skip any contexts not associated with an ICU.
|
|
12743
|
+
const icuContext = i18nContexts.get(op.context);
|
|
12744
|
+
if (icuContext.contextKind !== I18nContextKind.Icu) {
|
|
12745
|
+
continue;
|
|
12611
12746
|
}
|
|
12612
|
-
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
|
|
12617
|
-
const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
|
|
12618
|
-
unit.create.push(subMessage);
|
|
12619
|
-
const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
|
|
12620
|
-
const parentMessage = i18nBlockMessages.get(rootI18nId);
|
|
12621
|
-
parentMessage?.subMessages.push(subMessage.xref);
|
|
12747
|
+
// Skip ICUs that share a context with their i18n message. These represent root-level
|
|
12748
|
+
// ICUs, not sub-messages.
|
|
12749
|
+
const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
|
|
12750
|
+
if (i18nBlock.context === icuContext.xref) {
|
|
12751
|
+
continue;
|
|
12622
12752
|
}
|
|
12623
|
-
|
|
12753
|
+
// Find the root message and push this ICUs message as a sub-message.
|
|
12754
|
+
const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
|
|
12755
|
+
const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
|
|
12756
|
+
if (rootMessage === undefined) {
|
|
12757
|
+
throw Error('AssertionError: ICU sub-message should belong to a root message.');
|
|
12758
|
+
}
|
|
12759
|
+
const subMessage = i18nMessagesByContext.get(icuContext.xref);
|
|
12760
|
+
subMessage.messagePlaceholder = op.messagePlaceholder;
|
|
12761
|
+
rootMessage.subMessages.push(subMessage.xref);
|
|
12624
12762
|
break;
|
|
12625
12763
|
case OpKind.IcuEnd:
|
|
12764
|
+
currentIcu = null;
|
|
12765
|
+
OpList.remove(op);
|
|
12766
|
+
break;
|
|
12767
|
+
case OpKind.IcuPlaceholder:
|
|
12768
|
+
// Add ICU placeholders to the message, then remove the ICU placeholder ops.
|
|
12769
|
+
if (currentIcu === null || currentIcu.context == null) {
|
|
12770
|
+
throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
|
|
12771
|
+
}
|
|
12772
|
+
const msg = i18nMessagesByContext.get(currentIcu.context);
|
|
12773
|
+
msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
|
|
12626
12774
|
OpList.remove(op);
|
|
12627
12775
|
break;
|
|
12628
12776
|
}
|
|
@@ -12635,14 +12783,19 @@ function extractI18nMessages(job) {
|
|
|
12635
12783
|
function createI18nMessage(job, context, messagePlaceholder) {
|
|
12636
12784
|
let formattedParams = formatParams(context.params);
|
|
12637
12785
|
const formattedPostprocessingParams = formatParams(context.postprocessingParams);
|
|
12638
|
-
let needsPostprocessing =
|
|
12639
|
-
for (const values of context.params.values()) {
|
|
12640
|
-
if (values.length > 1) {
|
|
12641
|
-
needsPostprocessing = true;
|
|
12642
|
-
}
|
|
12643
|
-
}
|
|
12786
|
+
let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
|
|
12644
12787
|
return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
|
|
12645
12788
|
}
|
|
12789
|
+
/**
|
|
12790
|
+
* Formats an ICU placeholder into a single string with expression placeholders.
|
|
12791
|
+
*/
|
|
12792
|
+
function formatIcuPlaceholder(op) {
|
|
12793
|
+
if (op.strings.length !== op.expressionPlaceholders.length + 1) {
|
|
12794
|
+
throw Error(`AsserionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
|
|
12795
|
+
}
|
|
12796
|
+
const values = op.expressionPlaceholders.map(formatValue);
|
|
12797
|
+
return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
|
|
12798
|
+
}
|
|
12646
12799
|
/**
|
|
12647
12800
|
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12648
12801
|
*/
|
|
@@ -12981,7 +13134,7 @@ const BANG_IMPORTANT = '!important';
|
|
|
12981
13134
|
*/
|
|
12982
13135
|
function parseHostStyleProperties(job) {
|
|
12983
13136
|
for (const op of job.root.update) {
|
|
12984
|
-
if (op.kind
|
|
13137
|
+
if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
|
|
12985
13138
|
continue;
|
|
12986
13139
|
}
|
|
12987
13140
|
if (op.name.endsWith(BANG_IMPORTANT)) {
|
|
@@ -12991,7 +13144,7 @@ function parseHostStyleProperties(job) {
|
|
|
12991
13144
|
if (op.name.startsWith(STYLE_DOT)) {
|
|
12992
13145
|
op.bindingKind = BindingKind.StyleProperty;
|
|
12993
13146
|
op.name = op.name.substring(STYLE_DOT.length);
|
|
12994
|
-
if (isCssCustomProperty$1(op.name)) {
|
|
13147
|
+
if (!isCssCustomProperty$1(op.name)) {
|
|
12995
13148
|
op.name = hyphenate$1(op.name);
|
|
12996
13149
|
}
|
|
12997
13150
|
const { property, suffix } = parseProperty$1(op.name);
|
|
@@ -20139,7 +20292,7 @@ function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
|
|
|
20139
20292
|
let transformFn = undefined;
|
|
20140
20293
|
// If nescessary, add a post-processing step and resolve any placeholder params that are
|
|
20141
20294
|
// set in post-processing.
|
|
20142
|
-
if (messageOp.needsPostprocessing) {
|
|
20295
|
+
if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
|
|
20143
20296
|
// Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
|
|
20144
20297
|
const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
|
|
20145
20298
|
const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */ false);
|
|
@@ -20169,7 +20322,6 @@ function addSubMessageParams(messageOp, subMessagePlaceholders) {
|
|
|
20169
20322
|
else {
|
|
20170
20323
|
messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
|
|
20171
20324
|
messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
|
|
20172
|
-
messageOp.needsPostprocessing = true;
|
|
20173
20325
|
}
|
|
20174
20326
|
}
|
|
20175
20327
|
}
|
|
@@ -20255,6 +20407,7 @@ function convertI18nText(job) {
|
|
|
20255
20407
|
let currentIcu = null;
|
|
20256
20408
|
const textNodeI18nBlocks = new Map();
|
|
20257
20409
|
const textNodeIcus = new Map();
|
|
20410
|
+
const icuPlaceholderByText = new Map();
|
|
20258
20411
|
for (const op of unit.create) {
|
|
20259
20412
|
switch (op.kind) {
|
|
20260
20413
|
case OpKind.I18nStart:
|
|
@@ -20279,7 +20432,19 @@ function convertI18nText(job) {
|
|
|
20279
20432
|
if (currentI18n !== null) {
|
|
20280
20433
|
textNodeI18nBlocks.set(op.xref, currentI18n);
|
|
20281
20434
|
textNodeIcus.set(op.xref, currentIcu);
|
|
20282
|
-
|
|
20435
|
+
if (op.icuPlaceholder !== null) {
|
|
20436
|
+
// Create an op to represent the ICU placeholder. Initially set its static text to the
|
|
20437
|
+
// value of the text op, though this may be overwritten later if this text op is a
|
|
20438
|
+
// placeholder for an interpolation.
|
|
20439
|
+
const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
|
|
20440
|
+
OpList.replace(op, icuPlaceholderOp);
|
|
20441
|
+
icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
|
|
20442
|
+
}
|
|
20443
|
+
else {
|
|
20444
|
+
// Otherwise just remove the text op, since its value is already accounted for in the
|
|
20445
|
+
// translated message.
|
|
20446
|
+
OpList.remove(op);
|
|
20447
|
+
}
|
|
20283
20448
|
}
|
|
20284
20449
|
break;
|
|
20285
20450
|
}
|
|
@@ -20294,6 +20459,7 @@ function convertI18nText(job) {
|
|
|
20294
20459
|
}
|
|
20295
20460
|
const i18nOp = textNodeI18nBlocks.get(op.target);
|
|
20296
20461
|
const icuOp = textNodeIcus.get(op.target);
|
|
20462
|
+
const icuPlaceholder = icuPlaceholderByText.get(op.target);
|
|
20297
20463
|
const contextId = icuOp ? icuOp.context : i18nOp.context;
|
|
20298
20464
|
const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing :
|
|
20299
20465
|
I18nParamResolutionTime.Creation;
|
|
@@ -20302,9 +20468,14 @@ function convertI18nText(job) {
|
|
|
20302
20468
|
const expr = op.interpolation.expressions[i];
|
|
20303
20469
|
// For now, this i18nExpression depends on the slot context of the enclosing i18n block.
|
|
20304
20470
|
// Later, we will modify this, and advance to a different point.
|
|
20305
|
-
ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, op.interpolation.i18nPlaceholders[i], resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
|
|
20471
|
+
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));
|
|
20306
20472
|
}
|
|
20307
20473
|
OpList.replaceWithMany(op, ops);
|
|
20474
|
+
// If this interpolation is part of an ICU placeholder, add the strings and expressions to
|
|
20475
|
+
// the placeholder.
|
|
20476
|
+
if (icuPlaceholder !== undefined) {
|
|
20477
|
+
icuPlaceholder.strings = op.interpolation.strings;
|
|
20478
|
+
}
|
|
20308
20479
|
break;
|
|
20309
20480
|
}
|
|
20310
20481
|
}
|
|
@@ -20413,6 +20584,7 @@ function parse(value) {
|
|
|
20413
20584
|
break;
|
|
20414
20585
|
case 58 /* Char.Colon */:
|
|
20415
20586
|
if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
|
|
20587
|
+
// TODO: Do not hyphenate CSS custom property names like: `--intentionallyCamelCase`
|
|
20416
20588
|
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
20417
20589
|
valueStart = i;
|
|
20418
20590
|
}
|
|
@@ -20487,7 +20659,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
20487
20659
|
op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
|
|
20488
20660
|
break;
|
|
20489
20661
|
case OpKind.Variable:
|
|
20490
|
-
varNames.set(op.xref, getVariableName(op.variable, state));
|
|
20662
|
+
varNames.set(op.xref, getVariableName(unit, op.variable, state));
|
|
20491
20663
|
break;
|
|
20492
20664
|
case OpKind.RepeaterCreate:
|
|
20493
20665
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
@@ -20542,15 +20714,23 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
20542
20714
|
});
|
|
20543
20715
|
}
|
|
20544
20716
|
}
|
|
20545
|
-
function getVariableName(variable, state) {
|
|
20717
|
+
function getVariableName(unit, variable, state) {
|
|
20546
20718
|
if (variable.name === null) {
|
|
20547
20719
|
switch (variable.kind) {
|
|
20548
20720
|
case SemanticVariableKind.Context:
|
|
20549
20721
|
variable.name = `ctx_r${state.index++}`;
|
|
20550
20722
|
break;
|
|
20551
20723
|
case SemanticVariableKind.Identifier:
|
|
20552
|
-
|
|
20553
|
-
|
|
20724
|
+
if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
|
|
20725
|
+
// TODO: Prefix increment and `_r` are for compatiblity with the old naming scheme.
|
|
20726
|
+
// This has the potential to cause collisions when `ctx` is the identifier, so we need a
|
|
20727
|
+
// special check for that as well.
|
|
20728
|
+
const compatPrefix = variable.identifier === 'ctx' ? 'i' : '';
|
|
20729
|
+
variable.name = `${variable.identifier}_${compatPrefix}r${++state.index}`;
|
|
20730
|
+
}
|
|
20731
|
+
else {
|
|
20732
|
+
variable.name = `${variable.identifier}_i${state.index++}`;
|
|
20733
|
+
}
|
|
20554
20734
|
break;
|
|
20555
20735
|
default:
|
|
20556
20736
|
// TODO: Prefix increment for compatibility only.
|
|
@@ -20747,17 +20927,27 @@ const CREATE_ORDERING = [
|
|
|
20747
20927
|
* op kinds.
|
|
20748
20928
|
*/
|
|
20749
20929
|
const UPDATE_ORDERING = [
|
|
20750
|
-
{ test: kindWithInterpolationTest(OpKind.HostProperty, true) },
|
|
20751
|
-
{ test: kindWithInterpolationTest(OpKind.HostProperty, false) },
|
|
20752
20930
|
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
20753
20931
|
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
20754
20932
|
{ test: kindTest(OpKind.StyleProp) },
|
|
20755
20933
|
{ test: kindTest(OpKind.ClassProp) },
|
|
20756
|
-
{ test: kindWithInterpolationTest(OpKind.Property, true) },
|
|
20757
20934
|
{ test: kindWithInterpolationTest(OpKind.Attribute, true) },
|
|
20935
|
+
{ test: kindWithInterpolationTest(OpKind.Property, true) },
|
|
20758
20936
|
{ test: kindWithInterpolationTest(OpKind.Property, false) },
|
|
20759
20937
|
{ test: kindWithInterpolationTest(OpKind.Attribute, false) },
|
|
20760
20938
|
];
|
|
20939
|
+
/**
|
|
20940
|
+
* Host bindings have their own update ordering.
|
|
20941
|
+
*/
|
|
20942
|
+
const UPDATE_HOST_ORDERING = [
|
|
20943
|
+
{ test: kindWithInterpolationTest(OpKind.HostProperty, true) },
|
|
20944
|
+
{ test: kindWithInterpolationTest(OpKind.HostProperty, false) },
|
|
20945
|
+
{ test: kindTest(OpKind.Attribute) },
|
|
20946
|
+
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
20947
|
+
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
20948
|
+
{ test: kindTest(OpKind.StyleProp) },
|
|
20949
|
+
{ test: kindTest(OpKind.ClassProp) },
|
|
20950
|
+
];
|
|
20761
20951
|
/**
|
|
20762
20952
|
* The set of all op kinds we handle in the reordering phase.
|
|
20763
20953
|
*/
|
|
@@ -20778,7 +20968,8 @@ function orderOps(job) {
|
|
|
20778
20968
|
// Create mode:
|
|
20779
20969
|
orderWithin(unit.create, CREATE_ORDERING);
|
|
20780
20970
|
// Update mode:
|
|
20781
|
-
|
|
20971
|
+
const ordering = unit.job.kind === CompilationJobKind.Host ? UPDATE_HOST_ORDERING : UPDATE_ORDERING;
|
|
20972
|
+
orderWithin(unit.update, ordering);
|
|
20782
20973
|
}
|
|
20783
20974
|
}
|
|
20784
20975
|
/**
|
|
@@ -20833,21 +21024,39 @@ function keepLast(ops) {
|
|
|
20833
21024
|
* class property.
|
|
20834
21025
|
*/
|
|
20835
21026
|
function parseExtractedStyles(job) {
|
|
21027
|
+
const elements = new Map();
|
|
21028
|
+
for (const unit of job.units) {
|
|
21029
|
+
for (const op of unit.create) {
|
|
21030
|
+
if (isElementOrContainerOp(op)) {
|
|
21031
|
+
elements.set(op.xref, op);
|
|
21032
|
+
}
|
|
21033
|
+
}
|
|
21034
|
+
}
|
|
20836
21035
|
for (const unit of job.units) {
|
|
20837
21036
|
for (const op of unit.create) {
|
|
20838
21037
|
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
20839
21038
|
isStringLiteral(op.expression)) {
|
|
21039
|
+
const target = elements.get(op.target);
|
|
21040
|
+
if (target !== undefined && target.kind === OpKind.Template &&
|
|
21041
|
+
target.templateKind === TemplateKind.Structural) {
|
|
21042
|
+
// TemplateDefinitionBuilder will not apply class and style bindings to structural
|
|
21043
|
+
// directives; instead, it will leave them as attributes.
|
|
21044
|
+
// (It's not clear what that would mean, anyway -- classes and styles on a structural
|
|
21045
|
+
// element should probably be a parse error.)
|
|
21046
|
+
// TODO: We may be able to remove this once Template Pipeline is the default.
|
|
21047
|
+
continue;
|
|
21048
|
+
}
|
|
20840
21049
|
if (op.name === 'style') {
|
|
20841
21050
|
const parsedStyles = parse(op.expression.value);
|
|
20842
21051
|
for (let i = 0; i < parsedStyles.length - 1; i += 2) {
|
|
20843
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
21052
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, null, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
|
|
20844
21053
|
}
|
|
20845
21054
|
OpList.remove(op);
|
|
20846
21055
|
}
|
|
20847
21056
|
else if (op.name === 'class') {
|
|
20848
21057
|
const parsedClasses = op.expression.value.trim().split(/\s+/g);
|
|
20849
21058
|
for (const parsedClass of parsedClasses) {
|
|
20850
|
-
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
21059
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, null, parsedClass, null, null, null, SecurityContext.NONE), op);
|
|
20851
21060
|
}
|
|
20852
21061
|
OpList.remove(op);
|
|
20853
21062
|
}
|
|
@@ -20871,15 +21080,6 @@ function removeContentSelectors(job) {
|
|
|
20871
21080
|
OpList.remove(op);
|
|
20872
21081
|
}
|
|
20873
21082
|
break;
|
|
20874
|
-
case OpKind.Projection:
|
|
20875
|
-
// op.attributes is an array of [attr1-name, attr1-value, attr2-name, attr2-value, ...],
|
|
20876
|
-
// find the "select" attribute and remove its name and corresponding value.
|
|
20877
|
-
for (let i = op.attributes.length - 2; i >= 0; i -= 2) {
|
|
20878
|
-
if (isSelectAttribute(op.attributes[i])) {
|
|
20879
|
-
op.attributes.splice(i, 2);
|
|
20880
|
-
}
|
|
20881
|
-
}
|
|
20882
|
-
break;
|
|
20883
21083
|
}
|
|
20884
21084
|
}
|
|
20885
21085
|
}
|
|
@@ -21051,8 +21251,10 @@ function wrapTemplateWithI18n(unit, parentI18n) {
|
|
|
21051
21251
|
// Only add i18n ops if they have not already been propagated to this template.
|
|
21052
21252
|
if (unit.create.head.next?.kind !== OpKind.I18nStart) {
|
|
21053
21253
|
const id = unit.job.allocateXrefId();
|
|
21054
|
-
OpList.insertAfter(
|
|
21055
|
-
|
|
21254
|
+
OpList.insertAfter(
|
|
21255
|
+
// Nested ng-template i18n start/end ops should not recieve source spans.
|
|
21256
|
+
createI18nStartOp(id, parentI18n.message, parentI18n.root, null), unit.create.head);
|
|
21257
|
+
OpList.insertBefore(createI18nEndOp(id, null), unit.create.tail);
|
|
21056
21258
|
}
|
|
21057
21259
|
}
|
|
21058
21260
|
|
|
@@ -21233,9 +21435,7 @@ function namespaceMath() {
|
|
|
21233
21435
|
return call(Identifiers.namespaceMathML, [], null);
|
|
21234
21436
|
}
|
|
21235
21437
|
function advance(delta, sourceSpan) {
|
|
21236
|
-
return call(Identifiers.advance, [
|
|
21237
|
-
literal(delta),
|
|
21238
|
-
], sourceSpan);
|
|
21438
|
+
return call(Identifiers.advance, delta > 1 ? [literal(delta)] : [], sourceSpan);
|
|
21239
21439
|
}
|
|
21240
21440
|
function reference(slot) {
|
|
21241
21441
|
return importExpr(Identifiers.reference).callFn([
|
|
@@ -21313,22 +21513,22 @@ function projectionDef(def) {
|
|
|
21313
21513
|
}
|
|
21314
21514
|
function projection(slot, projectionSlotIndex, attributes, sourceSpan) {
|
|
21315
21515
|
const args = [literal(slot)];
|
|
21316
|
-
if (projectionSlotIndex !== 0 || attributes
|
|
21516
|
+
if (projectionSlotIndex !== 0 || attributes !== null) {
|
|
21317
21517
|
args.push(literal(projectionSlotIndex));
|
|
21318
|
-
if (attributes
|
|
21319
|
-
args.push(
|
|
21518
|
+
if (attributes !== null) {
|
|
21519
|
+
args.push(attributes);
|
|
21320
21520
|
}
|
|
21321
21521
|
}
|
|
21322
21522
|
return call(Identifiers.projection, args, sourceSpan);
|
|
21323
21523
|
}
|
|
21324
|
-
function i18nStart(slot, constIndex, subTemplateIndex) {
|
|
21524
|
+
function i18nStart(slot, constIndex, subTemplateIndex, sourceSpan) {
|
|
21325
21525
|
const args = [literal(slot), literal(constIndex)];
|
|
21326
21526
|
if (subTemplateIndex !== null) {
|
|
21327
21527
|
args.push(literal(subTemplateIndex));
|
|
21328
21528
|
}
|
|
21329
|
-
return call(Identifiers.i18nStart, args,
|
|
21529
|
+
return call(Identifiers.i18nStart, args, sourceSpan);
|
|
21330
21530
|
}
|
|
21331
|
-
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, sourceSpan) {
|
|
21531
|
+
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, emptyTag, emptyConstIndex, sourceSpan) {
|
|
21332
21532
|
const args = [
|
|
21333
21533
|
literal(slot),
|
|
21334
21534
|
variable(viewFnName),
|
|
@@ -21342,6 +21542,12 @@ function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByF
|
|
|
21342
21542
|
args.push(literal(trackByUsesComponentInstance));
|
|
21343
21543
|
if (emptyViewFnName !== null) {
|
|
21344
21544
|
args.push(variable(emptyViewFnName), literal(emptyDecls), literal(emptyVars));
|
|
21545
|
+
if (emptyTag !== null || emptyConstIndex !== null) {
|
|
21546
|
+
args.push(literal(emptyTag));
|
|
21547
|
+
}
|
|
21548
|
+
if (emptyConstIndex !== null) {
|
|
21549
|
+
args.push(literal(emptyConstIndex));
|
|
21550
|
+
}
|
|
21345
21551
|
}
|
|
21346
21552
|
}
|
|
21347
21553
|
return call(Identifiers.repeaterCreate, args, sourceSpan);
|
|
@@ -21352,15 +21558,15 @@ function repeater(collection, sourceSpan) {
|
|
|
21352
21558
|
function deferWhen(prefetch, expr, sourceSpan) {
|
|
21353
21559
|
return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
|
|
21354
21560
|
}
|
|
21355
|
-
function i18n(slot, constIndex, subTemplateIndex) {
|
|
21561
|
+
function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
|
|
21356
21562
|
const args = [literal(slot), literal(constIndex)];
|
|
21357
21563
|
if (subTemplateIndex) {
|
|
21358
21564
|
args.push(literal(subTemplateIndex));
|
|
21359
21565
|
}
|
|
21360
|
-
return call(Identifiers.i18n, args,
|
|
21566
|
+
return call(Identifiers.i18n, args, sourceSpan);
|
|
21361
21567
|
}
|
|
21362
|
-
function i18nEnd() {
|
|
21363
|
-
return call(Identifiers.i18nEnd, [],
|
|
21568
|
+
function i18nEnd(endSourceSpan) {
|
|
21569
|
+
return call(Identifiers.i18nEnd, [], endSourceSpan);
|
|
21364
21570
|
}
|
|
21365
21571
|
function i18nAttributes(slot, i18nAttributesConfig) {
|
|
21366
21572
|
const args = [literal(slot), literal(i18nAttributesConfig)];
|
|
@@ -21373,10 +21579,13 @@ function property(name, expression, sanitizer, sourceSpan) {
|
|
|
21373
21579
|
}
|
|
21374
21580
|
return call(Identifiers.property, args, sourceSpan);
|
|
21375
21581
|
}
|
|
21376
|
-
function attribute(name, expression, sanitizer) {
|
|
21582
|
+
function attribute(name, expression, sanitizer, namespace) {
|
|
21377
21583
|
const args = [literal(name), expression];
|
|
21378
|
-
if (sanitizer !== null) {
|
|
21379
|
-
args.push(sanitizer);
|
|
21584
|
+
if (sanitizer !== null || namespace !== null) {
|
|
21585
|
+
args.push(sanitizer ?? literal(null));
|
|
21586
|
+
}
|
|
21587
|
+
if (namespace !== null) {
|
|
21588
|
+
args.push(literal(namespace));
|
|
21380
21589
|
}
|
|
21381
21590
|
return call(Identifiers.attribute, args, null);
|
|
21382
21591
|
}
|
|
@@ -21720,6 +21929,31 @@ function reify(job) {
|
|
|
21720
21929
|
reifyUpdateOperations(unit, unit.update);
|
|
21721
21930
|
}
|
|
21722
21931
|
}
|
|
21932
|
+
/**
|
|
21933
|
+
* This function can be used a sanity check -- it walks every expression in the const pool, and
|
|
21934
|
+
* every expression reachable from an op, and makes sure that there are no IR expressions
|
|
21935
|
+
* left. This is nice to use for debugging mysterious failures where an IR expression cannot be
|
|
21936
|
+
* output from the output AST code.
|
|
21937
|
+
*/
|
|
21938
|
+
function ensureNoIrForDebug(job) {
|
|
21939
|
+
for (const stmt of job.pool.statements) {
|
|
21940
|
+
transformExpressionsInStatement(stmt, expr => {
|
|
21941
|
+
if (isIrExpression(expr)) {
|
|
21942
|
+
throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
|
|
21943
|
+
}
|
|
21944
|
+
return expr;
|
|
21945
|
+
}, VisitorContextFlag.None);
|
|
21946
|
+
}
|
|
21947
|
+
for (const unit of job.units) {
|
|
21948
|
+
for (const op of unit.ops()) {
|
|
21949
|
+
visitExpressionsInOp(op, expr => {
|
|
21950
|
+
if (isIrExpression(expr)) {
|
|
21951
|
+
throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
|
|
21952
|
+
}
|
|
21953
|
+
});
|
|
21954
|
+
}
|
|
21955
|
+
}
|
|
21956
|
+
}
|
|
21723
21957
|
function reifyCreateOperations(unit, ops) {
|
|
21724
21958
|
for (const op of ops) {
|
|
21725
21959
|
transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
|
|
@@ -21728,31 +21962,31 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21728
21962
|
OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
|
|
21729
21963
|
break;
|
|
21730
21964
|
case OpKind.ElementStart:
|
|
21731
|
-
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21965
|
+
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21732
21966
|
break;
|
|
21733
21967
|
case OpKind.Element:
|
|
21734
|
-
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.
|
|
21968
|
+
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21735
21969
|
break;
|
|
21736
21970
|
case OpKind.ElementEnd:
|
|
21737
21971
|
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
21738
21972
|
break;
|
|
21739
21973
|
case OpKind.ContainerStart:
|
|
21740
|
-
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21974
|
+
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21741
21975
|
break;
|
|
21742
21976
|
case OpKind.Container:
|
|
21743
|
-
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.
|
|
21977
|
+
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
|
|
21744
21978
|
break;
|
|
21745
21979
|
case OpKind.ContainerEnd:
|
|
21746
21980
|
OpList.replace(op, elementContainerEnd());
|
|
21747
21981
|
break;
|
|
21748
21982
|
case OpKind.I18nStart:
|
|
21749
|
-
OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21983
|
+
OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
|
|
21750
21984
|
break;
|
|
21751
21985
|
case OpKind.I18nEnd:
|
|
21752
|
-
OpList.replace(op, i18nEnd());
|
|
21986
|
+
OpList.replace(op, i18nEnd(op.sourceSpan));
|
|
21753
21987
|
break;
|
|
21754
21988
|
case OpKind.I18n:
|
|
21755
|
-
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
21989
|
+
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
|
|
21756
21990
|
break;
|
|
21757
21991
|
case OpKind.I18nAttributes:
|
|
21758
21992
|
if (op.i18nAttributesConfig === null) {
|
|
@@ -21768,7 +22002,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21768
22002
|
throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
|
|
21769
22003
|
}
|
|
21770
22004
|
const childView = unit.job.views.get(op.xref);
|
|
21771
|
-
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.
|
|
22005
|
+
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
|
|
21772
22006
|
break;
|
|
21773
22007
|
case OpKind.DisableBindings:
|
|
21774
22008
|
OpList.replace(op, disableBindings());
|
|
@@ -21783,7 +22017,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21783
22017
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
21784
22018
|
const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
|
|
21785
22019
|
if (eventTargetResolver === undefined) {
|
|
21786
|
-
throw new Error(`
|
|
22020
|
+
throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
|
|
21787
22021
|
}
|
|
21788
22022
|
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
21789
22023
|
break;
|
|
@@ -21870,7 +22104,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
21870
22104
|
emptyDecls = emptyView.decls;
|
|
21871
22105
|
emptyVars = emptyView.vars;
|
|
21872
22106
|
}
|
|
21873
|
-
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.
|
|
22107
|
+
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.emptyTag, op.emptyAttributes, op.wholeSourceSpan));
|
|
21874
22108
|
break;
|
|
21875
22109
|
case OpKind.Statement:
|
|
21876
22110
|
// Pass statement operations directly through.
|
|
@@ -21936,7 +22170,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
21936
22170
|
OpList.replace(op, attributeInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer, op.sourceSpan));
|
|
21937
22171
|
}
|
|
21938
22172
|
else {
|
|
21939
|
-
OpList.replace(op, attribute(op.name, op.expression, op.sanitizer));
|
|
22173
|
+
OpList.replace(op, attribute(op.name, op.expression, op.sanitizer, op.namespace));
|
|
21940
22174
|
}
|
|
21941
22175
|
break;
|
|
21942
22176
|
case OpKind.HostProperty:
|
|
@@ -22125,42 +22359,6 @@ function removeUnusedI18nAttributesOps(job) {
|
|
|
22125
22359
|
}
|
|
22126
22360
|
}
|
|
22127
22361
|
|
|
22128
|
-
/**
|
|
22129
|
-
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
22130
|
-
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
22131
|
-
* expression.
|
|
22132
|
-
*/
|
|
22133
|
-
function generateRepeaterDerivedVars(job) {
|
|
22134
|
-
const repeaters = new Map();
|
|
22135
|
-
for (const unit of job.units) {
|
|
22136
|
-
for (const op of unit.ops()) {
|
|
22137
|
-
if (op.kind === OpKind.RepeaterCreate) {
|
|
22138
|
-
repeaters.set(op.xref, op);
|
|
22139
|
-
}
|
|
22140
|
-
}
|
|
22141
|
-
}
|
|
22142
|
-
for (const unit of job.units) {
|
|
22143
|
-
for (const op of unit.ops()) {
|
|
22144
|
-
transformExpressionsInOp(op, expr => {
|
|
22145
|
-
if (!(expr instanceof DerivedRepeaterVarExpr)) {
|
|
22146
|
-
return expr;
|
|
22147
|
-
}
|
|
22148
|
-
const repeaterOp = repeaters.get(expr.xref);
|
|
22149
|
-
switch (expr.identity) {
|
|
22150
|
-
case DerivedRepeaterVarIdentity.First:
|
|
22151
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), literal(0));
|
|
22152
|
-
case DerivedRepeaterVarIdentity.Last:
|
|
22153
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), new BinaryOperatorExpr(BinaryOperator.Minus, new LexicalReadExpr(repeaterOp.varNames.$count), literal(1)));
|
|
22154
|
-
case DerivedRepeaterVarIdentity.Even:
|
|
22155
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
22156
|
-
case DerivedRepeaterVarIdentity.Odd:
|
|
22157
|
-
return new BinaryOperatorExpr(BinaryOperator.NotIdentical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
22158
|
-
}
|
|
22159
|
-
}, VisitorContextFlag.None);
|
|
22160
|
-
}
|
|
22161
|
-
}
|
|
22162
|
-
}
|
|
22163
|
-
|
|
22164
22362
|
/**
|
|
22165
22363
|
* Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
|
|
22166
22364
|
* either the `ctx` parameter to component functions (for the current view context) or to variables
|
|
@@ -22500,6 +22698,7 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22500
22698
|
// Record all of the i18n context ops, and the sub-template index for each i18n op.
|
|
22501
22699
|
const subTemplateIndicies = new Map();
|
|
22502
22700
|
const i18nContexts = new Map();
|
|
22701
|
+
const icuPlaceholders = new Map();
|
|
22503
22702
|
for (const unit of job.units) {
|
|
22504
22703
|
for (const op of unit.create) {
|
|
22505
22704
|
switch (op.kind) {
|
|
@@ -22509,6 +22708,9 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22509
22708
|
case OpKind.I18nContext:
|
|
22510
22709
|
i18nContexts.set(op.xref, op);
|
|
22511
22710
|
break;
|
|
22711
|
+
case OpKind.IcuPlaceholder:
|
|
22712
|
+
icuPlaceholders.set(op.xref, op);
|
|
22713
|
+
break;
|
|
22512
22714
|
}
|
|
22513
22715
|
}
|
|
22514
22716
|
}
|
|
@@ -22522,76 +22724,32 @@ function resolveI18nExpressionPlaceholders(job) {
|
|
|
22522
22724
|
for (const unit of job.units) {
|
|
22523
22725
|
for (const op of unit.update) {
|
|
22524
22726
|
if (op.kind === OpKind.I18nExpression) {
|
|
22525
|
-
const i18nContext = i18nContexts.get(op.context);
|
|
22526
22727
|
const index = expressionIndices.get(referenceIndex(op)) || 0;
|
|
22527
22728
|
const subTemplateIndex = subTemplateIndicies.get(op.i18nOwner) ?? null;
|
|
22528
|
-
|
|
22529
|
-
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22530
|
-
i18nContext.params :
|
|
22531
|
-
i18nContext.postprocessingParams;
|
|
22532
|
-
const values = params.get(op.i18nPlaceholder) || [];
|
|
22533
|
-
values.push({
|
|
22729
|
+
const value = {
|
|
22534
22730
|
value: index,
|
|
22535
22731
|
subTemplateIndex: subTemplateIndex,
|
|
22536
22732
|
flags: I18nParamValueFlags.ExpressionIndex
|
|
22537
|
-
}
|
|
22538
|
-
|
|
22733
|
+
};
|
|
22734
|
+
updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
|
|
22539
22735
|
expressionIndices.set(referenceIndex(op), index + 1);
|
|
22540
22736
|
}
|
|
22541
22737
|
}
|
|
22542
22738
|
}
|
|
22543
22739
|
}
|
|
22544
|
-
|
|
22545
|
-
|
|
22546
|
-
|
|
22547
|
-
|
|
22548
|
-
|
|
22549
|
-
|
|
22550
|
-
|
|
22551
|
-
|
|
22552
|
-
|
|
22553
|
-
node.visit(new ResolveIcuPlaceholdersVisitor(op.postprocessingParams));
|
|
22554
|
-
}
|
|
22555
|
-
}
|
|
22556
|
-
}
|
|
22740
|
+
function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
|
|
22741
|
+
if (op.i18nPlaceholder !== null) {
|
|
22742
|
+
const i18nContext = i18nContexts.get(op.context);
|
|
22743
|
+
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
22744
|
+
i18nContext.params :
|
|
22745
|
+
i18nContext.postprocessingParams;
|
|
22746
|
+
const values = params.get(op.i18nPlaceholder) || [];
|
|
22747
|
+
values.push(value);
|
|
22748
|
+
params.set(op.i18nPlaceholder, values);
|
|
22557
22749
|
}
|
|
22558
|
-
|
|
22559
|
-
|
|
22560
|
-
|
|
22561
|
-
*/
|
|
22562
|
-
class ResolveIcuPlaceholdersVisitor extends RecurseVisitor {
|
|
22563
|
-
constructor(params) {
|
|
22564
|
-
super();
|
|
22565
|
-
this.params = params;
|
|
22566
|
-
}
|
|
22567
|
-
visitContainerPlaceholder(placeholder) {
|
|
22568
|
-
// Add the start and end source span for container placeholders. These need to be recorded for
|
|
22569
|
-
// elements inside ICUs. The slots for the nodes were recorded separately under the i18n
|
|
22570
|
-
// block's context as part of the `resolveI18nElementPlaceholders` phase.
|
|
22571
|
-
if (placeholder.startName && placeholder.startSourceSpan &&
|
|
22572
|
-
!this.params.has(placeholder.startName)) {
|
|
22573
|
-
this.params.set(placeholder.startName, [{
|
|
22574
|
-
value: placeholder.startSourceSpan?.toString(),
|
|
22575
|
-
subTemplateIndex: null,
|
|
22576
|
-
flags: I18nParamValueFlags.None
|
|
22577
|
-
}]);
|
|
22578
|
-
}
|
|
22579
|
-
if (placeholder.closeName && placeholder.endSourceSpan &&
|
|
22580
|
-
!this.params.has(placeholder.closeName)) {
|
|
22581
|
-
this.params.set(placeholder.closeName, [{
|
|
22582
|
-
value: placeholder.endSourceSpan?.toString(),
|
|
22583
|
-
subTemplateIndex: null,
|
|
22584
|
-
flags: I18nParamValueFlags.None
|
|
22585
|
-
}]);
|
|
22586
|
-
}
|
|
22587
|
-
}
|
|
22588
|
-
visitTagPlaceholder(placeholder) {
|
|
22589
|
-
super.visitTagPlaceholder(placeholder);
|
|
22590
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22591
|
-
}
|
|
22592
|
-
visitBlockPlaceholder(placeholder) {
|
|
22593
|
-
super.visitBlockPlaceholder(placeholder);
|
|
22594
|
-
this.visitContainerPlaceholder(placeholder);
|
|
22750
|
+
if (op.icuPlaceholder !== null) {
|
|
22751
|
+
const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
|
|
22752
|
+
icuPlaceholderOp?.expressionPlaceholders.push(value);
|
|
22595
22753
|
}
|
|
22596
22754
|
}
|
|
22597
22755
|
|
|
@@ -23043,6 +23201,9 @@ function generateTrackFns(job) {
|
|
|
23043
23201
|
// Find all component context reads.
|
|
23044
23202
|
let usesComponentContext = false;
|
|
23045
23203
|
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
23204
|
+
if (expr instanceof PipeBindingExpr || expr instanceof PipeBindingVariadicExpr) {
|
|
23205
|
+
throw new Error(`Illegal State: Pipes are not allowed in this context`);
|
|
23206
|
+
}
|
|
23046
23207
|
if (expr instanceof TrackContextExpr) {
|
|
23047
23208
|
usesComponentContext = true;
|
|
23048
23209
|
return variable('this');
|
|
@@ -23266,7 +23427,14 @@ function varsUsedByOp(op) {
|
|
|
23266
23427
|
return op.interpolation.expressions.length;
|
|
23267
23428
|
case OpKind.I18nExpression:
|
|
23268
23429
|
case OpKind.Conditional:
|
|
23430
|
+
case OpKind.DeferWhen:
|
|
23269
23431
|
return 1;
|
|
23432
|
+
case OpKind.RepeaterCreate:
|
|
23433
|
+
// Repeaters may require an extra variable binding slot, if they have an empty view, for the
|
|
23434
|
+
// empty block tracking.
|
|
23435
|
+
// TODO: It's a bit odd to have a create mode instruction consume variable slots. Maybe we can
|
|
23436
|
+
// find a way to use the Repeater update op instead.
|
|
23437
|
+
return op.emptyView ? 1 : 0;
|
|
23270
23438
|
default:
|
|
23271
23439
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
23272
23440
|
}
|
|
@@ -23722,12 +23890,13 @@ function wrapI18nIcus(job) {
|
|
|
23722
23890
|
case OpKind.IcuStart:
|
|
23723
23891
|
if (currentI18nOp === null) {
|
|
23724
23892
|
addedI18nId = job.allocateXrefId();
|
|
23725
|
-
|
|
23893
|
+
// ICU i18n start/end ops should not recieve source spans.
|
|
23894
|
+
OpList.insertBefore(createI18nStartOp(addedI18nId, op.message, undefined, null), op);
|
|
23726
23895
|
}
|
|
23727
23896
|
break;
|
|
23728
23897
|
case OpKind.IcuEnd:
|
|
23729
23898
|
if (addedI18nId !== null) {
|
|
23730
|
-
OpList.insertAfter(createI18nEndOp(addedI18nId), op);
|
|
23899
|
+
OpList.insertAfter(createI18nEndOp(addedI18nId, null), op);
|
|
23731
23900
|
addedI18nId = null;
|
|
23732
23901
|
}
|
|
23733
23902
|
break;
|
|
@@ -23750,6 +23919,7 @@ const phases = [
|
|
|
23750
23919
|
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
23751
23920
|
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
23752
23921
|
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
23922
|
+
{ kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
|
|
23753
23923
|
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
23754
23924
|
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
23755
23925
|
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
@@ -23773,7 +23943,6 @@ const phases = [
|
|
|
23773
23943
|
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
23774
23944
|
{ kind: CompilationJobKind.Both, fn: deleteAnyCasts },
|
|
23775
23945
|
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
23776
|
-
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
23777
23946
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
23778
23947
|
{ kind: CompilationJobKind.Both, fn: resolveNames },
|
|
23779
23948
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
@@ -23788,7 +23957,6 @@ const phases = [
|
|
|
23788
23957
|
{ kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
|
|
23789
23958
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
23790
23959
|
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
23791
|
-
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nIcuPlaceholders },
|
|
23792
23960
|
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
23793
23961
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
23794
23962
|
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
@@ -23948,7 +24116,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23948
24116
|
const securityContexts = bindingParser
|
|
23949
24117
|
.calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
|
|
23950
24118
|
.filter(context => context !== SecurityContext.NONE);
|
|
23951
|
-
ingestHostProperty(job, property, bindingKind,
|
|
24119
|
+
ingestHostProperty(job, property, bindingKind, securityContexts);
|
|
23952
24120
|
}
|
|
23953
24121
|
for (const [name, expr] of Object.entries(input.attributes) ?? []) {
|
|
23954
24122
|
const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true)
|
|
@@ -23962,7 +24130,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
|
|
|
23962
24130
|
}
|
|
23963
24131
|
// TODO: We should refactor the parser to use the same types and structures for host bindings as
|
|
23964
24132
|
// with ordinary components. This would allow us to share a lot more ingestion code.
|
|
23965
|
-
function ingestHostProperty(job, property, bindingKind,
|
|
24133
|
+
function ingestHostProperty(job, property, bindingKind, securityContexts) {
|
|
23966
24134
|
let expression;
|
|
23967
24135
|
const ast = property.expression.ast;
|
|
23968
24136
|
if (ast instanceof Interpolation$1) {
|
|
@@ -23971,20 +24139,21 @@ function ingestHostProperty(job, property, bindingKind, isTextAttribute, securit
|
|
|
23971
24139
|
else {
|
|
23972
24140
|
expression = convertAst(ast, job, property.sourceSpan);
|
|
23973
24141
|
}
|
|
23974
|
-
job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts,
|
|
24142
|
+
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));
|
|
23975
24143
|
}
|
|
23976
24144
|
function ingestHostAttribute(job, name, value, securityContexts) {
|
|
23977
|
-
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
|
|
24145
|
+
const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
|
|
24146
|
+
/* Host attributes should always be extracted to const hostAttrs, even if they are not
|
|
24147
|
+
*strictly* text literals */
|
|
24148
|
+
true, false, null,
|
|
23978
24149
|
/* TODO */ null,
|
|
23979
|
-
|
|
24150
|
+
/** TODO: May be null? */ value.sourceSpan);
|
|
23980
24151
|
job.root.update.push(attrBinding);
|
|
23981
24152
|
}
|
|
23982
24153
|
function ingestHostEvent(job, event) {
|
|
23983
24154
|
const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
|
|
23984
24155
|
[event.targetOrPhase, null];
|
|
23985
|
-
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null,
|
|
23986
|
-
// TODO: Can this be a chain?
|
|
23987
|
-
eventBinding.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(event.handler.ast, job, event.sourceSpan), event.handlerSpan)));
|
|
24156
|
+
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
|
|
23988
24157
|
job.root.create.push(eventBinding);
|
|
23989
24158
|
}
|
|
23990
24159
|
/**
|
|
@@ -24002,10 +24171,10 @@ function ingestNodes(unit, template) {
|
|
|
24002
24171
|
ingestContent(unit, node);
|
|
24003
24172
|
}
|
|
24004
24173
|
else if (node instanceof Text$3) {
|
|
24005
|
-
ingestText(unit, node);
|
|
24174
|
+
ingestText(unit, node, null);
|
|
24006
24175
|
}
|
|
24007
24176
|
else if (node instanceof BoundText) {
|
|
24008
|
-
ingestBoundText(unit, node);
|
|
24177
|
+
ingestBoundText(unit, node, null);
|
|
24009
24178
|
}
|
|
24010
24179
|
else if (node instanceof IfBlock) {
|
|
24011
24180
|
ingestIfBlock(unit, node);
|
|
@@ -24037,7 +24206,7 @@ function ingestElement(unit, element) {
|
|
|
24037
24206
|
}
|
|
24038
24207
|
const id = unit.job.allocateXrefId();
|
|
24039
24208
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
24040
|
-
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
24209
|
+
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
|
|
24041
24210
|
unit.create.push(startOp);
|
|
24042
24211
|
ingestElementBindings(unit, startOp, element);
|
|
24043
24212
|
ingestReferences(startOp, element);
|
|
@@ -24045,7 +24214,7 @@ function ingestElement(unit, element) {
|
|
|
24045
24214
|
let i18nBlockId = null;
|
|
24046
24215
|
if (element.i18n instanceof Message) {
|
|
24047
24216
|
i18nBlockId = unit.job.allocateXrefId();
|
|
24048
|
-
unit.create.push(createI18nStartOp(i18nBlockId, element.i18n));
|
|
24217
|
+
unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
|
|
24049
24218
|
}
|
|
24050
24219
|
ingestNodes(unit, element.children);
|
|
24051
24220
|
// The source span for the end op is typically the element closing tag. However, if no closing tag
|
|
@@ -24057,7 +24226,7 @@ function ingestElement(unit, element) {
|
|
|
24057
24226
|
unit.create.push(endOp);
|
|
24058
24227
|
// If there is an i18n message associated with this element, insert i18n start and end ops.
|
|
24059
24228
|
if (i18nBlockId !== null) {
|
|
24060
|
-
OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
|
|
24229
|
+
OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
|
|
24061
24230
|
}
|
|
24062
24231
|
}
|
|
24063
24232
|
/**
|
|
@@ -24080,7 +24249,7 @@ function ingestTemplate(unit, tmpl) {
|
|
|
24080
24249
|
'' :
|
|
24081
24250
|
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
24082
24251
|
const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
|
|
24083
|
-
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
24252
|
+
const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
|
|
24084
24253
|
unit.create.push(templateOp);
|
|
24085
24254
|
ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
|
|
24086
24255
|
ingestReferences(templateOp, tmpl);
|
|
@@ -24093,8 +24262,8 @@ function ingestTemplate(unit, tmpl) {
|
|
|
24093
24262
|
// element/template the directive is placed on.
|
|
24094
24263
|
if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
|
|
24095
24264
|
const id = unit.job.allocateXrefId();
|
|
24096
|
-
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
24097
|
-
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
24265
|
+
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n, undefined, tmpl.startSourceSpan), childView.create.head);
|
|
24266
|
+
OpList.insertBefore(createI18nEndOp(id, tmpl.endSourceSpan ?? tmpl.startSourceSpan), childView.create.tail);
|
|
24098
24267
|
}
|
|
24099
24268
|
}
|
|
24100
24269
|
/**
|
|
@@ -24104,8 +24273,7 @@ function ingestContent(unit, content) {
|
|
|
24104
24273
|
if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
|
|
24105
24274
|
throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
|
|
24106
24275
|
}
|
|
24107
|
-
const
|
|
24108
|
-
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, attrs, content.sourceSpan);
|
|
24276
|
+
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, content.sourceSpan);
|
|
24109
24277
|
for (const attr of content.attributes) {
|
|
24110
24278
|
const securityContext = domSchema.securityContext(content.name, attr.name, true);
|
|
24111
24279
|
unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
@@ -24115,13 +24283,13 @@ function ingestContent(unit, content) {
|
|
|
24115
24283
|
/**
|
|
24116
24284
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
24117
24285
|
*/
|
|
24118
|
-
function ingestText(unit, text) {
|
|
24119
|
-
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, text.sourceSpan));
|
|
24286
|
+
function ingestText(unit, text, icuPlaceholder) {
|
|
24287
|
+
unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, icuPlaceholder, text.sourceSpan));
|
|
24120
24288
|
}
|
|
24121
24289
|
/**
|
|
24122
24290
|
* Ingest an interpolated text node from the AST into the given `ViewCompilation`.
|
|
24123
24291
|
*/
|
|
24124
|
-
function ingestBoundText(unit, text,
|
|
24292
|
+
function ingestBoundText(unit, text, icuPlaceholder) {
|
|
24125
24293
|
let value = text.value;
|
|
24126
24294
|
if (value instanceof ASTWithSource) {
|
|
24127
24295
|
value = value.ast;
|
|
@@ -24132,19 +24300,16 @@ function ingestBoundText(unit, text, i18nPlaceholders) {
|
|
|
24132
24300
|
if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
|
|
24133
24301
|
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
24134
24302
|
}
|
|
24135
|
-
|
|
24136
|
-
|
|
24137
|
-
|
|
24138
|
-
|
|
24139
|
-
|
|
24140
|
-
.map(placeholder => placeholder.name) :
|
|
24141
|
-
[];
|
|
24142
|
-
}
|
|
24303
|
+
const i18nPlaceholders = text.i18n instanceof Container ?
|
|
24304
|
+
text.i18n.children
|
|
24305
|
+
.filter((node) => node instanceof Placeholder)
|
|
24306
|
+
.map(placeholder => placeholder.name) :
|
|
24307
|
+
[];
|
|
24143
24308
|
if (i18nPlaceholders.length > 0 && i18nPlaceholders.length !== value.expressions.length) {
|
|
24144
24309
|
throw Error(`Unexpected number of i18n placeholders (${value.expressions.length}) for BoundText with ${value.expressions.length} expressions`);
|
|
24145
24310
|
}
|
|
24146
24311
|
const textXref = unit.job.allocateXrefId();
|
|
24147
|
-
unit.create.push(createTextOp(textXref, '', text.sourceSpan));
|
|
24312
|
+
unit.create.push(createTextOp(textXref, '', icuPlaceholder, text.sourceSpan));
|
|
24148
24313
|
// TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
|
|
24149
24314
|
// interpolation. We copy that behavior in compatibility mode.
|
|
24150
24315
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
@@ -24177,7 +24342,7 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
24177
24342
|
}
|
|
24178
24343
|
ifCaseI18nMeta = ifCase.i18n;
|
|
24179
24344
|
}
|
|
24180
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.sourceSpan);
|
|
24345
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
|
|
24181
24346
|
unit.create.push(templateOp);
|
|
24182
24347
|
if (firstXref === null) {
|
|
24183
24348
|
firstXref = cView.xref;
|
|
@@ -24195,6 +24360,10 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
24195
24360
|
* Ingest an `@switch` block into the given `ViewCompilation`.
|
|
24196
24361
|
*/
|
|
24197
24362
|
function ingestSwitchBlock(unit, switchBlock) {
|
|
24363
|
+
// Don't ingest empty switches since they won't render anything.
|
|
24364
|
+
if (switchBlock.cases.length === 0) {
|
|
24365
|
+
return;
|
|
24366
|
+
}
|
|
24198
24367
|
let firstXref = null;
|
|
24199
24368
|
let firstSlotHandle = null;
|
|
24200
24369
|
let conditions = [];
|
|
@@ -24207,7 +24376,7 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
24207
24376
|
}
|
|
24208
24377
|
switchCaseI18nMeta = switchCase.i18n;
|
|
24209
24378
|
}
|
|
24210
|
-
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.sourceSpan);
|
|
24379
|
+
const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
|
|
24211
24380
|
unit.create.push(templateOp);
|
|
24212
24381
|
if (firstXref === null) {
|
|
24213
24382
|
firstXref = cView.xref;
|
|
@@ -24232,7 +24401,7 @@ function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
|
|
|
24232
24401
|
}
|
|
24233
24402
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
24234
24403
|
ingestNodes(secondaryView, children);
|
|
24235
|
-
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan);
|
|
24404
|
+
const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan, sourceSpan);
|
|
24236
24405
|
unit.create.push(templateOp);
|
|
24237
24406
|
return templateOp;
|
|
24238
24407
|
}
|
|
@@ -24310,6 +24479,11 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
24310
24479
|
deferOnOps.push(deferOnOp);
|
|
24311
24480
|
}
|
|
24312
24481
|
if (triggers.when !== undefined) {
|
|
24482
|
+
if (triggers.when.value instanceof Interpolation$1) {
|
|
24483
|
+
// TemplateDefinitionBuilder supports this case, but it's very strange to me. What would it
|
|
24484
|
+
// even mean?
|
|
24485
|
+
throw new Error(`Unexpected interpolation in defer block when trigger`);
|
|
24486
|
+
}
|
|
24313
24487
|
const deferOnOp = createDeferWhenOp(deferXref, convertAst(triggers.when.value, unit.job, triggers.when.sourceSpan), prefetch, triggers.when.sourceSpan);
|
|
24314
24488
|
deferWhenOps.push(deferOnOp);
|
|
24315
24489
|
}
|
|
@@ -24329,10 +24503,10 @@ function ingestIcu(unit, icu) {
|
|
|
24329
24503
|
unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
|
|
24330
24504
|
for (const [placeholder, text] of Object.entries({ ...icu.vars, ...icu.placeholders })) {
|
|
24331
24505
|
if (text instanceof BoundText) {
|
|
24332
|
-
ingestBoundText(unit, text,
|
|
24506
|
+
ingestBoundText(unit, text, placeholder);
|
|
24333
24507
|
}
|
|
24334
24508
|
else {
|
|
24335
|
-
ingestText(unit, text);
|
|
24509
|
+
ingestText(unit, text, placeholder);
|
|
24336
24510
|
}
|
|
24337
24511
|
}
|
|
24338
24512
|
unit.create.push(createIcuEndOp(xref));
|
|
@@ -24346,29 +24520,52 @@ function ingestIcu(unit, icu) {
|
|
|
24346
24520
|
*/
|
|
24347
24521
|
function ingestForBlock(unit, forBlock) {
|
|
24348
24522
|
const repeaterView = unit.job.allocateView(unit.xref);
|
|
24349
|
-
const createRepeaterAlias = (ident, repeaterVar) => {
|
|
24350
|
-
repeaterView.aliases.add({
|
|
24351
|
-
kind: SemanticVariableKind.Alias,
|
|
24352
|
-
name: null,
|
|
24353
|
-
identifier: ident,
|
|
24354
|
-
expression: new DerivedRepeaterVarExpr(repeaterView.xref, repeaterVar),
|
|
24355
|
-
});
|
|
24356
|
-
};
|
|
24357
24523
|
// Set all the context variables and aliases available in the repeater.
|
|
24358
24524
|
repeaterView.contextVariables.set(forBlock.item.name, forBlock.item.value);
|
|
24359
24525
|
repeaterView.contextVariables.set(forBlock.contextVariables.$index.name, forBlock.contextVariables.$index.value);
|
|
24360
24526
|
repeaterView.contextVariables.set(forBlock.contextVariables.$count.name, forBlock.contextVariables.$count.value);
|
|
24361
|
-
|
|
24362
|
-
|
|
24363
|
-
|
|
24364
|
-
|
|
24527
|
+
// We copy TemplateDefinitionBuilder's scheme of creating names for `$count` and `$index` that are
|
|
24528
|
+
// suffixed with special information, to disambiguate which level of nested loop the below aliases
|
|
24529
|
+
// refer to.
|
|
24530
|
+
// TODO: We should refactor Template Pipeline's variable phases to gracefully handle shadowing,
|
|
24531
|
+
// and arbitrarily many levels of variables depending on each other.
|
|
24532
|
+
const indexName = `ɵ${forBlock.contextVariables.$index.name}_${repeaterView.xref}`;
|
|
24533
|
+
const countName = `ɵ${forBlock.contextVariables.$count.name}_${repeaterView.xref}`;
|
|
24534
|
+
repeaterView.contextVariables.set(indexName, forBlock.contextVariables.$index.value);
|
|
24535
|
+
repeaterView.contextVariables.set(countName, forBlock.contextVariables.$count.value);
|
|
24536
|
+
repeaterView.aliases.add({
|
|
24537
|
+
kind: SemanticVariableKind.Alias,
|
|
24538
|
+
name: null,
|
|
24539
|
+
identifier: forBlock.contextVariables.$first.name,
|
|
24540
|
+
expression: new LexicalReadExpr(indexName).identical(literal(0))
|
|
24541
|
+
});
|
|
24542
|
+
repeaterView.aliases.add({
|
|
24543
|
+
kind: SemanticVariableKind.Alias,
|
|
24544
|
+
name: null,
|
|
24545
|
+
identifier: forBlock.contextVariables.$last.name,
|
|
24546
|
+
expression: new LexicalReadExpr(indexName).identical(new LexicalReadExpr(countName).minus(literal(1)))
|
|
24547
|
+
});
|
|
24548
|
+
repeaterView.aliases.add({
|
|
24549
|
+
kind: SemanticVariableKind.Alias,
|
|
24550
|
+
name: null,
|
|
24551
|
+
identifier: forBlock.contextVariables.$even.name,
|
|
24552
|
+
expression: new LexicalReadExpr(indexName).modulo(literal(2)).identical(literal(0))
|
|
24553
|
+
});
|
|
24554
|
+
repeaterView.aliases.add({
|
|
24555
|
+
kind: SemanticVariableKind.Alias,
|
|
24556
|
+
name: null,
|
|
24557
|
+
identifier: forBlock.contextVariables.$odd.name,
|
|
24558
|
+
expression: new LexicalReadExpr(indexName).modulo(literal(2)).notIdentical(literal(0))
|
|
24559
|
+
});
|
|
24365
24560
|
const sourceSpan = convertSourceSpan(forBlock.trackBy.span, forBlock.sourceSpan);
|
|
24366
24561
|
const track = convertAst(forBlock.trackBy, unit.job, sourceSpan);
|
|
24367
24562
|
ingestNodes(repeaterView, forBlock.children);
|
|
24368
24563
|
let emptyView = null;
|
|
24564
|
+
let emptyTagName = null;
|
|
24369
24565
|
if (forBlock.empty !== null) {
|
|
24370
24566
|
emptyView = unit.job.allocateView(unit.xref);
|
|
24371
24567
|
ingestNodes(emptyView, forBlock.empty.children);
|
|
24568
|
+
emptyTagName = ingestControlFlowInsertionPoint(unit, emptyView.xref, forBlock.empty);
|
|
24372
24569
|
}
|
|
24373
24570
|
const varNames = {
|
|
24374
24571
|
$index: forBlock.contextVariables.$index.name,
|
|
@@ -24389,7 +24586,7 @@ function ingestForBlock(unit, forBlock) {
|
|
|
24389
24586
|
const i18nPlaceholder = forBlock.i18n;
|
|
24390
24587
|
const emptyI18nPlaceholder = forBlock.empty?.i18n;
|
|
24391
24588
|
const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
|
|
24392
|
-
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, forBlock.sourceSpan);
|
|
24589
|
+
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, emptyTagName, i18nPlaceholder, emptyI18nPlaceholder, forBlock.startSourceSpan, forBlock.sourceSpan);
|
|
24393
24590
|
unit.create.push(repeaterCreate);
|
|
24394
24591
|
const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
|
|
24395
24592
|
const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
|
|
@@ -24403,7 +24600,29 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24403
24600
|
return convertAst(ast.ast, job, baseSourceSpan);
|
|
24404
24601
|
}
|
|
24405
24602
|
else if (ast instanceof PropertyRead) {
|
|
24406
|
-
|
|
24603
|
+
const isThisReceiver = ast.receiver instanceof ThisReceiver;
|
|
24604
|
+
// Whether this is an implicit receiver, *excluding* explicit reads of `this`.
|
|
24605
|
+
const isImplicitReceiver = ast.receiver instanceof ImplicitReceiver && !(ast.receiver instanceof ThisReceiver);
|
|
24606
|
+
// Whether the name of the read is a node that should be never retain its explicit this
|
|
24607
|
+
// receiver.
|
|
24608
|
+
const isSpecialNode = ast.name === '$any' || ast.name === '$event';
|
|
24609
|
+
// TODO: The most sensible condition here would be simply `isImplicitReceiver`, to convert only
|
|
24610
|
+
// actual implicit `this` reads, and not explicit ones. However, TemplateDefinitionBuilder (and
|
|
24611
|
+
// the Typecheck block!) both have the same bug, in which they also consider explicit `this`
|
|
24612
|
+
// reads to be implicit. This causes problems when the explicit `this` read is inside a
|
|
24613
|
+
// template with a context that also provides the variable name being read:
|
|
24614
|
+
// ```
|
|
24615
|
+
// <ng-template let-a>{{this.a}}</ng-template>
|
|
24616
|
+
// ```
|
|
24617
|
+
// The whole point of the explicit `this` was to access the class property, but TDB and the
|
|
24618
|
+
// current TCB treat the read as implicit, and give you the context property instead!
|
|
24619
|
+
//
|
|
24620
|
+
// For now, we emulate this old behvaior by aggressively converting explicit reads to to
|
|
24621
|
+
// implicit reads, except for the special cases that TDB and the current TCB protect. However,
|
|
24622
|
+
// it would be an improvement to fix this.
|
|
24623
|
+
//
|
|
24624
|
+
// See also the corresponding comment for the TCB, in `type_check_block.ts`.
|
|
24625
|
+
if (isImplicitReceiver || (isThisReceiver && !isSpecialNode)) {
|
|
24407
24626
|
return new LexicalReadExpr(ast.name);
|
|
24408
24627
|
}
|
|
24409
24628
|
else {
|
|
@@ -24507,13 +24726,13 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
24507
24726
|
throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
|
|
24508
24727
|
}
|
|
24509
24728
|
}
|
|
24510
|
-
function convertAstWithInterpolation(job, value, i18nMeta) {
|
|
24729
|
+
function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
|
|
24511
24730
|
let expression;
|
|
24512
24731
|
if (value instanceof Interpolation$1) {
|
|
24513
|
-
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24732
|
+
expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, sourceSpan ?? null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
|
|
24514
24733
|
}
|
|
24515
24734
|
else if (value instanceof AST) {
|
|
24516
|
-
expression = convertAst(value, job, null);
|
|
24735
|
+
expression = convertAst(value, job, sourceSpan ?? null);
|
|
24517
24736
|
}
|
|
24518
24737
|
else {
|
|
24519
24738
|
expression = literal(value);
|
|
@@ -24626,7 +24845,7 @@ function ingestTemplateBindings(unit, op, template, templateKind) {
|
|
|
24626
24845
|
output.type !== 1 /* e.ParsedEventType.Animation */) {
|
|
24627
24846
|
// Animation bindings are excluded from the structural template's const array.
|
|
24628
24847
|
const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
|
|
24629
|
-
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null, null, securityContext));
|
|
24848
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, null, output.name, null, null, null, securityContext));
|
|
24630
24849
|
}
|
|
24631
24850
|
}
|
|
24632
24851
|
// TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
|
|
@@ -24674,7 +24893,7 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
|
|
|
24674
24893
|
// inner node of a structural template. We can't skip it entirely, because we still need it on
|
|
24675
24894
|
// the ng-template's consts (e.g. for the purposes of directive matching). However, we should
|
|
24676
24895
|
// not generate an update instruction for it.
|
|
24677
|
-
return createExtractedAttributeOp(xref, BindingKind.Property, name, null, null, i18nMessage, securityContext);
|
|
24896
|
+
return createExtractedAttributeOp(xref, BindingKind.Property, null, name, null, null, i18nMessage, securityContext);
|
|
24678
24897
|
}
|
|
24679
24898
|
if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
|
|
24680
24899
|
// Again, this binding doesn't really target the ng-template; it actually targets the element
|
|
@@ -28476,6 +28695,9 @@ class TemplateDefinitionBuilder {
|
|
|
28476
28695
|
this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
|
|
28477
28696
|
}
|
|
28478
28697
|
visitSwitchBlock(block) {
|
|
28698
|
+
if (block.cases.length === 0) {
|
|
28699
|
+
return;
|
|
28700
|
+
}
|
|
28479
28701
|
// We have to process the block in two steps: once here and again in the update instruction
|
|
28480
28702
|
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
28481
28703
|
const caseData = block.cases.map(currentCase => {
|
|
@@ -28705,7 +28927,12 @@ class TemplateDefinitionBuilder {
|
|
|
28705
28927
|
});
|
|
28706
28928
|
const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
|
|
28707
28929
|
let emptyData = null;
|
|
28930
|
+
let emptyTagName = null;
|
|
28931
|
+
let emptyAttrsExprs;
|
|
28708
28932
|
if (block.empty !== null) {
|
|
28933
|
+
const emptyInferred = this.inferProjectionDataFromInsertionPoint(block.empty);
|
|
28934
|
+
emptyTagName = emptyInferred.tagName;
|
|
28935
|
+
emptyAttrsExprs = emptyInferred.attrsExprs;
|
|
28709
28936
|
emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty', undefined, block.empty.i18n);
|
|
28710
28937
|
// Allocate an extra slot for the empty block tracking.
|
|
28711
28938
|
this.allocateBindingSlots(null);
|
|
@@ -28723,13 +28950,13 @@ class TemplateDefinitionBuilder {
|
|
|
28723
28950
|
trackByExpression,
|
|
28724
28951
|
];
|
|
28725
28952
|
if (emptyData !== null) {
|
|
28726
|
-
params.push(literal(trackByUsesComponentInstance), variable(emptyData.name), literal(emptyData.getConstCount()), literal(emptyData.getVarCount()));
|
|
28953
|
+
params.push(literal(trackByUsesComponentInstance), variable(emptyData.name), literal(emptyData.getConstCount()), literal(emptyData.getVarCount()), literal(emptyTagName), this.addAttrsToConsts(emptyAttrsExprs || null));
|
|
28727
28954
|
}
|
|
28728
28955
|
else if (trackByUsesComponentInstance) {
|
|
28729
28956
|
// If the tracking function doesn't use the component instance, we can omit the flag.
|
|
28730
28957
|
params.push(literal(trackByUsesComponentInstance));
|
|
28731
28958
|
}
|
|
28732
|
-
return params;
|
|
28959
|
+
return trimTrailingNulls(params);
|
|
28733
28960
|
});
|
|
28734
28961
|
// Note: the expression needs to be processed *after* the template,
|
|
28735
28962
|
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
@@ -28934,7 +29161,7 @@ class TemplateDefinitionBuilder {
|
|
|
28934
29161
|
if (delta < 1) {
|
|
28935
29162
|
throw new Error('advance instruction can only go forwards');
|
|
28936
29163
|
}
|
|
28937
|
-
this.instructionFn(this._updateCodeFns, span, Identifiers.advance, [literal(delta)]);
|
|
29164
|
+
this.instructionFn(this._updateCodeFns, span, Identifiers.advance, delta > 1 ? [literal(delta)] : []);
|
|
28938
29165
|
this._currentIndex = nodeIndex;
|
|
28939
29166
|
}
|
|
28940
29167
|
}
|
|
@@ -29488,12 +29715,16 @@ class BindingScope {
|
|
|
29488
29715
|
}
|
|
29489
29716
|
/** Binding scope of a `track` function inside a `for` loop block. */
|
|
29490
29717
|
class TrackByBindingScope extends BindingScope {
|
|
29491
|
-
constructor(parentScope,
|
|
29718
|
+
constructor(parentScope, globalOverrides) {
|
|
29492
29719
|
super(parentScope.bindingLevel + 1, parentScope);
|
|
29493
|
-
this.
|
|
29720
|
+
this.globalOverrides = globalOverrides;
|
|
29494
29721
|
this.componentAccessCount = 0;
|
|
29495
29722
|
}
|
|
29496
29723
|
get(name) {
|
|
29724
|
+
// Intercept any overridden globals.
|
|
29725
|
+
if (this.globalOverrides.hasOwnProperty(name)) {
|
|
29726
|
+
return variable(this.globalOverrides[name]);
|
|
29727
|
+
}
|
|
29497
29728
|
let current = this.parent;
|
|
29498
29729
|
// Prevent accesses of template variables outside the `for` loop.
|
|
29499
29730
|
while (current) {
|
|
@@ -29502,10 +29733,6 @@ class TrackByBindingScope extends BindingScope {
|
|
|
29502
29733
|
}
|
|
29503
29734
|
current = current.parent;
|
|
29504
29735
|
}
|
|
29505
|
-
// Intercept any aliased globals.
|
|
29506
|
-
if (this.globalAliases[name]) {
|
|
29507
|
-
return variable(this.globalAliases[name]);
|
|
29508
|
-
}
|
|
29509
29736
|
// When the component scope is accessed, we redirect it through `this`.
|
|
29510
29737
|
this.componentAccessCount++;
|
|
29511
29738
|
return variable('this').prop(name);
|
|
@@ -31633,8 +31860,10 @@ function convertDirectiveFacadeToMetadata(facade) {
|
|
|
31633
31860
|
bindingPropertyName: ann.alias || field,
|
|
31634
31861
|
classPropertyName: field,
|
|
31635
31862
|
required: ann.required || false,
|
|
31636
|
-
//
|
|
31637
|
-
|
|
31863
|
+
// For JIT, decorators are used to declare signal inputs. That is because of
|
|
31864
|
+
// a technical limitation where it's not possible to statically reflect class
|
|
31865
|
+
// members of a directive/component at runtime before instantiating the class.
|
|
31866
|
+
isSignal: !!ann.isSignal,
|
|
31638
31867
|
transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null,
|
|
31639
31868
|
};
|
|
31640
31869
|
}
|
|
@@ -32046,7 +32275,7 @@ function publishFacade(global) {
|
|
|
32046
32275
|
* @description
|
|
32047
32276
|
* Entry point for all public APIs of the compiler package.
|
|
32048
32277
|
*/
|
|
32049
|
-
const VERSION = new Version('17.1.0-
|
|
32278
|
+
const VERSION = new Version('17.1.0-rc.0');
|
|
32050
32279
|
|
|
32051
32280
|
class CompilerConfig {
|
|
32052
32281
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -33612,7 +33841,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
|
|
|
33612
33841
|
function compileDeclareClassMetadata(metadata) {
|
|
33613
33842
|
const definitionMap = new DefinitionMap();
|
|
33614
33843
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
33615
|
-
definitionMap.set('version', literal('17.1.0-
|
|
33844
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
33616
33845
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
33617
33846
|
definitionMap.set('type', metadata.type);
|
|
33618
33847
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -33708,7 +33937,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
33708
33937
|
const definitionMap = new DefinitionMap();
|
|
33709
33938
|
const minVersion = getMinimumVersionForPartialOutput(meta);
|
|
33710
33939
|
definitionMap.set('minVersion', literal(minVersion));
|
|
33711
|
-
definitionMap.set('version', literal('17.1.0-
|
|
33940
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
33712
33941
|
// e.g. `type: MyDirective`
|
|
33713
33942
|
definitionMap.set('type', meta.type.value);
|
|
33714
33943
|
if (meta.isStandalone) {
|
|
@@ -33766,8 +33995,8 @@ function getMinimumVersionForPartialOutput(meta) {
|
|
|
33766
33995
|
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
33767
33996
|
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
33768
33997
|
// in 16.1 is actually used.
|
|
33769
|
-
const
|
|
33770
|
-
if (
|
|
33998
|
+
const hasDecoratorTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
|
|
33999
|
+
if (hasDecoratorTransformFunctions) {
|
|
33771
34000
|
minVersion = '16.1.0';
|
|
33772
34001
|
}
|
|
33773
34002
|
// If there are input flags and we need the new emit, use the actual minimum version,
|
|
@@ -34092,7 +34321,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
34092
34321
|
function compileDeclareFactoryFunction(meta) {
|
|
34093
34322
|
const definitionMap = new DefinitionMap();
|
|
34094
34323
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
34095
|
-
definitionMap.set('version', literal('17.1.0-
|
|
34324
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
34096
34325
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34097
34326
|
definitionMap.set('type', meta.type.value);
|
|
34098
34327
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -34127,7 +34356,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
34127
34356
|
function createInjectableDefinitionMap(meta) {
|
|
34128
34357
|
const definitionMap = new DefinitionMap();
|
|
34129
34358
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
34130
|
-
definitionMap.set('version', literal('17.1.0-
|
|
34359
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
34131
34360
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34132
34361
|
definitionMap.set('type', meta.type.value);
|
|
34133
34362
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -34178,7 +34407,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
34178
34407
|
function createInjectorDefinitionMap(meta) {
|
|
34179
34408
|
const definitionMap = new DefinitionMap();
|
|
34180
34409
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
34181
|
-
definitionMap.set('version', literal('17.1.0-
|
|
34410
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
34182
34411
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34183
34412
|
definitionMap.set('type', meta.type.value);
|
|
34184
34413
|
definitionMap.set('providers', meta.providers);
|
|
@@ -34211,7 +34440,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
34211
34440
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
34212
34441
|
}
|
|
34213
34442
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
34214
|
-
definitionMap.set('version', literal('17.1.0-
|
|
34443
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
34215
34444
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34216
34445
|
definitionMap.set('type', meta.type.value);
|
|
34217
34446
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -34262,7 +34491,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
34262
34491
|
function createPipeDefinitionMap(meta) {
|
|
34263
34492
|
const definitionMap = new DefinitionMap();
|
|
34264
34493
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
34265
|
-
definitionMap.set('version', literal('17.1.0-
|
|
34494
|
+
definitionMap.set('version', literal('17.1.0-rc.0'));
|
|
34266
34495
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34267
34496
|
// e.g. `type: MyPipe`
|
|
34268
34497
|
definitionMap.set('type', meta.type.value);
|