@angular/compiler 17.0.0-next.7 → 17.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/compiler.mjs +4 -3
- package/esm2022/src/config.mjs +2 -4
- package/esm2022/src/ml_parser/html_tags.mjs +4 -4
- package/esm2022/src/ml_parser/lexer.mjs +18 -10
- package/esm2022/src/ml_parser/parser.mjs +28 -10
- package/esm2022/src/ml_parser/tokens.mjs +1 -1
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_ast.mjs +37 -19
- package/esm2022/src/render3/r3_class_debug_info_compiler.mjs +36 -0
- package/esm2022/src/render3/r3_control_flow.mjs +40 -23
- package/esm2022/src/render3/r3_deferred_blocks.mjs +13 -3
- package/esm2022/src/render3/r3_identifiers.mjs +3 -1
- package/esm2022/src/render3/r3_template_transform.mjs +5 -2
- package/esm2022/src/render3/view/t2_binder.mjs +8 -7
- package/esm2022/src/render3/view/template.mjs +35 -24
- package/esm2022/src/shadow_css.mjs +10 -5
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +25 -1
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +3 -1
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +20 -3
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +16 -3
- package/esm2022/src/template/pipeline/ir/src/traits.mjs +1 -1
- package/esm2022/src/template/pipeline/src/emit.mjs +9 -1
- package/esm2022/src/template/pipeline/src/ingest.mjs +47 -12
- package/esm2022/src/template/pipeline/src/instruction.mjs +14 -6
- package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +33 -0
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +1 -19
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +1 -2
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +3 -4
- package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +25 -12
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/icu_extraction.mjs +53 -0
- package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +1 -2
- package/esm2022/src/template/pipeline/src/phases/namespace.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +3 -2
- package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +1 -6
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +57 -0
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +233 -50
- package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +2 -3
- package/esm2022/src/template/pipeline/src/phases/wrap_icus.mjs +34 -0
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +756 -236
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +77 -12
- package/package.json +2 -8
- package/esm2022/src/render3/view/block_syntax_switch.mjs +0 -13
- package/esm2022/testing/index.mjs +0 -13
- package/esm2022/testing/public_api.mjs +0 -16
- package/esm2022/testing/src/testing.mjs +0 -29
- package/esm2022/testing/testing.mjs +0 -5
- package/fesm2022/testing.mjs +0 -39
- package/fesm2022/testing.mjs.map +0 -1
- package/testing/index.d.ts +0 -25
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-
|
|
2
|
+
* @license Angular v17.0.0-rc.0
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2482,6 +2482,7 @@ class Identifiers {
|
|
|
2482
2482
|
static { this.deferPrefetchOnHover = { name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE }; }
|
|
2483
2483
|
static { this.deferPrefetchOnInteraction = { name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE }; }
|
|
2484
2484
|
static { this.deferPrefetchOnViewport = { name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE }; }
|
|
2485
|
+
static { this.deferEnableTimerScheduling = { name: 'ɵɵdeferEnableTimerScheduling', moduleName: CORE }; }
|
|
2485
2486
|
static { this.conditional = { name: 'ɵɵconditional', moduleName: CORE }; }
|
|
2486
2487
|
static { this.repeater = { name: 'ɵɵrepeater', moduleName: CORE }; }
|
|
2487
2488
|
static { this.repeaterCreate = { name: 'ɵɵrepeaterCreate', moduleName: CORE }; }
|
|
@@ -2605,6 +2606,7 @@ class Identifiers {
|
|
|
2605
2606
|
static { this.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; }
|
|
2606
2607
|
static { this.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; }
|
|
2607
2608
|
static { this.setClassMetadataAsync = { name: 'ɵsetClassMetadataAsync', moduleName: CORE }; }
|
|
2609
|
+
static { this.setClassDebugInfo = { name: 'ɵsetClassDebugInfo', moduleName: CORE }; }
|
|
2608
2610
|
static { this.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; }
|
|
2609
2611
|
static { this.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; }
|
|
2610
2612
|
static { this.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; }
|
|
@@ -3868,12 +3870,13 @@ class DeferredBlockError {
|
|
|
3868
3870
|
}
|
|
3869
3871
|
}
|
|
3870
3872
|
class DeferredBlock {
|
|
3871
|
-
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3873
|
+
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3872
3874
|
this.children = children;
|
|
3873
3875
|
this.placeholder = placeholder;
|
|
3874
3876
|
this.loading = loading;
|
|
3875
3877
|
this.error = error;
|
|
3876
3878
|
this.sourceSpan = sourceSpan;
|
|
3879
|
+
this.mainBlockSpan = mainBlockSpan;
|
|
3877
3880
|
this.startSourceSpan = startSourceSpan;
|
|
3878
3881
|
this.endSourceSpan = endSourceSpan;
|
|
3879
3882
|
this.triggers = triggers;
|
|
@@ -3890,20 +3893,23 @@ class DeferredBlock {
|
|
|
3890
3893
|
this.visitTriggers(this.definedTriggers, this.triggers, visitor);
|
|
3891
3894
|
this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
|
|
3892
3895
|
visitAll$1(visitor, this.children);
|
|
3893
|
-
this.placeholder
|
|
3894
|
-
|
|
3895
|
-
this.error && visitor.visitDeferredBlockError(this.error);
|
|
3896
|
+
const remainingBlocks = [this.placeholder, this.loading, this.error].filter(x => x !== null);
|
|
3897
|
+
visitAll$1(visitor, remainingBlocks);
|
|
3896
3898
|
}
|
|
3897
3899
|
visitTriggers(keys, triggers, visitor) {
|
|
3898
|
-
|
|
3899
|
-
visitor.visitDeferredTrigger(triggers[key]);
|
|
3900
|
-
}
|
|
3900
|
+
visitAll$1(visitor, keys.map(k => triggers[k]));
|
|
3901
3901
|
}
|
|
3902
3902
|
}
|
|
3903
3903
|
class SwitchBlock {
|
|
3904
|
-
constructor(expression, cases,
|
|
3904
|
+
constructor(expression, cases,
|
|
3905
|
+
/**
|
|
3906
|
+
* These blocks are only captured to allow for autocompletion in the language service. They
|
|
3907
|
+
* aren't meant to be processed in any other way.
|
|
3908
|
+
*/
|
|
3909
|
+
unknownBlocks, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3905
3910
|
this.expression = expression;
|
|
3906
3911
|
this.cases = cases;
|
|
3912
|
+
this.unknownBlocks = unknownBlocks;
|
|
3907
3913
|
this.sourceSpan = sourceSpan;
|
|
3908
3914
|
this.startSourceSpan = startSourceSpan;
|
|
3909
3915
|
this.endSourceSpan = endSourceSpan;
|
|
@@ -3913,18 +3919,19 @@ class SwitchBlock {
|
|
|
3913
3919
|
}
|
|
3914
3920
|
}
|
|
3915
3921
|
class SwitchBlockCase {
|
|
3916
|
-
constructor(expression, children, sourceSpan, startSourceSpan) {
|
|
3922
|
+
constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3917
3923
|
this.expression = expression;
|
|
3918
3924
|
this.children = children;
|
|
3919
3925
|
this.sourceSpan = sourceSpan;
|
|
3920
3926
|
this.startSourceSpan = startSourceSpan;
|
|
3927
|
+
this.endSourceSpan = endSourceSpan;
|
|
3921
3928
|
}
|
|
3922
3929
|
visit(visitor) {
|
|
3923
3930
|
return visitor.visitSwitchBlockCase(this);
|
|
3924
3931
|
}
|
|
3925
3932
|
}
|
|
3926
3933
|
class ForLoopBlock {
|
|
3927
|
-
constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3934
|
+
constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3928
3935
|
this.item = item;
|
|
3929
3936
|
this.expression = expression;
|
|
3930
3937
|
this.trackBy = trackBy;
|
|
@@ -3932,6 +3939,7 @@ class ForLoopBlock {
|
|
|
3932
3939
|
this.children = children;
|
|
3933
3940
|
this.empty = empty;
|
|
3934
3941
|
this.sourceSpan = sourceSpan;
|
|
3942
|
+
this.mainBlockSpan = mainBlockSpan;
|
|
3935
3943
|
this.startSourceSpan = startSourceSpan;
|
|
3936
3944
|
this.endSourceSpan = endSourceSpan;
|
|
3937
3945
|
}
|
|
@@ -3940,10 +3948,11 @@ class ForLoopBlock {
|
|
|
3940
3948
|
}
|
|
3941
3949
|
}
|
|
3942
3950
|
class ForLoopBlockEmpty {
|
|
3943
|
-
constructor(children, sourceSpan, startSourceSpan) {
|
|
3951
|
+
constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3944
3952
|
this.children = children;
|
|
3945
3953
|
this.sourceSpan = sourceSpan;
|
|
3946
3954
|
this.startSourceSpan = startSourceSpan;
|
|
3955
|
+
this.endSourceSpan = endSourceSpan;
|
|
3947
3956
|
}
|
|
3948
3957
|
visit(visitor) {
|
|
3949
3958
|
return visitor.visitForLoopBlockEmpty(this);
|
|
@@ -3961,17 +3970,27 @@ class IfBlock {
|
|
|
3961
3970
|
}
|
|
3962
3971
|
}
|
|
3963
3972
|
class IfBlockBranch {
|
|
3964
|
-
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan) {
|
|
3973
|
+
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3965
3974
|
this.expression = expression;
|
|
3966
3975
|
this.children = children;
|
|
3967
3976
|
this.expressionAlias = expressionAlias;
|
|
3968
3977
|
this.sourceSpan = sourceSpan;
|
|
3969
3978
|
this.startSourceSpan = startSourceSpan;
|
|
3979
|
+
this.endSourceSpan = endSourceSpan;
|
|
3970
3980
|
}
|
|
3971
3981
|
visit(visitor) {
|
|
3972
3982
|
return visitor.visitIfBlockBranch(this);
|
|
3973
3983
|
}
|
|
3974
3984
|
}
|
|
3985
|
+
class UnknownBlock {
|
|
3986
|
+
constructor(name, sourceSpan) {
|
|
3987
|
+
this.name = name;
|
|
3988
|
+
this.sourceSpan = sourceSpan;
|
|
3989
|
+
}
|
|
3990
|
+
visit(visitor) {
|
|
3991
|
+
return visitor.visitUnknownBlock(this);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3975
3994
|
class Template {
|
|
3976
3995
|
constructor(
|
|
3977
3996
|
// tagName is the name of the container element, if applicable.
|
|
@@ -4078,10 +4097,9 @@ class RecursiveVisitor$1 {
|
|
|
4078
4097
|
visitAll$1(this, block.children);
|
|
4079
4098
|
}
|
|
4080
4099
|
visitForLoopBlock(block) {
|
|
4081
|
-
block.item.
|
|
4082
|
-
|
|
4083
|
-
visitAll$1(this,
|
|
4084
|
-
block.empty?.visit(this);
|
|
4100
|
+
const blockItems = [block.item, ...Object.values(block.contextVariables), ...block.children];
|
|
4101
|
+
block.empty && blockItems.push(block.empty);
|
|
4102
|
+
visitAll$1(this, blockItems);
|
|
4085
4103
|
}
|
|
4086
4104
|
visitForLoopBlockEmpty(block) {
|
|
4087
4105
|
visitAll$1(this, block.children);
|
|
@@ -4090,8 +4108,9 @@ class RecursiveVisitor$1 {
|
|
|
4090
4108
|
visitAll$1(this, block.branches);
|
|
4091
4109
|
}
|
|
4092
4110
|
visitIfBlockBranch(block) {
|
|
4093
|
-
|
|
4094
|
-
block.expressionAlias
|
|
4111
|
+
const blockItems = block.children;
|
|
4112
|
+
block.expressionAlias && blockItems.push(block.expressionAlias);
|
|
4113
|
+
visitAll$1(this, blockItems);
|
|
4095
4114
|
}
|
|
4096
4115
|
visitContent(content) { }
|
|
4097
4116
|
visitVariable(variable) { }
|
|
@@ -4103,6 +4122,7 @@ class RecursiveVisitor$1 {
|
|
|
4103
4122
|
visitBoundText(text) { }
|
|
4104
4123
|
visitIcu(icu) { }
|
|
4105
4124
|
visitDeferredTrigger(trigger) { }
|
|
4125
|
+
visitUnknownBlock(block) { }
|
|
4106
4126
|
}
|
|
4107
4127
|
function visitAll$1(visitor, nodes) {
|
|
4108
4128
|
const result = [];
|
|
@@ -8297,7 +8317,7 @@ class ShadowCss {
|
|
|
8297
8317
|
// (ie: ".\fc ber" for ".über") is not a separator between 2 selectors
|
|
8298
8318
|
// also keep in mind that backslashes are replaced by a placeholder by SafeSelector
|
|
8299
8319
|
// These escaped selectors happen for example when esbuild runs with optimization.minify.
|
|
8300
|
-
if (part.match(
|
|
8320
|
+
if (part.match(/__esc-ph-(\d+)__/) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
|
|
8301
8321
|
continue;
|
|
8302
8322
|
}
|
|
8303
8323
|
shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
|
|
@@ -8328,7 +8348,13 @@ class SafeSelector {
|
|
|
8328
8348
|
// pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
|
|
8329
8349
|
// Replace all escape sequences (`\` followed by a character) with a placeholder so
|
|
8330
8350
|
// that our handling of pseudo-selectors doesn't mess with them.
|
|
8331
|
-
|
|
8351
|
+
// Escaped characters have a specific placeholder so they can be detected separately.
|
|
8352
|
+
selector = selector.replace(/(\\.)/g, (_, keep) => {
|
|
8353
|
+
const replaceBy = `__esc-ph-${this.index}__`;
|
|
8354
|
+
this.placeholders.push(keep);
|
|
8355
|
+
this.index++;
|
|
8356
|
+
return replaceBy;
|
|
8357
|
+
});
|
|
8332
8358
|
// Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
|
|
8333
8359
|
// WS and "+" would otherwise be interpreted as selector separators.
|
|
8334
8360
|
this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
|
|
@@ -8339,7 +8365,7 @@ class SafeSelector {
|
|
|
8339
8365
|
});
|
|
8340
8366
|
}
|
|
8341
8367
|
restore(content) {
|
|
8342
|
-
return content.replace(
|
|
8368
|
+
return content.replace(/__(?:ph|esc-ph)-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
|
|
8343
8369
|
}
|
|
8344
8370
|
content() {
|
|
8345
8371
|
return this._content;
|
|
@@ -8391,7 +8417,6 @@ const _commentRe = /\/\*[\s\S]*?\*\//g;
|
|
|
8391
8417
|
const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=/g;
|
|
8392
8418
|
const COMMENT_PLACEHOLDER = '%COMMENT%';
|
|
8393
8419
|
const _commentWithHashPlaceHolderRe = new RegExp(COMMENT_PLACEHOLDER, 'g');
|
|
8394
|
-
const _placeholderRe = /__ph-(\d+)__/g;
|
|
8395
8420
|
const BLOCK_PLACEHOLDER = '%BLOCK%';
|
|
8396
8421
|
const _ruleRe = new RegExp(`(\\s*(?:${COMMENT_PLACEHOLDER}\\s*)*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))`, 'g');
|
|
8397
8422
|
const CONTENT_PAIRS = new Map([['{', '}']]);
|
|
@@ -8821,6 +8846,14 @@ var OpKind;
|
|
|
8821
8846
|
* An instruction that applies a set of i18n expressions.
|
|
8822
8847
|
*/
|
|
8823
8848
|
OpKind[OpKind["I18nApply"] = 38] = "I18nApply";
|
|
8849
|
+
/**
|
|
8850
|
+
* An instruction to create an ICU expression.
|
|
8851
|
+
*/
|
|
8852
|
+
OpKind[OpKind["Icu"] = 39] = "Icu";
|
|
8853
|
+
/**
|
|
8854
|
+
* An instruction to update an ICU expression.
|
|
8855
|
+
*/
|
|
8856
|
+
OpKind[OpKind["IcuUpdate"] = 40] = "IcuUpdate";
|
|
8824
8857
|
})(OpKind || (OpKind = {}));
|
|
8825
8858
|
/**
|
|
8826
8859
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -8999,6 +9032,22 @@ var BindingKind;
|
|
|
8999
9032
|
*/
|
|
9000
9033
|
BindingKind[BindingKind["Animation"] = 6] = "Animation";
|
|
9001
9034
|
})(BindingKind || (BindingKind = {}));
|
|
9035
|
+
/**
|
|
9036
|
+
* Enumeration of possible times i18n params can be resolved.
|
|
9037
|
+
*/
|
|
9038
|
+
var I18nParamResolutionTime;
|
|
9039
|
+
(function (I18nParamResolutionTime) {
|
|
9040
|
+
/**
|
|
9041
|
+
* Param is resolved at message creation time. Most params should be resolved at message creation
|
|
9042
|
+
* time. However, ICU params need to be handled in post-processing.
|
|
9043
|
+
*/
|
|
9044
|
+
I18nParamResolutionTime[I18nParamResolutionTime["Creation"] = 0] = "Creation";
|
|
9045
|
+
/**
|
|
9046
|
+
* Param is resolved during post-processing. This should be used for params who's value comes from
|
|
9047
|
+
* an ICU.
|
|
9048
|
+
*/
|
|
9049
|
+
I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
|
|
9050
|
+
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
|
|
9002
9051
|
|
|
9003
9052
|
/**
|
|
9004
9053
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9297,12 +9346,14 @@ function createConditionalOp(target, test, conditions, sourceSpan) {
|
|
|
9297
9346
|
/**
|
|
9298
9347
|
* Create an i18n expression op.
|
|
9299
9348
|
*/
|
|
9300
|
-
function createI18nExpressionOp(
|
|
9349
|
+
function createI18nExpressionOp(owner, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9301
9350
|
return {
|
|
9302
9351
|
kind: OpKind.I18nExpression,
|
|
9303
|
-
|
|
9352
|
+
owner,
|
|
9353
|
+
target: owner,
|
|
9304
9354
|
expression,
|
|
9305
9355
|
i18nPlaceholder,
|
|
9356
|
+
resolutionTime,
|
|
9306
9357
|
sourceSpan,
|
|
9307
9358
|
...NEW_OP,
|
|
9308
9359
|
...TRAIT_CONSUMES_VARS,
|
|
@@ -9321,6 +9372,17 @@ function createI18nApplyOp(target, sourceSpan) {
|
|
|
9321
9372
|
...TRAIT_USES_SLOT_INDEX,
|
|
9322
9373
|
};
|
|
9323
9374
|
}
|
|
9375
|
+
/**
|
|
9376
|
+
* Creates an op to update an ICU expression.
|
|
9377
|
+
*/
|
|
9378
|
+
function createIcuUpdateOp(xref, sourceSpan) {
|
|
9379
|
+
return {
|
|
9380
|
+
kind: OpKind.IcuUpdate,
|
|
9381
|
+
xref,
|
|
9382
|
+
sourceSpan,
|
|
9383
|
+
...NEW_OP,
|
|
9384
|
+
};
|
|
9385
|
+
}
|
|
9324
9386
|
|
|
9325
9387
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
9326
9388
|
/**
|
|
@@ -10043,6 +10105,8 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10043
10105
|
case OpKind.Advance:
|
|
10044
10106
|
case OpKind.Namespace:
|
|
10045
10107
|
case OpKind.I18nApply:
|
|
10108
|
+
case OpKind.Icu:
|
|
10109
|
+
case OpKind.IcuUpdate:
|
|
10046
10110
|
// These operations contain no expressions.
|
|
10047
10111
|
break;
|
|
10048
10112
|
default:
|
|
@@ -10448,7 +10512,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10448
10512
|
/**
|
|
10449
10513
|
* Create a `TemplateOp`.
|
|
10450
10514
|
*/
|
|
10451
|
-
function createTemplateOp(xref, tag, namespace, generatedInBlock,
|
|
10515
|
+
function createTemplateOp(xref, tag, namespace, generatedInBlock, i18nPlaceholder, sourceSpan) {
|
|
10452
10516
|
return {
|
|
10453
10517
|
kind: OpKind.Template,
|
|
10454
10518
|
xref,
|
|
@@ -10460,6 +10524,7 @@ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSp
|
|
|
10460
10524
|
localRefs: [],
|
|
10461
10525
|
nonBindable: false,
|
|
10462
10526
|
namespace,
|
|
10527
|
+
i18nPlaceholder,
|
|
10463
10528
|
sourceSpan,
|
|
10464
10529
|
...TRAIT_CONSUMES_SLOT,
|
|
10465
10530
|
...NEW_OP,
|
|
@@ -10633,13 +10698,17 @@ function createExtractedMessageOp(owner, expression, statements) {
|
|
|
10633
10698
|
/**
|
|
10634
10699
|
* Create an `I18nStartOp`.
|
|
10635
10700
|
*/
|
|
10636
|
-
function createI18nStartOp(xref, message) {
|
|
10701
|
+
function createI18nStartOp(xref, message, root) {
|
|
10637
10702
|
return {
|
|
10638
10703
|
kind: OpKind.I18nStart,
|
|
10639
10704
|
xref,
|
|
10705
|
+
root: root ?? xref,
|
|
10640
10706
|
message,
|
|
10641
10707
|
params: new Map(),
|
|
10708
|
+
postprocessingParams: new Map(),
|
|
10642
10709
|
messageIndex: null,
|
|
10710
|
+
subTemplateIndex: null,
|
|
10711
|
+
needsPostprocessing: false,
|
|
10643
10712
|
...NEW_OP,
|
|
10644
10713
|
...TRAIT_CONSUMES_SLOT,
|
|
10645
10714
|
};
|
|
@@ -10654,6 +10723,18 @@ function createI18nEndOp(xref) {
|
|
|
10654
10723
|
...NEW_OP,
|
|
10655
10724
|
};
|
|
10656
10725
|
}
|
|
10726
|
+
/**
|
|
10727
|
+
* Creates an op to create an ICU expression.
|
|
10728
|
+
*/
|
|
10729
|
+
function createIcuOp(xref, message, sourceSpan) {
|
|
10730
|
+
return {
|
|
10731
|
+
kind: OpKind.Icu,
|
|
10732
|
+
xref,
|
|
10733
|
+
message,
|
|
10734
|
+
sourceSpan,
|
|
10735
|
+
...NEW_OP,
|
|
10736
|
+
};
|
|
10737
|
+
}
|
|
10657
10738
|
function literalOrArrayLiteral$1(value) {
|
|
10658
10739
|
if (Array.isArray(value)) {
|
|
10659
10740
|
return literalArr(value.map(literalOrArrayLiteral$1));
|
|
@@ -11019,7 +11100,7 @@ function phaseApplyI18nExpressions(job) {
|
|
|
11019
11100
|
// Only add apply after expressions that are not followed by more expressions.
|
|
11020
11101
|
if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
|
|
11021
11102
|
// TODO: what should be the source span for the apply op?
|
|
11022
|
-
OpList.insertAfter(createI18nApplyOp(op.
|
|
11103
|
+
OpList.insertAfter(createI18nApplyOp(op.owner, null), op);
|
|
11023
11104
|
}
|
|
11024
11105
|
}
|
|
11025
11106
|
}
|
|
@@ -11033,12 +11114,37 @@ function needsApplication(op) {
|
|
|
11033
11114
|
return true;
|
|
11034
11115
|
}
|
|
11035
11116
|
// If the next op is an expression targeting a different i18n block, we need to apply.
|
|
11036
|
-
if (op.next.
|
|
11117
|
+
if (op.next.owner !== op.owner) {
|
|
11037
11118
|
return true;
|
|
11038
11119
|
}
|
|
11039
11120
|
return false;
|
|
11040
11121
|
}
|
|
11041
11122
|
|
|
11123
|
+
/**
|
|
11124
|
+
* Updates i18n expression ops to depend on the last slot in their owning i18n block.
|
|
11125
|
+
*/
|
|
11126
|
+
function phaseAssignI18nSlotDependencies(job) {
|
|
11127
|
+
const i18nLastSlotConsumers = new Map();
|
|
11128
|
+
let lastSlotConsumer = null;
|
|
11129
|
+
for (const unit of job.units) {
|
|
11130
|
+
// Record the last consumed slot before each i18n end instruction.
|
|
11131
|
+
for (const op of unit.create) {
|
|
11132
|
+
if (op.kind === OpKind.I18nEnd) {
|
|
11133
|
+
i18nLastSlotConsumers.set(op.xref, lastSlotConsumer);
|
|
11134
|
+
}
|
|
11135
|
+
if (hasConsumesSlotTrait(op)) {
|
|
11136
|
+
lastSlotConsumer = op.xref;
|
|
11137
|
+
}
|
|
11138
|
+
}
|
|
11139
|
+
// Assign i18n expressions to target the last slot in its owning block.
|
|
11140
|
+
for (const op of unit.update) {
|
|
11141
|
+
if (op.kind === OpKind.I18nExpression) {
|
|
11142
|
+
op.target = i18nLastSlotConsumers.get(op.owner);
|
|
11143
|
+
}
|
|
11144
|
+
}
|
|
11145
|
+
}
|
|
11146
|
+
}
|
|
11147
|
+
|
|
11042
11148
|
/**
|
|
11043
11149
|
* Gets a map of all elements in the given view by their xref id.
|
|
11044
11150
|
*/
|
|
@@ -11793,31 +11899,13 @@ function phaseGenerateAdvance(job) {
|
|
|
11793
11899
|
for (const unit of job.units) {
|
|
11794
11900
|
// First build a map of all of the declarations in the view that have assigned slots.
|
|
11795
11901
|
const slotMap = new Map();
|
|
11796
|
-
let lastSlotOp = null;
|
|
11797
11902
|
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
|
-
}
|
|
11814
11903
|
if (!hasConsumesSlotTrait(op)) {
|
|
11815
11904
|
continue;
|
|
11816
11905
|
}
|
|
11817
11906
|
else if (op.slot === null) {
|
|
11818
11907
|
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
11819
11908
|
}
|
|
11820
|
-
lastSlotOp = op;
|
|
11821
11909
|
slotMap.set(op.xref, op.slot);
|
|
11822
11910
|
}
|
|
11823
11911
|
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
@@ -11955,7 +12043,6 @@ function getScopeForView(view, parent) {
|
|
|
11955
12043
|
}
|
|
11956
12044
|
for (const op of view.create) {
|
|
11957
12045
|
switch (op.kind) {
|
|
11958
|
-
case OpKind.Element:
|
|
11959
12046
|
case OpKind.ElementStart:
|
|
11960
12047
|
case OpKind.Template:
|
|
11961
12048
|
if (!Array.isArray(op.localRefs)) {
|
|
@@ -12123,9 +12210,8 @@ function phaseI18nConstCollection(job) {
|
|
|
12123
12210
|
// Assign const index to i18n ops that messages were extracted from.
|
|
12124
12211
|
for (const unit of job.units) {
|
|
12125
12212
|
for (const op of unit.create) {
|
|
12126
|
-
if (
|
|
12127
|
-
messageConstIndices[op.
|
|
12128
|
-
op.messageIndex = messageConstIndices[op.xref];
|
|
12213
|
+
if (op.kind === OpKind.I18nStart) {
|
|
12214
|
+
op.messageIndex = messageConstIndices[op.root];
|
|
12129
12215
|
}
|
|
12130
12216
|
}
|
|
12131
12217
|
}
|
|
@@ -14421,7 +14507,7 @@ let TAG_DEFINITIONS;
|
|
|
14421
14507
|
function getHtmlTagDefinition(tagName) {
|
|
14422
14508
|
if (!TAG_DEFINITIONS) {
|
|
14423
14509
|
DEFAULT_TAG_DEFINITION = new HtmlTagDefinition({ canSelfClose: true });
|
|
14424
|
-
TAG_DEFINITIONS = {
|
|
14510
|
+
TAG_DEFINITIONS = Object.assign(Object.create(null), {
|
|
14425
14511
|
'base': new HtmlTagDefinition({ isVoid: true }),
|
|
14426
14512
|
'meta': new HtmlTagDefinition({ isVoid: true }),
|
|
14427
14513
|
'area': new HtmlTagDefinition({ isVoid: true }),
|
|
@@ -14483,9 +14569,9 @@ function getHtmlTagDefinition(tagName) {
|
|
|
14483
14569
|
contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA }
|
|
14484
14570
|
}),
|
|
14485
14571
|
'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
|
|
14486
|
-
};
|
|
14572
|
+
});
|
|
14487
14573
|
new DomElementSchemaRegistry().allKnownElementNames().forEach(knownTagName => {
|
|
14488
|
-
if (!TAG_DEFINITIONS
|
|
14574
|
+
if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) {
|
|
14489
14575
|
TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({ canSelfClose: false });
|
|
14490
14576
|
}
|
|
14491
14577
|
});
|
|
@@ -17078,7 +17164,7 @@ class _Tokenizer {
|
|
|
17078
17164
|
this.handleError(e);
|
|
17079
17165
|
}
|
|
17080
17166
|
}
|
|
17081
|
-
this._beginToken(
|
|
17167
|
+
this._beginToken(29 /* TokenType.EOF */);
|
|
17082
17168
|
this._endToken([]);
|
|
17083
17169
|
}
|
|
17084
17170
|
_getBlockName() {
|
|
@@ -17099,7 +17185,7 @@ class _Tokenizer {
|
|
|
17099
17185
|
}
|
|
17100
17186
|
_consumeBlockStart(start) {
|
|
17101
17187
|
this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
|
|
17102
|
-
this._endToken([this._getBlockName()]);
|
|
17188
|
+
const startToken = this._endToken([this._getBlockName()]);
|
|
17103
17189
|
if (this._cursor.peek() === $LPAREN) {
|
|
17104
17190
|
// Advance past the opening paren.
|
|
17105
17191
|
this._cursor.advance();
|
|
@@ -17107,14 +17193,22 @@ class _Tokenizer {
|
|
|
17107
17193
|
this._consumeBlockParameters();
|
|
17108
17194
|
// Allow spaces before the closing paren.
|
|
17109
17195
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17196
|
+
if (this._attemptCharCode($RPAREN)) {
|
|
17197
|
+
// Allow spaces after the paren.
|
|
17198
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
17199
|
+
}
|
|
17200
|
+
else {
|
|
17201
|
+
startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
|
|
17202
|
+
return;
|
|
17203
|
+
}
|
|
17204
|
+
}
|
|
17205
|
+
if (this._attemptCharCode($LBRACE)) {
|
|
17206
|
+
this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
|
|
17207
|
+
this._endToken([]);
|
|
17208
|
+
}
|
|
17209
|
+
else {
|
|
17210
|
+
startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
|
|
17114
17211
|
}
|
|
17115
|
-
this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
|
|
17116
|
-
this._requireCharCode($LBRACE);
|
|
17117
|
-
this._endToken([]);
|
|
17118
17212
|
}
|
|
17119
17213
|
_consumeBlockEnd(start) {
|
|
17120
17214
|
this._beginToken(26 /* TokenType.BLOCK_CLOSE */, start);
|
|
@@ -18087,7 +18181,7 @@ class _TreeBuilder {
|
|
|
18087
18181
|
this._advance();
|
|
18088
18182
|
}
|
|
18089
18183
|
build() {
|
|
18090
|
-
while (this._peek.type !==
|
|
18184
|
+
while (this._peek.type !== 29 /* TokenType.EOF */) {
|
|
18091
18185
|
if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
|
|
18092
18186
|
this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
|
|
18093
18187
|
this._consumeStartTag(this._advance());
|
|
@@ -18119,6 +18213,10 @@ class _TreeBuilder {
|
|
|
18119
18213
|
this._closeVoidElement();
|
|
18120
18214
|
this._consumeBlockClose(this._advance());
|
|
18121
18215
|
}
|
|
18216
|
+
else if (this._peek.type === 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */) {
|
|
18217
|
+
this._closeVoidElement();
|
|
18218
|
+
this._consumeIncompleteBlock(this._advance());
|
|
18219
|
+
}
|
|
18122
18220
|
else {
|
|
18123
18221
|
// Skip all other tokens...
|
|
18124
18222
|
this._advance();
|
|
@@ -18192,7 +18290,7 @@ class _TreeBuilder {
|
|
|
18192
18290
|
if (!exp)
|
|
18193
18291
|
return null;
|
|
18194
18292
|
const end = this._advance();
|
|
18195
|
-
exp.push({ type:
|
|
18293
|
+
exp.push({ type: 29 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
|
|
18196
18294
|
// parse everything in between { and }
|
|
18197
18295
|
const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
|
|
18198
18296
|
expansionCaseParser.build();
|
|
@@ -18232,7 +18330,7 @@ class _TreeBuilder {
|
|
|
18232
18330
|
return null;
|
|
18233
18331
|
}
|
|
18234
18332
|
}
|
|
18235
|
-
if (this._peek.type ===
|
|
18333
|
+
if (this._peek.type === 29 /* TokenType.EOF */) {
|
|
18236
18334
|
this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
|
|
18237
18335
|
return null;
|
|
18238
18336
|
}
|
|
@@ -18434,17 +18532,31 @@ class _TreeBuilder {
|
|
|
18434
18532
|
const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
|
|
18435
18533
|
const block = new Block(token.parts[0], parameters, [], span, startSpan);
|
|
18436
18534
|
this._pushContainer(block, false);
|
|
18437
|
-
return block;
|
|
18438
18535
|
}
|
|
18439
18536
|
_consumeBlockClose(token) {
|
|
18440
|
-
const previousContainer = this._getContainer();
|
|
18441
18537
|
if (!this._popContainer(null, Block, token.sourceSpan)) {
|
|
18442
|
-
|
|
18443
|
-
`
|
|
18444
|
-
`
|
|
18445
|
-
this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. ${context}`));
|
|
18538
|
+
this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` +
|
|
18539
|
+
`If you meant to write the } character, you should use the "}" ` +
|
|
18540
|
+
`HTML entity instead.`));
|
|
18446
18541
|
}
|
|
18447
18542
|
}
|
|
18543
|
+
_consumeIncompleteBlock(token) {
|
|
18544
|
+
const parameters = [];
|
|
18545
|
+
while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
|
|
18546
|
+
const paramToken = this._advance();
|
|
18547
|
+
parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
|
|
18548
|
+
}
|
|
18549
|
+
const end = this._peek.sourceSpan.fullStart;
|
|
18550
|
+
const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
|
|
18551
|
+
// Create a separate `startSpan` because `span` will be modified when there is an `end` span.
|
|
18552
|
+
const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
|
|
18553
|
+
const block = new Block(token.parts[0], parameters, [], span, startSpan);
|
|
18554
|
+
this._pushContainer(block, false);
|
|
18555
|
+
// Incomplete blocks don't have children so we close them immediately and report an error.
|
|
18556
|
+
this._popContainer(null, Block, null);
|
|
18557
|
+
this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` +
|
|
18558
|
+
`you should use the "@" HTML entity instead.`));
|
|
18559
|
+
}
|
|
18448
18560
|
_getContainer() {
|
|
18449
18561
|
return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
|
|
18450
18562
|
null;
|
|
@@ -18997,17 +19109,29 @@ function phaseI18nMessageExtraction(job) {
|
|
|
18997
19109
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
18998
19110
|
for (const unit of job.units) {
|
|
18999
19111
|
for (const op of unit.create) {
|
|
19000
|
-
if (
|
|
19001
|
-
//
|
|
19002
|
-
|
|
19003
|
-
|
|
19004
|
-
|
|
19005
|
-
|
|
19006
|
-
|
|
19007
|
-
|
|
19008
|
-
|
|
19009
|
-
|
|
19010
|
-
|
|
19112
|
+
if (op.kind === OpKind.I18nStart) {
|
|
19113
|
+
// Only extract messages from root i18n ops, not sub-template ones.
|
|
19114
|
+
if (op.xref === op.root) {
|
|
19115
|
+
// Sort the params map to match the ordering in TemplateDefinitionBuilder.
|
|
19116
|
+
const params = new Map([...op.params.entries()].sort());
|
|
19117
|
+
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
19118
|
+
// Closure Compiler requires const names to start with `MSG_` but disallows any other
|
|
19119
|
+
// const to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
19120
|
+
// `goog.getMsg` call
|
|
19121
|
+
const closureVar = i18nGenerateClosureVar(job.pool, op.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
|
|
19122
|
+
let transformFn = undefined;
|
|
19123
|
+
// If nescessary, add a post-processing step and resolve any placeholder params that are
|
|
19124
|
+
// set in post-processing.
|
|
19125
|
+
if (op.needsPostprocessing) {
|
|
19126
|
+
const extraTransformFnParams = [];
|
|
19127
|
+
if (op.postprocessingParams.size > 0) {
|
|
19128
|
+
extraTransformFnParams.push(literalMap([...op.postprocessingParams.entries()].map(([key, value]) => ({ key, value, quoted: true }))));
|
|
19129
|
+
}
|
|
19130
|
+
transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
|
|
19131
|
+
}
|
|
19132
|
+
const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, params, transformFn);
|
|
19133
|
+
unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
|
|
19134
|
+
}
|
|
19011
19135
|
}
|
|
19012
19136
|
}
|
|
19013
19137
|
}
|
|
@@ -19118,7 +19242,7 @@ function phaseI18nTextExtraction(job) {
|
|
|
19118
19242
|
for (let i = 0; i < op.interpolation.expressions.length; i++) {
|
|
19119
19243
|
const expr = op.interpolation.expressions[i];
|
|
19120
19244
|
const placeholder = op.i18nPlaceholders[i];
|
|
19121
|
-
ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder, expr.sourceSpan ?? op.sourceSpan));
|
|
19245
|
+
ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder.name, I18nParamResolutionTime.Creation, expr.sourceSpan ?? op.sourceSpan));
|
|
19122
19246
|
}
|
|
19123
19247
|
if (ops.length > 0) {
|
|
19124
19248
|
// ops.push(ir.createI18nApplyOp(i18nBlockId, op.i18nPlaceholders, op.sourceSpan));
|
|
@@ -19130,6 +19254,50 @@ function phaseI18nTextExtraction(job) {
|
|
|
19130
19254
|
}
|
|
19131
19255
|
}
|
|
19132
19256
|
|
|
19257
|
+
/**
|
|
19258
|
+
* Extracts ICUs into i18n expressions.
|
|
19259
|
+
*/
|
|
19260
|
+
function phaseIcuExtraction(job) {
|
|
19261
|
+
for (const unit of job.units) {
|
|
19262
|
+
// Build a map of ICU to the i18n block they belong to, then remove the `Icu` ops.
|
|
19263
|
+
const icus = new Map();
|
|
19264
|
+
let currentI18nId = null;
|
|
19265
|
+
for (const op of unit.create) {
|
|
19266
|
+
switch (op.kind) {
|
|
19267
|
+
case OpKind.I18nStart:
|
|
19268
|
+
currentI18nId = op.xref;
|
|
19269
|
+
break;
|
|
19270
|
+
case OpKind.I18nEnd:
|
|
19271
|
+
currentI18nId = null;
|
|
19272
|
+
break;
|
|
19273
|
+
case OpKind.Icu:
|
|
19274
|
+
if (currentI18nId === null) {
|
|
19275
|
+
throw Error('Unexpected ICU outside of an i18n block.');
|
|
19276
|
+
}
|
|
19277
|
+
icus.set(op.xref, { message: op.message, i18nBlockId: currentI18nId });
|
|
19278
|
+
OpList.remove(op);
|
|
19279
|
+
break;
|
|
19280
|
+
}
|
|
19281
|
+
}
|
|
19282
|
+
// Replace the `IcuUpdate` ops with `i18nExpr` ops.
|
|
19283
|
+
for (const op of unit.update) {
|
|
19284
|
+
switch (op.kind) {
|
|
19285
|
+
case OpKind.IcuUpdate:
|
|
19286
|
+
const { message, i18nBlockId } = icus.get(op.xref);
|
|
19287
|
+
const icuNode = message.nodes.find((n) => n instanceof Icu);
|
|
19288
|
+
if (icuNode === undefined) {
|
|
19289
|
+
throw Error('Could not find ICU in i18n AST');
|
|
19290
|
+
}
|
|
19291
|
+
if (icuNode.expressionPlaceholder === undefined) {
|
|
19292
|
+
throw Error('ICU is missing an i18n placeholder');
|
|
19293
|
+
}
|
|
19294
|
+
OpList.replace(op, createI18nExpressionOp(i18nBlockId, new LexicalReadExpr(icuNode.expression), icuNode.expressionPlaceholder, I18nParamResolutionTime.Postproccessing, null));
|
|
19295
|
+
break;
|
|
19296
|
+
}
|
|
19297
|
+
}
|
|
19298
|
+
}
|
|
19299
|
+
}
|
|
19300
|
+
|
|
19133
19301
|
/**
|
|
19134
19302
|
* Lifts local reference declarations on element-like structures within each view into an entry in
|
|
19135
19303
|
* the `consts` array for the whole component.
|
|
@@ -19139,7 +19307,6 @@ function phaseLocalRefs(job) {
|
|
|
19139
19307
|
for (const op of unit.create) {
|
|
19140
19308
|
switch (op.kind) {
|
|
19141
19309
|
case OpKind.ElementStart:
|
|
19142
|
-
case OpKind.Element:
|
|
19143
19310
|
case OpKind.Template:
|
|
19144
19311
|
if (!Array.isArray(op.localRefs)) {
|
|
19145
19312
|
throw new Error(`AssertionError: expected localRefs to be an array still`);
|
|
@@ -19172,7 +19339,7 @@ function phaseNamespace(job) {
|
|
|
19172
19339
|
for (const unit of job.units) {
|
|
19173
19340
|
let activeNamespace = Namespace.HTML;
|
|
19174
19341
|
for (const op of unit.create) {
|
|
19175
|
-
if (op.kind !== OpKind.
|
|
19342
|
+
if (op.kind !== OpKind.ElementStart) {
|
|
19176
19343
|
continue;
|
|
19177
19344
|
}
|
|
19178
19345
|
if (op.namespace !== activeNamespace) {
|
|
@@ -19317,7 +19484,8 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
19317
19484
|
if (op.slot === null) {
|
|
19318
19485
|
throw new Error(`Expected slot to be assigned`);
|
|
19319
19486
|
}
|
|
19320
|
-
|
|
19487
|
+
const tagToken = op.tag === null ? '' : '_' + prefixWithNamespace(op.tag, op.namespace);
|
|
19488
|
+
addNamesToView(childView, `${baseName}${tagToken}_${op.slot}`, state, compatibility);
|
|
19321
19489
|
break;
|
|
19322
19490
|
case OpKind.StyleProp:
|
|
19323
19491
|
op.name = normalizeStylePropName(op.name);
|
|
@@ -19451,11 +19619,6 @@ function phaseNgContainer(job) {
|
|
|
19451
19619
|
for (const unit of job.units) {
|
|
19452
19620
|
const updatedElementXrefs = new Set();
|
|
19453
19621
|
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
|
-
}
|
|
19459
19622
|
if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
|
|
19460
19623
|
// Transmute the `ElementStart` instruction to `ContainerStart`.
|
|
19461
19624
|
op.kind = OpKind.ContainerStart;
|
|
@@ -19739,6 +19902,55 @@ function phasePipeVariadic(job) {
|
|
|
19739
19902
|
}
|
|
19740
19903
|
}
|
|
19741
19904
|
|
|
19905
|
+
/**
|
|
19906
|
+
* Propagate i18n blocks down through child templates that act as placeholders in the root i18n
|
|
19907
|
+
* message.
|
|
19908
|
+
*/
|
|
19909
|
+
function phasePropagateI18nBlocks(job) {
|
|
19910
|
+
propagateI18nBlocksToTemplates(job.root, 0);
|
|
19911
|
+
}
|
|
19912
|
+
/**
|
|
19913
|
+
* Propagates i18n ops in the given view through to any child views recursively.
|
|
19914
|
+
*/
|
|
19915
|
+
function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
|
|
19916
|
+
let i18nBlock = null;
|
|
19917
|
+
for (const op of unit.create) {
|
|
19918
|
+
switch (op.kind) {
|
|
19919
|
+
case OpKind.I18nStart:
|
|
19920
|
+
op.subTemplateIndex = subTemplateIndex === 0 ? null : subTemplateIndex;
|
|
19921
|
+
i18nBlock = op;
|
|
19922
|
+
break;
|
|
19923
|
+
case OpKind.I18nEnd:
|
|
19924
|
+
i18nBlock = null;
|
|
19925
|
+
break;
|
|
19926
|
+
case OpKind.Template:
|
|
19927
|
+
const templateView = unit.job.views.get(op.xref);
|
|
19928
|
+
// We found an <ng-template> inside an i18n block; increment the sub-template counter and
|
|
19929
|
+
// wrap the template's view in a child i18n block.
|
|
19930
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
19931
|
+
if (i18nBlock === null) {
|
|
19932
|
+
throw Error('Expected template with i18n placeholder to be in an i18n block.');
|
|
19933
|
+
}
|
|
19934
|
+
subTemplateIndex++;
|
|
19935
|
+
wrapTemplateWithI18n(templateView, i18nBlock);
|
|
19936
|
+
}
|
|
19937
|
+
// Continue traversing inside the template's view.
|
|
19938
|
+
propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
|
|
19939
|
+
}
|
|
19940
|
+
}
|
|
19941
|
+
}
|
|
19942
|
+
/**
|
|
19943
|
+
* Wraps a template view with i18n start and end ops.
|
|
19944
|
+
*/
|
|
19945
|
+
function wrapTemplateWithI18n(unit, parentI18n) {
|
|
19946
|
+
// Only add i18n ops if they have not already been propagated to this template.
|
|
19947
|
+
if (unit.create.head.next?.kind !== OpKind.I18nStart) {
|
|
19948
|
+
const id = unit.job.allocateXrefId();
|
|
19949
|
+
OpList.insertAfter(createI18nStartOp(id, parentI18n.message, parentI18n.root), unit.create.head);
|
|
19950
|
+
OpList.insertBefore(createI18nEndOp(id), unit.create.tail);
|
|
19951
|
+
}
|
|
19952
|
+
}
|
|
19953
|
+
|
|
19742
19954
|
function phasePureFunctionExtraction(job) {
|
|
19743
19955
|
for (const view of job.units) {
|
|
19744
19956
|
for (const op of view.ops()) {
|
|
@@ -19869,7 +20081,7 @@ function elementContainerEnd() {
|
|
|
19869
20081
|
}
|
|
19870
20082
|
function template(slot, templateFnRef, decls, vars, tag, constIndex, sourceSpan) {
|
|
19871
20083
|
const args = [literal(slot), templateFnRef, literal(decls), literal(vars)];
|
|
19872
|
-
if (tag !== null) {
|
|
20084
|
+
if (tag !== null || constIndex !== null) {
|
|
19873
20085
|
args.push(literal(tag));
|
|
19874
20086
|
if (constIndex !== null) {
|
|
19875
20087
|
args.push(literal(constIndex));
|
|
@@ -19975,11 +20187,19 @@ function projection(slot, projectionSlotIndex, attributes) {
|
|
|
19975
20187
|
}
|
|
19976
20188
|
return call(Identifiers.projection, args, null);
|
|
19977
20189
|
}
|
|
19978
|
-
function i18nStart(slot, constIndex) {
|
|
19979
|
-
|
|
20190
|
+
function i18nStart(slot, constIndex, subTemplateIndex) {
|
|
20191
|
+
const args = [literal(slot), literal(constIndex)];
|
|
20192
|
+
if (subTemplateIndex !== null) {
|
|
20193
|
+
args.push(literal(subTemplateIndex));
|
|
20194
|
+
}
|
|
20195
|
+
return call(Identifiers.i18nStart, args, null);
|
|
19980
20196
|
}
|
|
19981
|
-
function i18n(slot, constIndex) {
|
|
19982
|
-
|
|
20197
|
+
function i18n(slot, constIndex, subTemplateIndex) {
|
|
20198
|
+
const args = [literal(slot), literal(constIndex)];
|
|
20199
|
+
if (subTemplateIndex) {
|
|
20200
|
+
args.push(literal(subTemplateIndex));
|
|
20201
|
+
}
|
|
20202
|
+
return call(Identifiers.i18n, args, null);
|
|
19983
20203
|
}
|
|
19984
20204
|
function i18nEnd() {
|
|
19985
20205
|
return call(Identifiers.i18nEnd, [], null);
|
|
@@ -20362,13 +20582,13 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20362
20582
|
OpList.replace(op, elementContainerEnd());
|
|
20363
20583
|
break;
|
|
20364
20584
|
case OpKind.I18nStart:
|
|
20365
|
-
OpList.replace(op, i18nStart(op.slot, op.messageIndex));
|
|
20585
|
+
OpList.replace(op, i18nStart(op.slot, op.messageIndex, op.subTemplateIndex));
|
|
20366
20586
|
break;
|
|
20367
20587
|
case OpKind.I18nEnd:
|
|
20368
20588
|
OpList.replace(op, i18nEnd());
|
|
20369
20589
|
break;
|
|
20370
20590
|
case OpKind.I18n:
|
|
20371
|
-
OpList.replace(op, i18n(op.slot, op.messageIndex));
|
|
20591
|
+
OpList.replace(op, i18n(op.slot, op.messageIndex, op.subTemplateIndex));
|
|
20372
20592
|
break;
|
|
20373
20593
|
case OpKind.Template:
|
|
20374
20594
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
@@ -20706,96 +20926,279 @@ function resolveDollarEvent(unit, ops) {
|
|
|
20706
20926
|
* The escape sequence used indicate message param values.
|
|
20707
20927
|
*/
|
|
20708
20928
|
const ESCAPE = '\uFFFD';
|
|
20929
|
+
/**
|
|
20930
|
+
* Marker used to indicate an element tag.
|
|
20931
|
+
*/
|
|
20932
|
+
const ELEMENT_MARKER = '#';
|
|
20933
|
+
/**
|
|
20934
|
+
* Marker used to indicate a template tag.
|
|
20935
|
+
*/
|
|
20936
|
+
const TEMPLATE_MARKER = '*';
|
|
20937
|
+
/**
|
|
20938
|
+
* Marker used to indicate closing of an element or template tag.
|
|
20939
|
+
*/
|
|
20940
|
+
const TAG_CLOSE_MARKER = '/';
|
|
20941
|
+
/**
|
|
20942
|
+
* Marker used to indicate the sub-template context.
|
|
20943
|
+
*/
|
|
20944
|
+
const CONTEXT_MARKER = ':';
|
|
20945
|
+
/**
|
|
20946
|
+
* Marker used to indicate the start of a list of values.
|
|
20947
|
+
*/
|
|
20948
|
+
const LIST_START_MARKER = '[';
|
|
20949
|
+
/**
|
|
20950
|
+
* Marker used to indicate the end of a list of values.
|
|
20951
|
+
*/
|
|
20952
|
+
const LIST_END_MARKER = ']';
|
|
20953
|
+
/**
|
|
20954
|
+
* Delimiter used to separate multiple values in a list.
|
|
20955
|
+
*/
|
|
20956
|
+
const LIST_DELIMITER = '|';
|
|
20957
|
+
/**
|
|
20958
|
+
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
20959
|
+
* the final map.
|
|
20960
|
+
*/
|
|
20961
|
+
var I18nParamValueFlags;
|
|
20962
|
+
(function (I18nParamValueFlags) {
|
|
20963
|
+
I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
|
|
20964
|
+
/**
|
|
20965
|
+
* This value represtents an element tag.
|
|
20966
|
+
*/
|
|
20967
|
+
I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
|
|
20968
|
+
/**
|
|
20969
|
+
* This value represents a template tag.
|
|
20970
|
+
*/
|
|
20971
|
+
I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
|
|
20972
|
+
/**
|
|
20973
|
+
* This value represents the opening of a tag.
|
|
20974
|
+
*/
|
|
20975
|
+
I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
|
|
20976
|
+
/**
|
|
20977
|
+
* This value represents the closing of a tag.
|
|
20978
|
+
*/
|
|
20979
|
+
I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
|
|
20980
|
+
})(I18nParamValueFlags || (I18nParamValueFlags = {}));
|
|
20981
|
+
/**
|
|
20982
|
+
* Represents the complete i18n params map for an i18n op.
|
|
20983
|
+
*/
|
|
20984
|
+
class I18nPlaceholderParams {
|
|
20985
|
+
constructor() {
|
|
20986
|
+
this.values = new Map();
|
|
20987
|
+
}
|
|
20988
|
+
/**
|
|
20989
|
+
* Adds a new value to the params map.
|
|
20990
|
+
*/
|
|
20991
|
+
addValue(placeholder, value, subTemplateIndex, resolutionTime, flags) {
|
|
20992
|
+
const placeholderValues = this.values.get(placeholder) ?? [];
|
|
20993
|
+
placeholderValues.push({ value, subTemplateIndex, resolutionTime, flags });
|
|
20994
|
+
this.values.set(placeholder, placeholderValues);
|
|
20995
|
+
}
|
|
20996
|
+
/**
|
|
20997
|
+
* Saves the params map, in serialized form, into the given i18n op.
|
|
20998
|
+
*/
|
|
20999
|
+
saveToOp(op) {
|
|
21000
|
+
for (const [placeholder, placeholderValues] of this.values) {
|
|
21001
|
+
// We need to run post-processing for any 1i8n ops that contain parameters with more than
|
|
21002
|
+
// one value, even if there are no parameters resolved at post-processing time.
|
|
21003
|
+
const creationValues = placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Creation);
|
|
21004
|
+
if (creationValues.length > 1) {
|
|
21005
|
+
op.needsPostprocessing = true;
|
|
21006
|
+
}
|
|
21007
|
+
// Save creation time params to op.
|
|
21008
|
+
const serializedCreationValues = this.serializeValues(creationValues);
|
|
21009
|
+
if (serializedCreationValues !== null) {
|
|
21010
|
+
op.params.set(placeholder, literal(serializedCreationValues));
|
|
21011
|
+
}
|
|
21012
|
+
// Save post-processing time params to op.
|
|
21013
|
+
const serializedPostprocessingValues = this.serializeValues(placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Postproccessing));
|
|
21014
|
+
if (serializedPostprocessingValues !== null) {
|
|
21015
|
+
op.needsPostprocessing = true;
|
|
21016
|
+
op.postprocessingParams.set(placeholder, literal(serializedPostprocessingValues));
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
21019
|
+
}
|
|
21020
|
+
/**
|
|
21021
|
+
* Merges another param map into this one.
|
|
21022
|
+
*/
|
|
21023
|
+
merge(other) {
|
|
21024
|
+
for (const [placeholder, otherValues] of other.values) {
|
|
21025
|
+
const currentValues = this.values.get(placeholder) || [];
|
|
21026
|
+
// Child element close tag params should be prepended to maintain the same order as
|
|
21027
|
+
// TemplateDefinitionBuilder.
|
|
21028
|
+
const flags = otherValues[0].flags;
|
|
21029
|
+
if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
|
|
21030
|
+
this.values.set(placeholder, [...otherValues, ...currentValues]);
|
|
21031
|
+
}
|
|
21032
|
+
else {
|
|
21033
|
+
this.values.set(placeholder, [...currentValues, ...otherValues]);
|
|
21034
|
+
}
|
|
21035
|
+
}
|
|
21036
|
+
}
|
|
21037
|
+
/**
|
|
21038
|
+
* Serializes a list of i18n placeholder values.
|
|
21039
|
+
*/
|
|
21040
|
+
serializeValues(values) {
|
|
21041
|
+
if (values.length === 0) {
|
|
21042
|
+
return null;
|
|
21043
|
+
}
|
|
21044
|
+
const serializedValues = values.map(value => this.serializeValue(value));
|
|
21045
|
+
return serializedValues.length === 1 ?
|
|
21046
|
+
serializedValues[0] :
|
|
21047
|
+
`${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
|
|
21048
|
+
}
|
|
21049
|
+
/**
|
|
21050
|
+
* Serializes a single i18n placeholder value.
|
|
21051
|
+
*/
|
|
21052
|
+
serializeValue(value) {
|
|
21053
|
+
let tagMarker = '';
|
|
21054
|
+
let closeMarker = '';
|
|
21055
|
+
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
21056
|
+
tagMarker = ELEMENT_MARKER;
|
|
21057
|
+
}
|
|
21058
|
+
else if (value.flags & I18nParamValueFlags.TemplateTag) {
|
|
21059
|
+
tagMarker = TEMPLATE_MARKER;
|
|
21060
|
+
}
|
|
21061
|
+
if (tagMarker !== '') {
|
|
21062
|
+
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
21063
|
+
}
|
|
21064
|
+
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
21065
|
+
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
21066
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
21067
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
21068
|
+
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
21069
|
+
}
|
|
21070
|
+
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
21071
|
+
}
|
|
21072
|
+
}
|
|
20709
21073
|
/**
|
|
20710
21074
|
* Resolve the placeholders in i18n messages.
|
|
20711
21075
|
*/
|
|
20712
21076
|
function phaseResolveI18nPlaceholders(job) {
|
|
21077
|
+
const params = new Map();
|
|
21078
|
+
const i18nOps = new Map();
|
|
21079
|
+
resolvePlaceholders(job, params, i18nOps);
|
|
21080
|
+
propagatePlaceholders(params, i18nOps);
|
|
21081
|
+
// After colleccting all params, save them to the i18n ops.
|
|
21082
|
+
for (const [xref, i18nOpParams] of params) {
|
|
21083
|
+
i18nOpParams.saveToOp(i18nOps.get(xref));
|
|
21084
|
+
}
|
|
21085
|
+
// Validate the root i18n ops have all placeholders filled in.
|
|
21086
|
+
for (const op of i18nOps.values()) {
|
|
21087
|
+
if (op.xref === op.root) {
|
|
21088
|
+
for (const placeholder in op.message.placeholders) {
|
|
21089
|
+
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
21090
|
+
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
21091
|
+
}
|
|
21092
|
+
}
|
|
21093
|
+
}
|
|
21094
|
+
}
|
|
21095
|
+
}
|
|
21096
|
+
/**
|
|
21097
|
+
* Resolve placeholders for each i18n op.
|
|
21098
|
+
*/
|
|
21099
|
+
function resolvePlaceholders(job, params, i18nOps) {
|
|
20713
21100
|
for (const unit of job.units) {
|
|
20714
|
-
const
|
|
20715
|
-
let startTagSlots = new Map();
|
|
20716
|
-
let closeTagSlots = new Map();
|
|
21101
|
+
const elements = new Map();
|
|
20717
21102
|
let currentI18nOp = null;
|
|
20718
21103
|
// Record slots for tag name placeholders.
|
|
20719
21104
|
for (const op of unit.create) {
|
|
20720
21105
|
switch (op.kind) {
|
|
20721
21106
|
case OpKind.I18nStart:
|
|
20722
|
-
case OpKind.I18n:
|
|
20723
|
-
// Initialize collected slots for a new i18n block.
|
|
20724
21107
|
i18nOps.set(op.xref, op);
|
|
20725
21108
|
currentI18nOp = op.kind === OpKind.I18nStart ? op : null;
|
|
20726
|
-
startTagSlots = new Map();
|
|
20727
|
-
closeTagSlots = new Map();
|
|
20728
21109
|
break;
|
|
20729
21110
|
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
21111
|
currentI18nOp = null;
|
|
20741
21112
|
break;
|
|
20742
|
-
case OpKind.Element:
|
|
20743
21113
|
case OpKind.ElementStart:
|
|
20744
|
-
//
|
|
20745
|
-
|
|
21114
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21115
|
+
// corresponding tag start placeholder.
|
|
21116
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
20746
21117
|
if (currentI18nOp === null) {
|
|
20747
21118
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
20748
21119
|
}
|
|
20749
|
-
|
|
20750
|
-
throw Error('Slots should be allocated before i18n placeholder resolution');
|
|
20751
|
-
}
|
|
21120
|
+
elements.set(op.xref, op);
|
|
20752
21121
|
const { startName, closeName } = op.i18nPlaceholder;
|
|
20753
|
-
|
|
20754
|
-
|
|
21122
|
+
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
21123
|
+
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
21124
|
+
// placeholder accounts for the start and close of the element.
|
|
21125
|
+
if (closeName === '') {
|
|
21126
|
+
flags |= I18nParamValueFlags.CloseTag;
|
|
21127
|
+
}
|
|
21128
|
+
addParam(params, currentI18nOp, startName, op.slot, currentI18nOp.subTemplateIndex, I18nParamResolutionTime.Creation, flags);
|
|
21129
|
+
}
|
|
21130
|
+
break;
|
|
21131
|
+
case OpKind.ElementEnd:
|
|
21132
|
+
const startOp = elements.get(op.xref);
|
|
21133
|
+
if (startOp && startOp.i18nPlaceholder !== undefined) {
|
|
21134
|
+
if (currentI18nOp === null) {
|
|
21135
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21136
|
+
}
|
|
21137
|
+
const { closeName } = startOp.i18nPlaceholder;
|
|
21138
|
+
// Self-closing tags don't have a closing tag placeholder.
|
|
21139
|
+
if (closeName !== '') {
|
|
21140
|
+
addParam(params, currentI18nOp, closeName, startOp.slot, currentI18nOp.subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
|
|
21141
|
+
}
|
|
21142
|
+
}
|
|
21143
|
+
break;
|
|
21144
|
+
case OpKind.Template:
|
|
21145
|
+
if (op.i18nPlaceholder !== undefined) {
|
|
21146
|
+
if (currentI18nOp === null) {
|
|
21147
|
+
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21148
|
+
}
|
|
21149
|
+
const subTemplateIndex = getSubTemplateIndexForTemplateTag(job, currentI18nOp, op);
|
|
21150
|
+
addParam(params, currentI18nOp, op.i18nPlaceholder.startName, op.slot, subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.TemplateTag);
|
|
21151
|
+
addParam(params, currentI18nOp, op.i18nPlaceholder.closeName, op.slot, subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag);
|
|
20755
21152
|
}
|
|
20756
21153
|
break;
|
|
20757
21154
|
}
|
|
20758
21155
|
}
|
|
20759
|
-
// Fill in values for each of the expression placeholders
|
|
21156
|
+
// Fill in values for each of the i18n expression placeholders.
|
|
20760
21157
|
const i18nBlockPlaceholderIndices = new Map();
|
|
20761
21158
|
for (const op of unit.update) {
|
|
20762
21159
|
if (op.kind === OpKind.I18nExpression) {
|
|
20763
|
-
const i18nOp = i18nOps.get(op.
|
|
20764
|
-
let index = i18nBlockPlaceholderIndices.get(op.
|
|
21160
|
+
const i18nOp = i18nOps.get(op.owner);
|
|
21161
|
+
let index = i18nBlockPlaceholderIndices.get(op.owner) || 0;
|
|
20765
21162
|
if (!i18nOp) {
|
|
20766
21163
|
throw Error('Cannot find corresponding i18nStart for i18nExpr');
|
|
20767
21164
|
}
|
|
20768
|
-
i18nOp
|
|
20769
|
-
i18nBlockPlaceholderIndices.set(op.
|
|
20770
|
-
}
|
|
20771
|
-
}
|
|
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
|
-
}
|
|
21165
|
+
addParam(params, i18nOp, op.i18nPlaceholder, index++, i18nOp.subTemplateIndex, op.resolutionTime);
|
|
21166
|
+
i18nBlockPlaceholderIndices.set(op.owner, index);
|
|
20778
21167
|
}
|
|
20779
21168
|
}
|
|
20780
21169
|
}
|
|
20781
21170
|
}
|
|
20782
21171
|
/**
|
|
20783
|
-
*
|
|
21172
|
+
* Add a param to the params map for the given i18n op.
|
|
20784
21173
|
*/
|
|
20785
|
-
function
|
|
20786
|
-
const
|
|
20787
|
-
|
|
20788
|
-
|
|
21174
|
+
function addParam(params, i18nOp, placeholder, value, subTemplateIndex, resolutionTime, flags = I18nParamValueFlags.None) {
|
|
21175
|
+
const i18nOpParams = params.get(i18nOp.xref) || new I18nPlaceholderParams();
|
|
21176
|
+
i18nOpParams.addValue(placeholder, value, subTemplateIndex, resolutionTime, flags);
|
|
21177
|
+
params.set(i18nOp.xref, i18nOpParams);
|
|
21178
|
+
}
|
|
21179
|
+
/**
|
|
21180
|
+
* Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
|
|
21181
|
+
* the child i18n block inside the template.
|
|
21182
|
+
*/
|
|
21183
|
+
function getSubTemplateIndexForTemplateTag(job, i18nOp, op) {
|
|
21184
|
+
for (const childOp of job.views.get(op.xref).create) {
|
|
21185
|
+
if (childOp.kind === OpKind.I18nStart) {
|
|
21186
|
+
return childOp.subTemplateIndex;
|
|
21187
|
+
}
|
|
21188
|
+
}
|
|
21189
|
+
return i18nOp.subTemplateIndex;
|
|
20789
21190
|
}
|
|
20790
21191
|
/**
|
|
20791
|
-
*
|
|
21192
|
+
* Propagate placeholders up to their root i18n op.
|
|
20792
21193
|
*/
|
|
20793
|
-
function
|
|
20794
|
-
|
|
20795
|
-
|
|
20796
|
-
|
|
21194
|
+
function propagatePlaceholders(params, i18nOps) {
|
|
21195
|
+
for (const [xref, opParams] of params) {
|
|
21196
|
+
const op = i18nOps.get(xref);
|
|
21197
|
+
if (op.xref !== op.root) {
|
|
21198
|
+
const rootParams = params.get(op.root) || new I18nPlaceholderParams();
|
|
21199
|
+
rootParams.merge(opParams);
|
|
21200
|
+
}
|
|
20797
21201
|
}
|
|
20798
|
-
return literal(`[${slotStrings.join('|')}]`);
|
|
20799
21202
|
}
|
|
20800
21203
|
|
|
20801
21204
|
/**
|
|
@@ -20938,8 +21341,7 @@ function phaseResolveSanitizers(job) {
|
|
|
20938
21341
|
* Checks whether the given op represents an iframe element.
|
|
20939
21342
|
*/
|
|
20940
21343
|
function isIframeElement$1(op) {
|
|
20941
|
-
return
|
|
20942
|
-
op.tag.toLowerCase() === 'iframe';
|
|
21344
|
+
return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
|
|
20943
21345
|
}
|
|
20944
21346
|
|
|
20945
21347
|
function phaseSaveRestoreView(job) {
|
|
@@ -21553,18 +21955,47 @@ function allowConservativeInlining(decl, target) {
|
|
|
21553
21955
|
}
|
|
21554
21956
|
}
|
|
21555
21957
|
|
|
21958
|
+
/**
|
|
21959
|
+
* Wraps ICUs that do not already belong to an i18n block in a new i18n block.
|
|
21960
|
+
*/
|
|
21961
|
+
function phaseWrapIcus(job) {
|
|
21962
|
+
for (const unit of job.units) {
|
|
21963
|
+
let currentI18nOp = null;
|
|
21964
|
+
for (const op of unit.create) {
|
|
21965
|
+
switch (op.kind) {
|
|
21966
|
+
case OpKind.I18nStart:
|
|
21967
|
+
currentI18nOp = op;
|
|
21968
|
+
break;
|
|
21969
|
+
case OpKind.I18nEnd:
|
|
21970
|
+
currentI18nOp = null;
|
|
21971
|
+
break;
|
|
21972
|
+
case OpKind.Icu:
|
|
21973
|
+
if (currentI18nOp === null) {
|
|
21974
|
+
const id = job.allocateXrefId();
|
|
21975
|
+
OpList.insertBefore(createI18nStartOp(id, op.message), op);
|
|
21976
|
+
OpList.insertAfter(createI18nEndOp(id), op);
|
|
21977
|
+
}
|
|
21978
|
+
break;
|
|
21979
|
+
}
|
|
21980
|
+
}
|
|
21981
|
+
}
|
|
21982
|
+
}
|
|
21983
|
+
|
|
21556
21984
|
const phases = [
|
|
21557
21985
|
{ kind: CompilationJobKind.Tmpl, fn: phaseRemoveContentSelectors },
|
|
21558
21986
|
{ kind: CompilationJobKind.Host, fn: phaseHostStylePropertyParsing },
|
|
21559
21987
|
{ kind: CompilationJobKind.Tmpl, fn: phaseNamespace },
|
|
21560
21988
|
{ kind: CompilationJobKind.Both, fn: phaseStyleBindingSpecialization },
|
|
21561
21989
|
{ kind: CompilationJobKind.Both, fn: phaseBindingSpecialization },
|
|
21990
|
+
{ kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nBlocks },
|
|
21991
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseWrapIcus },
|
|
21562
21992
|
{ kind: CompilationJobKind.Both, fn: phaseAttributeExtraction },
|
|
21563
21993
|
{ kind: CompilationJobKind.Both, fn: phaseParseExtractedStyles },
|
|
21564
21994
|
{ kind: CompilationJobKind.Tmpl, fn: phaseRemoveEmptyBindings },
|
|
21565
21995
|
{ kind: CompilationJobKind.Tmpl, fn: phaseConditionals },
|
|
21566
21996
|
{ kind: CompilationJobKind.Tmpl, fn: phasePipeCreation },
|
|
21567
21997
|
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
|
|
21998
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseIcuExtraction },
|
|
21568
21999
|
{ kind: CompilationJobKind.Tmpl, fn: phaseApplyI18nExpressions },
|
|
21569
22000
|
{ kind: CompilationJobKind.Tmpl, fn: phasePipeVariadic },
|
|
21570
22001
|
{ kind: CompilationJobKind.Both, fn: phasePureLiteralStructures },
|
|
@@ -21586,6 +22017,7 @@ const phases = [
|
|
|
21586
22017
|
{ kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
|
|
21587
22018
|
{ kind: CompilationJobKind.Tmpl, fn: phaseConstTraitCollection },
|
|
21588
22019
|
{ kind: CompilationJobKind.Both, fn: phaseConstCollection },
|
|
22020
|
+
{ kind: CompilationJobKind.Tmpl, fn: phaseAssignI18nSlotDependencies },
|
|
21589
22021
|
{ kind: CompilationJobKind.Both, fn: phaseVarCounting },
|
|
21590
22022
|
{ kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
|
|
21591
22023
|
{ kind: CompilationJobKind.Both, fn: phaseVariableOptimization },
|
|
@@ -21798,6 +22230,9 @@ function ingestNodes(unit, template) {
|
|
|
21798
22230
|
else if (node instanceof DeferredBlock) {
|
|
21799
22231
|
ingestDeferBlock(unit, node);
|
|
21800
22232
|
}
|
|
22233
|
+
else if (node instanceof Icu$1) {
|
|
22234
|
+
ingestIcu(unit, node);
|
|
22235
|
+
}
|
|
21801
22236
|
else {
|
|
21802
22237
|
throw new Error(`Unsupported template node: ${node.constructor.name}`);
|
|
21803
22238
|
}
|
|
@@ -21835,7 +22270,8 @@ function ingestElement(unit, element) {
|
|
|
21835
22270
|
* Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
|
|
21836
22271
|
*/
|
|
21837
22272
|
function ingestTemplate(unit, tmpl) {
|
|
21838
|
-
if (tmpl.i18n !== undefined &&
|
|
22273
|
+
if (tmpl.i18n !== undefined &&
|
|
22274
|
+
!(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
|
|
21839
22275
|
throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
|
|
21840
22276
|
}
|
|
21841
22277
|
const childView = unit.job.allocateView(unit.xref);
|
|
@@ -21844,8 +22280,8 @@ function ingestTemplate(unit, tmpl) {
|
|
|
21844
22280
|
if (tmpl.tagName) {
|
|
21845
22281
|
[namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
|
|
21846
22282
|
}
|
|
21847
|
-
|
|
21848
|
-
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace
|
|
22283
|
+
const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
|
|
22284
|
+
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace, namespaceForKey(namespacePrefix), false, i18nPlaceholder, tmpl.startSourceSpan);
|
|
21849
22285
|
unit.create.push(tplOp);
|
|
21850
22286
|
ingestBindings(unit, tplOp, tmpl);
|
|
21851
22287
|
ingestReferences(tplOp, tmpl);
|
|
@@ -21853,8 +22289,10 @@ function ingestTemplate(unit, tmpl) {
|
|
|
21853
22289
|
for (const { name, value } of tmpl.variables) {
|
|
21854
22290
|
childView.contextVariables.set(name, value);
|
|
21855
22291
|
}
|
|
21856
|
-
// If there is an i18n message associated with
|
|
21857
|
-
|
|
22292
|
+
// If this is a plain template and there is an i18n message associated with it, insert i18n start
|
|
22293
|
+
// and end ops. For structural directive templates, the i18n ops will be added when ingesting the
|
|
22294
|
+
// element/template the directive is placed on.
|
|
22295
|
+
if (isPlainTemplate(tmpl) && tmpl.i18n instanceof Message) {
|
|
21858
22296
|
const id = unit.job.allocateXrefId();
|
|
21859
22297
|
OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
|
|
21860
22298
|
OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
|
|
@@ -21888,7 +22326,7 @@ function ingestBoundText(unit, text) {
|
|
|
21888
22326
|
throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
|
|
21889
22327
|
}
|
|
21890
22328
|
if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
|
|
21891
|
-
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n
|
|
22329
|
+
throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
|
|
21892
22330
|
}
|
|
21893
22331
|
const i18nPlaceholders = text.i18n instanceof Container ?
|
|
21894
22332
|
text.i18n.children.filter((node) => node instanceof Placeholder) :
|
|
@@ -21915,7 +22353,7 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
21915
22353
|
if (firstXref === null) {
|
|
21916
22354
|
firstXref = cView.xref;
|
|
21917
22355
|
}
|
|
21918
|
-
unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined
|
|
22356
|
+
unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan));
|
|
21919
22357
|
const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
|
|
21920
22358
|
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref, ifCase.expressionAlias);
|
|
21921
22359
|
conditions.push(conditionalCaseExpr);
|
|
@@ -21935,7 +22373,7 @@ function ingestSwitchBlock(unit, switchBlock) {
|
|
|
21935
22373
|
if (firstXref === null) {
|
|
21936
22374
|
firstXref = cView.xref;
|
|
21937
22375
|
}
|
|
21938
|
-
unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined
|
|
22376
|
+
unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan));
|
|
21939
22377
|
const caseExpr = switchCase.expression ?
|
|
21940
22378
|
convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
|
|
21941
22379
|
null;
|
|
@@ -21990,6 +22428,16 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
21990
22428
|
// Add all ops to the view.
|
|
21991
22429
|
unit.create.push(deferOnOp);
|
|
21992
22430
|
}
|
|
22431
|
+
function ingestIcu(unit, icu) {
|
|
22432
|
+
if (icu.i18n instanceof Message) {
|
|
22433
|
+
const xref = unit.job.allocateXrefId();
|
|
22434
|
+
unit.create.push(createIcuOp(xref, icu.i18n, null));
|
|
22435
|
+
unit.update.push(createIcuUpdateOp(xref, null));
|
|
22436
|
+
}
|
|
22437
|
+
else {
|
|
22438
|
+
throw Error(`Unhandled i18n metadata type for ICU: ${icu.i18n?.constructor.name}`);
|
|
22439
|
+
}
|
|
22440
|
+
}
|
|
21993
22441
|
/**
|
|
21994
22442
|
* Convert a template AST expression into an output AST expression.
|
|
21995
22443
|
*/
|
|
@@ -22083,16 +22531,35 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
22083
22531
|
throw new Error(`Unhandled expression type: ${ast.constructor.name}`);
|
|
22084
22532
|
}
|
|
22085
22533
|
}
|
|
22534
|
+
/**
|
|
22535
|
+
* Checks whether the given template is a plain ng-template (as opposed to another kind of template
|
|
22536
|
+
* such as a structural directive template or control flow template). This is checked based on the
|
|
22537
|
+
* tagName. We can expect that only plain ng-templates will come through with a tagName of
|
|
22538
|
+
* 'ng-template'.
|
|
22539
|
+
*
|
|
22540
|
+
* Here are some of the cases we expect:
|
|
22541
|
+
*
|
|
22542
|
+
* | Angular HTML | Template tagName |
|
|
22543
|
+
* | ---------------------------------- | ------------------ |
|
|
22544
|
+
* | `<ng-template>` | 'ng-template' |
|
|
22545
|
+
* | `<div *ngIf="true">` | 'div' |
|
|
22546
|
+
* | `<svg><ng-template>` | 'svg:ng-template' |
|
|
22547
|
+
* | `@if (true) {` | 'Conditional' |
|
|
22548
|
+
* | `<ng-template *ngIf>` (plain) | 'ng-template' |
|
|
22549
|
+
* | `<ng-template *ngIf>` (structural) | null |
|
|
22550
|
+
*/
|
|
22551
|
+
function isPlainTemplate(tmpl) {
|
|
22552
|
+
return splitNsName(tmpl.tagName ?? '')[1] === 'ng-template';
|
|
22553
|
+
}
|
|
22086
22554
|
/**
|
|
22087
22555
|
* Process all of the bindings on an element-like structure in the template AST and convert them
|
|
22088
22556
|
* to their IR representation.
|
|
22089
22557
|
*/
|
|
22090
22558
|
function ingestBindings(unit, op, element) {
|
|
22091
22559
|
let flags = BindingFlags.None;
|
|
22092
|
-
const isPlainTemplate = element instanceof Template && splitNsName(element.tagName ?? '')[1] === 'ng-template';
|
|
22093
22560
|
if (element instanceof Template) {
|
|
22094
22561
|
flags |= BindingFlags.OnNgTemplateElement;
|
|
22095
|
-
if (isPlainTemplate) {
|
|
22562
|
+
if (element instanceof Template && isPlainTemplate(element)) {
|
|
22096
22563
|
flags |= BindingFlags.BindingTargetsTemplate;
|
|
22097
22564
|
}
|
|
22098
22565
|
const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
|
|
@@ -22121,7 +22588,7 @@ function ingestBindings(unit, op, element) {
|
|
|
22121
22588
|
throw Error('Animation listener should have a phase');
|
|
22122
22589
|
}
|
|
22123
22590
|
}
|
|
22124
|
-
if (element instanceof Template && !isPlainTemplate) {
|
|
22591
|
+
if (element instanceof Template && !isPlainTemplate(element)) {
|
|
22125
22592
|
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
|
|
22126
22593
|
continue;
|
|
22127
22594
|
}
|
|
@@ -23385,13 +23852,13 @@ function normalizeNgContentSelect(selectAttr) {
|
|
|
23385
23852
|
/** Pattern for the expression in a for loop block. */
|
|
23386
23853
|
const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
|
|
23387
23854
|
/** Pattern for the tracking expression in a for loop block. */
|
|
23388
|
-
const FOR_LOOP_TRACK_PATTERN = /^track\s+(
|
|
23855
|
+
const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
|
|
23389
23856
|
/** Pattern for the `as` expression in a conditional block. */
|
|
23390
23857
|
const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
|
|
23391
23858
|
/** Pattern used to identify an `else if` block. */
|
|
23392
23859
|
const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
|
|
23393
23860
|
/** Pattern used to identify a `let` parameter. */
|
|
23394
|
-
const FOR_LOOP_LET_PATTERN = /^let\s+(
|
|
23861
|
+
const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
|
|
23395
23862
|
/** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
|
|
23396
23863
|
const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
|
|
23397
23864
|
/**
|
|
@@ -23412,28 +23879,33 @@ function isConnectedIfLoopBlock(name) {
|
|
|
23412
23879
|
function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
23413
23880
|
const errors = validateIfConnectedBlocks(connectedBlocks);
|
|
23414
23881
|
const branches = [];
|
|
23415
|
-
if (errors.length > 0) {
|
|
23416
|
-
return { node: null, errors };
|
|
23417
|
-
}
|
|
23418
23882
|
const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
|
|
23419
23883
|
if (mainBlockParams !== null) {
|
|
23420
|
-
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan));
|
|
23884
|
+
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan));
|
|
23421
23885
|
}
|
|
23422
|
-
// Assumes that the structure is valid since we validated it above.
|
|
23423
23886
|
for (const block of connectedBlocks) {
|
|
23424
|
-
const children = visitAll(visitor, block.children, block.children);
|
|
23425
23887
|
if (ELSE_IF_PATTERN.test(block.name)) {
|
|
23426
23888
|
const params = parseConditionalBlockParameters(block, errors, bindingParser);
|
|
23427
23889
|
if (params !== null) {
|
|
23428
|
-
|
|
23890
|
+
const children = visitAll(visitor, block.children, block.children);
|
|
23891
|
+
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
|
|
23429
23892
|
}
|
|
23430
23893
|
}
|
|
23431
23894
|
else if (block.name === 'else') {
|
|
23432
|
-
|
|
23895
|
+
const children = visitAll(visitor, block.children, block.children);
|
|
23896
|
+
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
|
|
23433
23897
|
}
|
|
23434
23898
|
}
|
|
23899
|
+
// The outer IfBlock should have a span that encapsulates all branches.
|
|
23900
|
+
const ifBlockStartSourceSpan = branches.length > 0 ? branches[0].startSourceSpan : ast.startSourceSpan;
|
|
23901
|
+
const ifBlockEndSourceSpan = branches.length > 0 ? branches[branches.length - 1].endSourceSpan : ast.endSourceSpan;
|
|
23902
|
+
let wholeSourceSpan = ast.sourceSpan;
|
|
23903
|
+
const lastBranch = branches[branches.length - 1];
|
|
23904
|
+
if (lastBranch !== undefined) {
|
|
23905
|
+
wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
|
|
23906
|
+
}
|
|
23435
23907
|
return {
|
|
23436
|
-
node: new IfBlock(branches,
|
|
23908
|
+
node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan),
|
|
23437
23909
|
errors,
|
|
23438
23910
|
};
|
|
23439
23911
|
}
|
|
@@ -23452,7 +23924,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23452
23924
|
errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
|
|
23453
23925
|
}
|
|
23454
23926
|
else {
|
|
23455
|
-
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan);
|
|
23927
|
+
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
|
|
23456
23928
|
}
|
|
23457
23929
|
}
|
|
23458
23930
|
else {
|
|
@@ -23461,10 +23933,16 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23461
23933
|
}
|
|
23462
23934
|
if (params !== null) {
|
|
23463
23935
|
if (params.trackBy === null) {
|
|
23936
|
+
// TODO: We should not fail here, and instead try to produce some AST for the language
|
|
23937
|
+
// service.
|
|
23464
23938
|
errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
|
|
23465
23939
|
}
|
|
23466
23940
|
else {
|
|
23467
|
-
|
|
23941
|
+
// The `for` block has a main span that includes the `empty` branch. For only the span of the
|
|
23942
|
+
// main `for` body, use `mainSourceSpan`.
|
|
23943
|
+
const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
|
|
23944
|
+
const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
|
|
23945
|
+
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan);
|
|
23468
23946
|
}
|
|
23469
23947
|
}
|
|
23470
23948
|
return { node, errors };
|
|
@@ -23472,21 +23950,25 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
23472
23950
|
/** Creates a switch block from an HTML AST node. */
|
|
23473
23951
|
function createSwitchBlock(ast, visitor, bindingParser) {
|
|
23474
23952
|
const errors = validateSwitchBlock(ast);
|
|
23475
|
-
|
|
23476
|
-
|
|
23477
|
-
|
|
23478
|
-
const primaryExpression = parseBlockParameterToBinding(ast.parameters[0], bindingParser);
|
|
23953
|
+
const primaryExpression = ast.parameters.length > 0 ?
|
|
23954
|
+
parseBlockParameterToBinding(ast.parameters[0], bindingParser) :
|
|
23955
|
+
bindingParser.parseBinding('', false, ast.sourceSpan, 0);
|
|
23479
23956
|
const cases = [];
|
|
23957
|
+
const unknownBlocks = [];
|
|
23480
23958
|
let defaultCase = null;
|
|
23481
23959
|
// Here we assume that all the blocks are valid given that we validated them above.
|
|
23482
23960
|
for (const node of ast.children) {
|
|
23483
23961
|
if (!(node instanceof Block)) {
|
|
23484
23962
|
continue;
|
|
23485
23963
|
}
|
|
23964
|
+
if ((node.name !== 'case' || node.parameters.length === 0) && node.name !== 'default') {
|
|
23965
|
+
unknownBlocks.push(new UnknownBlock(node.name, node.sourceSpan));
|
|
23966
|
+
continue;
|
|
23967
|
+
}
|
|
23486
23968
|
const expression = node.name === 'case' ?
|
|
23487
23969
|
parseBlockParameterToBinding(node.parameters[0], bindingParser) :
|
|
23488
23970
|
null;
|
|
23489
|
-
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan);
|
|
23971
|
+
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
|
|
23490
23972
|
if (expression === null) {
|
|
23491
23973
|
defaultCase = ast;
|
|
23492
23974
|
}
|
|
@@ -23499,7 +23981,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
|
|
|
23499
23981
|
cases.push(defaultCase);
|
|
23500
23982
|
}
|
|
23501
23983
|
return {
|
|
23502
|
-
node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
23984
|
+
node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
23503
23985
|
errors
|
|
23504
23986
|
};
|
|
23505
23987
|
}
|
|
@@ -23543,8 +24025,10 @@ function parseForLoopParameters(block, errors, bindingParser) {
|
|
|
23543
24025
|
// Fill out any variables that haven't been defined explicitly.
|
|
23544
24026
|
for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
|
|
23545
24027
|
if (!result.context.hasOwnProperty(variableName)) {
|
|
23546
|
-
|
|
23547
|
-
|
|
24028
|
+
// Give ambiently-available context variables empty spans at the end of the start of the `for`
|
|
24029
|
+
// block, since they are not explicitly defined.
|
|
24030
|
+
const emptySpanAfterForBlockStart = new ParseSourceSpan(block.startSourceSpan.end, block.startSourceSpan.end);
|
|
24031
|
+
result.context[variableName] = new Variable(variableName, variableName, emptySpanAfterForBlockStart, emptySpanAfterForBlockStart);
|
|
23548
24032
|
}
|
|
23549
24033
|
}
|
|
23550
24034
|
return result;
|
|
@@ -24039,7 +24523,17 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24039
24523
|
const errors = [];
|
|
24040
24524
|
const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
|
|
24041
24525
|
const { triggers, prefetchTriggers } = parsePrimaryTriggers(ast.parameters, bindingParser, errors, placeholder);
|
|
24042
|
-
|
|
24526
|
+
// The `defer` block has a main span encompassing all of the connected branches as well. For the
|
|
24527
|
+
// span of only the first "main" branch, use `mainSourceSpan`.
|
|
24528
|
+
let lastEndSourceSpan = ast.endSourceSpan;
|
|
24529
|
+
let endOfLastSourceSpan = ast.sourceSpan.end;
|
|
24530
|
+
if (connectedBlocks.length > 0) {
|
|
24531
|
+
const lastConnectedBlock = connectedBlocks[connectedBlocks.length - 1];
|
|
24532
|
+
lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
|
|
24533
|
+
endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
|
|
24534
|
+
}
|
|
24535
|
+
const mainDeferredSourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
|
|
24536
|
+
const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, mainDeferredSourceSpan, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
|
|
24043
24537
|
return { node, errors };
|
|
24044
24538
|
}
|
|
24045
24539
|
function parseConnectedBlocks(connectedBlocks, errors, visitor) {
|
|
@@ -24445,7 +24939,10 @@ class HtmlAstToIvyAst {
|
|
|
24445
24939
|
else {
|
|
24446
24940
|
errorMessage = `Unrecognized block @${block.name}.`;
|
|
24447
24941
|
}
|
|
24448
|
-
result = {
|
|
24942
|
+
result = {
|
|
24943
|
+
node: new UnknownBlock(block.name, block.sourceSpan),
|
|
24944
|
+
errors: [new ParseError(block.sourceSpan, errorMessage)],
|
|
24945
|
+
};
|
|
24449
24946
|
break;
|
|
24450
24947
|
}
|
|
24451
24948
|
this.errors.push(...result.errors);
|
|
@@ -24686,19 +25183,6 @@ function textContents(node) {
|
|
|
24686
25183
|
}
|
|
24687
25184
|
}
|
|
24688
25185
|
|
|
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
|
-
|
|
24702
25186
|
var TagType;
|
|
24703
25187
|
(function (TagType) {
|
|
24704
25188
|
TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
|
|
@@ -25046,6 +25530,7 @@ class TemplateDefinitionBuilder {
|
|
|
25046
25530
|
this.visitIfBlockBranch = invalid;
|
|
25047
25531
|
this.visitSwitchBlockCase = invalid;
|
|
25048
25532
|
this.visitForLoopBlockEmpty = invalid;
|
|
25533
|
+
this.visitUnknownBlock = invalid;
|
|
25049
25534
|
this._bindingScope = parentBindingScope.nestedScope(level);
|
|
25050
25535
|
// Turn the relative context file path into an identifier by replacing non-alphanumeric
|
|
25051
25536
|
// characters with underscores.
|
|
@@ -25771,18 +26256,17 @@ class TemplateDefinitionBuilder {
|
|
|
25771
26256
|
// callback in order to generate the correct expressions when pipes or pure functions are
|
|
25772
26257
|
// used inside the branch expressions.
|
|
25773
26258
|
const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
|
|
25774
|
-
const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
|
|
25775
26259
|
// If the branch has an alias, it'll be assigned directly to the container's context.
|
|
25776
26260
|
// We define a variable referring directly to the context so that any nested usages can be
|
|
25777
26261
|
// rewritten to refer to it.
|
|
25778
26262
|
const variables = expressionAlias !== null ?
|
|
25779
26263
|
[new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
|
|
25780
26264
|
undefined;
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
};
|
|
26265
|
+
// Note: the template needs to be created *before* we process the expression,
|
|
26266
|
+
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26267
|
+
const index = this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables);
|
|
26268
|
+
const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
|
|
26269
|
+
return { index, expression: processedExpression, alias: expressionAlias };
|
|
25786
26270
|
});
|
|
25787
26271
|
// Use the index of the first block as the index for the entire container.
|
|
25788
26272
|
const containerIndex = branchData[0].index;
|
|
@@ -25828,20 +26312,21 @@ class TemplateDefinitionBuilder {
|
|
|
25828
26312
|
this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
|
|
25829
26313
|
}
|
|
25830
26314
|
visitSwitchBlock(block) {
|
|
25831
|
-
const blockExpression = block.expression.visit(this._valueConverter);
|
|
25832
|
-
this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
|
|
25833
26315
|
// We have to process the block in two steps: once here and again in the update instruction
|
|
25834
26316
|
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
25835
26317
|
const caseData = block.cases.map(currentCase => {
|
|
25836
|
-
|
|
25837
|
-
|
|
25838
|
-
|
|
25839
|
-
|
|
25840
|
-
|
|
25841
|
-
};
|
|
26318
|
+
const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
|
|
26319
|
+
const expression = currentCase.expression === null ?
|
|
26320
|
+
null :
|
|
26321
|
+
currentCase.expression.visit(this._valueConverter);
|
|
26322
|
+
return { index, expression };
|
|
25842
26323
|
});
|
|
25843
26324
|
// Use the index of the first block as the index for the entire container.
|
|
25844
26325
|
const containerIndex = caseData[0].index;
|
|
26326
|
+
// Note: the expression needs to be processed *after* the template,
|
|
26327
|
+
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26328
|
+
const blockExpression = block.expression.visit(this._valueConverter);
|
|
26329
|
+
this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
|
|
25845
26330
|
this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
|
|
25846
26331
|
const generateCases = (caseIndex) => {
|
|
25847
26332
|
// If we've gone beyond the last branch, return the special -1
|
|
@@ -25909,12 +26394,17 @@ class TemplateDefinitionBuilder {
|
|
|
25909
26394
|
literal(errorIndex),
|
|
25910
26395
|
loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
|
|
25911
26396
|
placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
|
|
26397
|
+
(loadingConsts?.length || placeholderConsts) ?
|
|
26398
|
+
importExpr(Identifiers.deferEnableTimerScheduling) :
|
|
26399
|
+
TYPED_NULL_EXPR,
|
|
25912
26400
|
]));
|
|
25913
|
-
this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
|
|
25914
|
-
this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
|
|
25915
26401
|
// Allocate an extra data slot right after a defer block slot to store
|
|
25916
26402
|
// instance-specific state of that defer block at runtime.
|
|
25917
26403
|
this.allocateDataSlot();
|
|
26404
|
+
// Note: the triggers need to be processed *after* the various templates,
|
|
26405
|
+
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26406
|
+
this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
|
|
26407
|
+
this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
|
|
25918
26408
|
}
|
|
25919
26409
|
createDeferredDepsFunction(name, metadata) {
|
|
25920
26410
|
if (metadata.deps.length === 0) {
|
|
@@ -26006,12 +26496,13 @@ class TemplateDefinitionBuilder {
|
|
|
26006
26496
|
// are implicitly inferred by the runtime to index + 1 and index + 2.
|
|
26007
26497
|
const blockIndex = this.allocateDataSlot();
|
|
26008
26498
|
const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
|
|
26009
|
-
const emptyData = block.empty === null ?
|
|
26010
|
-
null :
|
|
26011
|
-
this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
|
|
26012
26499
|
const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
|
|
26013
|
-
|
|
26014
|
-
|
|
26500
|
+
let emptyData = null;
|
|
26501
|
+
if (block.empty !== null) {
|
|
26502
|
+
emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
|
|
26503
|
+
// Allocate an extra slot for the empty block tracking.
|
|
26504
|
+
this.allocateBindingSlots(null);
|
|
26505
|
+
}
|
|
26015
26506
|
this.registerComputedLoopVariables(block, primaryData.scope);
|
|
26016
26507
|
// `repeaterCreate(0, ...)`
|
|
26017
26508
|
this.creationInstruction(block.sourceSpan, Identifiers.repeaterCreate, () => {
|
|
@@ -26031,6 +26522,11 @@ class TemplateDefinitionBuilder {
|
|
|
26031
26522
|
}
|
|
26032
26523
|
return params;
|
|
26033
26524
|
});
|
|
26525
|
+
// Note: the expression needs to be processed *after* the template,
|
|
26526
|
+
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26527
|
+
// Note: we don't allocate binding slots for this expression,
|
|
26528
|
+
// because its value isn't stored in the LView.
|
|
26529
|
+
const value = block.expression.visit(this._valueConverter);
|
|
26034
26530
|
// `repeater(0, iterable)`
|
|
26035
26531
|
this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
|
|
26036
26532
|
}
|
|
@@ -26906,7 +27402,7 @@ function parseTemplate(template, templateUrl, options = {}) {
|
|
|
26906
27402
|
leadingTriviaChars: LEADING_TRIVIA_CHARS,
|
|
26907
27403
|
...options,
|
|
26908
27404
|
tokenizeExpansionForms: true,
|
|
26909
|
-
tokenizeBlocks: options.enableBlockSyntax ??
|
|
27405
|
+
tokenizeBlocks: options.enableBlockSyntax ?? true,
|
|
26910
27406
|
});
|
|
26911
27407
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
26912
27408
|
parseResult.errors.length > 0) {
|
|
@@ -28051,6 +28547,7 @@ class Scope {
|
|
|
28051
28547
|
visitTextAttribute(attr) { }
|
|
28052
28548
|
visitIcu(icu) { }
|
|
28053
28549
|
visitDeferredTrigger(trigger) { }
|
|
28550
|
+
visitUnknownBlock(block) { }
|
|
28054
28551
|
maybeDeclare(thing) {
|
|
28055
28552
|
// Declare something with a name, as long as that name isn't taken.
|
|
28056
28553
|
if (!this.namedEntities.has(thing.name)) {
|
|
@@ -28252,6 +28749,7 @@ class DirectiveBinder {
|
|
|
28252
28749
|
visitBoundText(text) { }
|
|
28253
28750
|
visitIcu(icu) { }
|
|
28254
28751
|
visitDeferredTrigger(trigger) { }
|
|
28752
|
+
visitUnknownBlock(block) { }
|
|
28255
28753
|
}
|
|
28256
28754
|
/**
|
|
28257
28755
|
* Processes a template and extract metadata about expressions and symbols within.
|
|
@@ -28380,6 +28878,8 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
28380
28878
|
visitText(text) { }
|
|
28381
28879
|
visitContent(content) { }
|
|
28382
28880
|
visitTextAttribute(attribute) { }
|
|
28881
|
+
visitUnknownBlock(block) { }
|
|
28882
|
+
visitDeferredTrigger() { }
|
|
28383
28883
|
visitIcu(icu) {
|
|
28384
28884
|
Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this));
|
|
28385
28885
|
Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this));
|
|
@@ -28394,15 +28894,12 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
28394
28894
|
visitDeferredBlock(deferred) {
|
|
28395
28895
|
this.deferBlocks.add(deferred);
|
|
28396
28896
|
this.ingestScopedNode(deferred);
|
|
28897
|
+
deferred.triggers.when?.value.visit(this);
|
|
28898
|
+
deferred.prefetchTriggers.when?.value.visit(this);
|
|
28397
28899
|
deferred.placeholder && this.visitNode(deferred.placeholder);
|
|
28398
28900
|
deferred.loading && this.visitNode(deferred.loading);
|
|
28399
28901
|
deferred.error && this.visitNode(deferred.error);
|
|
28400
28902
|
}
|
|
28401
|
-
visitDeferredTrigger(trigger) {
|
|
28402
|
-
if (trigger instanceof BoundDeferredTrigger) {
|
|
28403
|
-
trigger.value.visit(this);
|
|
28404
|
-
}
|
|
28405
|
-
}
|
|
28406
28903
|
visitDeferredBlockPlaceholder(block) {
|
|
28407
28904
|
this.ingestScopedNode(block);
|
|
28408
28905
|
}
|
|
@@ -29259,13 +29756,11 @@ function publishFacade(global) {
|
|
|
29259
29756
|
* @description
|
|
29260
29757
|
* Entry point for all public APIs of the compiler package.
|
|
29261
29758
|
*/
|
|
29262
|
-
const VERSION = new Version('17.0.0-
|
|
29759
|
+
const VERSION = new Version('17.0.0-rc.0');
|
|
29263
29760
|
|
|
29264
29761
|
class CompilerConfig {
|
|
29265
|
-
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated,
|
|
29762
|
+
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
29266
29763
|
this.defaultEncapsulation = defaultEncapsulation;
|
|
29267
|
-
this.useJit = !!useJit;
|
|
29268
|
-
this.missingTranslation = missingTranslation;
|
|
29269
29764
|
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
|
|
29270
29765
|
this.strictInjectionParameters = strictInjectionParameters === true;
|
|
29271
29766
|
}
|
|
@@ -30755,6 +31250,31 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
|
|
|
30755
31250
|
return iife.callFn([]);
|
|
30756
31251
|
}
|
|
30757
31252
|
|
|
31253
|
+
/**
|
|
31254
|
+
* Generate an ngDevMode guarded call to setClassDebugInfo with the debug info about the class
|
|
31255
|
+
* (e.g., the file name in which the class is defined)
|
|
31256
|
+
*/
|
|
31257
|
+
function compileClassDebugInfo(debugInfo) {
|
|
31258
|
+
const debugInfoObject = {
|
|
31259
|
+
className: debugInfo.className,
|
|
31260
|
+
};
|
|
31261
|
+
// Include file path and line number only if the file relative path is calculated successfully.
|
|
31262
|
+
if (debugInfo.filePath) {
|
|
31263
|
+
debugInfoObject.filePath = debugInfo.filePath;
|
|
31264
|
+
debugInfoObject.lineNumber = debugInfo.lineNumber;
|
|
31265
|
+
}
|
|
31266
|
+
// Include forbidOrphanRendering only if it's set to true (to reduce generated code)
|
|
31267
|
+
if (debugInfo.forbidOrphanRendering) {
|
|
31268
|
+
debugInfoObject.forbidOrphanRendering = literal(true);
|
|
31269
|
+
}
|
|
31270
|
+
const fnCall = importExpr(Identifiers.setClassDebugInfo).callFn([
|
|
31271
|
+
debugInfo.type,
|
|
31272
|
+
mapLiteral(debugInfoObject),
|
|
31273
|
+
]);
|
|
31274
|
+
const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
|
|
31275
|
+
return iife.callFn([]);
|
|
31276
|
+
}
|
|
31277
|
+
|
|
30758
31278
|
/**
|
|
30759
31279
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
30760
31280
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
@@ -30766,7 +31286,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
30766
31286
|
function compileDeclareClassMetadata(metadata) {
|
|
30767
31287
|
const definitionMap = new DefinitionMap();
|
|
30768
31288
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
30769
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31289
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
30770
31290
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
30771
31291
|
definitionMap.set('type', metadata.type);
|
|
30772
31292
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -30874,7 +31394,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
30874
31394
|
// in 16.1 is actually used.
|
|
30875
31395
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
30876
31396
|
definitionMap.set('minVersion', literal(minVersion));
|
|
30877
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31397
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
30878
31398
|
// e.g. `type: MyDirective`
|
|
30879
31399
|
definitionMap.set('type', meta.type.value);
|
|
30880
31400
|
if (meta.isStandalone) {
|
|
@@ -31151,7 +31671,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
31151
31671
|
function compileDeclareFactoryFunction(meta) {
|
|
31152
31672
|
const definitionMap = new DefinitionMap();
|
|
31153
31673
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
31154
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31674
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
31155
31675
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31156
31676
|
definitionMap.set('type', meta.type.value);
|
|
31157
31677
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -31186,7 +31706,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
31186
31706
|
function createInjectableDefinitionMap(meta) {
|
|
31187
31707
|
const definitionMap = new DefinitionMap();
|
|
31188
31708
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
31189
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31709
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
31190
31710
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31191
31711
|
definitionMap.set('type', meta.type.value);
|
|
31192
31712
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -31237,7 +31757,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
31237
31757
|
function createInjectorDefinitionMap(meta) {
|
|
31238
31758
|
const definitionMap = new DefinitionMap();
|
|
31239
31759
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
31240
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31760
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
31241
31761
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31242
31762
|
definitionMap.set('type', meta.type.value);
|
|
31243
31763
|
definitionMap.set('providers', meta.providers);
|
|
@@ -31270,7 +31790,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
31270
31790
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
31271
31791
|
}
|
|
31272
31792
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
31273
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31793
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
31274
31794
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31275
31795
|
definitionMap.set('type', meta.type.value);
|
|
31276
31796
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -31321,7 +31841,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
31321
31841
|
function createPipeDefinitionMap(meta) {
|
|
31322
31842
|
const definitionMap = new DefinitionMap();
|
|
31323
31843
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
31324
|
-
definitionMap.set('version', literal('17.0.0-
|
|
31844
|
+
definitionMap.set('version', literal('17.0.0-rc.0'));
|
|
31325
31845
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31326
31846
|
// e.g. `type: MyPipe`
|
|
31327
31847
|
definitionMap.set('type', meta.type.value);
|
|
@@ -31354,5 +31874,5 @@ publishFacade(_global);
|
|
|
31354
31874
|
|
|
31355
31875
|
// This file is not used to build this module. It is only used during editing
|
|
31356
31876
|
|
|
31357
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
31877
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, UnknownBlock as TmplAstUnknownBlock, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
31358
31878
|
//# sourceMappingURL=compiler.mjs.map
|