@angular/compiler 17.0.0-next.6 → 17.0.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/injectable_compiler_2.mjs +3 -6
- package/esm2022/src/jit_compiler_facade.mjs +2 -7
- package/esm2022/src/ml_parser/lexer.mjs +2 -2
- package/esm2022/src/output/abstract_emitter.mjs +8 -1
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/component.mjs +45 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_factory.mjs +2 -2
- package/esm2022/src/render3/r3_template_transform.mjs +18 -25
- package/esm2022/src/render3/util.mjs +3 -3
- package/esm2022/src/render3/view/block_syntax_switch.mjs +13 -0
- package/esm2022/src/render3/view/compiler.mjs +8 -6
- package/esm2022/src/render3/view/template.mjs +4 -6
- package/esm2022/src/render3/view/util.mjs +8 -2
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +42 -9
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +61 -16
- package/esm2022/src/template/pipeline/ir/src/operations.mjs +2 -2
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +52 -12
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +34 -4
- package/esm2022/src/template/pipeline/ir/src/traits.mjs +17 -2
- package/esm2022/src/template/pipeline/ir/src/variable.mjs +6 -2
- package/esm2022/src/template/pipeline/src/conversion.mjs +3 -2
- package/esm2022/src/template/pipeline/src/emit.mjs +10 -10
- package/esm2022/src/template/pipeline/src/ingest.mjs +157 -18
- package/esm2022/src/template/pipeline/src/instruction.mjs +34 -5
- package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +37 -0
- package/esm2022/src/template/pipeline/src/phases/chaining.mjs +13 -12
- package/esm2022/src/template/pipeline/src/phases/conditionals.mjs +22 -9
- package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +14 -3
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +19 -1
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +6 -2
- package/esm2022/src/template/pipeline/src/phases/has_const_trait_collection.mjs +34 -0
- package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +6 -1
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +3 -2
- package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +8 -8
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +31 -5
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +6 -1
- package/esm2022/src/template/pipeline/src/phases/pure_function_extraction.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +24 -9
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +79 -37
- package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +5 -5
- package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +53 -38
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +10 -1
- package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +9 -1
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1033 -467
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +5 -7
- package/package.json +2 -2
- package/testing/index.d.ts +1 -1
- package/esm2022/src/template/pipeline/src/phases/generate_i18n_blocks.mjs +0 -38
- package/esm2022/src/template/pipeline/src/phases/no_listeners_on_templates.mjs +0 -32
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-next.
|
|
2
|
+
* @license Angular v17.0.0-next.7
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -3139,7 +3139,14 @@ class AbstractEmitterVisitor {
|
|
|
3139
3139
|
return null;
|
|
3140
3140
|
}
|
|
3141
3141
|
visitInvokeFunctionExpr(expr, ctx) {
|
|
3142
|
+
const shouldParenthesize = expr.fn instanceof ArrowFunctionExpr;
|
|
3143
|
+
if (shouldParenthesize) {
|
|
3144
|
+
ctx.print(expr.fn, '(');
|
|
3145
|
+
}
|
|
3142
3146
|
expr.fn.visitExpression(this, ctx);
|
|
3147
|
+
if (shouldParenthesize) {
|
|
3148
|
+
ctx.print(expr.fn, ')');
|
|
3149
|
+
}
|
|
3143
3150
|
ctx.print(expr, `(`);
|
|
3144
3151
|
this.visitAllExpressions(expr.args, ctx, ',');
|
|
3145
3152
|
ctx.print(expr, `)`);
|
|
@@ -3438,7 +3445,7 @@ function wrapReference(value) {
|
|
|
3438
3445
|
}
|
|
3439
3446
|
function refsToArray(refs, shouldForwardDeclare) {
|
|
3440
3447
|
const values = literalArr(refs.map(ref => ref.value));
|
|
3441
|
-
return shouldForwardDeclare ?
|
|
3448
|
+
return shouldForwardDeclare ? arrowFn([], values) : values;
|
|
3442
3449
|
}
|
|
3443
3450
|
function createMayBeForwardRefExpression(expression, forwardRef) {
|
|
3444
3451
|
return { expression, forwardRef };
|
|
@@ -3471,7 +3478,7 @@ function convertFromMaybeForwardRefExpression({ expression, forwardRef }) {
|
|
|
3471
3478
|
* ```
|
|
3472
3479
|
*/
|
|
3473
3480
|
function generateForwardRef(expr) {
|
|
3474
|
-
return importExpr(Identifiers.forwardRef).callFn([
|
|
3481
|
+
return importExpr(Identifiers.forwardRef).callFn([arrowFn([], expr)]);
|
|
3475
3482
|
}
|
|
3476
3483
|
|
|
3477
3484
|
var R3FactoryDelegateType;
|
|
@@ -3559,7 +3566,7 @@ function compileFactoryFunction(meta) {
|
|
|
3559
3566
|
if (baseFactoryVar !== null) {
|
|
3560
3567
|
// There is a base factory variable so wrap its declaration along with the factory function into
|
|
3561
3568
|
// an IIFE.
|
|
3562
|
-
factoryFn =
|
|
3569
|
+
factoryFn = arrowFn([], [
|
|
3563
3570
|
new DeclareVarStmt(baseFactoryVar.name), new ReturnStatement(factoryFn)
|
|
3564
3571
|
]).callFn([], /* sourceSpan */ undefined, /* pure */ true);
|
|
3565
3572
|
}
|
|
@@ -4931,7 +4938,13 @@ class DefinitionMap {
|
|
|
4931
4938
|
}
|
|
4932
4939
|
set(key, value) {
|
|
4933
4940
|
if (value) {
|
|
4934
|
-
this.values.
|
|
4941
|
+
const existing = this.values.find(value => value.key === key);
|
|
4942
|
+
if (existing) {
|
|
4943
|
+
existing.value = value;
|
|
4944
|
+
}
|
|
4945
|
+
else {
|
|
4946
|
+
this.values.push({ key: key, value, quoted: false });
|
|
4947
|
+
}
|
|
4935
4948
|
}
|
|
4936
4949
|
}
|
|
4937
4950
|
toLiteralMap() {
|
|
@@ -5074,10 +5087,7 @@ function compileInjectable(meta, resolveForwardRefs) {
|
|
|
5074
5087
|
});
|
|
5075
5088
|
}
|
|
5076
5089
|
else {
|
|
5077
|
-
result = {
|
|
5078
|
-
statements: [],
|
|
5079
|
-
expression: fn([], [new ReturnStatement(meta.useFactory.callFn([]))])
|
|
5080
|
-
};
|
|
5090
|
+
result = { statements: [], expression: arrowFn([], meta.useFactory.callFn([])) };
|
|
5081
5091
|
}
|
|
5082
5092
|
}
|
|
5083
5093
|
else if (meta.useValue !== undefined) {
|
|
@@ -5146,7 +5156,7 @@ function delegateToFactory(type, useType, unwrapForwardRefs) {
|
|
|
5146
5156
|
return createFactoryFunction(unwrappedType);
|
|
5147
5157
|
}
|
|
5148
5158
|
function createFactoryFunction(type) {
|
|
5149
|
-
return
|
|
5159
|
+
return arrowFn([new FnParam('t', DYNAMIC_TYPE)], type.prop('ɵfac').callFn([variable('t')]));
|
|
5150
5160
|
}
|
|
5151
5161
|
|
|
5152
5162
|
const UNUSABLE_INTERPOLATION_REGEXPS = [
|
|
@@ -8759,38 +8769,58 @@ var OpKind;
|
|
|
8759
8769
|
* An attribute that has been extracted for inclusion in the consts array.
|
|
8760
8770
|
*/
|
|
8761
8771
|
OpKind[OpKind["ExtractedAttribute"] = 25] = "ExtractedAttribute";
|
|
8772
|
+
/**
|
|
8773
|
+
* An operation that configures a `@defer` block.
|
|
8774
|
+
*/
|
|
8775
|
+
OpKind[OpKind["Defer"] = 26] = "Defer";
|
|
8776
|
+
/**
|
|
8777
|
+
* An IR operation that provides secondary templates of a `@defer` block.
|
|
8778
|
+
*/
|
|
8779
|
+
OpKind[OpKind["DeferSecondaryBlock"] = 27] = "DeferSecondaryBlock";
|
|
8780
|
+
/**
|
|
8781
|
+
* An operation that controls when a `@defer` loads.
|
|
8782
|
+
*/
|
|
8783
|
+
OpKind[OpKind["DeferOn"] = 28] = "DeferOn";
|
|
8762
8784
|
/**
|
|
8763
8785
|
* An i18n message that has been extracted for inclusion in the consts array.
|
|
8764
8786
|
*/
|
|
8765
|
-
OpKind[OpKind["ExtractedMessage"] =
|
|
8787
|
+
OpKind[OpKind["ExtractedMessage"] = 29] = "ExtractedMessage";
|
|
8766
8788
|
/**
|
|
8767
8789
|
* A host binding property.
|
|
8768
8790
|
*/
|
|
8769
|
-
OpKind[OpKind["HostProperty"] =
|
|
8791
|
+
OpKind[OpKind["HostProperty"] = 30] = "HostProperty";
|
|
8770
8792
|
/**
|
|
8771
8793
|
* A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
|
|
8772
8794
|
*/
|
|
8773
|
-
OpKind[OpKind["Namespace"] =
|
|
8795
|
+
OpKind[OpKind["Namespace"] = 31] = "Namespace";
|
|
8774
8796
|
/**
|
|
8775
8797
|
* Configure a content projeciton definition for the view.
|
|
8776
8798
|
*/
|
|
8777
|
-
OpKind[OpKind["ProjectionDef"] =
|
|
8799
|
+
OpKind[OpKind["ProjectionDef"] = 32] = "ProjectionDef";
|
|
8778
8800
|
/**
|
|
8779
8801
|
* Create a content projection slot.
|
|
8780
8802
|
*/
|
|
8781
|
-
OpKind[OpKind["Projection"] =
|
|
8803
|
+
OpKind[OpKind["Projection"] = 33] = "Projection";
|
|
8782
8804
|
/**
|
|
8783
8805
|
* The start of an i18n block.
|
|
8784
8806
|
*/
|
|
8785
|
-
OpKind[OpKind["I18nStart"] =
|
|
8807
|
+
OpKind[OpKind["I18nStart"] = 34] = "I18nStart";
|
|
8786
8808
|
/**
|
|
8787
8809
|
* A self-closing i18n on a single element.
|
|
8788
8810
|
*/
|
|
8789
|
-
OpKind[OpKind["I18n"] =
|
|
8811
|
+
OpKind[OpKind["I18n"] = 35] = "I18n";
|
|
8790
8812
|
/**
|
|
8791
8813
|
* The end of an i18n block.
|
|
8792
8814
|
*/
|
|
8793
|
-
OpKind[OpKind["I18nEnd"] =
|
|
8815
|
+
OpKind[OpKind["I18nEnd"] = 36] = "I18nEnd";
|
|
8816
|
+
/**
|
|
8817
|
+
* An expression in an i18n message.
|
|
8818
|
+
*/
|
|
8819
|
+
OpKind[OpKind["I18nExpression"] = 37] = "I18nExpression";
|
|
8820
|
+
/**
|
|
8821
|
+
* An instruction that applies a set of i18n expressions.
|
|
8822
|
+
*/
|
|
8823
|
+
OpKind[OpKind["I18nApply"] = 38] = "I18nApply";
|
|
8794
8824
|
})(OpKind || (OpKind = {}));
|
|
8795
8825
|
/**
|
|
8796
8826
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -8881,6 +8911,10 @@ var ExpressionKind;
|
|
|
8881
8911
|
* An expression that will cause a literal slot index to be emitted.
|
|
8882
8912
|
*/
|
|
8883
8913
|
ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 20] = "SlotLiteralExpr";
|
|
8914
|
+
/**
|
|
8915
|
+
* A test expression for a conditional op.
|
|
8916
|
+
*/
|
|
8917
|
+
ExpressionKind[ExpressionKind["ConditionalCase"] = 21] = "ConditionalCase";
|
|
8884
8918
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
8885
8919
|
/**
|
|
8886
8920
|
* Distinguishes between different kinds of `SemanticVariable`s.
|
|
@@ -8922,6 +8956,15 @@ var SanitizerFn;
|
|
|
8922
8956
|
SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
|
|
8923
8957
|
SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
|
|
8924
8958
|
})(SanitizerFn || (SanitizerFn = {}));
|
|
8959
|
+
/**
|
|
8960
|
+
* Enumeration of the different kinds of `@defer` secondary blocks.
|
|
8961
|
+
*/
|
|
8962
|
+
var DeferSecondaryKind;
|
|
8963
|
+
(function (DeferSecondaryKind) {
|
|
8964
|
+
DeferSecondaryKind[DeferSecondaryKind["Loading"] = 0] = "Loading";
|
|
8965
|
+
DeferSecondaryKind[DeferSecondaryKind["Placeholder"] = 1] = "Placeholder";
|
|
8966
|
+
DeferSecondaryKind[DeferSecondaryKind["Error"] = 2] = "Error";
|
|
8967
|
+
})(DeferSecondaryKind || (DeferSecondaryKind = {}));
|
|
8925
8968
|
/**
|
|
8926
8969
|
* Enumeration of the types of attributes which can be applied to an element.
|
|
8927
8970
|
*/
|
|
@@ -8977,6 +9020,10 @@ const ConsumesVarsTrait = Symbol('ConsumesVars');
|
|
|
8977
9020
|
* Marker symbol for `UsesVarOffset` trait.
|
|
8978
9021
|
*/
|
|
8979
9022
|
const UsesVarOffset = Symbol('UsesVarOffset');
|
|
9023
|
+
/**
|
|
9024
|
+
* Marker symbol for `HasConst` trait.
|
|
9025
|
+
*/
|
|
9026
|
+
const HasConst = Symbol('HasConst');
|
|
8980
9027
|
/**
|
|
8981
9028
|
* Default values for most `ConsumesSlotOpTrait` fields (used with the spread operator to initialize
|
|
8982
9029
|
* implementors of the trait).
|
|
@@ -8992,7 +9039,7 @@ const TRAIT_CONSUMES_SLOT = {
|
|
|
8992
9039
|
*/
|
|
8993
9040
|
const TRAIT_USES_SLOT_INDEX = {
|
|
8994
9041
|
[UsesSlotIndex]: true,
|
|
8995
|
-
|
|
9042
|
+
targetSlot: null,
|
|
8996
9043
|
};
|
|
8997
9044
|
/**
|
|
8998
9045
|
* Default values for most `DependsOnSlotContextOpTrait` fields (used with the spread operator to
|
|
@@ -9016,6 +9063,14 @@ const TRAIT_USES_VAR_OFFSET = {
|
|
|
9016
9063
|
[UsesVarOffset]: true,
|
|
9017
9064
|
varOffset: null,
|
|
9018
9065
|
};
|
|
9066
|
+
/**
|
|
9067
|
+
* Default values for `HasConst` fields (used with the spread operator to initialize
|
|
9068
|
+
* implementors of this trait).
|
|
9069
|
+
*/
|
|
9070
|
+
const TRAIT_HAS_CONST = {
|
|
9071
|
+
[HasConst]: true,
|
|
9072
|
+
constIndex: null,
|
|
9073
|
+
};
|
|
9019
9074
|
/**
|
|
9020
9075
|
* Test whether an operation implements `ConsumesSlotOpTrait`.
|
|
9021
9076
|
*/
|
|
@@ -9040,6 +9095,9 @@ function hasUsesVarOffsetTrait(expr) {
|
|
|
9040
9095
|
function hasUsesSlotIndexTrait(value) {
|
|
9041
9096
|
return value[UsesSlotIndex] === true;
|
|
9042
9097
|
}
|
|
9098
|
+
function hasConstTrait(value) {
|
|
9099
|
+
return value[HasConst] === true;
|
|
9100
|
+
}
|
|
9043
9101
|
|
|
9044
9102
|
/**
|
|
9045
9103
|
* Create a `StatementOp`.
|
|
@@ -9078,11 +9136,12 @@ const NEW_OP = {
|
|
|
9078
9136
|
/**
|
|
9079
9137
|
* Create an `InterpolationTextOp`.
|
|
9080
9138
|
*/
|
|
9081
|
-
function createInterpolateTextOp(xref, interpolation, sourceSpan) {
|
|
9139
|
+
function createInterpolateTextOp(xref, interpolation, i18nPlaceholders, sourceSpan) {
|
|
9082
9140
|
return {
|
|
9083
9141
|
kind: OpKind.InterpolateText,
|
|
9084
9142
|
target: xref,
|
|
9085
9143
|
interpolation,
|
|
9144
|
+
i18nPlaceholders,
|
|
9086
9145
|
sourceSpan,
|
|
9087
9146
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9088
9147
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9220,17 +9279,46 @@ function createAdvanceOp(delta, sourceSpan) {
|
|
|
9220
9279
|
/**
|
|
9221
9280
|
* Create a conditional op, which will display an embedded view according to a condtion.
|
|
9222
9281
|
*/
|
|
9223
|
-
function createConditionalOp(target, test, sourceSpan) {
|
|
9282
|
+
function createConditionalOp(target, test, conditions, sourceSpan) {
|
|
9224
9283
|
return {
|
|
9225
9284
|
kind: OpKind.Conditional,
|
|
9226
9285
|
target,
|
|
9227
9286
|
test,
|
|
9228
|
-
conditions
|
|
9287
|
+
conditions,
|
|
9229
9288
|
processed: null,
|
|
9230
9289
|
sourceSpan,
|
|
9290
|
+
contextValue: null,
|
|
9231
9291
|
...NEW_OP,
|
|
9232
9292
|
...TRAIT_USES_SLOT_INDEX,
|
|
9233
9293
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9294
|
+
...TRAIT_CONSUMES_VARS,
|
|
9295
|
+
};
|
|
9296
|
+
}
|
|
9297
|
+
/**
|
|
9298
|
+
* Create an i18n expression op.
|
|
9299
|
+
*/
|
|
9300
|
+
function createI18nExpressionOp(target, expression, i18nPlaceholder, sourceSpan) {
|
|
9301
|
+
return {
|
|
9302
|
+
kind: OpKind.I18nExpression,
|
|
9303
|
+
target,
|
|
9304
|
+
expression,
|
|
9305
|
+
i18nPlaceholder,
|
|
9306
|
+
sourceSpan,
|
|
9307
|
+
...NEW_OP,
|
|
9308
|
+
...TRAIT_CONSUMES_VARS,
|
|
9309
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9310
|
+
};
|
|
9311
|
+
}
|
|
9312
|
+
/**
|
|
9313
|
+
* Creates an op to apply i18n expression ops.
|
|
9314
|
+
*/
|
|
9315
|
+
function createI18nApplyOp(target, sourceSpan) {
|
|
9316
|
+
return {
|
|
9317
|
+
kind: OpKind.I18nApply,
|
|
9318
|
+
target,
|
|
9319
|
+
sourceSpan,
|
|
9320
|
+
...NEW_OP,
|
|
9321
|
+
...TRAIT_USES_SLOT_INDEX,
|
|
9234
9322
|
};
|
|
9235
9323
|
}
|
|
9236
9324
|
|
|
@@ -9281,7 +9369,7 @@ class ReferenceExpr extends ExpressionBase {
|
|
|
9281
9369
|
this.offset = offset;
|
|
9282
9370
|
this.kind = ExpressionKind.Reference;
|
|
9283
9371
|
this[_a] = true;
|
|
9284
|
-
this.
|
|
9372
|
+
this.targetSlot = null;
|
|
9285
9373
|
}
|
|
9286
9374
|
visitExpression() { }
|
|
9287
9375
|
isEquivalent(e) {
|
|
@@ -9293,7 +9381,7 @@ class ReferenceExpr extends ExpressionBase {
|
|
|
9293
9381
|
transformInternalExpressions() { }
|
|
9294
9382
|
clone() {
|
|
9295
9383
|
const expr = new ReferenceExpr(this.target, this.offset);
|
|
9296
|
-
expr.
|
|
9384
|
+
expr.targetSlot = this.targetSlot;
|
|
9297
9385
|
return expr;
|
|
9298
9386
|
}
|
|
9299
9387
|
}
|
|
@@ -9530,7 +9618,7 @@ class PipeBindingExpr extends ExpressionBase {
|
|
|
9530
9618
|
this[_d] = true;
|
|
9531
9619
|
this[_e] = true;
|
|
9532
9620
|
this[_f] = true;
|
|
9533
|
-
this.
|
|
9621
|
+
this.targetSlot = null;
|
|
9534
9622
|
this.varOffset = null;
|
|
9535
9623
|
}
|
|
9536
9624
|
visitExpression(visitor, context) {
|
|
@@ -9551,7 +9639,7 @@ class PipeBindingExpr extends ExpressionBase {
|
|
|
9551
9639
|
}
|
|
9552
9640
|
clone() {
|
|
9553
9641
|
const r = new PipeBindingExpr(this.target, this.name, this.args.map(a => a.clone()));
|
|
9554
|
-
r.
|
|
9642
|
+
r.targetSlot = this.targetSlot;
|
|
9555
9643
|
r.varOffset = this.varOffset;
|
|
9556
9644
|
return r;
|
|
9557
9645
|
}
|
|
@@ -9568,7 +9656,7 @@ class PipeBindingVariadicExpr extends ExpressionBase {
|
|
|
9568
9656
|
this[_g] = true;
|
|
9569
9657
|
this[_h] = true;
|
|
9570
9658
|
this[_j] = true;
|
|
9571
|
-
this.
|
|
9659
|
+
this.targetSlot = null;
|
|
9572
9660
|
this.varOffset = null;
|
|
9573
9661
|
}
|
|
9574
9662
|
visitExpression(visitor, context) {
|
|
@@ -9585,7 +9673,7 @@ class PipeBindingVariadicExpr extends ExpressionBase {
|
|
|
9585
9673
|
}
|
|
9586
9674
|
clone() {
|
|
9587
9675
|
const r = new PipeBindingVariadicExpr(this.target, this.name, this.args.clone(), this.numArgs);
|
|
9588
|
-
r.
|
|
9676
|
+
r.targetSlot = this.targetSlot;
|
|
9589
9677
|
r.varOffset = this.varOffset;
|
|
9590
9678
|
return r;
|
|
9591
9679
|
}
|
|
@@ -9785,20 +9873,56 @@ class SlotLiteralExpr extends ExpressionBase {
|
|
|
9785
9873
|
this.target = target;
|
|
9786
9874
|
this.kind = ExpressionKind.SlotLiteralExpr;
|
|
9787
9875
|
this[_k] = true;
|
|
9788
|
-
this.
|
|
9876
|
+
this.targetSlot = null;
|
|
9789
9877
|
}
|
|
9790
9878
|
visitExpression(visitor, context) { }
|
|
9791
9879
|
isEquivalent(e) {
|
|
9792
|
-
return e instanceof SlotLiteralExpr && e.target === this.target &&
|
|
9880
|
+
return e instanceof SlotLiteralExpr && e.target === this.target &&
|
|
9881
|
+
e.targetSlot === this.targetSlot;
|
|
9793
9882
|
}
|
|
9794
9883
|
isConstant() {
|
|
9795
9884
|
return true;
|
|
9796
9885
|
}
|
|
9797
9886
|
clone() {
|
|
9798
|
-
|
|
9887
|
+
const copy = new SlotLiteralExpr(this.target);
|
|
9888
|
+
copy.targetSlot = this.targetSlot;
|
|
9889
|
+
return copy;
|
|
9799
9890
|
}
|
|
9800
9891
|
transformInternalExpressions() { }
|
|
9801
9892
|
}
|
|
9893
|
+
class ConditionalCaseExpr extends ExpressionBase {
|
|
9894
|
+
/**
|
|
9895
|
+
* Create an expression for one branch of a conditional.
|
|
9896
|
+
* @param expr The expression to be tested for this case. Might be null, as in an `else` case.
|
|
9897
|
+
* @param target The Xref of the view to be displayed if this condition is true.
|
|
9898
|
+
*/
|
|
9899
|
+
constructor(expr, target, alias = null) {
|
|
9900
|
+
super();
|
|
9901
|
+
this.expr = expr;
|
|
9902
|
+
this.target = target;
|
|
9903
|
+
this.alias = alias;
|
|
9904
|
+
this.kind = ExpressionKind.ConditionalCase;
|
|
9905
|
+
}
|
|
9906
|
+
visitExpression(visitor, context) {
|
|
9907
|
+
if (this.expr !== null) {
|
|
9908
|
+
this.expr.visitExpression(visitor, context);
|
|
9909
|
+
}
|
|
9910
|
+
}
|
|
9911
|
+
isEquivalent(e) {
|
|
9912
|
+
return e instanceof ConditionalCaseExpr && e.expr === this.expr;
|
|
9913
|
+
}
|
|
9914
|
+
isConstant() {
|
|
9915
|
+
return true;
|
|
9916
|
+
}
|
|
9917
|
+
clone() {
|
|
9918
|
+
return new ConditionalCaseExpr(this.expr, this.target);
|
|
9919
|
+
}
|
|
9920
|
+
transformInternalExpressions(transform, flags) {
|
|
9921
|
+
if (this.expr !== null) {
|
|
9922
|
+
this.expr = transformExpressionsInExpression(this.expr, transform, flags);
|
|
9923
|
+
}
|
|
9924
|
+
}
|
|
9925
|
+
}
|
|
9802
9926
|
/**
|
|
9803
9927
|
* Visits all `Expression`s in the AST of `op` with the `visitor` function.
|
|
9804
9928
|
*/
|
|
@@ -9851,6 +9975,9 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9851
9975
|
op.sanitizer =
|
|
9852
9976
|
op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
|
|
9853
9977
|
break;
|
|
9978
|
+
case OpKind.I18nExpression:
|
|
9979
|
+
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
9980
|
+
break;
|
|
9854
9981
|
case OpKind.InterpolateText:
|
|
9855
9982
|
transformExpressionsInInterpolation(op.interpolation, transform, flags);
|
|
9856
9983
|
break;
|
|
@@ -9862,15 +9989,18 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9862
9989
|
break;
|
|
9863
9990
|
case OpKind.Conditional:
|
|
9864
9991
|
for (const condition of op.conditions) {
|
|
9865
|
-
if (condition
|
|
9992
|
+
if (condition.expr === null) {
|
|
9866
9993
|
// This is a default case.
|
|
9867
9994
|
continue;
|
|
9868
9995
|
}
|
|
9869
|
-
condition
|
|
9996
|
+
condition.expr = transformExpressionsInExpression(condition.expr, transform, flags);
|
|
9870
9997
|
}
|
|
9871
9998
|
if (op.processed !== null) {
|
|
9872
9999
|
op.processed = transformExpressionsInExpression(op.processed, transform, flags);
|
|
9873
10000
|
}
|
|
10001
|
+
if (op.contextValue !== null) {
|
|
10002
|
+
op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
|
|
10003
|
+
}
|
|
9874
10004
|
break;
|
|
9875
10005
|
case OpKind.Listener:
|
|
9876
10006
|
for (const innerOp of op.handlerOps) {
|
|
@@ -9887,18 +10017,20 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9887
10017
|
transformExpressionsInStatement(statement, transform, flags);
|
|
9888
10018
|
}
|
|
9889
10019
|
break;
|
|
10020
|
+
case OpKind.I18n:
|
|
9890
10021
|
case OpKind.I18nStart:
|
|
9891
|
-
for (const placeholder
|
|
9892
|
-
op.
|
|
9893
|
-
transformExpressionsInExpression(op.tagNameParams[placeholder], transform, flags);
|
|
10022
|
+
for (const [placeholder, expression] of op.params) {
|
|
10023
|
+
op.params.set(placeholder, transformExpressionsInExpression(expression, transform, flags));
|
|
9894
10024
|
}
|
|
9895
10025
|
break;
|
|
10026
|
+
case OpKind.Defer:
|
|
10027
|
+
case OpKind.DeferSecondaryBlock:
|
|
10028
|
+
case OpKind.DeferOn:
|
|
9896
10029
|
case OpKind.Projection:
|
|
9897
10030
|
case OpKind.ProjectionDef:
|
|
9898
10031
|
case OpKind.Element:
|
|
9899
10032
|
case OpKind.ElementStart:
|
|
9900
10033
|
case OpKind.ElementEnd:
|
|
9901
|
-
case OpKind.I18n:
|
|
9902
10034
|
case OpKind.I18nEnd:
|
|
9903
10035
|
case OpKind.Container:
|
|
9904
10036
|
case OpKind.ContainerStart:
|
|
@@ -9910,6 +10042,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
9910
10042
|
case OpKind.Pipe:
|
|
9911
10043
|
case OpKind.Advance:
|
|
9912
10044
|
case OpKind.Namespace:
|
|
10045
|
+
case OpKind.I18nApply:
|
|
9913
10046
|
// These operations contain no expressions.
|
|
9914
10047
|
break;
|
|
9915
10048
|
default:
|
|
@@ -10190,7 +10323,7 @@ class OpList {
|
|
|
10190
10323
|
// Replace `oldOp` with the chain `first` -> `last`.
|
|
10191
10324
|
if (oldPrev !== null) {
|
|
10192
10325
|
oldPrev.next = first;
|
|
10193
|
-
first.prev =
|
|
10326
|
+
first.prev = oldPrev;
|
|
10194
10327
|
}
|
|
10195
10328
|
if (oldNext !== null) {
|
|
10196
10329
|
oldNext.prev = last;
|
|
@@ -10297,7 +10430,7 @@ function isElementOrContainerOp(op) {
|
|
|
10297
10430
|
/**
|
|
10298
10431
|
* Create an `ElementStartOp`.
|
|
10299
10432
|
*/
|
|
10300
|
-
function createElementStartOp(tag, xref, namespace,
|
|
10433
|
+
function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan) {
|
|
10301
10434
|
return {
|
|
10302
10435
|
kind: OpKind.ElementStart,
|
|
10303
10436
|
xref,
|
|
@@ -10306,7 +10439,7 @@ function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
|
|
|
10306
10439
|
localRefs: [],
|
|
10307
10440
|
nonBindable: false,
|
|
10308
10441
|
namespace,
|
|
10309
|
-
|
|
10442
|
+
i18nPlaceholder,
|
|
10310
10443
|
sourceSpan,
|
|
10311
10444
|
...TRAIT_CONSUMES_SLOT,
|
|
10312
10445
|
...NEW_OP,
|
|
@@ -10315,19 +10448,18 @@ function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
|
|
|
10315
10448
|
/**
|
|
10316
10449
|
* Create a `TemplateOp`.
|
|
10317
10450
|
*/
|
|
10318
|
-
function createTemplateOp(xref, tag, namespace,
|
|
10451
|
+
function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSpan) {
|
|
10319
10452
|
return {
|
|
10320
10453
|
kind: OpKind.Template,
|
|
10321
10454
|
xref,
|
|
10322
10455
|
attributes: null,
|
|
10323
10456
|
tag,
|
|
10324
|
-
|
|
10457
|
+
block: generatedInBlock,
|
|
10325
10458
|
decls: null,
|
|
10326
10459
|
vars: null,
|
|
10327
10460
|
localRefs: [],
|
|
10328
10461
|
nonBindable: false,
|
|
10329
10462
|
namespace,
|
|
10330
|
-
i18n,
|
|
10331
10463
|
sourceSpan,
|
|
10332
10464
|
...TRAIT_CONSUMES_SLOT,
|
|
10333
10465
|
...NEW_OP,
|
|
@@ -10432,11 +10564,9 @@ function createProjectionOp(xref, selector) {
|
|
|
10432
10564
|
attributes: null,
|
|
10433
10565
|
localRefs: [],
|
|
10434
10566
|
nonBindable: false,
|
|
10435
|
-
i18n: undefined,
|
|
10436
10567
|
sourceSpan: null,
|
|
10437
10568
|
...NEW_OP,
|
|
10438
10569
|
...TRAIT_CONSUMES_SLOT,
|
|
10439
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
10440
10570
|
};
|
|
10441
10571
|
}
|
|
10442
10572
|
/**
|
|
@@ -10452,6 +10582,42 @@ function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
|
10452
10582
|
...NEW_OP,
|
|
10453
10583
|
};
|
|
10454
10584
|
}
|
|
10585
|
+
function createDeferOp(xref, main, sourceSpan) {
|
|
10586
|
+
return {
|
|
10587
|
+
kind: OpKind.Defer,
|
|
10588
|
+
xref,
|
|
10589
|
+
target: main,
|
|
10590
|
+
loading: null,
|
|
10591
|
+
placeholder: null,
|
|
10592
|
+
error: null,
|
|
10593
|
+
sourceSpan,
|
|
10594
|
+
...NEW_OP,
|
|
10595
|
+
...TRAIT_CONSUMES_SLOT,
|
|
10596
|
+
...TRAIT_USES_SLOT_INDEX,
|
|
10597
|
+
};
|
|
10598
|
+
}
|
|
10599
|
+
function createDeferSecondaryOp(deferOp, secondaryView, secondaryBlockKind) {
|
|
10600
|
+
return {
|
|
10601
|
+
kind: OpKind.DeferSecondaryBlock,
|
|
10602
|
+
deferOp,
|
|
10603
|
+
target: secondaryView,
|
|
10604
|
+
secondaryBlockKind,
|
|
10605
|
+
constValue: null,
|
|
10606
|
+
makeExpression: literalOrArrayLiteral$1,
|
|
10607
|
+
...NEW_OP,
|
|
10608
|
+
...TRAIT_USES_SLOT_INDEX,
|
|
10609
|
+
...TRAIT_HAS_CONST,
|
|
10610
|
+
};
|
|
10611
|
+
}
|
|
10612
|
+
function createDeferOnOp(xref, sourceSpan) {
|
|
10613
|
+
return {
|
|
10614
|
+
kind: OpKind.DeferOn,
|
|
10615
|
+
xref,
|
|
10616
|
+
sourceSpan,
|
|
10617
|
+
...NEW_OP,
|
|
10618
|
+
...TRAIT_CONSUMES_SLOT,
|
|
10619
|
+
};
|
|
10620
|
+
}
|
|
10455
10621
|
/**
|
|
10456
10622
|
* Create an `ExtractedMessageOp`.
|
|
10457
10623
|
*/
|
|
@@ -10467,12 +10633,12 @@ function createExtractedMessageOp(owner, expression, statements) {
|
|
|
10467
10633
|
/**
|
|
10468
10634
|
* Create an `I18nStartOp`.
|
|
10469
10635
|
*/
|
|
10470
|
-
function createI18nStartOp(xref,
|
|
10636
|
+
function createI18nStartOp(xref, message) {
|
|
10471
10637
|
return {
|
|
10472
10638
|
kind: OpKind.I18nStart,
|
|
10473
10639
|
xref,
|
|
10474
|
-
|
|
10475
|
-
|
|
10640
|
+
message,
|
|
10641
|
+
params: new Map(),
|
|
10476
10642
|
messageIndex: null,
|
|
10477
10643
|
...NEW_OP,
|
|
10478
10644
|
...TRAIT_CONSUMES_SLOT,
|
|
@@ -10488,6 +10654,12 @@ function createI18nEndOp(xref) {
|
|
|
10488
10654
|
...NEW_OP,
|
|
10489
10655
|
};
|
|
10490
10656
|
}
|
|
10657
|
+
function literalOrArrayLiteral$1(value) {
|
|
10658
|
+
if (Array.isArray(value)) {
|
|
10659
|
+
return literalArr(value.map(literalOrArrayLiteral$1));
|
|
10660
|
+
}
|
|
10661
|
+
return literal(value, INFERRED_TYPE);
|
|
10662
|
+
}
|
|
10491
10663
|
|
|
10492
10664
|
function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan) {
|
|
10493
10665
|
return {
|
|
@@ -10501,6 +10673,12 @@ function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan)
|
|
|
10501
10673
|
};
|
|
10502
10674
|
}
|
|
10503
10675
|
|
|
10676
|
+
/**
|
|
10677
|
+
* When referenced in the template's context parameters, this indicates a reference to the entire
|
|
10678
|
+
* context object, rather than a specific parameter.
|
|
10679
|
+
*/
|
|
10680
|
+
const CTX_REF = 'CTX_REF_MARKER';
|
|
10681
|
+
|
|
10504
10682
|
var CompilationJobKind;
|
|
10505
10683
|
(function (CompilationJobKind) {
|
|
10506
10684
|
CompilationJobKind[CompilationJobKind["Tmpl"] = 0] = "Tmpl";
|
|
@@ -10688,10 +10866,16 @@ function phaseVarCounting(job) {
|
|
|
10688
10866
|
// First, count the vars used in each view, and update the view-level counter.
|
|
10689
10867
|
for (const unit of job.units) {
|
|
10690
10868
|
let varCount = 0;
|
|
10869
|
+
// Count variables on top-level ops first. Don't explore nested expressions just yet.
|
|
10691
10870
|
for (const op of unit.ops()) {
|
|
10692
10871
|
if (hasConsumesVarsTrait(op)) {
|
|
10693
10872
|
varCount += varsUsedByOp(op);
|
|
10694
10873
|
}
|
|
10874
|
+
}
|
|
10875
|
+
// Count variables on expressions inside ops. We do this later because some of these expressions
|
|
10876
|
+
// might be conditional (e.g. `pipeBinding` inside of a ternary), and we don't want to interfere
|
|
10877
|
+
// with indices for top-level binding slots (e.g. `property`).
|
|
10878
|
+
for (const op of unit.ops()) {
|
|
10695
10879
|
visitExpressionsInOp(op, expr => {
|
|
10696
10880
|
if (!isIrExpression(expr)) {
|
|
10697
10881
|
return;
|
|
@@ -10752,6 +10936,9 @@ function varsUsedByOp(op) {
|
|
|
10752
10936
|
case OpKind.InterpolateText:
|
|
10753
10937
|
// `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
|
|
10754
10938
|
return op.interpolation.expressions.length;
|
|
10939
|
+
case OpKind.I18nExpression:
|
|
10940
|
+
case OpKind.Conditional:
|
|
10941
|
+
return 1;
|
|
10755
10942
|
default:
|
|
10756
10943
|
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
10757
10944
|
}
|
|
@@ -10823,6 +11010,35 @@ function removeAnys(e) {
|
|
|
10823
11010
|
return e;
|
|
10824
11011
|
}
|
|
10825
11012
|
|
|
11013
|
+
/**
|
|
11014
|
+
* Adds apply operations after i18n expressions.
|
|
11015
|
+
*/
|
|
11016
|
+
function phaseApplyI18nExpressions(job) {
|
|
11017
|
+
for (const unit of job.units) {
|
|
11018
|
+
for (const op of unit.update) {
|
|
11019
|
+
// Only add apply after expressions that are not followed by more expressions.
|
|
11020
|
+
if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
|
|
11021
|
+
// TODO: what should be the source span for the apply op?
|
|
11022
|
+
OpList.insertAfter(createI18nApplyOp(op.target, null), op);
|
|
11023
|
+
}
|
|
11024
|
+
}
|
|
11025
|
+
}
|
|
11026
|
+
}
|
|
11027
|
+
/**
|
|
11028
|
+
* Checks whether the given expression op needs to be followed with an apply op.
|
|
11029
|
+
*/
|
|
11030
|
+
function needsApplication(op) {
|
|
11031
|
+
// If the next op is not another expression, we need to apply.
|
|
11032
|
+
if (op.next?.kind !== OpKind.I18nExpression) {
|
|
11033
|
+
return true;
|
|
11034
|
+
}
|
|
11035
|
+
// If the next op is an expression targeting a different i18n block, we need to apply.
|
|
11036
|
+
if (op.next.target !== op.target) {
|
|
11037
|
+
return true;
|
|
11038
|
+
}
|
|
11039
|
+
return false;
|
|
11040
|
+
}
|
|
11041
|
+
|
|
10826
11042
|
/**
|
|
10827
11043
|
* Gets a map of all elements in the given view by their xref id.
|
|
10828
11044
|
*/
|
|
@@ -10984,14 +11200,20 @@ function phaseBindingSpecialization(job) {
|
|
|
10984
11200
|
}
|
|
10985
11201
|
|
|
10986
11202
|
const CHAINABLE = new Set([
|
|
10987
|
-
Identifiers.
|
|
10988
|
-
Identifiers.
|
|
11203
|
+
Identifiers.attribute,
|
|
11204
|
+
Identifiers.classProp,
|
|
10989
11205
|
Identifiers.element,
|
|
10990
|
-
Identifiers.
|
|
11206
|
+
Identifiers.elementContainer,
|
|
11207
|
+
Identifiers.elementContainerEnd,
|
|
11208
|
+
Identifiers.elementContainerStart,
|
|
11209
|
+
Identifiers.elementEnd,
|
|
11210
|
+
Identifiers.elementStart,
|
|
10991
11211
|
Identifiers.hostProperty,
|
|
10992
|
-
Identifiers.
|
|
11212
|
+
Identifiers.i18nExp,
|
|
11213
|
+
Identifiers.listener,
|
|
11214
|
+
Identifiers.listener,
|
|
11215
|
+
Identifiers.property,
|
|
10993
11216
|
Identifiers.styleProp,
|
|
10994
|
-
Identifiers.attribute,
|
|
10995
11217
|
Identifiers.stylePropInterpolate1,
|
|
10996
11218
|
Identifiers.stylePropInterpolate2,
|
|
10997
11219
|
Identifiers.stylePropInterpolate3,
|
|
@@ -11001,13 +11223,8 @@ const CHAINABLE = new Set([
|
|
|
11001
11223
|
Identifiers.stylePropInterpolate7,
|
|
11002
11224
|
Identifiers.stylePropInterpolate8,
|
|
11003
11225
|
Identifiers.stylePropInterpolateV,
|
|
11004
|
-
Identifiers.classProp,
|
|
11005
|
-
Identifiers.listener,
|
|
11006
|
-
Identifiers.elementContainerStart,
|
|
11007
|
-
Identifiers.elementContainerEnd,
|
|
11008
|
-
Identifiers.elementContainer,
|
|
11009
|
-
Identifiers.listener,
|
|
11010
11226
|
Identifiers.syntheticHostListener,
|
|
11227
|
+
Identifiers.syntheticHostProperty,
|
|
11011
11228
|
Identifiers.templateCreate,
|
|
11012
11229
|
]);
|
|
11013
11230
|
/**
|
|
@@ -11084,9 +11301,9 @@ function phaseConditionals(job) {
|
|
|
11084
11301
|
}
|
|
11085
11302
|
let test;
|
|
11086
11303
|
// Any case with a `null` condition is `default`. If one exists, default to it instead.
|
|
11087
|
-
const defaultCase = op.conditions.findIndex((
|
|
11304
|
+
const defaultCase = op.conditions.findIndex((cond) => cond.expr === null);
|
|
11088
11305
|
if (defaultCase >= 0) {
|
|
11089
|
-
const
|
|
11306
|
+
const xref = op.conditions.splice(defaultCase, 1)[0].target;
|
|
11090
11307
|
test = new SlotLiteralExpr(xref);
|
|
11091
11308
|
}
|
|
11092
11309
|
else {
|
|
@@ -11094,13 +11311,26 @@ function phaseConditionals(job) {
|
|
|
11094
11311
|
test = literal(-1);
|
|
11095
11312
|
}
|
|
11096
11313
|
// Switch expressions assign their main test to a temporary, to avoid re-executing it.
|
|
11097
|
-
let tmp = new AssignTemporaryExpr(op.test, job.allocateXrefId());
|
|
11098
|
-
// For each remaining condition, test whether the temporary satifies the check.
|
|
11314
|
+
let tmp = op.test == null ? null : new AssignTemporaryExpr(op.test, job.allocateXrefId());
|
|
11315
|
+
// For each remaining condition, test whether the temporary satifies the check. (If no temp is
|
|
11316
|
+
// present, just check each expression directly.)
|
|
11099
11317
|
for (let i = op.conditions.length - 1; i >= 0; i--) {
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11318
|
+
let conditionalCase = op.conditions[i];
|
|
11319
|
+
if (conditionalCase.expr === null) {
|
|
11320
|
+
continue;
|
|
11321
|
+
}
|
|
11322
|
+
if (tmp !== null) {
|
|
11323
|
+
const useTmp = i === 0 ? tmp : new ReadTemporaryExpr(tmp.xref);
|
|
11324
|
+
conditionalCase.expr =
|
|
11325
|
+
new BinaryOperatorExpr(BinaryOperator.Identical, useTmp, conditionalCase.expr);
|
|
11326
|
+
}
|
|
11327
|
+
else if (conditionalCase.alias !== null) {
|
|
11328
|
+
const caseExpressionTemporaryXref = job.allocateXrefId();
|
|
11329
|
+
conditionalCase.expr =
|
|
11330
|
+
new AssignTemporaryExpr(conditionalCase.expr, caseExpressionTemporaryXref);
|
|
11331
|
+
op.contextValue = new ReadTemporaryExpr(caseExpressionTemporaryXref);
|
|
11332
|
+
}
|
|
11333
|
+
test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.target), test);
|
|
11104
11334
|
}
|
|
11105
11335
|
// Save the resulting aggregate Joost-expression.
|
|
11106
11336
|
op.processed = test;
|
|
@@ -11162,14 +11392,15 @@ const BINARY_OPERATORS = new Map([
|
|
|
11162
11392
|
['||', BinaryOperator.Or],
|
|
11163
11393
|
['+', BinaryOperator.Plus],
|
|
11164
11394
|
]);
|
|
11165
|
-
const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
|
|
11166
11395
|
function namespaceForKey(namespacePrefixKey) {
|
|
11396
|
+
const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
|
|
11167
11397
|
if (namespacePrefixKey === null) {
|
|
11168
11398
|
return Namespace.HTML;
|
|
11169
11399
|
}
|
|
11170
11400
|
return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
|
|
11171
11401
|
}
|
|
11172
11402
|
function keyForNamespace(namespace) {
|
|
11403
|
+
const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
|
|
11173
11404
|
for (const [k, n] of NAMESPACES.entries()) {
|
|
11174
11405
|
if (n === namespace) {
|
|
11175
11406
|
return k;
|
|
@@ -11345,6 +11576,10 @@ const REPLACEMENTS = new Map([
|
|
|
11345
11576
|
[OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]],
|
|
11346
11577
|
[OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]],
|
|
11347
11578
|
]);
|
|
11579
|
+
/**
|
|
11580
|
+
* Op kinds that should not prevent merging of start/end ops.
|
|
11581
|
+
*/
|
|
11582
|
+
const IGNORED_OP_KINDS = new Set([OpKind.Pipe]);
|
|
11348
11583
|
/**
|
|
11349
11584
|
* Replace sequences of mergable elements (e.g. `ElementStart` and `ElementEnd`) with a consolidated
|
|
11350
11585
|
* element (e.g. `Element`).
|
|
@@ -11352,15 +11587,22 @@ const REPLACEMENTS = new Map([
|
|
|
11352
11587
|
function phaseEmptyElements(job) {
|
|
11353
11588
|
for (const unit of job.units) {
|
|
11354
11589
|
for (const op of unit.create) {
|
|
11590
|
+
// Find end ops that may be able to be merged.
|
|
11355
11591
|
const opReplacements = REPLACEMENTS.get(op.kind);
|
|
11356
11592
|
if (opReplacements === undefined) {
|
|
11357
11593
|
continue;
|
|
11358
11594
|
}
|
|
11359
11595
|
const [startKind, mergedKind] = opReplacements;
|
|
11360
|
-
|
|
11596
|
+
// Locate the previous (non-ignored) op.
|
|
11597
|
+
let prevOp = op.prev;
|
|
11598
|
+
while (prevOp !== null && IGNORED_OP_KINDS.has(prevOp.kind)) {
|
|
11599
|
+
prevOp = prevOp.prev;
|
|
11600
|
+
}
|
|
11601
|
+
// If the previous op is the corresponding start op, we can megre.
|
|
11602
|
+
if (prevOp !== null && prevOp.kind === startKind) {
|
|
11361
11603
|
// Transmute the start instruction to the merged version. This is safe as they're designed
|
|
11362
11604
|
// to be identical apart from the `kind`.
|
|
11363
|
-
|
|
11605
|
+
prevOp.kind = mergedKind;
|
|
11364
11606
|
// Remove the end instruction.
|
|
11365
11607
|
OpList.remove(op);
|
|
11366
11608
|
}
|
|
@@ -11551,13 +11793,31 @@ function phaseGenerateAdvance(job) {
|
|
|
11551
11793
|
for (const unit of job.units) {
|
|
11552
11794
|
// First build a map of all of the declarations in the view that have assigned slots.
|
|
11553
11795
|
const slotMap = new Map();
|
|
11796
|
+
let lastSlotOp = null;
|
|
11554
11797
|
for (const op of unit.create) {
|
|
11798
|
+
// For i18n blocks, we want to advance to the last element index in the block before invoking
|
|
11799
|
+
// `i18nExp` instructions, to make sure the necessary lifecycle hooks of components/directives
|
|
11800
|
+
// are properly flushed.
|
|
11801
|
+
if (op.kind === OpKind.I18nEnd) {
|
|
11802
|
+
if (lastSlotOp === null) {
|
|
11803
|
+
throw Error('Expected to have encountered an op prior to i18nEnd that consumes a slot');
|
|
11804
|
+
}
|
|
11805
|
+
// TODO(mmalerba): For empty i18n blocks, we move to the next slot to match
|
|
11806
|
+
// TemplateDefinitionBuilder. This seems like just a quirk resulting from the special
|
|
11807
|
+
// handling of i18n blocks that can be removed when compatibility is no longer required.
|
|
11808
|
+
let lastSlot = lastSlotOp.slot;
|
|
11809
|
+
if (lastSlotOp.kind === OpKind.I18nStart && job.compatibility) {
|
|
11810
|
+
lastSlot++;
|
|
11811
|
+
}
|
|
11812
|
+
slotMap.set(op.xref, lastSlot);
|
|
11813
|
+
}
|
|
11555
11814
|
if (!hasConsumesSlotTrait(op)) {
|
|
11556
11815
|
continue;
|
|
11557
11816
|
}
|
|
11558
11817
|
else if (op.slot === null) {
|
|
11559
11818
|
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
11560
11819
|
}
|
|
11820
|
+
lastSlotOp = op;
|
|
11561
11821
|
slotMap.set(op.xref, op.slot);
|
|
11562
11822
|
}
|
|
11563
11823
|
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
@@ -11592,31 +11852,39 @@ function phaseGenerateAdvance(job) {
|
|
|
11592
11852
|
}
|
|
11593
11853
|
|
|
11594
11854
|
/**
|
|
11595
|
-
*
|
|
11855
|
+
* Locate projection slots, populate the each component's `ngContentSelectors` literal field,
|
|
11856
|
+
* populate `project` arguments, and generate the required `projectionDef` instruction for the job's
|
|
11857
|
+
* root view.
|
|
11596
11858
|
*/
|
|
11597
|
-
function
|
|
11859
|
+
function phaseGenerateProjectionDef(job) {
|
|
11860
|
+
// TODO: Why does TemplateDefinitionBuilder force a shared constant?
|
|
11861
|
+
const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
|
|
11862
|
+
// Collect all selectors from this component, and its nested views. Also, assign each projection a
|
|
11863
|
+
// unique ascending projection slot index.
|
|
11864
|
+
const selectors = [];
|
|
11865
|
+
let projectionSlotIndex = 0;
|
|
11598
11866
|
for (const unit of job.units) {
|
|
11599
|
-
const elements = getElementsByXrefId(unit);
|
|
11600
11867
|
for (const op of unit.create) {
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
if (start.i18n instanceof Message) {
|
|
11605
|
-
const id = job.allocateXrefId();
|
|
11606
|
-
OpList.insertAfter(createI18nStartOp(id, start.i18n), start);
|
|
11607
|
-
OpList.insertBefore(createI18nEndOp(id), op);
|
|
11608
|
-
}
|
|
11609
|
-
break;
|
|
11610
|
-
case OpKind.Template:
|
|
11611
|
-
if (op.i18n !== undefined) {
|
|
11612
|
-
const id = job.allocateXrefId();
|
|
11613
|
-
OpList.insertBefore(createI18nStartOp(id, op.i18n), op);
|
|
11614
|
-
OpList.insertAfter(createI18nEndOp(id), op);
|
|
11615
|
-
}
|
|
11616
|
-
break;
|
|
11868
|
+
if (op.kind === OpKind.Projection) {
|
|
11869
|
+
selectors.push(op.selector);
|
|
11870
|
+
op.projectionSlotIndex = projectionSlotIndex++;
|
|
11617
11871
|
}
|
|
11618
11872
|
}
|
|
11619
11873
|
}
|
|
11874
|
+
if (selectors.length > 0) {
|
|
11875
|
+
// Create the projectionDef array. If we only found a single wildcard selector, then we use the
|
|
11876
|
+
// default behavior with no arguments instead.
|
|
11877
|
+
let defExpr = null;
|
|
11878
|
+
if (selectors.length > 1 || selectors[0] !== '*') {
|
|
11879
|
+
const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
|
|
11880
|
+
defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
|
|
11881
|
+
}
|
|
11882
|
+
// Create the ngContentSelectors constant.
|
|
11883
|
+
job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
|
|
11884
|
+
// The projection def instruction goes at the beginning of the root view, before any
|
|
11885
|
+
// `projection` instructions.
|
|
11886
|
+
job.root.create.prepend([createProjectionDefOp(defExpr)]);
|
|
11887
|
+
}
|
|
11620
11888
|
}
|
|
11621
11889
|
|
|
11622
11890
|
/**
|
|
@@ -11727,7 +11995,11 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
11727
11995
|
}
|
|
11728
11996
|
// Add variables for all context variables available in this scope's view.
|
|
11729
11997
|
for (const [name, value] of view.job.views.get(scope.view).contextVariables) {
|
|
11730
|
-
|
|
11998
|
+
const context = new ContextExpr(scope.view);
|
|
11999
|
+
// We either read the context, or, if the variable is CTX_REF, use the context directly.
|
|
12000
|
+
const variable = value === CTX_REF ? context : new ReadPropExpr(context, value);
|
|
12001
|
+
// Add the variable declaration.
|
|
12002
|
+
newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), variable));
|
|
11731
12003
|
}
|
|
11732
12004
|
// Add variables for all local references declared for elements in this scope.
|
|
11733
12005
|
for (const ref of scope.references) {
|
|
@@ -11740,15 +12012,46 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
11740
12012
|
return newOps;
|
|
11741
12013
|
}
|
|
11742
12014
|
|
|
12015
|
+
/**
|
|
12016
|
+
* Looks for the HasConst trait, indicating that an op or expression has some data which
|
|
12017
|
+
* should be collected into the constant array. Capable of collecting either a single literal value,
|
|
12018
|
+
* or an array literal.
|
|
12019
|
+
*/
|
|
12020
|
+
function phaseConstTraitCollection(job) {
|
|
12021
|
+
const collectGlobalConsts = (e) => {
|
|
12022
|
+
if (e instanceof ExpressionBase && hasConstTrait(e)) {
|
|
12023
|
+
// TODO: Figure out how to make this type narrowing work.
|
|
12024
|
+
const ea = e;
|
|
12025
|
+
if (ea.constValue !== null) {
|
|
12026
|
+
ea.constIndex = job.addConst(ea.constValue);
|
|
12027
|
+
}
|
|
12028
|
+
}
|
|
12029
|
+
return e;
|
|
12030
|
+
};
|
|
12031
|
+
for (const unit of job.units) {
|
|
12032
|
+
for (const op of unit.ops()) {
|
|
12033
|
+
if (hasConstTrait(op) && op.constValue !== null) {
|
|
12034
|
+
op.constIndex = job.addConst(op.makeExpression(op.constValue));
|
|
12035
|
+
}
|
|
12036
|
+
transformExpressionsInOp(op, collectGlobalConsts, VisitorContextFlag.None);
|
|
12037
|
+
}
|
|
12038
|
+
}
|
|
12039
|
+
}
|
|
12040
|
+
|
|
11743
12041
|
const STYLE_DOT = 'style.';
|
|
11744
12042
|
const CLASS_DOT = 'class.';
|
|
11745
12043
|
const STYLE_BANG = 'style!';
|
|
11746
12044
|
const CLASS_BANG = 'class!';
|
|
12045
|
+
const BANG_IMPORTANT = '!important';
|
|
11747
12046
|
function phaseHostStylePropertyParsing(job) {
|
|
11748
12047
|
for (const op of job.root.update) {
|
|
11749
12048
|
if (op.kind !== OpKind.Binding) {
|
|
11750
12049
|
continue;
|
|
11751
12050
|
}
|
|
12051
|
+
if (op.name.endsWith(BANG_IMPORTANT)) {
|
|
12052
|
+
// Delete any `!important` suffixes from the binding name.
|
|
12053
|
+
op.name = op.name.substring(0, op.name.length - BANG_IMPORTANT.length);
|
|
12054
|
+
}
|
|
11752
12055
|
if (op.name.startsWith(STYLE_DOT)) {
|
|
11753
12056
|
op.bindingKind = BindingKind.StyleProperty;
|
|
11754
12057
|
op.name = op.name.substring(STYLE_DOT.length);
|
|
@@ -11802,6 +12105,32 @@ function parseProperty$1(name) {
|
|
|
11802
12105
|
return { property, suffix };
|
|
11803
12106
|
}
|
|
11804
12107
|
|
|
12108
|
+
/**
|
|
12109
|
+
* Lifts i18n properties into the consts array.
|
|
12110
|
+
*/
|
|
12111
|
+
function phaseI18nConstCollection(job) {
|
|
12112
|
+
// Serialize the extracted messages into the const array.
|
|
12113
|
+
// TODO: Use `Map` instead of object.
|
|
12114
|
+
const messageConstIndices = {};
|
|
12115
|
+
for (const unit of job.units) {
|
|
12116
|
+
for (const op of unit.create) {
|
|
12117
|
+
if (op.kind === OpKind.ExtractedMessage) {
|
|
12118
|
+
messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
|
|
12119
|
+
OpList.remove(op);
|
|
12120
|
+
}
|
|
12121
|
+
}
|
|
12122
|
+
}
|
|
12123
|
+
// Assign const index to i18n ops that messages were extracted from.
|
|
12124
|
+
for (const unit of job.units) {
|
|
12125
|
+
for (const op of unit.create) {
|
|
12126
|
+
if ((op.kind === OpKind.I18nStart || op.kind === OpKind.I18n) &&
|
|
12127
|
+
messageConstIndices[op.xref] !== undefined) {
|
|
12128
|
+
op.messageIndex = messageConstIndices[op.xref];
|
|
12129
|
+
}
|
|
12130
|
+
}
|
|
12131
|
+
}
|
|
12132
|
+
}
|
|
12133
|
+
|
|
11805
12134
|
function mapEntry(key, value) {
|
|
11806
12135
|
return { key, value, quoted: false };
|
|
11807
12136
|
}
|
|
@@ -16691,7 +17020,7 @@ class _Tokenizer {
|
|
|
16691
17020
|
new PlainCharacterCursor(_file, range);
|
|
16692
17021
|
this._preserveLineEndings = options.preserveLineEndings || false;
|
|
16693
17022
|
this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
|
|
16694
|
-
this._tokenizeBlocks = options.tokenizeBlocks
|
|
17023
|
+
this._tokenizeBlocks = options.tokenizeBlocks ?? true;
|
|
16695
17024
|
try {
|
|
16696
17025
|
this._cursor.init();
|
|
16697
17026
|
}
|
|
@@ -18668,16 +18997,16 @@ function phaseI18nMessageExtraction(job) {
|
|
|
18668
18997
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
18669
18998
|
for (const unit of job.units) {
|
|
18670
18999
|
for (const op of unit.create) {
|
|
18671
|
-
if (op.kind === OpKind.I18nStart
|
|
19000
|
+
if ((op.kind === OpKind.I18nStart || op.kind === OpKind.I18n)) {
|
|
18672
19001
|
// Sort the params map to match the ordering in TemplateDefinitionBuilder.
|
|
18673
|
-
const params =
|
|
19002
|
+
const params = new Map([...op.params.entries()].sort());
|
|
18674
19003
|
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
18675
19004
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other const
|
|
18676
19005
|
// to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
18677
19006
|
// `goog.getMsg` call
|
|
18678
|
-
const closureVar = i18nGenerateClosureVar(job.pool, op.
|
|
19007
|
+
const closureVar = i18nGenerateClosureVar(job.pool, op.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
|
|
18679
19008
|
// TODO: figure out transformFn.
|
|
18680
|
-
const statements = getTranslationDeclStmts$1(op.
|
|
19009
|
+
const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, params, undefined /*transformFn*/);
|
|
18681
19010
|
unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
|
|
18682
19011
|
}
|
|
18683
19012
|
}
|
|
@@ -18709,10 +19038,11 @@ function phaseI18nMessageExtraction(job) {
|
|
|
18709
19038
|
* post-processing).
|
|
18710
19039
|
* @returns An array of statements that defined a given translation.
|
|
18711
19040
|
*/
|
|
18712
|
-
function getTranslationDeclStmts$1(message, variable, closureVar, params
|
|
19041
|
+
function getTranslationDeclStmts$1(message, variable, closureVar, params, transformFn) {
|
|
19042
|
+
const paramsObject = Object.fromEntries(params);
|
|
18713
19043
|
const statements = [
|
|
18714
19044
|
declareI18nVariable(variable),
|
|
18715
|
-
ifStmt(createClosureModeGuard$1(), createGoogleGetMsgStatements(variable, message, closureVar,
|
|
19045
|
+
ifStmt(createClosureModeGuard$1(), createGoogleGetMsgStatements(variable, message, closureVar, paramsObject), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(paramsObject, /* useCamelCase */ false))),
|
|
18716
19046
|
];
|
|
18717
19047
|
if (transformFn) {
|
|
18718
19048
|
statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
|
|
@@ -18755,22 +19085,48 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
|
|
|
18755
19085
|
*/
|
|
18756
19086
|
function phaseI18nTextExtraction(job) {
|
|
18757
19087
|
for (const unit of job.units) {
|
|
18758
|
-
|
|
19088
|
+
// Remove all text nodes within i18n blocks, their content is already captured in the i18n
|
|
19089
|
+
// message.
|
|
19090
|
+
let currentI18nId = null;
|
|
19091
|
+
const textNodes = new Map();
|
|
18759
19092
|
for (const op of unit.create) {
|
|
18760
19093
|
switch (op.kind) {
|
|
18761
19094
|
case OpKind.I18nStart:
|
|
18762
|
-
|
|
19095
|
+
currentI18nId = op.xref;
|
|
18763
19096
|
break;
|
|
18764
19097
|
case OpKind.I18nEnd:
|
|
18765
|
-
|
|
19098
|
+
currentI18nId = null;
|
|
18766
19099
|
break;
|
|
18767
19100
|
case OpKind.Text:
|
|
18768
|
-
if (
|
|
19101
|
+
if (currentI18nId !== null) {
|
|
19102
|
+
textNodes.set(op.xref, currentI18nId);
|
|
18769
19103
|
OpList.remove(op);
|
|
18770
19104
|
}
|
|
18771
19105
|
break;
|
|
18772
19106
|
}
|
|
18773
19107
|
}
|
|
19108
|
+
// Update any interpolations to the removed text, and instead represent them as a series of i18n
|
|
19109
|
+
// expressions that we then apply.
|
|
19110
|
+
for (const op of unit.update) {
|
|
19111
|
+
switch (op.kind) {
|
|
19112
|
+
case OpKind.InterpolateText:
|
|
19113
|
+
if (!textNodes.has(op.target)) {
|
|
19114
|
+
continue;
|
|
19115
|
+
}
|
|
19116
|
+
const i18nBlockId = textNodes.get(op.target);
|
|
19117
|
+
const ops = [];
|
|
19118
|
+
for (let i = 0; i < op.interpolation.expressions.length; i++) {
|
|
19119
|
+
const expr = op.interpolation.expressions[i];
|
|
19120
|
+
const placeholder = op.i18nPlaceholders[i];
|
|
19121
|
+
ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder, expr.sourceSpan ?? op.sourceSpan));
|
|
19122
|
+
}
|
|
19123
|
+
if (ops.length > 0) {
|
|
19124
|
+
// ops.push(ir.createI18nApplyOp(i18nBlockId, op.i18nPlaceholders, op.sourceSpan));
|
|
19125
|
+
}
|
|
19126
|
+
OpList.replaceWithMany(op, ops);
|
|
19127
|
+
break;
|
|
19128
|
+
}
|
|
19129
|
+
}
|
|
18774
19130
|
}
|
|
18775
19131
|
}
|
|
18776
19132
|
|
|
@@ -18934,7 +19290,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
18934
19290
|
if (op.handlerFnName !== null) {
|
|
18935
19291
|
break;
|
|
18936
19292
|
}
|
|
18937
|
-
if (!op.hostListener && op.
|
|
19293
|
+
if (!op.hostListener && op.targetSlot === null) {
|
|
18938
19294
|
throw new Error(`Expected a slot to be assigned`);
|
|
18939
19295
|
}
|
|
18940
19296
|
let animation = '';
|
|
@@ -18946,7 +19302,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
18946
19302
|
op.handlerFnName = `${baseName}_${animation}${op.name}_HostBindingHandler`;
|
|
18947
19303
|
}
|
|
18948
19304
|
else {
|
|
18949
|
-
op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.
|
|
19305
|
+
op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot}_listener`;
|
|
18950
19306
|
}
|
|
18951
19307
|
op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
|
|
18952
19308
|
break;
|
|
@@ -19095,6 +19451,11 @@ function phaseNgContainer(job) {
|
|
|
19095
19451
|
for (const unit of job.units) {
|
|
19096
19452
|
const updatedElementXrefs = new Set();
|
|
19097
19453
|
for (const op of unit.create) {
|
|
19454
|
+
if (op.kind === OpKind.Element && op.tag === CONTAINER_TAG) {
|
|
19455
|
+
// Transmute the `Element` instruction to `Container`.
|
|
19456
|
+
op.kind = OpKind.Container;
|
|
19457
|
+
updatedElementXrefs.add(op.xref);
|
|
19458
|
+
}
|
|
19098
19459
|
if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
|
|
19099
19460
|
// Transmute the `ElementStart` instruction to `ContainerStart`.
|
|
19100
19461
|
op.kind = OpKind.ContainerStart;
|
|
@@ -19108,30 +19469,6 @@ function phaseNgContainer(job) {
|
|
|
19108
19469
|
}
|
|
19109
19470
|
}
|
|
19110
19471
|
|
|
19111
|
-
function phaseNoListenersOnTemplates(job) {
|
|
19112
|
-
for (const unit of job.units) {
|
|
19113
|
-
let inTemplate = false;
|
|
19114
|
-
for (const op of unit.create) {
|
|
19115
|
-
switch (op.kind) {
|
|
19116
|
-
case OpKind.Template:
|
|
19117
|
-
inTemplate = true;
|
|
19118
|
-
break;
|
|
19119
|
-
case OpKind.ElementStart:
|
|
19120
|
-
case OpKind.Element:
|
|
19121
|
-
case OpKind.ContainerStart:
|
|
19122
|
-
case OpKind.Container:
|
|
19123
|
-
inTemplate = false;
|
|
19124
|
-
break;
|
|
19125
|
-
case OpKind.Listener:
|
|
19126
|
-
if (inTemplate) {
|
|
19127
|
-
OpList.remove(op);
|
|
19128
|
-
}
|
|
19129
|
-
break;
|
|
19130
|
-
}
|
|
19131
|
-
}
|
|
19132
|
-
}
|
|
19133
|
-
}
|
|
19134
|
-
|
|
19135
19472
|
/**
|
|
19136
19473
|
* Looks up an element in the given map by xref ID.
|
|
19137
19474
|
*/
|
|
@@ -19189,7 +19526,96 @@ function phaseNullishCoalescing(job) {
|
|
|
19189
19526
|
}
|
|
19190
19527
|
}
|
|
19191
19528
|
|
|
19192
|
-
|
|
19529
|
+
function kindTest(kind) {
|
|
19530
|
+
return (op) => op.kind === kind;
|
|
19531
|
+
}
|
|
19532
|
+
/**
|
|
19533
|
+
* Defines the groups based on `OpKind` that ops will be divided into, for the various create
|
|
19534
|
+
* binding kinds. Ops will be collected into groups, then optionally transformed, before recombining
|
|
19535
|
+
* the groups in the order defined here.
|
|
19536
|
+
*/
|
|
19537
|
+
const CREATE_ORDERING = [
|
|
19538
|
+
{ test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener },
|
|
19539
|
+
{ test: op => op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener) },
|
|
19540
|
+
];
|
|
19541
|
+
/**
|
|
19542
|
+
* As above, but for update ops.
|
|
19543
|
+
*/
|
|
19544
|
+
const UPDATE_ORDERING = [
|
|
19545
|
+
{ test: op => op.kind === OpKind.HostProperty && op.expression instanceof Interpolation },
|
|
19546
|
+
{ test: op => op.kind === OpKind.HostProperty && !(op.expression instanceof Interpolation) },
|
|
19547
|
+
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
19548
|
+
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
19549
|
+
{ test: kindTest(OpKind.StyleProp) },
|
|
19550
|
+
{ test: kindTest(OpKind.ClassProp) },
|
|
19551
|
+
{ test: op => op.kind === OpKind.Property && op.expression instanceof Interpolation },
|
|
19552
|
+
{ test: op => op.kind === OpKind.Property && !(op.expression instanceof Interpolation) },
|
|
19553
|
+
{ test: kindTest(OpKind.Attribute) },
|
|
19554
|
+
];
|
|
19555
|
+
/**
|
|
19556
|
+
* The set of all op kinds we handle in the reordering phase.
|
|
19557
|
+
*/
|
|
19558
|
+
const handledOpKinds = new Set([
|
|
19559
|
+
OpKind.Listener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp,
|
|
19560
|
+
OpKind.ClassProp, OpKind.Property, OpKind.HostProperty, OpKind.Attribute
|
|
19561
|
+
]);
|
|
19562
|
+
function phaseOrdering(job) {
|
|
19563
|
+
for (const unit of job.units) {
|
|
19564
|
+
// First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
|
|
19565
|
+
// be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
|
|
19566
|
+
// still have ops pulled at the end, put them back in the correct order.
|
|
19567
|
+
// Create mode:
|
|
19568
|
+
let opsToOrder = [];
|
|
19569
|
+
for (const op of unit.create) {
|
|
19570
|
+
if (handledOpKinds.has(op.kind)) {
|
|
19571
|
+
opsToOrder.push(op);
|
|
19572
|
+
OpList.remove(op);
|
|
19573
|
+
}
|
|
19574
|
+
else {
|
|
19575
|
+
OpList.insertBefore(reorder(opsToOrder, CREATE_ORDERING), op);
|
|
19576
|
+
opsToOrder = [];
|
|
19577
|
+
}
|
|
19578
|
+
}
|
|
19579
|
+
unit.create.push(reorder(opsToOrder, CREATE_ORDERING));
|
|
19580
|
+
// Update mode:
|
|
19581
|
+
opsToOrder = [];
|
|
19582
|
+
for (const op of unit.update) {
|
|
19583
|
+
if (handledOpKinds.has(op.kind)) {
|
|
19584
|
+
opsToOrder.push(op);
|
|
19585
|
+
OpList.remove(op);
|
|
19586
|
+
}
|
|
19587
|
+
else {
|
|
19588
|
+
OpList.insertBefore(reorder(opsToOrder, UPDATE_ORDERING), op);
|
|
19589
|
+
opsToOrder = [];
|
|
19590
|
+
}
|
|
19591
|
+
}
|
|
19592
|
+
unit.update.push(reorder(opsToOrder, UPDATE_ORDERING));
|
|
19593
|
+
}
|
|
19594
|
+
}
|
|
19595
|
+
/**
|
|
19596
|
+
* Reorders the given list of ops according to the ordering defined by `ORDERING`.
|
|
19597
|
+
*/
|
|
19598
|
+
function reorder(ops, ordering) {
|
|
19599
|
+
// Break the ops list into groups based on OpKind.
|
|
19600
|
+
const groups = Array.from(ordering, () => new Array());
|
|
19601
|
+
for (const op of ops) {
|
|
19602
|
+
const groupIndex = ordering.findIndex(o => o.test(op));
|
|
19603
|
+
groups[groupIndex].push(op);
|
|
19604
|
+
}
|
|
19605
|
+
// Reassemble the groups into a single list, in the correct order.
|
|
19606
|
+
return groups.flatMap((group, i) => {
|
|
19607
|
+
const transform = ordering[i].transform;
|
|
19608
|
+
return transform ? transform(group) : group;
|
|
19609
|
+
});
|
|
19610
|
+
}
|
|
19611
|
+
/**
|
|
19612
|
+
* Keeps only the last op in a list of ops.
|
|
19613
|
+
*/
|
|
19614
|
+
function keepLast(ops) {
|
|
19615
|
+
return ops.slice(ops.length - 1);
|
|
19616
|
+
}
|
|
19617
|
+
|
|
19618
|
+
/**
|
|
19193
19619
|
* Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
|
|
19194
19620
|
* class property.
|
|
19195
19621
|
*/
|
|
@@ -19217,6 +19643,36 @@ function phaseParseExtractedStyles(cpl) {
|
|
|
19217
19643
|
}
|
|
19218
19644
|
}
|
|
19219
19645
|
|
|
19646
|
+
/**
|
|
19647
|
+
* Attributes of `ng-content` named 'select' are specifically removed, because they control which
|
|
19648
|
+
* content matches as a property of the `projection`, and are not a plain attribute.
|
|
19649
|
+
*/
|
|
19650
|
+
function phaseRemoveContentSelectors(job) {
|
|
19651
|
+
for (const unit of job.units) {
|
|
19652
|
+
const elements = getElementsByXrefId(unit);
|
|
19653
|
+
for (const op of unit.update) {
|
|
19654
|
+
switch (op.kind) {
|
|
19655
|
+
case OpKind.Binding:
|
|
19656
|
+
const target = lookupElement(elements, op.target);
|
|
19657
|
+
if (op.name.toLowerCase() === 'select' && target.kind === OpKind.Projection) {
|
|
19658
|
+
OpList.remove(op);
|
|
19659
|
+
}
|
|
19660
|
+
continue;
|
|
19661
|
+
}
|
|
19662
|
+
}
|
|
19663
|
+
}
|
|
19664
|
+
}
|
|
19665
|
+
/**
|
|
19666
|
+
* Looks up an element in the given map by xref ID.
|
|
19667
|
+
*/
|
|
19668
|
+
function lookupElement(elements, xref) {
|
|
19669
|
+
const el = elements.get(xref);
|
|
19670
|
+
if (el === undefined) {
|
|
19671
|
+
throw new Error('All attributes should have an element-like target.');
|
|
19672
|
+
}
|
|
19673
|
+
return el;
|
|
19674
|
+
}
|
|
19675
|
+
|
|
19220
19676
|
function phasePipeCreation(job) {
|
|
19221
19677
|
for (const unit of job.units) {
|
|
19222
19678
|
processPipeBindingsInView(unit);
|
|
@@ -19283,95 +19739,6 @@ function phasePipeVariadic(job) {
|
|
|
19283
19739
|
}
|
|
19284
19740
|
}
|
|
19285
19741
|
|
|
19286
|
-
function kindTest(kind) {
|
|
19287
|
-
return (op) => op.kind === kind;
|
|
19288
|
-
}
|
|
19289
|
-
/**
|
|
19290
|
-
* Defines the groups based on `OpKind` that ops will be divided into, for the various create
|
|
19291
|
-
* binding kinds. Ops will be collected into groups, then optionally transformed, before recombining
|
|
19292
|
-
* the groups in the order defined here.
|
|
19293
|
-
*/
|
|
19294
|
-
const CREATE_ORDERING = [
|
|
19295
|
-
{ test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener },
|
|
19296
|
-
{ test: op => op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener) },
|
|
19297
|
-
];
|
|
19298
|
-
/**
|
|
19299
|
-
* As above, but for update ops.
|
|
19300
|
-
*/
|
|
19301
|
-
const UPDATE_ORDERING = [
|
|
19302
|
-
{ test: op => op.kind === OpKind.HostProperty && op.expression instanceof Interpolation },
|
|
19303
|
-
{ test: op => op.kind === OpKind.HostProperty && !(op.expression instanceof Interpolation) },
|
|
19304
|
-
{ test: kindTest(OpKind.StyleMap), transform: keepLast },
|
|
19305
|
-
{ test: kindTest(OpKind.ClassMap), transform: keepLast },
|
|
19306
|
-
{ test: kindTest(OpKind.StyleProp) },
|
|
19307
|
-
{ test: kindTest(OpKind.ClassProp) },
|
|
19308
|
-
{ test: op => op.kind === OpKind.Property && op.expression instanceof Interpolation },
|
|
19309
|
-
{ test: op => op.kind === OpKind.Property && !(op.expression instanceof Interpolation) },
|
|
19310
|
-
{ test: kindTest(OpKind.Attribute) },
|
|
19311
|
-
];
|
|
19312
|
-
/**
|
|
19313
|
-
* The set of all op kinds we handle in the reordering phase.
|
|
19314
|
-
*/
|
|
19315
|
-
const handledOpKinds = new Set([
|
|
19316
|
-
OpKind.Listener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp,
|
|
19317
|
-
OpKind.ClassProp, OpKind.Property, OpKind.HostProperty, OpKind.Attribute
|
|
19318
|
-
]);
|
|
19319
|
-
function phaseOrdering(job) {
|
|
19320
|
-
for (const unit of job.units) {
|
|
19321
|
-
// First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
|
|
19322
|
-
// be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
|
|
19323
|
-
// still have ops pulled at the end, put them back in the correct order.
|
|
19324
|
-
// Create mode:
|
|
19325
|
-
let opsToOrder = [];
|
|
19326
|
-
for (const op of unit.create) {
|
|
19327
|
-
if (handledOpKinds.has(op.kind)) {
|
|
19328
|
-
opsToOrder.push(op);
|
|
19329
|
-
OpList.remove(op);
|
|
19330
|
-
}
|
|
19331
|
-
else {
|
|
19332
|
-
OpList.insertBefore(reorder(opsToOrder, CREATE_ORDERING), op);
|
|
19333
|
-
opsToOrder = [];
|
|
19334
|
-
}
|
|
19335
|
-
}
|
|
19336
|
-
unit.create.push(reorder(opsToOrder, CREATE_ORDERING));
|
|
19337
|
-
// Update mode:
|
|
19338
|
-
opsToOrder = [];
|
|
19339
|
-
for (const op of unit.update) {
|
|
19340
|
-
if (handledOpKinds.has(op.kind)) {
|
|
19341
|
-
opsToOrder.push(op);
|
|
19342
|
-
OpList.remove(op);
|
|
19343
|
-
}
|
|
19344
|
-
else {
|
|
19345
|
-
OpList.insertBefore(reorder(opsToOrder, UPDATE_ORDERING), op);
|
|
19346
|
-
opsToOrder = [];
|
|
19347
|
-
}
|
|
19348
|
-
}
|
|
19349
|
-
unit.update.push(reorder(opsToOrder, UPDATE_ORDERING));
|
|
19350
|
-
}
|
|
19351
|
-
}
|
|
19352
|
-
/**
|
|
19353
|
-
* Reorders the given list of ops according to the ordering defined by `ORDERING`.
|
|
19354
|
-
*/
|
|
19355
|
-
function reorder(ops, ordering) {
|
|
19356
|
-
// Break the ops list into groups based on OpKind.
|
|
19357
|
-
const groups = Array.from(ordering, () => new Array());
|
|
19358
|
-
for (const op of ops) {
|
|
19359
|
-
const groupIndex = ordering.findIndex(o => o.test(op));
|
|
19360
|
-
groups[groupIndex].push(op);
|
|
19361
|
-
}
|
|
19362
|
-
// Reassemble the groups into a single list, in the correct order.
|
|
19363
|
-
return groups.flatMap((group, i) => {
|
|
19364
|
-
const transform = ordering[i].transform;
|
|
19365
|
-
return transform ? transform(group) : group;
|
|
19366
|
-
});
|
|
19367
|
-
}
|
|
19368
|
-
/**
|
|
19369
|
-
* Keeps only the last op in a list of ops.
|
|
19370
|
-
*/
|
|
19371
|
-
function keepLast(ops) {
|
|
19372
|
-
return ops.slice(ops.length - 1);
|
|
19373
|
-
}
|
|
19374
|
-
|
|
19375
19742
|
function phasePureFunctionExtraction(job) {
|
|
19376
19743
|
for (const view of job.units) {
|
|
19377
19744
|
for (const op of view.ops()) {
|
|
@@ -19402,7 +19769,7 @@ class PureFunctionConstant extends GenericKeyFn {
|
|
|
19402
19769
|
toSharedConstantDeclaration(declName, keyExpr) {
|
|
19403
19770
|
const fnParams = [];
|
|
19404
19771
|
for (let idx = 0; idx < this.numArgs; idx++) {
|
|
19405
|
-
fnParams.push(new FnParam('
|
|
19772
|
+
fnParams.push(new FnParam('a' + idx));
|
|
19406
19773
|
}
|
|
19407
19774
|
// We will never visit `ir.PureFunctionParameterExpr`s that don't belong to us, because this
|
|
19408
19775
|
// transform runs inside another visitor which will visit nested pure functions before this one.
|
|
@@ -19410,9 +19777,9 @@ class PureFunctionConstant extends GenericKeyFn {
|
|
|
19410
19777
|
if (!(expr instanceof PureFunctionParameterExpr)) {
|
|
19411
19778
|
return expr;
|
|
19412
19779
|
}
|
|
19413
|
-
return variable('
|
|
19780
|
+
return variable('a' + expr.index);
|
|
19414
19781
|
}, VisitorContextFlag.None);
|
|
19415
|
-
return new
|
|
19782
|
+
return new DeclareVarStmt(declName, new ArrowFunctionExpr(fnParams, returnExpr), undefined, StmtModifier.Final);
|
|
19416
19783
|
}
|
|
19417
19784
|
}
|
|
19418
19785
|
|
|
@@ -19576,6 +19943,25 @@ function text(slot, initialValue, sourceSpan) {
|
|
|
19576
19943
|
}
|
|
19577
19944
|
return call(Identifiers.text, args, sourceSpan);
|
|
19578
19945
|
}
|
|
19946
|
+
function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot, loadingConfigIndex, placeholderConfigIndex, sourceSpan) {
|
|
19947
|
+
const args = [
|
|
19948
|
+
literal(selfSlot),
|
|
19949
|
+
literal(primarySlot),
|
|
19950
|
+
literal(dependencyResolverFn),
|
|
19951
|
+
literal(loadingSlot),
|
|
19952
|
+
literal(placeholderSlot),
|
|
19953
|
+
literal(errorSlot),
|
|
19954
|
+
literal(loadingConfigIndex),
|
|
19955
|
+
literal(placeholderConfigIndex),
|
|
19956
|
+
];
|
|
19957
|
+
while (args[args.length - 1].value === null) {
|
|
19958
|
+
args.pop();
|
|
19959
|
+
}
|
|
19960
|
+
return call(Identifiers.defer, args, sourceSpan);
|
|
19961
|
+
}
|
|
19962
|
+
function deferOn(sourceSpan) {
|
|
19963
|
+
return call(Identifiers.deferOnIdle, [], sourceSpan);
|
|
19964
|
+
}
|
|
19579
19965
|
function projectionDef(def) {
|
|
19580
19966
|
return call(Identifiers.projectionDef, def ? [def] : [], null);
|
|
19581
19967
|
}
|
|
@@ -19592,8 +19978,8 @@ function projection(slot, projectionSlotIndex, attributes) {
|
|
|
19592
19978
|
function i18nStart(slot, constIndex) {
|
|
19593
19979
|
return call(Identifiers.i18nStart, [literal(slot), literal(constIndex)], null);
|
|
19594
19980
|
}
|
|
19595
|
-
function i18n(slot) {
|
|
19596
|
-
return call(Identifiers.i18n, [literal(slot)], null);
|
|
19981
|
+
function i18n(slot, constIndex) {
|
|
19982
|
+
return call(Identifiers.i18n, [literal(slot), literal(constIndex)], null);
|
|
19597
19983
|
}
|
|
19598
19984
|
function i18nEnd() {
|
|
19599
19985
|
return call(Identifiers.i18nEnd, [], null);
|
|
@@ -19670,6 +20056,12 @@ function textInterpolate(strings, expressions, sourceSpan) {
|
|
|
19670
20056
|
}
|
|
19671
20057
|
return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
|
|
19672
20058
|
}
|
|
20059
|
+
function i18nExp(expr, sourceSpan) {
|
|
20060
|
+
return call(Identifiers.i18nExp, [expr], sourceSpan);
|
|
20061
|
+
}
|
|
20062
|
+
function i18nApply(slot, sourceSpan) {
|
|
20063
|
+
return call(Identifiers.i18nApply, [literal(slot)], sourceSpan);
|
|
20064
|
+
}
|
|
19673
20065
|
function propertyInterpolate(name, strings, expressions, sanitizer, sourceSpan) {
|
|
19674
20066
|
const interpolationArgs = collateInterpolationArgs(strings, expressions);
|
|
19675
20067
|
const extraArgs = [];
|
|
@@ -19739,8 +20131,12 @@ function call(instruction, args, sourceSpan) {
|
|
|
19739
20131
|
const expr = importExpr(instruction).callFn(args, sourceSpan);
|
|
19740
20132
|
return createStatementOp(new ExpressionStatement(expr, sourceSpan));
|
|
19741
20133
|
}
|
|
19742
|
-
function conditional(slot, condition) {
|
|
19743
|
-
|
|
20134
|
+
function conditional(slot, condition, contextValue, sourceSpan) {
|
|
20135
|
+
const args = [literal(slot), condition];
|
|
20136
|
+
if (contextValue !== null) {
|
|
20137
|
+
args.push(contextValue);
|
|
20138
|
+
}
|
|
20139
|
+
return call(Identifiers.conditional, args, sourceSpan);
|
|
19744
20140
|
}
|
|
19745
20141
|
/**
|
|
19746
20142
|
* `InterpolationConfig` for the `textInterpolate` instruction.
|
|
@@ -19972,14 +20368,14 @@ function reifyCreateOperations(unit, ops) {
|
|
|
19972
20368
|
OpList.replace(op, i18nEnd());
|
|
19973
20369
|
break;
|
|
19974
20370
|
case OpKind.I18n:
|
|
19975
|
-
OpList.replace(op, i18n(op.slot));
|
|
20371
|
+
OpList.replace(op, i18n(op.slot, op.messageIndex));
|
|
19976
20372
|
break;
|
|
19977
20373
|
case OpKind.Template:
|
|
19978
20374
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
19979
20375
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
19980
20376
|
}
|
|
19981
20377
|
const childView = unit.job.views.get(op.xref);
|
|
19982
|
-
OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.
|
|
20378
|
+
OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.block ? null : op.tag, op.attributes, op.sourceSpan));
|
|
19983
20379
|
break;
|
|
19984
20380
|
case OpKind.DisableBindings:
|
|
19985
20381
|
OpList.replace(op, disableBindings());
|
|
@@ -20016,6 +20412,15 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20016
20412
|
break;
|
|
20017
20413
|
}
|
|
20018
20414
|
break;
|
|
20415
|
+
case OpKind.Defer:
|
|
20416
|
+
OpList.replace(op, defer(op.slot, op.targetSlot, null, op.loading && op.loading.targetSlot, op.placeholder && op.placeholder.targetSlot, op.error && op.error.targetSlot, op.loading?.constIndex ?? null, op.placeholder?.constIndex ?? null, op.sourceSpan));
|
|
20417
|
+
break;
|
|
20418
|
+
case OpKind.DeferSecondaryBlock:
|
|
20419
|
+
OpList.remove(op);
|
|
20420
|
+
break;
|
|
20421
|
+
case OpKind.DeferOn:
|
|
20422
|
+
OpList.replace(op, deferOn(op.sourceSpan));
|
|
20423
|
+
break;
|
|
20019
20424
|
case OpKind.ProjectionDef:
|
|
20020
20425
|
OpList.replace(op, projectionDef(op.def));
|
|
20021
20426
|
break;
|
|
@@ -20075,6 +20480,12 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
20075
20480
|
OpList.replace(op, classMap(op.expression, op.sourceSpan));
|
|
20076
20481
|
}
|
|
20077
20482
|
break;
|
|
20483
|
+
case OpKind.I18nExpression:
|
|
20484
|
+
OpList.replace(op, i18nExp(op.expression, op.sourceSpan));
|
|
20485
|
+
break;
|
|
20486
|
+
case OpKind.I18nApply:
|
|
20487
|
+
OpList.replace(op, i18nApply(op.targetSlot, op.sourceSpan));
|
|
20488
|
+
break;
|
|
20078
20489
|
case OpKind.InterpolateText:
|
|
20079
20490
|
OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
|
|
20080
20491
|
break;
|
|
@@ -20109,10 +20520,10 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
20109
20520
|
if (op.processed === null) {
|
|
20110
20521
|
throw new Error(`Conditional test was not set.`);
|
|
20111
20522
|
}
|
|
20112
|
-
if (op.
|
|
20523
|
+
if (op.targetSlot === null) {
|
|
20113
20524
|
throw new Error(`Conditional slot was not set.`);
|
|
20114
20525
|
}
|
|
20115
|
-
OpList.replace(op, conditional(op.
|
|
20526
|
+
OpList.replace(op, conditional(op.targetSlot, op.processed, op.contextValue, op.sourceSpan));
|
|
20116
20527
|
break;
|
|
20117
20528
|
case OpKind.Statement:
|
|
20118
20529
|
// Pass statement operations directly through.
|
|
@@ -20130,7 +20541,7 @@ function reifyIrExpression(expr) {
|
|
|
20130
20541
|
case ExpressionKind.NextContext:
|
|
20131
20542
|
return nextContext(expr.steps);
|
|
20132
20543
|
case ExpressionKind.Reference:
|
|
20133
|
-
return reference(expr.
|
|
20544
|
+
return reference(expr.targetSlot + 1 + expr.offset);
|
|
20134
20545
|
case ExpressionKind.LexicalRead:
|
|
20135
20546
|
throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
|
|
20136
20547
|
case ExpressionKind.RestoreView:
|
|
@@ -20165,13 +20576,13 @@ function reifyIrExpression(expr) {
|
|
|
20165
20576
|
case ExpressionKind.PureFunctionParameterExpr:
|
|
20166
20577
|
throw new Error(`AssertionError: expected PureFunctionParameterExpr to have been extracted`);
|
|
20167
20578
|
case ExpressionKind.PipeBinding:
|
|
20168
|
-
return pipeBind(expr.
|
|
20579
|
+
return pipeBind(expr.targetSlot, expr.varOffset, expr.args);
|
|
20169
20580
|
case ExpressionKind.PipeBindingVariadic:
|
|
20170
|
-
return pipeBindV(expr.
|
|
20581
|
+
return pipeBindV(expr.targetSlot, expr.varOffset, expr.args);
|
|
20171
20582
|
case ExpressionKind.SanitizerExpr:
|
|
20172
20583
|
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
20173
20584
|
case ExpressionKind.SlotLiteralExpr:
|
|
20174
|
-
return literal(expr.
|
|
20585
|
+
return literal(expr.targetSlot);
|
|
20175
20586
|
default:
|
|
20176
20587
|
throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
|
|
20177
20588
|
}
|
|
@@ -20300,49 +20711,92 @@ const ESCAPE = '\uFFFD';
|
|
|
20300
20711
|
*/
|
|
20301
20712
|
function phaseResolveI18nPlaceholders(job) {
|
|
20302
20713
|
for (const unit of job.units) {
|
|
20303
|
-
|
|
20304
|
-
let
|
|
20305
|
-
let
|
|
20714
|
+
const i18nOps = new Map();
|
|
20715
|
+
let startTagSlots = new Map();
|
|
20716
|
+
let closeTagSlots = new Map();
|
|
20717
|
+
let currentI18nOp = null;
|
|
20718
|
+
// Record slots for tag name placeholders.
|
|
20306
20719
|
for (const op of unit.create) {
|
|
20307
|
-
|
|
20308
|
-
|
|
20309
|
-
|
|
20310
|
-
|
|
20311
|
-
|
|
20720
|
+
switch (op.kind) {
|
|
20721
|
+
case OpKind.I18nStart:
|
|
20722
|
+
case OpKind.I18n:
|
|
20723
|
+
// Initialize collected slots for a new i18n block.
|
|
20724
|
+
i18nOps.set(op.xref, op);
|
|
20725
|
+
currentI18nOp = op.kind === OpKind.I18nStart ? op : null;
|
|
20726
|
+
startTagSlots = new Map();
|
|
20727
|
+
closeTagSlots = new Map();
|
|
20728
|
+
break;
|
|
20729
|
+
case OpKind.I18nEnd:
|
|
20730
|
+
// Add values for tag placeholders.
|
|
20731
|
+
if (currentI18nOp === null) {
|
|
20732
|
+
throw Error('Missing corresponding i18n start op for i18n end op');
|
|
20733
|
+
}
|
|
20734
|
+
for (const [placeholder, slots] of startTagSlots) {
|
|
20735
|
+
currentI18nOp.params.set(placeholder, serializeSlots(slots, true));
|
|
20736
|
+
}
|
|
20737
|
+
for (const [placeholder, slots] of closeTagSlots) {
|
|
20738
|
+
currentI18nOp.params.set(placeholder, serializeSlots(slots, false));
|
|
20739
|
+
}
|
|
20740
|
+
currentI18nOp = null;
|
|
20741
|
+
break;
|
|
20742
|
+
case OpKind.Element:
|
|
20743
|
+
case OpKind.ElementStart:
|
|
20744
|
+
// Record slots for tag placeholders.
|
|
20745
|
+
if (op.i18nPlaceholder != undefined) {
|
|
20746
|
+
if (currentI18nOp === null) {
|
|
20747
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
20748
|
+
}
|
|
20749
|
+
if (!op.slot) {
|
|
20750
|
+
throw Error('Slots should be allocated before i18n placeholder resolution');
|
|
20751
|
+
}
|
|
20752
|
+
const { startName, closeName } = op.i18nPlaceholder;
|
|
20753
|
+
addTagSlot(startTagSlots, startName, op.slot);
|
|
20754
|
+
addTagSlot(closeTagSlots, closeName, op.slot);
|
|
20755
|
+
}
|
|
20756
|
+
break;
|
|
20312
20757
|
}
|
|
20313
|
-
|
|
20314
|
-
|
|
20315
|
-
|
|
20316
|
-
|
|
20758
|
+
}
|
|
20759
|
+
// Fill in values for each of the expression placeholders applied in i18nApply operations.
|
|
20760
|
+
const i18nBlockPlaceholderIndices = new Map();
|
|
20761
|
+
for (const op of unit.update) {
|
|
20762
|
+
if (op.kind === OpKind.I18nExpression) {
|
|
20763
|
+
const i18nOp = i18nOps.get(op.target);
|
|
20764
|
+
let index = i18nBlockPlaceholderIndices.get(op.target) || 0;
|
|
20765
|
+
if (!i18nOp) {
|
|
20766
|
+
throw Error('Cannot find corresponding i18nStart for i18nExpr');
|
|
20317
20767
|
}
|
|
20318
|
-
|
|
20319
|
-
|
|
20320
|
-
// TODO: when TemplateDefinitionBuilder compatibility is not required, we can just add both
|
|
20321
|
-
// keys directly to the map here.
|
|
20322
|
-
startTags.push({
|
|
20323
|
-
i18nOp,
|
|
20324
|
-
placeholder: op.i18n.startName,
|
|
20325
|
-
value: literal(`${ESCAPE}#${op.slot}${ESCAPE}`)
|
|
20326
|
-
});
|
|
20327
|
-
closeTags.push({
|
|
20328
|
-
i18nOp,
|
|
20329
|
-
placeholder: op.i18n.closeName,
|
|
20330
|
-
value: literal(`${ESCAPE}/#${op.slot}${ESCAPE}`)
|
|
20331
|
-
});
|
|
20768
|
+
i18nOp.params.set(op.i18nPlaceholder.name, literal(`${ESCAPE}${index++}${ESCAPE}`));
|
|
20769
|
+
i18nBlockPlaceholderIndices.set(op.target, index);
|
|
20332
20770
|
}
|
|
20333
20771
|
}
|
|
20334
|
-
//
|
|
20335
|
-
for (const
|
|
20336
|
-
|
|
20337
|
-
|
|
20338
|
-
|
|
20339
|
-
|
|
20340
|
-
|
|
20341
|
-
const { i18nOp, placeholder, value } = closeTags[i];
|
|
20342
|
-
i18nOp.tagNameParams[placeholder] = value;
|
|
20772
|
+
// Verify that all placeholders have been resolved.
|
|
20773
|
+
for (const op of i18nOps.values()) {
|
|
20774
|
+
for (const placeholder in op.message.placeholders) {
|
|
20775
|
+
if (!op.params.has(placeholder)) {
|
|
20776
|
+
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
20777
|
+
}
|
|
20778
|
+
}
|
|
20343
20779
|
}
|
|
20344
20780
|
}
|
|
20345
20781
|
}
|
|
20782
|
+
/**
|
|
20783
|
+
* Updates the given slots map with the specified slot.
|
|
20784
|
+
*/
|
|
20785
|
+
function addTagSlot(tagSlots, placeholder, slot) {
|
|
20786
|
+
const slots = tagSlots.get(placeholder) || [];
|
|
20787
|
+
slots.push(slot);
|
|
20788
|
+
tagSlots.set(placeholder, slots);
|
|
20789
|
+
}
|
|
20790
|
+
/**
|
|
20791
|
+
* Serializes a list of slots to a string literal expression.
|
|
20792
|
+
*/
|
|
20793
|
+
function serializeSlots(slots, start) {
|
|
20794
|
+
const slotStrings = slots.map(slot => `${ESCAPE}${start ? '' : '/'}#${slot}${ESCAPE}`);
|
|
20795
|
+
if (slotStrings.length === 1) {
|
|
20796
|
+
return literal(slotStrings[0]);
|
|
20797
|
+
}
|
|
20798
|
+
return literal(`[${slotStrings.join('|')}]`);
|
|
20799
|
+
}
|
|
20346
20800
|
|
|
20347
20801
|
/**
|
|
20348
20802
|
* Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
|
|
@@ -20586,19 +21040,19 @@ function phaseSlotAllocation(job) {
|
|
|
20586
21040
|
const childView = job.views.get(op.xref);
|
|
20587
21041
|
op.decls = childView.decls;
|
|
20588
21042
|
}
|
|
20589
|
-
if (hasUsesSlotIndexTrait(op) && op.
|
|
21043
|
+
if (hasUsesSlotIndexTrait(op) && op.targetSlot === null) {
|
|
20590
21044
|
if (!slotMap.has(op.target)) {
|
|
20591
21045
|
// We do expect to find a slot allocated for everything which might be referenced.
|
|
20592
21046
|
throw new Error(`AssertionError: no slot allocated for ${OpKind[op.kind]} target ${op.target}`);
|
|
20593
21047
|
}
|
|
20594
|
-
op.
|
|
21048
|
+
op.targetSlot = slotMap.get(op.target);
|
|
20595
21049
|
}
|
|
20596
21050
|
// Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
|
|
20597
21051
|
visitExpressionsInOp(op, expr => {
|
|
20598
21052
|
if (!isIrExpression(expr)) {
|
|
20599
21053
|
return;
|
|
20600
21054
|
}
|
|
20601
|
-
if (!hasUsesSlotIndexTrait(expr) || expr.
|
|
21055
|
+
if (!hasUsesSlotIndexTrait(expr) || expr.targetSlot !== null) {
|
|
20602
21056
|
return;
|
|
20603
21057
|
}
|
|
20604
21058
|
// The `UsesSlotIndexExprTrait` indicates that this expression references something declared
|
|
@@ -20609,7 +21063,7 @@ function phaseSlotAllocation(job) {
|
|
|
20609
21063
|
throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
|
|
20610
21064
|
}
|
|
20611
21065
|
// Record the allocated slot on the expression.
|
|
20612
|
-
expr.
|
|
21066
|
+
expr.targetSlot = slotMap.get(expr.target);
|
|
20613
21067
|
});
|
|
20614
21068
|
}
|
|
20615
21069
|
}
|
|
@@ -20660,47 +21114,62 @@ function phaseStyleBindingSpecialization(cpl) {
|
|
|
20660
21114
|
*/
|
|
20661
21115
|
function phaseTemporaryVariables(cpl) {
|
|
20662
21116
|
for (const unit of cpl.units) {
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20671
|
-
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
|
|
20678
|
-
|
|
20679
|
-
|
|
20680
|
-
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
21117
|
+
unit.create.prepend(generateTemporaries(unit.create));
|
|
21118
|
+
unit.update.prepend(generateTemporaries(unit.update));
|
|
21119
|
+
}
|
|
21120
|
+
}
|
|
21121
|
+
function generateTemporaries(ops) {
|
|
21122
|
+
let opCount = 0;
|
|
21123
|
+
let generatedStatements = [];
|
|
21124
|
+
// For each op, search for any variables that are assigned or read. For each variable, generate a
|
|
21125
|
+
// name and produce a `DeclareVarStmt` to the beginning of the block.
|
|
21126
|
+
for (const op of ops) {
|
|
21127
|
+
// Identify the final time each temp var is read.
|
|
21128
|
+
const finalReads = new Map();
|
|
21129
|
+
visitExpressionsInOp(op, (expr, flag) => {
|
|
21130
|
+
if (flag & VisitorContextFlag.InChildOperation) {
|
|
21131
|
+
return;
|
|
21132
|
+
}
|
|
21133
|
+
if (expr instanceof ReadTemporaryExpr) {
|
|
21134
|
+
finalReads.set(expr.xref, expr);
|
|
21135
|
+
}
|
|
21136
|
+
});
|
|
21137
|
+
// Name the temp vars, accounting for the fact that a name can be reused after it has been
|
|
21138
|
+
// read for the final time.
|
|
21139
|
+
let count = 0;
|
|
21140
|
+
const assigned = new Set();
|
|
21141
|
+
const released = new Set();
|
|
21142
|
+
const defs = new Map();
|
|
21143
|
+
visitExpressionsInOp(op, (expr, flag) => {
|
|
21144
|
+
if (flag & VisitorContextFlag.InChildOperation) {
|
|
21145
|
+
return;
|
|
21146
|
+
}
|
|
21147
|
+
if (expr instanceof AssignTemporaryExpr) {
|
|
21148
|
+
if (!assigned.has(expr.xref)) {
|
|
21149
|
+
assigned.add(expr.xref);
|
|
21150
|
+
// TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
|
|
21151
|
+
// It seems to rely on an expression index instead of an op index.
|
|
21152
|
+
defs.set(expr.xref, `tmp_${opCount}_${count++}`);
|
|
20688
21153
|
}
|
|
20689
|
-
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
|
|
20693
|
-
|
|
20694
|
-
|
|
21154
|
+
assignName(defs, expr);
|
|
21155
|
+
}
|
|
21156
|
+
else if (expr instanceof ReadTemporaryExpr) {
|
|
21157
|
+
if (finalReads.get(expr.xref) === expr) {
|
|
21158
|
+
released.add(expr.xref);
|
|
21159
|
+
count--;
|
|
20695
21160
|
}
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
21161
|
+
assignName(defs, expr);
|
|
21162
|
+
}
|
|
21163
|
+
});
|
|
21164
|
+
// Add declarations for the temp vars.
|
|
21165
|
+
generatedStatements.push(...Array.from(new Set(defs.values()))
|
|
21166
|
+
.map(name => createStatementOp(new DeclareVarStmt(name))));
|
|
21167
|
+
opCount++;
|
|
21168
|
+
if (op.kind === OpKind.Listener) {
|
|
21169
|
+
op.handlerOps.prepend(generateTemporaries(op.handlerOps));
|
|
20701
21170
|
}
|
|
20702
|
-
unit.update.prepend(generatedStatements);
|
|
20703
21171
|
}
|
|
21172
|
+
return generatedStatements;
|
|
20704
21173
|
}
|
|
20705
21174
|
/**
|
|
20706
21175
|
* Assigns a name to the temporary variable in the given temporary variable expression.
|
|
@@ -21068,6 +21537,13 @@ function allowConservativeInlining(decl, target) {
|
|
|
21068
21537
|
// that behavior here.
|
|
21069
21538
|
switch (decl.variable.kind) {
|
|
21070
21539
|
case SemanticVariableKind.Identifier:
|
|
21540
|
+
if (decl.initializer instanceof ReadVarExpr && decl.initializer.name === 'ctx') {
|
|
21541
|
+
// Although TemplateDefinitionBuilder is cautious about inlining, we still want to do so
|
|
21542
|
+
// when the variable is the context, to imitate its behavior with aliases in control flow
|
|
21543
|
+
// blocks. This quirky behavior will become dead code once compatibility mode is no longer
|
|
21544
|
+
// supported.
|
|
21545
|
+
return true;
|
|
21546
|
+
}
|
|
21071
21547
|
return false;
|
|
21072
21548
|
case SemanticVariableKind.Context:
|
|
21073
21549
|
// Context can only be inlined into other variables.
|
|
@@ -21077,101 +21553,8 @@ function allowConservativeInlining(decl, target) {
|
|
|
21077
21553
|
}
|
|
21078
21554
|
}
|
|
21079
21555
|
|
|
21080
|
-
/**
|
|
21081
|
-
* Locate projection slots, populate the each component's `ngContentSelectors` literal field,
|
|
21082
|
-
* populate `project` arguments, and generate the required `projectionDef` instruction for the job's
|
|
21083
|
-
* root view.
|
|
21084
|
-
*/
|
|
21085
|
-
function phaseGenerateProjectionDef(job) {
|
|
21086
|
-
// TODO: Why does TemplateDefinitionBuilder force a shared constant?
|
|
21087
|
-
const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
|
|
21088
|
-
// Collect all selectors from this component, and its nested views. Also, assign each projection a
|
|
21089
|
-
// unique ascending projection slot index.
|
|
21090
|
-
const selectors = [];
|
|
21091
|
-
let projectionSlotIndex = 0;
|
|
21092
|
-
for (const unit of job.units) {
|
|
21093
|
-
for (const op of unit.create) {
|
|
21094
|
-
if (op.kind === OpKind.Projection) {
|
|
21095
|
-
selectors.push(op.selector);
|
|
21096
|
-
op.projectionSlotIndex = projectionSlotIndex++;
|
|
21097
|
-
}
|
|
21098
|
-
}
|
|
21099
|
-
}
|
|
21100
|
-
if (selectors.length > 0) {
|
|
21101
|
-
// Create the projectionDef array. If we only found a single wildcard selector, then we use the
|
|
21102
|
-
// default behavior with no arguments instead.
|
|
21103
|
-
let defExpr = null;
|
|
21104
|
-
if (selectors.length > 1 || selectors[0] !== '*') {
|
|
21105
|
-
const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
|
|
21106
|
-
defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
|
|
21107
|
-
}
|
|
21108
|
-
// Create the ngContentSelectors constant.
|
|
21109
|
-
job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
|
|
21110
|
-
// The projection def instruction goes at the beginning of the root view, before any
|
|
21111
|
-
// `projection` instructions.
|
|
21112
|
-
job.root.create.prepend([createProjectionDefOp(defExpr)]);
|
|
21113
|
-
}
|
|
21114
|
-
}
|
|
21115
|
-
|
|
21116
|
-
/**
|
|
21117
|
-
* Lifts i18n properties into the consts array.
|
|
21118
|
-
*/
|
|
21119
|
-
function phaseI18nConstCollection(job) {
|
|
21120
|
-
// Serialize the extracted messages into the const array.
|
|
21121
|
-
// TODO: Use `Map` instead of object.
|
|
21122
|
-
const messageConstIndices = {};
|
|
21123
|
-
for (const unit of job.units) {
|
|
21124
|
-
for (const op of unit.create) {
|
|
21125
|
-
if (op.kind === OpKind.ExtractedMessage) {
|
|
21126
|
-
messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
|
|
21127
|
-
OpList.remove(op);
|
|
21128
|
-
}
|
|
21129
|
-
}
|
|
21130
|
-
}
|
|
21131
|
-
// Assign const index to i18n ops that messages were extracted from.
|
|
21132
|
-
for (const unit of job.units) {
|
|
21133
|
-
for (const op of unit.create) {
|
|
21134
|
-
if (op.kind === OpKind.I18nStart && messageConstIndices[op.xref] !== undefined) {
|
|
21135
|
-
op.messageIndex = messageConstIndices[op.xref];
|
|
21136
|
-
}
|
|
21137
|
-
}
|
|
21138
|
-
}
|
|
21139
|
-
}
|
|
21140
|
-
|
|
21141
|
-
/**
|
|
21142
|
-
* Attributes of `ng-content` named 'select' are specifically removed, because they control which
|
|
21143
|
-
* content matches as a property of the `projection`, and are not a plain attribute.
|
|
21144
|
-
*/
|
|
21145
|
-
function phaseRemoveContentSelectors(job) {
|
|
21146
|
-
for (const unit of job.units) {
|
|
21147
|
-
const elements = getElementsByXrefId(unit);
|
|
21148
|
-
for (const op of unit.update) {
|
|
21149
|
-
switch (op.kind) {
|
|
21150
|
-
case OpKind.Binding:
|
|
21151
|
-
const target = lookupElement(elements, op.target);
|
|
21152
|
-
if (op.name.toLowerCase() === 'select' && target.kind === OpKind.Projection) {
|
|
21153
|
-
OpList.remove(op);
|
|
21154
|
-
}
|
|
21155
|
-
continue;
|
|
21156
|
-
}
|
|
21157
|
-
}
|
|
21158
|
-
}
|
|
21159
|
-
}
|
|
21160
|
-
/**
|
|
21161
|
-
* Looks up an element in the given map by xref ID.
|
|
21162
|
-
*/
|
|
21163
|
-
function lookupElement(elements, xref) {
|
|
21164
|
-
const el = elements.get(xref);
|
|
21165
|
-
if (el === undefined) {
|
|
21166
|
-
throw new Error('All attributes should have an element-like target.');
|
|
21167
|
-
}
|
|
21168
|
-
return el;
|
|
21169
|
-
}
|
|
21170
|
-
|
|
21171
21556
|
const phases = [
|
|
21172
21557
|
{ kind: CompilationJobKind.Tmpl, fn: phaseRemoveContentSelectors },
|
|
21173
|
-
{ kind: CompilationJobKind.Tmpl, fn: phaseGenerateI18nBlocks },
|
|
21174
|
-
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
|
|
21175
21558
|
{ kind: CompilationJobKind.Host, fn: phaseHostStylePropertyParsing },
|
|
21176
21559
|
{ kind: CompilationJobKind.Tmpl, fn: phaseNamespace },
|
|
21177
21560
|
{ kind: CompilationJobKind.Both, fn: phaseStyleBindingSpecialization },
|
|
@@ -21180,8 +21563,9 @@ const phases = [
|
|
|
21180
21563
|
{ kind: CompilationJobKind.Both, fn: phaseParseExtractedStyles },
|
|
21181
21564
|
{ kind: CompilationJobKind.Tmpl, fn: phaseRemoveEmptyBindings },
|
|
21182
21565
|
{ kind: CompilationJobKind.Tmpl, fn: phaseConditionals },
|
|
21183
|
-
{ kind: CompilationJobKind.Tmpl, fn: phaseNoListenersOnTemplates },
|
|
21184
21566
|
{ kind: CompilationJobKind.Tmpl, fn: phasePipeCreation },
|
|
21567
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
|
|
21568
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseApplyI18nExpressions },
|
|
21185
21569
|
{ kind: CompilationJobKind.Tmpl, fn: phasePipeVariadic },
|
|
21186
21570
|
{ kind: CompilationJobKind.Both, fn: phasePureLiteralStructures },
|
|
21187
21571
|
{ kind: CompilationJobKind.Tmpl, fn: phaseGenerateProjectionDef },
|
|
@@ -21200,6 +21584,7 @@ const phases = [
|
|
|
21200
21584
|
{ kind: CompilationJobKind.Tmpl, fn: phaseResolveI18nPlaceholders },
|
|
21201
21585
|
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nMessageExtraction },
|
|
21202
21586
|
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
|
|
21587
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseConstTraitCollection },
|
|
21203
21588
|
{ kind: CompilationJobKind.Both, fn: phaseConstCollection },
|
|
21204
21589
|
{ kind: CompilationJobKind.Both, fn: phaseVarCounting },
|
|
21205
21590
|
{ kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
|
|
@@ -21404,9 +21789,15 @@ function ingestNodes(unit, template) {
|
|
|
21404
21789
|
else if (node instanceof BoundText) {
|
|
21405
21790
|
ingestBoundText(unit, node);
|
|
21406
21791
|
}
|
|
21792
|
+
else if (node instanceof IfBlock) {
|
|
21793
|
+
ingestIfBlock(unit, node);
|
|
21794
|
+
}
|
|
21407
21795
|
else if (node instanceof SwitchBlock) {
|
|
21408
21796
|
ingestSwitchBlock(unit, node);
|
|
21409
21797
|
}
|
|
21798
|
+
else if (node instanceof DeferredBlock) {
|
|
21799
|
+
ingestDeferBlock(unit, node);
|
|
21800
|
+
}
|
|
21410
21801
|
else {
|
|
21411
21802
|
throw new Error(`Unsupported template node: ${node.constructor.name}`);
|
|
21412
21803
|
}
|
|
@@ -21416,23 +21807,37 @@ function ingestNodes(unit, template) {
|
|
|
21416
21807
|
* Ingest an element AST from the template into the given `ViewCompilation`.
|
|
21417
21808
|
*/
|
|
21418
21809
|
function ingestElement(unit, element) {
|
|
21810
|
+
if (element.i18n !== undefined &&
|
|
21811
|
+
!(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
|
|
21812
|
+
throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
|
|
21813
|
+
}
|
|
21419
21814
|
const staticAttributes = {};
|
|
21420
21815
|
for (const attr of element.attributes) {
|
|
21421
21816
|
staticAttributes[attr.name] = attr.value;
|
|
21422
21817
|
}
|
|
21423
21818
|
const id = unit.job.allocateXrefId();
|
|
21424
21819
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
21425
|
-
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n, element.startSourceSpan);
|
|
21820
|
+
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
21426
21821
|
unit.create.push(startOp);
|
|
21427
21822
|
ingestBindings(unit, startOp, element);
|
|
21428
21823
|
ingestReferences(startOp, element);
|
|
21429
21824
|
ingestNodes(unit, element.children);
|
|
21430
|
-
|
|
21825
|
+
const endOp = createElementEndOp(id, element.endSourceSpan);
|
|
21826
|
+
unit.create.push(endOp);
|
|
21827
|
+
// If there is an i18n message associated with this element, insert i18n start and end ops.
|
|
21828
|
+
if (element.i18n instanceof Message) {
|
|
21829
|
+
const i18nBlockId = unit.job.allocateXrefId();
|
|
21830
|
+
OpList.insertAfter(createI18nStartOp(i18nBlockId, element.i18n), startOp);
|
|
21831
|
+
OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
|
|
21832
|
+
}
|
|
21431
21833
|
}
|
|
21432
21834
|
/**
|
|
21433
21835
|
* Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
|
|
21434
21836
|
*/
|
|
21435
21837
|
function ingestTemplate(unit, tmpl) {
|
|
21838
|
+
if (tmpl.i18n !== undefined && !(tmpl.i18n instanceof Message)) {
|
|
21839
|
+
throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
|
|
21840
|
+
}
|
|
21436
21841
|
const childView = unit.job.allocateView(unit.xref);
|
|
21437
21842
|
let tagNameWithoutNamespace = tmpl.tagName;
|
|
21438
21843
|
let namespacePrefix = '';
|
|
@@ -21440,7 +21845,7 @@ function ingestTemplate(unit, tmpl) {
|
|
|
21440
21845
|
[namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
|
|
21441
21846
|
}
|
|
21442
21847
|
// TODO: validate the fallback tag name here.
|
|
21443
|
-
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false,
|
|
21848
|
+
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, undefined, tmpl.startSourceSpan);
|
|
21444
21849
|
unit.create.push(tplOp);
|
|
21445
21850
|
ingestBindings(unit, tplOp, tmpl);
|
|
21446
21851
|
ingestReferences(tplOp, tmpl);
|
|
@@ -21448,6 +21853,12 @@ function ingestTemplate(unit, tmpl) {
|
|
|
21448
21853
|
for (const { name, value } of tmpl.variables) {
|
|
21449
21854
|
childView.contextVariables.set(name, value);
|
|
21450
21855
|
}
|
|
21856
|
+
// If there is an i18n message associated with this template, insert i18n start and end ops.
|
|
21857
|
+
if (tmpl.i18n instanceof Message) {
|
|
21858
|
+
const id = unit.job.allocateXrefId();
|
|
21859
|
+
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
21860
|
+
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
21861
|
+
}
|
|
21451
21862
|
}
|
|
21452
21863
|
/**
|
|
21453
21864
|
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
@@ -21455,7 +21866,7 @@ function ingestTemplate(unit, tmpl) {
|
|
|
21455
21866
|
function ingestContent(unit, content) {
|
|
21456
21867
|
const op = createProjectionOp(unit.job.allocateXrefId(), content.selector);
|
|
21457
21868
|
for (const attr of content.attributes) {
|
|
21458
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan,
|
|
21869
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue);
|
|
21459
21870
|
}
|
|
21460
21871
|
unit.create.push(op);
|
|
21461
21872
|
}
|
|
@@ -21476,35 +21887,109 @@ function ingestBoundText(unit, text) {
|
|
|
21476
21887
|
if (!(value instanceof Interpolation$1)) {
|
|
21477
21888
|
throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
|
|
21478
21889
|
}
|
|
21890
|
+
if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
|
|
21891
|
+
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n.constructor.name}`);
|
|
21892
|
+
}
|
|
21893
|
+
const i18nPlaceholders = text.i18n instanceof Container ?
|
|
21894
|
+
text.i18n.children.filter((node) => node instanceof Placeholder) :
|
|
21895
|
+
[];
|
|
21479
21896
|
const textXref = unit.job.allocateXrefId();
|
|
21480
21897
|
unit.create.push(createTextOp(textXref, '', text.sourceSpan));
|
|
21481
21898
|
// TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
|
|
21482
21899
|
// interpolation. We copy that behavior in compatibility mode.
|
|
21483
21900
|
// TODO: is it actually correct to generate these extra maps in modern mode?
|
|
21484
21901
|
const baseSourceSpan = unit.job.compatibility ? null : text.sourceSpan;
|
|
21485
|
-
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))), text.sourceSpan));
|
|
21902
|
+
unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))), i18nPlaceholders, text.sourceSpan));
|
|
21486
21903
|
}
|
|
21487
21904
|
/**
|
|
21488
|
-
* Ingest
|
|
21905
|
+
* Ingest an `@if` block into the given `ViewCompilation`.
|
|
21906
|
+
*/
|
|
21907
|
+
function ingestIfBlock(unit, ifBlock) {
|
|
21908
|
+
let firstXref = null;
|
|
21909
|
+
let conditions = [];
|
|
21910
|
+
for (const ifCase of ifBlock.branches) {
|
|
21911
|
+
const cView = unit.job.allocateView(unit.xref);
|
|
21912
|
+
if (ifCase.expressionAlias !== null) {
|
|
21913
|
+
cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
|
|
21914
|
+
}
|
|
21915
|
+
if (firstXref === null) {
|
|
21916
|
+
firstXref = cView.xref;
|
|
21917
|
+
}
|
|
21918
|
+
unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined, ifCase.sourceSpan));
|
|
21919
|
+
const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
|
|
21920
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref, ifCase.expressionAlias);
|
|
21921
|
+
conditions.push(conditionalCaseExpr);
|
|
21922
|
+
ingestNodes(cView, ifCase.children);
|
|
21923
|
+
}
|
|
21924
|
+
const conditional = createConditionalOp(firstXref, null, conditions, ifBlock.sourceSpan);
|
|
21925
|
+
unit.update.push(conditional);
|
|
21926
|
+
}
|
|
21927
|
+
/**
|
|
21928
|
+
* Ingest an `@switch` block into the given `ViewCompilation`.
|
|
21489
21929
|
*/
|
|
21490
21930
|
function ingestSwitchBlock(unit, switchBlock) {
|
|
21491
21931
|
let firstXref = null;
|
|
21492
21932
|
let conditions = [];
|
|
21493
21933
|
for (const switchCase of switchBlock.cases) {
|
|
21494
21934
|
const cView = unit.job.allocateView(unit.xref);
|
|
21495
|
-
if (
|
|
21935
|
+
if (firstXref === null) {
|
|
21496
21936
|
firstXref = cView.xref;
|
|
21497
|
-
|
|
21937
|
+
}
|
|
21938
|
+
unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined, switchCase.sourceSpan));
|
|
21498
21939
|
const caseExpr = switchCase.expression ?
|
|
21499
21940
|
convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
|
|
21500
21941
|
null;
|
|
21501
|
-
|
|
21942
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref);
|
|
21943
|
+
conditions.push(conditionalCaseExpr);
|
|
21502
21944
|
ingestNodes(cView, switchCase.children);
|
|
21503
21945
|
}
|
|
21504
|
-
const conditional = createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job,
|
|
21505
|
-
conditional.conditions = conditions;
|
|
21946
|
+
const conditional = createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
|
|
21506
21947
|
unit.update.push(conditional);
|
|
21507
21948
|
}
|
|
21949
|
+
function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
21950
|
+
if (children === undefined) {
|
|
21951
|
+
return null;
|
|
21952
|
+
}
|
|
21953
|
+
const secondaryView = unit.job.allocateView(unit.xref);
|
|
21954
|
+
ingestNodes(secondaryView, children);
|
|
21955
|
+
const templateOp = createTemplateOp(secondaryView.xref, `Defer${suffix}`, Namespace.HTML, true, undefined, sourceSpan);
|
|
21956
|
+
unit.create.push(templateOp);
|
|
21957
|
+
return templateOp;
|
|
21958
|
+
}
|
|
21959
|
+
function ingestDeferBlock(unit, deferBlock) {
|
|
21960
|
+
// Generate the defer main view and all secondary views.
|
|
21961
|
+
const main = ingestDeferView(unit, '', deferBlock.children, deferBlock.sourceSpan);
|
|
21962
|
+
const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
|
|
21963
|
+
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
21964
|
+
const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
21965
|
+
// Create the main defer op, and ops for all secondary views.
|
|
21966
|
+
const deferOp = createDeferOp(unit.job.allocateXrefId(), main.xref, deferBlock.sourceSpan);
|
|
21967
|
+
unit.create.push(deferOp);
|
|
21968
|
+
if (loading && deferBlock.loading) {
|
|
21969
|
+
deferOp.loading =
|
|
21970
|
+
createDeferSecondaryOp(deferOp.xref, loading.xref, DeferSecondaryKind.Loading);
|
|
21971
|
+
if (deferBlock.loading.afterTime !== null || deferBlock.loading.minimumTime !== null) {
|
|
21972
|
+
deferOp.loading.constValue = [deferBlock.loading.minimumTime, deferBlock.loading.afterTime];
|
|
21973
|
+
}
|
|
21974
|
+
unit.create.push(deferOp.loading);
|
|
21975
|
+
}
|
|
21976
|
+
if (placeholder && deferBlock.placeholder) {
|
|
21977
|
+
deferOp.placeholder = createDeferSecondaryOp(deferOp.xref, placeholder.xref, DeferSecondaryKind.Placeholder);
|
|
21978
|
+
if (deferBlock.placeholder.minimumTime !== null) {
|
|
21979
|
+
deferOp.placeholder.constValue = [deferBlock.placeholder.minimumTime];
|
|
21980
|
+
}
|
|
21981
|
+
unit.create.push(deferOp.placeholder);
|
|
21982
|
+
}
|
|
21983
|
+
if (error && deferBlock.error) {
|
|
21984
|
+
deferOp.error =
|
|
21985
|
+
createDeferSecondaryOp(deferOp.xref, error.xref, DeferSecondaryKind.Error);
|
|
21986
|
+
unit.create.push(deferOp.error);
|
|
21987
|
+
}
|
|
21988
|
+
// Configure all defer conditions.
|
|
21989
|
+
const deferOnOp = createDeferOnOp(unit.job.allocateXrefId(), null);
|
|
21990
|
+
// Add all ops to the view.
|
|
21991
|
+
unit.create.push(deferOnOp);
|
|
21992
|
+
}
|
|
21508
21993
|
/**
|
|
21509
21994
|
* Convert a template AST expression into an output AST expression.
|
|
21510
21995
|
*/
|
|
@@ -21603,13 +22088,20 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
21603
22088
|
* to their IR representation.
|
|
21604
22089
|
*/
|
|
21605
22090
|
function ingestBindings(unit, op, element) {
|
|
22091
|
+
let flags = BindingFlags.None;
|
|
22092
|
+
const isPlainTemplate = element instanceof Template && splitNsName(element.tagName ?? '')[1] === 'ng-template';
|
|
21606
22093
|
if (element instanceof Template) {
|
|
22094
|
+
flags |= BindingFlags.OnNgTemplateElement;
|
|
22095
|
+
if (isPlainTemplate) {
|
|
22096
|
+
flags |= BindingFlags.BindingTargetsTemplate;
|
|
22097
|
+
}
|
|
22098
|
+
const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
|
|
21607
22099
|
for (const attr of element.templateAttrs) {
|
|
21608
22100
|
if (attr instanceof TextAttribute) {
|
|
21609
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan,
|
|
22101
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue);
|
|
21610
22102
|
}
|
|
21611
22103
|
else {
|
|
21612
|
-
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan,
|
|
22104
|
+
ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags);
|
|
21613
22105
|
}
|
|
21614
22106
|
}
|
|
21615
22107
|
}
|
|
@@ -21617,10 +22109,10 @@ function ingestBindings(unit, op, element) {
|
|
|
21617
22109
|
// This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
|
|
21618
22110
|
// `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
|
|
21619
22111
|
// `BindingType.Attribute`.
|
|
21620
|
-
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan,
|
|
22112
|
+
ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue);
|
|
21621
22113
|
}
|
|
21622
22114
|
for (const input of element.inputs) {
|
|
21623
|
-
ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan,
|
|
22115
|
+
ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, flags);
|
|
21624
22116
|
}
|
|
21625
22117
|
for (const output of element.outputs) {
|
|
21626
22118
|
let listenerOp;
|
|
@@ -21629,6 +22121,10 @@ function ingestBindings(unit, op, element) {
|
|
|
21629
22121
|
throw Error('Animation listener should have a phase');
|
|
21630
22122
|
}
|
|
21631
22123
|
}
|
|
22124
|
+
if (element instanceof Template && !isPlainTemplate) {
|
|
22125
|
+
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
|
|
22126
|
+
continue;
|
|
22127
|
+
}
|
|
21632
22128
|
listenerOp =
|
|
21633
22129
|
createListenerOp(op.xref, output.name, op.tag, output.phase, false, output.sourceSpan);
|
|
21634
22130
|
// if output.handler is a chain, then push each statement from the chain separately, and
|
|
@@ -21664,10 +22160,37 @@ const BINDING_KINDS = new Map([
|
|
|
21664
22160
|
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
21665
22161
|
[4 /* e.BindingType.Animation */, BindingKind.Animation],
|
|
21666
22162
|
]);
|
|
21667
|
-
|
|
22163
|
+
var BindingFlags;
|
|
22164
|
+
(function (BindingFlags) {
|
|
22165
|
+
BindingFlags[BindingFlags["None"] = 0] = "None";
|
|
22166
|
+
/**
|
|
22167
|
+
* The binding is to a static text literal and not to an expression.
|
|
22168
|
+
*/
|
|
22169
|
+
BindingFlags[BindingFlags["TextValue"] = 1] = "TextValue";
|
|
22170
|
+
/**
|
|
22171
|
+
* The binding belongs to the `<ng-template>` side of a `t.Template`.
|
|
22172
|
+
*/
|
|
22173
|
+
BindingFlags[BindingFlags["BindingTargetsTemplate"] = 2] = "BindingTargetsTemplate";
|
|
22174
|
+
/**
|
|
22175
|
+
* The binding is on a structural directive.
|
|
22176
|
+
*/
|
|
22177
|
+
BindingFlags[BindingFlags["IsStructuralTemplateAttribute"] = 4] = "IsStructuralTemplateAttribute";
|
|
22178
|
+
/**
|
|
22179
|
+
* The binding is on a `t.Template`.
|
|
22180
|
+
*/
|
|
22181
|
+
BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
|
|
22182
|
+
})(BindingFlags || (BindingFlags = {}));
|
|
22183
|
+
function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags) {
|
|
21668
22184
|
if (value instanceof ASTWithSource) {
|
|
21669
22185
|
value = value.ast;
|
|
21670
22186
|
}
|
|
22187
|
+
if (flags & BindingFlags.OnNgTemplateElement && !(flags & BindingFlags.BindingTargetsTemplate) &&
|
|
22188
|
+
type === 0 /* e.BindingType.Property */) {
|
|
22189
|
+
// This binding only exists for later const extraction, and is not an actual binding to be
|
|
22190
|
+
// created.
|
|
22191
|
+
view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null));
|
|
22192
|
+
return;
|
|
22193
|
+
}
|
|
21671
22194
|
let expression;
|
|
21672
22195
|
// TODO: We could easily generate source maps for subexpressions in these cases, but
|
|
21673
22196
|
// TemplateDefinitionBuilder does not. Should we do so?
|
|
@@ -21681,7 +22204,7 @@ function ingestBinding(view, xref, name, value, type, unit, securityContext, sou
|
|
|
21681
22204
|
expression = value;
|
|
21682
22205
|
}
|
|
21683
22206
|
const kind = BINDING_KINDS.get(type);
|
|
21684
|
-
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext,
|
|
22207
|
+
view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, !!(flags & BindingFlags.TextValue), !!(flags & BindingFlags.IsStructuralTemplateAttribute), sourceSpan));
|
|
21685
22208
|
}
|
|
21686
22209
|
/**
|
|
21687
22210
|
* Process all of the local references on an element-like structure in the template AST and
|
|
@@ -23891,26 +24414,6 @@ class HtmlAstToIvyAst {
|
|
|
23891
24414
|
if (this.processedNodes.has(block)) {
|
|
23892
24415
|
return null;
|
|
23893
24416
|
}
|
|
23894
|
-
if (!this.options.enabledBlockTypes.has(block.name)) {
|
|
23895
|
-
let errorMessage;
|
|
23896
|
-
if (isConnectedDeferLoopBlock(block.name)) {
|
|
23897
|
-
errorMessage = `@${block.name} block can only be used after an @defer block.`;
|
|
23898
|
-
this.processedNodes.add(block);
|
|
23899
|
-
}
|
|
23900
|
-
else if (isConnectedForLoopBlock(block.name)) {
|
|
23901
|
-
errorMessage = `@${block.name} block can only be used after an @for block.`;
|
|
23902
|
-
this.processedNodes.add(block);
|
|
23903
|
-
}
|
|
23904
|
-
else if (isConnectedIfLoopBlock(block.name)) {
|
|
23905
|
-
errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
|
|
23906
|
-
this.processedNodes.add(block);
|
|
23907
|
-
}
|
|
23908
|
-
else {
|
|
23909
|
-
errorMessage = `Unrecognized block @${block.name}.`;
|
|
23910
|
-
}
|
|
23911
|
-
this.reportError(errorMessage, block.sourceSpan);
|
|
23912
|
-
return null;
|
|
23913
|
-
}
|
|
23914
24417
|
let result = null;
|
|
23915
24418
|
switch (block.name) {
|
|
23916
24419
|
case 'defer':
|
|
@@ -23926,10 +24429,23 @@ class HtmlAstToIvyAst {
|
|
|
23926
24429
|
result = createIfBlock(block, this.findConnectedBlocks(index, context, isConnectedIfLoopBlock), this, this.bindingParser);
|
|
23927
24430
|
break;
|
|
23928
24431
|
default:
|
|
23929
|
-
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
24432
|
+
let errorMessage;
|
|
24433
|
+
if (isConnectedDeferLoopBlock(block.name)) {
|
|
24434
|
+
errorMessage = `@${block.name} block can only be used after an @defer block.`;
|
|
24435
|
+
this.processedNodes.add(block);
|
|
24436
|
+
}
|
|
24437
|
+
else if (isConnectedForLoopBlock(block.name)) {
|
|
24438
|
+
errorMessage = `@${block.name} block can only be used after an @for block.`;
|
|
24439
|
+
this.processedNodes.add(block);
|
|
24440
|
+
}
|
|
24441
|
+
else if (isConnectedIfLoopBlock(block.name)) {
|
|
24442
|
+
errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
|
|
24443
|
+
this.processedNodes.add(block);
|
|
24444
|
+
}
|
|
24445
|
+
else {
|
|
24446
|
+
errorMessage = `Unrecognized block @${block.name}.`;
|
|
24447
|
+
}
|
|
24448
|
+
result = { node: null, errors: [new ParseError(block.sourceSpan, errorMessage)] };
|
|
23933
24449
|
break;
|
|
23934
24450
|
}
|
|
23935
24451
|
this.errors.push(...result.errors);
|
|
@@ -24170,6 +24686,19 @@ function textContents(node) {
|
|
|
24170
24686
|
}
|
|
24171
24687
|
}
|
|
24172
24688
|
|
|
24689
|
+
/*!
|
|
24690
|
+
* @license
|
|
24691
|
+
* Copyright Google LLC All Rights Reserved.
|
|
24692
|
+
*
|
|
24693
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
24694
|
+
* found in the LICENSE file at https://angular.io/license
|
|
24695
|
+
*/
|
|
24696
|
+
/**
|
|
24697
|
+
* Whether the @ block syntax is enabled by default. This constant exists
|
|
24698
|
+
* so that we can temporarily disable the syntax internally.
|
|
24699
|
+
*/
|
|
24700
|
+
const BLOCK_SYNTAX_ENABLED_DEFAULT = true;
|
|
24701
|
+
|
|
24173
24702
|
var TagType;
|
|
24174
24703
|
(function (TagType) {
|
|
24175
24704
|
TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
|
|
@@ -26377,7 +26906,7 @@ function parseTemplate(template, templateUrl, options = {}) {
|
|
|
26377
26906
|
leadingTriviaChars: LEADING_TRIVIA_CHARS,
|
|
26378
26907
|
...options,
|
|
26379
26908
|
tokenizeExpansionForms: true,
|
|
26380
|
-
tokenizeBlocks: options.
|
|
26909
|
+
tokenizeBlocks: options.enableBlockSyntax ?? BLOCK_SYNTAX_ENABLED_DEFAULT,
|
|
26381
26910
|
});
|
|
26382
26911
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
26383
26912
|
parseResult.errors.length > 0) {
|
|
@@ -26429,10 +26958,7 @@ function parseTemplate(template, templateUrl, options = {}) {
|
|
|
26429
26958
|
rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
|
26430
26959
|
}
|
|
26431
26960
|
}
|
|
26432
|
-
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
|
|
26433
|
-
collectCommentNodes: !!options.collectCommentNodes,
|
|
26434
|
-
enabledBlockTypes: options.enabledBlockTypes || new Set(),
|
|
26435
|
-
});
|
|
26961
|
+
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
|
|
26436
26962
|
errors.push(...parseResult.errors, ...i18nMetaResult.errors);
|
|
26437
26963
|
const parsedTemplate = {
|
|
26438
26964
|
interpolationConfig,
|
|
@@ -26707,14 +27233,14 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
26707
27233
|
// - either as an array:
|
|
26708
27234
|
// `consts: [['one', 'two'], ['three', 'four']]`
|
|
26709
27235
|
// - or as a factory function in case additional statements are present (to support i18n):
|
|
26710
|
-
// `consts:
|
|
27236
|
+
// `consts: () => { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0];
|
|
26711
27237
|
// }`
|
|
26712
27238
|
const { constExpressions, prepareStatements } = templateBuilder.getConsts();
|
|
26713
27239
|
if (constExpressions.length > 0) {
|
|
26714
27240
|
let constsExpr = literalArr(constExpressions);
|
|
26715
27241
|
// Prepare statements are present - turn `consts` into a function.
|
|
26716
27242
|
if (prepareStatements.length > 0) {
|
|
26717
|
-
constsExpr =
|
|
27243
|
+
constsExpr = arrowFn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
|
|
26718
27244
|
}
|
|
26719
27245
|
definitionMap.set('consts', constsExpr);
|
|
26720
27246
|
}
|
|
@@ -26735,7 +27261,9 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
26735
27261
|
definitionMap.set('vars', literal(tpl.root.vars));
|
|
26736
27262
|
if (tpl.consts.length > 0) {
|
|
26737
27263
|
if (tpl.constsInitializers.length > 0) {
|
|
26738
|
-
definitionMap.set('consts',
|
|
27264
|
+
definitionMap.set('consts', arrowFn([], [
|
|
27265
|
+
...tpl.constsInitializers, new ReturnStatement(literalArr(tpl.consts))
|
|
27266
|
+
]));
|
|
26739
27267
|
}
|
|
26740
27268
|
else {
|
|
26741
27269
|
definitionMap.set('consts', literalArr(tpl.consts));
|
|
@@ -26829,11 +27357,11 @@ function compileDeclarationList(list, mode) {
|
|
|
26829
27357
|
return list;
|
|
26830
27358
|
case 1 /* DeclarationListEmitMode.Closure */:
|
|
26831
27359
|
// directives: function () { return [MyDir]; }
|
|
26832
|
-
return
|
|
27360
|
+
return arrowFn([], list);
|
|
26833
27361
|
case 2 /* DeclarationListEmitMode.ClosureResolved */:
|
|
26834
27362
|
// directives: function () { return [MyDir].map(ng.resolveForwardRef); }
|
|
26835
27363
|
const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
|
|
26836
|
-
return
|
|
27364
|
+
return arrowFn([], resolvedList);
|
|
26837
27365
|
case 3 /* DeclarationListEmitMode.RuntimeResolved */:
|
|
26838
27366
|
throw new Error(`Unsupported with an array of pre-resolved dependencies`);
|
|
26839
27367
|
}
|
|
@@ -28113,11 +28641,6 @@ function extractScopedNodeEntities(rootScope) {
|
|
|
28113
28641
|
class ResourceLoader {
|
|
28114
28642
|
}
|
|
28115
28643
|
|
|
28116
|
-
let enabledBlockTypes;
|
|
28117
|
-
/** Temporary utility that enables specific block types in JIT compilations. */
|
|
28118
|
-
function ɵsetEnabledBlockTypes(types) {
|
|
28119
|
-
enabledBlockTypes = types.length > 0 ? new Set(types) : undefined;
|
|
28120
|
-
}
|
|
28121
28644
|
class CompilerFacadeImpl {
|
|
28122
28645
|
constructor(jitEvaluator = new JitEvaluator()) {
|
|
28123
28646
|
this.jitEvaluator = jitEvaluator;
|
|
@@ -28523,7 +29046,7 @@ function convertPipeDeclarationToMetadata(pipe) {
|
|
|
28523
29046
|
function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
|
|
28524
29047
|
const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
|
|
28525
29048
|
// Parse the template and check for errors.
|
|
28526
|
-
const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig
|
|
29049
|
+
const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
|
|
28527
29050
|
if (parsed.errors !== null) {
|
|
28528
29051
|
const errors = parsed.errors.map(err => err.toString()).join(', ');
|
|
28529
29052
|
throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
|
|
@@ -28736,7 +29259,7 @@ function publishFacade(global) {
|
|
|
28736
29259
|
* @description
|
|
28737
29260
|
* Entry point for all public APIs of the compiler package.
|
|
28738
29261
|
*/
|
|
28739
|
-
const VERSION = new Version('17.0.0-next.
|
|
29262
|
+
const VERSION = new Version('17.0.0-next.7');
|
|
28740
29263
|
|
|
28741
29264
|
class CompilerConfig {
|
|
28742
29265
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -30243,7 +30766,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
30243
30766
|
function compileDeclareClassMetadata(metadata) {
|
|
30244
30767
|
const definitionMap = new DefinitionMap();
|
|
30245
30768
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
30246
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
30769
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30247
30770
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30248
30771
|
definitionMap.set('type', metadata.type);
|
|
30249
30772
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -30351,7 +30874,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
30351
30874
|
// in 16.1 is actually used.
|
|
30352
30875
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
30353
30876
|
definitionMap.set('minVersion', literal(minVersion));
|
|
30354
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
30877
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30355
30878
|
// e.g. `type: MyDirective`
|
|
30356
30879
|
definitionMap.set('type', meta.type.value);
|
|
30357
30880
|
if (meta.isStandalone) {
|
|
@@ -30477,10 +31000,17 @@ function compileDeclareComponentFromMetadata(meta, template, additionalTemplateI
|
|
|
30477
31000
|
*/
|
|
30478
31001
|
function createComponentDefinitionMap(meta, template, templateInfo) {
|
|
30479
31002
|
const definitionMap = createDirectiveDefinitionMap(meta);
|
|
31003
|
+
const blockVisitor = new BlockPresenceVisitor();
|
|
31004
|
+
visitAll$1(blockVisitor, template.nodes);
|
|
30480
31005
|
definitionMap.set('template', getTemplateExpression(template, templateInfo));
|
|
30481
31006
|
if (templateInfo.isInline) {
|
|
30482
31007
|
definitionMap.set('isInline', literal(true));
|
|
30483
31008
|
}
|
|
31009
|
+
// Set the minVersion to 17.0.0 if the component is using at least one block in its template.
|
|
31010
|
+
// We don't do this for templates without blocks, in order to preserve backwards compatibility.
|
|
31011
|
+
if (blockVisitor.hasBlocks) {
|
|
31012
|
+
definitionMap.set('minVersion', literal('17.0.0'));
|
|
31013
|
+
}
|
|
30484
31014
|
definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal));
|
|
30485
31015
|
definitionMap.set('dependencies', compileUsedDependenciesMetadata(meta));
|
|
30486
31016
|
definitionMap.set('viewProviders', meta.viewProviders);
|
|
@@ -30573,6 +31103,42 @@ function compileUsedDependenciesMetadata(meta) {
|
|
|
30573
31103
|
}
|
|
30574
31104
|
});
|
|
30575
31105
|
}
|
|
31106
|
+
class BlockPresenceVisitor extends RecursiveVisitor$1 {
|
|
31107
|
+
constructor() {
|
|
31108
|
+
super(...arguments);
|
|
31109
|
+
this.hasBlocks = false;
|
|
31110
|
+
}
|
|
31111
|
+
visitDeferredBlock() {
|
|
31112
|
+
this.hasBlocks = true;
|
|
31113
|
+
}
|
|
31114
|
+
visitDeferredBlockPlaceholder() {
|
|
31115
|
+
this.hasBlocks = true;
|
|
31116
|
+
}
|
|
31117
|
+
visitDeferredBlockLoading() {
|
|
31118
|
+
this.hasBlocks = true;
|
|
31119
|
+
}
|
|
31120
|
+
visitDeferredBlockError() {
|
|
31121
|
+
this.hasBlocks = true;
|
|
31122
|
+
}
|
|
31123
|
+
visitIfBlock() {
|
|
31124
|
+
this.hasBlocks = true;
|
|
31125
|
+
}
|
|
31126
|
+
visitIfBlockBranch() {
|
|
31127
|
+
this.hasBlocks = true;
|
|
31128
|
+
}
|
|
31129
|
+
visitForLoopBlock() {
|
|
31130
|
+
this.hasBlocks = true;
|
|
31131
|
+
}
|
|
31132
|
+
visitForLoopBlockEmpty() {
|
|
31133
|
+
this.hasBlocks = true;
|
|
31134
|
+
}
|
|
31135
|
+
visitSwitchBlock() {
|
|
31136
|
+
this.hasBlocks = true;
|
|
31137
|
+
}
|
|
31138
|
+
visitSwitchBlockCase() {
|
|
31139
|
+
this.hasBlocks = true;
|
|
31140
|
+
}
|
|
31141
|
+
}
|
|
30576
31142
|
|
|
30577
31143
|
/**
|
|
30578
31144
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
@@ -30585,7 +31151,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
30585
31151
|
function compileDeclareFactoryFunction(meta) {
|
|
30586
31152
|
const definitionMap = new DefinitionMap();
|
|
30587
31153
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
30588
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
31154
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30589
31155
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30590
31156
|
definitionMap.set('type', meta.type.value);
|
|
30591
31157
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -30620,7 +31186,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
30620
31186
|
function createInjectableDefinitionMap(meta) {
|
|
30621
31187
|
const definitionMap = new DefinitionMap();
|
|
30622
31188
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
30623
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
31189
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30624
31190
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30625
31191
|
definitionMap.set('type', meta.type.value);
|
|
30626
31192
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -30671,7 +31237,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
30671
31237
|
function createInjectorDefinitionMap(meta) {
|
|
30672
31238
|
const definitionMap = new DefinitionMap();
|
|
30673
31239
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
30674
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
31240
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30675
31241
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30676
31242
|
definitionMap.set('type', meta.type.value);
|
|
30677
31243
|
definitionMap.set('providers', meta.providers);
|
|
@@ -30704,7 +31270,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
30704
31270
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
30705
31271
|
}
|
|
30706
31272
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
30707
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
31273
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30708
31274
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30709
31275
|
definitionMap.set('type', meta.type.value);
|
|
30710
31276
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -30755,7 +31321,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
30755
31321
|
function createPipeDefinitionMap(meta) {
|
|
30756
31322
|
const definitionMap = new DefinitionMap();
|
|
30757
31323
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
30758
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
31324
|
+
definitionMap.set('version', literal('17.0.0-next.7'));
|
|
30759
31325
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30760
31326
|
// e.g. `type: MyPipe`
|
|
30761
31327
|
definitionMap.set('type', meta.type.value);
|