@angular/core 20.0.0-next.5 → 20.0.0-next.6
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/{api.d-mxcXqDpA.d.ts → api.d-DQLNOR5l.d.ts} +4 -4
- package/{discovery.d-CyYpOJ7j.d.ts → discovery.d-CFs2MaLO.d.ts} +7 -17
- package/{event_dispatcher.d-PWnbqZDx.d.ts → event_dispatcher.d-DlbccpYq.d.ts} +3 -3
- package/fesm2022/{attribute-B17mgaqe.mjs → attribute-BWp59EjE.mjs} +3 -3
- package/fesm2022/{attribute-B17mgaqe.mjs.map → attribute-BWp59EjE.mjs.map} +1 -1
- package/fesm2022/core.mjs +20 -18
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/{debug_node-xKpCIZm-.mjs → debug_node-z_3NG8qT.mjs} +77 -68
- package/fesm2022/{debug_node-xKpCIZm-.mjs.map → debug_node-z_3NG8qT.mjs.map} +1 -1
- package/fesm2022/primitives/di.mjs +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +2 -2
- package/fesm2022/primitives/signals.mjs +5 -5
- package/fesm2022/{resource-BPpYEDic.mjs → resource-CPPwEcg7.mjs} +6 -8
- package/fesm2022/resource-CPPwEcg7.mjs.map +1 -0
- package/fesm2022/{root_effect_scheduler-D0_b1cf_.mjs → root_effect_scheduler-VSXfCzDX.mjs} +46 -15
- package/fesm2022/root_effect_scheduler-VSXfCzDX.mjs.map +1 -0
- package/fesm2022/rxjs-interop.mjs +7 -84
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/{signal-DhRAAi7R.mjs → signal-B6pMq7KS.mjs} +3 -3
- package/fesm2022/{signal-DhRAAi7R.mjs.map → signal-B6pMq7KS.mjs.map} +1 -1
- package/fesm2022/testing.mjs +165 -103
- package/fesm2022/testing.mjs.map +1 -1
- package/fesm2022/{untracked-DaaW3JJm.mjs → untracked-Bz5WMeU1.mjs} +4 -4
- package/fesm2022/{untracked-DaaW3JJm.mjs.map → untracked-Bz5WMeU1.mjs.map} +1 -1
- package/fesm2022/{weak_ref-DrMdAIDh.mjs → weak_ref-BaIq-pgY.mjs} +3 -3
- package/fesm2022/{weak_ref-DrMdAIDh.mjs.map → weak_ref-BaIq-pgY.mjs.map} +1 -1
- package/{graph.d-StYigYp1.d.ts → graph.d-BcIOep_B.d.ts} +3 -3
- package/index.d.ts +18 -20
- package/{ng_i18n_closure_mode.d-DLxSUiDr.d.ts → ng_i18n_closure_mode.d-C9d2CaSt.d.ts} +5 -5
- package/package.json +2 -2
- package/primitives/di/index.d.ts +1 -1
- package/primitives/event-dispatch/index.d.ts +3 -3
- package/primitives/signals/index.d.ts +6 -6
- package/rxjs-interop/index.d.ts +8 -17
- package/schematics/bundles/{apply_import_manager-C-ysxahq.js → apply_import_manager-DnMqg1pY.js} +6 -6
- package/schematics/bundles/{change_tracker-0Ktek5Xl.js → change_tracker-UMPkv-eH.js} +3 -3
- package/schematics/bundles/{checker-DqUKCGda.js → checker-BFBQyesT.js} +20 -3
- package/schematics/bundles/cleanup-unused-imports.js +25 -20
- package/schematics/bundles/{compiler-CuoiHqkc.js → compiler-BQ7R7w2v.js} +962 -297
- package/schematics/bundles/compiler_host-CAfDJO3W.js +1 -1
- package/schematics/bundles/control-flow-migration.js +2 -2
- package/schematics/bundles/document-core.js +12 -12
- package/schematics/bundles/imports-CIX-JgAN.js +1 -1
- package/schematics/bundles/{index-WFXCe5Q0.js → index-Cv4Q415G.js} +127 -36
- package/schematics/bundles/{index-CwFQSYXZ.js → index-D8tMJPKa.js} +10 -10
- package/schematics/bundles/inject-flags.js +14 -14
- package/schematics/bundles/inject-migration.js +4 -4
- package/schematics/bundles/leading_space-D9nQ8UQC.js +1 -1
- package/schematics/bundles/{migrate_ts_type_references-BNuHufqZ.js → migrate_ts_type_references-Cq_ZBuT4.js} +21 -21
- package/schematics/bundles/ng_decorators-DznZ5jMl.js +1 -1
- package/schematics/bundles/nodes-B16H9JUd.js +1 -1
- package/schematics/bundles/output-migration.js +80 -22
- package/schematics/bundles/{run_in_devkit-CmHxABFr.js → project_paths-ql6qcf_c.js} +254 -244
- package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.js +1 -1
- package/schematics/bundles/property_name-BBwFuqMe.js +1 -1
- package/schematics/bundles/route-lazy-loading.js +4 -4
- package/schematics/bundles/self-closing-tags-migration.js +20 -15
- package/schematics/bundles/signal-input-migration.js +26 -21
- package/schematics/bundles/signal-queries-migration.js +32 -27
- package/schematics/bundles/signals.js +8 -8
- package/schematics/bundles/standalone-migration.js +5 -5
- package/schematics/bundles/symbol-VPWguRxr.js +1 -1
- package/schematics/bundles/test-bed-get.js +13 -13
- package/{signal.d-BeaTIeOE.d.ts → signal.d-E0e5nW1p.d.ts} +4 -4
- package/testing/index.d.ts +9 -25
- package/{weak_ref.d-ttyj86RV.d.ts → weak_ref.d-eGOEP9S1.d.ts} +2 -2
- package/fesm2022/resource-BPpYEDic.mjs.map +0 -1
- package/fesm2022/root_effect_scheduler-D0_b1cf_.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v20.0.0-next.
|
|
3
|
+
* @license Angular v20.0.0-next.6
|
|
4
4
|
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
@@ -4915,17 +4915,19 @@ let Element$1 = class Element {
|
|
|
4915
4915
|
attributes;
|
|
4916
4916
|
inputs;
|
|
4917
4917
|
outputs;
|
|
4918
|
+
directives;
|
|
4918
4919
|
children;
|
|
4919
4920
|
references;
|
|
4920
4921
|
sourceSpan;
|
|
4921
4922
|
startSourceSpan;
|
|
4922
4923
|
endSourceSpan;
|
|
4923
4924
|
i18n;
|
|
4924
|
-
constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
4925
|
+
constructor(name, attributes, inputs, outputs, directives, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
4925
4926
|
this.name = name;
|
|
4926
4927
|
this.attributes = attributes;
|
|
4927
4928
|
this.inputs = inputs;
|
|
4928
4929
|
this.outputs = outputs;
|
|
4930
|
+
this.directives = directives;
|
|
4929
4931
|
this.children = children;
|
|
4930
4932
|
this.references = references;
|
|
4931
4933
|
this.sourceSpan = sourceSpan;
|
|
@@ -5224,11 +5226,70 @@ let LetDeclaration$1 = class LetDeclaration {
|
|
|
5224
5226
|
return visitor.visitLetDeclaration(this);
|
|
5225
5227
|
}
|
|
5226
5228
|
};
|
|
5229
|
+
let Component$1 = class Component {
|
|
5230
|
+
componentName;
|
|
5231
|
+
tagName;
|
|
5232
|
+
fullName;
|
|
5233
|
+
attributes;
|
|
5234
|
+
inputs;
|
|
5235
|
+
outputs;
|
|
5236
|
+
directives;
|
|
5237
|
+
children;
|
|
5238
|
+
references;
|
|
5239
|
+
sourceSpan;
|
|
5240
|
+
startSourceSpan;
|
|
5241
|
+
endSourceSpan;
|
|
5242
|
+
i18n;
|
|
5243
|
+
constructor(componentName, tagName, fullName, attributes, inputs, outputs, directives, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
5244
|
+
this.componentName = componentName;
|
|
5245
|
+
this.tagName = tagName;
|
|
5246
|
+
this.fullName = fullName;
|
|
5247
|
+
this.attributes = attributes;
|
|
5248
|
+
this.inputs = inputs;
|
|
5249
|
+
this.outputs = outputs;
|
|
5250
|
+
this.directives = directives;
|
|
5251
|
+
this.children = children;
|
|
5252
|
+
this.references = references;
|
|
5253
|
+
this.sourceSpan = sourceSpan;
|
|
5254
|
+
this.startSourceSpan = startSourceSpan;
|
|
5255
|
+
this.endSourceSpan = endSourceSpan;
|
|
5256
|
+
this.i18n = i18n;
|
|
5257
|
+
}
|
|
5258
|
+
visit(visitor) {
|
|
5259
|
+
return visitor.visitComponent(this);
|
|
5260
|
+
}
|
|
5261
|
+
};
|
|
5262
|
+
let Directive$1 = class Directive {
|
|
5263
|
+
name;
|
|
5264
|
+
attributes;
|
|
5265
|
+
inputs;
|
|
5266
|
+
outputs;
|
|
5267
|
+
references;
|
|
5268
|
+
sourceSpan;
|
|
5269
|
+
startSourceSpan;
|
|
5270
|
+
endSourceSpan;
|
|
5271
|
+
i18n;
|
|
5272
|
+
constructor(name, attributes, inputs, outputs, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
5273
|
+
this.name = name;
|
|
5274
|
+
this.attributes = attributes;
|
|
5275
|
+
this.inputs = inputs;
|
|
5276
|
+
this.outputs = outputs;
|
|
5277
|
+
this.references = references;
|
|
5278
|
+
this.sourceSpan = sourceSpan;
|
|
5279
|
+
this.startSourceSpan = startSourceSpan;
|
|
5280
|
+
this.endSourceSpan = endSourceSpan;
|
|
5281
|
+
this.i18n = i18n;
|
|
5282
|
+
}
|
|
5283
|
+
visit(visitor) {
|
|
5284
|
+
return visitor.visitDirective(this);
|
|
5285
|
+
}
|
|
5286
|
+
};
|
|
5227
5287
|
class Template {
|
|
5228
5288
|
tagName;
|
|
5229
5289
|
attributes;
|
|
5230
5290
|
inputs;
|
|
5231
5291
|
outputs;
|
|
5292
|
+
directives;
|
|
5232
5293
|
templateAttrs;
|
|
5233
5294
|
children;
|
|
5234
5295
|
references;
|
|
@@ -5242,11 +5303,12 @@ class Template {
|
|
|
5242
5303
|
// `null` is a special case for when there is a structural directive on an `ng-template` so
|
|
5243
5304
|
// the renderer can differentiate between the synthetic template and the one written in the
|
|
5244
5305
|
// file.
|
|
5245
|
-
tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
5306
|
+
tagName, attributes, inputs, outputs, directives, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
5246
5307
|
this.tagName = tagName;
|
|
5247
5308
|
this.attributes = attributes;
|
|
5248
5309
|
this.inputs = inputs;
|
|
5249
5310
|
this.outputs = outputs;
|
|
5311
|
+
this.directives = directives;
|
|
5250
5312
|
this.templateAttrs = templateAttrs;
|
|
5251
5313
|
this.children = children;
|
|
5252
5314
|
this.references = references;
|
|
@@ -5265,13 +5327,17 @@ class Content {
|
|
|
5265
5327
|
attributes;
|
|
5266
5328
|
children;
|
|
5267
5329
|
sourceSpan;
|
|
5330
|
+
startSourceSpan;
|
|
5331
|
+
endSourceSpan;
|
|
5268
5332
|
i18n;
|
|
5269
5333
|
name = 'ng-content';
|
|
5270
|
-
constructor(selector, attributes, children, sourceSpan, i18n) {
|
|
5334
|
+
constructor(selector, attributes, children, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
5271
5335
|
this.selector = selector;
|
|
5272
5336
|
this.attributes = attributes;
|
|
5273
5337
|
this.children = children;
|
|
5274
5338
|
this.sourceSpan = sourceSpan;
|
|
5339
|
+
this.startSourceSpan = startSourceSpan;
|
|
5340
|
+
this.endSourceSpan = endSourceSpan;
|
|
5275
5341
|
this.i18n = i18n;
|
|
5276
5342
|
}
|
|
5277
5343
|
visit(visitor) {
|
|
@@ -5354,6 +5420,7 @@ let RecursiveVisitor$1 = class RecursiveVisitor {
|
|
|
5354
5420
|
visitAll$1(this, element.attributes);
|
|
5355
5421
|
visitAll$1(this, element.inputs);
|
|
5356
5422
|
visitAll$1(this, element.outputs);
|
|
5423
|
+
visitAll$1(this, element.directives);
|
|
5357
5424
|
visitAll$1(this, element.children);
|
|
5358
5425
|
visitAll$1(this, element.references);
|
|
5359
5426
|
}
|
|
@@ -5361,6 +5428,7 @@ let RecursiveVisitor$1 = class RecursiveVisitor {
|
|
|
5361
5428
|
visitAll$1(this, template.attributes);
|
|
5362
5429
|
visitAll$1(this, template.inputs);
|
|
5363
5430
|
visitAll$1(this, template.outputs);
|
|
5431
|
+
visitAll$1(this, template.directives);
|
|
5364
5432
|
visitAll$1(this, template.children);
|
|
5365
5433
|
visitAll$1(this, template.references);
|
|
5366
5434
|
visitAll$1(this, template.variables);
|
|
@@ -5402,6 +5470,20 @@ let RecursiveVisitor$1 = class RecursiveVisitor {
|
|
|
5402
5470
|
visitContent(content) {
|
|
5403
5471
|
visitAll$1(this, content.children);
|
|
5404
5472
|
}
|
|
5473
|
+
visitComponent(component) {
|
|
5474
|
+
visitAll$1(this, component.attributes);
|
|
5475
|
+
visitAll$1(this, component.inputs);
|
|
5476
|
+
visitAll$1(this, component.outputs);
|
|
5477
|
+
visitAll$1(this, component.directives);
|
|
5478
|
+
visitAll$1(this, component.children);
|
|
5479
|
+
visitAll$1(this, component.references);
|
|
5480
|
+
}
|
|
5481
|
+
visitDirective(directive) {
|
|
5482
|
+
visitAll$1(this, directive.attributes);
|
|
5483
|
+
visitAll$1(this, directive.inputs);
|
|
5484
|
+
visitAll$1(this, directive.outputs);
|
|
5485
|
+
visitAll$1(this, directive.references);
|
|
5486
|
+
}
|
|
5405
5487
|
visitVariable(variable) { }
|
|
5406
5488
|
visitReference(reference) { }
|
|
5407
5489
|
visitTextAttribute(attribute) { }
|
|
@@ -6028,8 +6110,8 @@ const I18N_ICU_VAR_PREFIX = 'VAR_';
|
|
|
6028
6110
|
function isI18nAttribute(name) {
|
|
6029
6111
|
return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
|
|
6030
6112
|
}
|
|
6031
|
-
function hasI18nAttrs(
|
|
6032
|
-
return
|
|
6113
|
+
function hasI18nAttrs(node) {
|
|
6114
|
+
return node.attrs.some((attr) => isI18nAttribute(attr.name));
|
|
6033
6115
|
}
|
|
6034
6116
|
function icuFromI18nMessage(message) {
|
|
6035
6117
|
return message.nodes[0];
|
|
@@ -13423,13 +13505,15 @@ class Attribute extends NodeWithI18n {
|
|
|
13423
13505
|
class Element extends NodeWithI18n {
|
|
13424
13506
|
name;
|
|
13425
13507
|
attrs;
|
|
13508
|
+
directives;
|
|
13426
13509
|
children;
|
|
13427
13510
|
startSourceSpan;
|
|
13428
13511
|
endSourceSpan;
|
|
13429
|
-
constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
|
|
13512
|
+
constructor(name, attrs, directives, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
|
|
13430
13513
|
super(sourceSpan, i18n);
|
|
13431
13514
|
this.name = name;
|
|
13432
13515
|
this.attrs = attrs;
|
|
13516
|
+
this.directives = directives;
|
|
13433
13517
|
this.children = children;
|
|
13434
13518
|
this.startSourceSpan = startSourceSpan;
|
|
13435
13519
|
this.endSourceSpan = endSourceSpan;
|
|
@@ -13469,6 +13553,47 @@ class Block extends NodeWithI18n {
|
|
|
13469
13553
|
return visitor.visitBlock(this, context);
|
|
13470
13554
|
}
|
|
13471
13555
|
}
|
|
13556
|
+
class Component extends NodeWithI18n {
|
|
13557
|
+
componentName;
|
|
13558
|
+
tagName;
|
|
13559
|
+
fullName;
|
|
13560
|
+
attrs;
|
|
13561
|
+
directives;
|
|
13562
|
+
children;
|
|
13563
|
+
startSourceSpan;
|
|
13564
|
+
endSourceSpan;
|
|
13565
|
+
constructor(componentName, tagName, fullName, attrs, directives, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
|
|
13566
|
+
super(sourceSpan, i18n);
|
|
13567
|
+
this.componentName = componentName;
|
|
13568
|
+
this.tagName = tagName;
|
|
13569
|
+
this.fullName = fullName;
|
|
13570
|
+
this.attrs = attrs;
|
|
13571
|
+
this.directives = directives;
|
|
13572
|
+
this.children = children;
|
|
13573
|
+
this.startSourceSpan = startSourceSpan;
|
|
13574
|
+
this.endSourceSpan = endSourceSpan;
|
|
13575
|
+
}
|
|
13576
|
+
visit(visitor, context) {
|
|
13577
|
+
return visitor.visitComponent(this, context);
|
|
13578
|
+
}
|
|
13579
|
+
}
|
|
13580
|
+
class Directive {
|
|
13581
|
+
name;
|
|
13582
|
+
attrs;
|
|
13583
|
+
sourceSpan;
|
|
13584
|
+
startSourceSpan;
|
|
13585
|
+
endSourceSpan;
|
|
13586
|
+
constructor(name, attrs, sourceSpan, startSourceSpan, endSourceSpan = null) {
|
|
13587
|
+
this.name = name;
|
|
13588
|
+
this.attrs = attrs;
|
|
13589
|
+
this.sourceSpan = sourceSpan;
|
|
13590
|
+
this.startSourceSpan = startSourceSpan;
|
|
13591
|
+
this.endSourceSpan = endSourceSpan;
|
|
13592
|
+
}
|
|
13593
|
+
visit(visitor, context) {
|
|
13594
|
+
return visitor.visitDirective(this, context);
|
|
13595
|
+
}
|
|
13596
|
+
}
|
|
13472
13597
|
class BlockParameter {
|
|
13473
13598
|
expression;
|
|
13474
13599
|
sourceSpan;
|
|
@@ -13515,6 +13640,7 @@ class RecursiveVisitor {
|
|
|
13515
13640
|
visitElement(ast, context) {
|
|
13516
13641
|
this.visitChildren(context, (visit) => {
|
|
13517
13642
|
visit(ast.attrs);
|
|
13643
|
+
visit(ast.directives);
|
|
13518
13644
|
visit(ast.children);
|
|
13519
13645
|
});
|
|
13520
13646
|
}
|
|
@@ -13535,6 +13661,17 @@ class RecursiveVisitor {
|
|
|
13535
13661
|
}
|
|
13536
13662
|
visitBlockParameter(ast, context) { }
|
|
13537
13663
|
visitLetDeclaration(decl, context) { }
|
|
13664
|
+
visitComponent(component, context) {
|
|
13665
|
+
this.visitChildren(context, (visit) => {
|
|
13666
|
+
visit(component.attrs);
|
|
13667
|
+
visit(component.children);
|
|
13668
|
+
});
|
|
13669
|
+
}
|
|
13670
|
+
visitDirective(directive, context) {
|
|
13671
|
+
this.visitChildren(context, (visit) => {
|
|
13672
|
+
visit(directive.attrs);
|
|
13673
|
+
});
|
|
13674
|
+
}
|
|
13538
13675
|
visitChildren(context, cb) {
|
|
13539
13676
|
let results = [];
|
|
13540
13677
|
let t = this;
|
|
@@ -15738,11 +15875,13 @@ class _Tokenizer {
|
|
|
15738
15875
|
_currentTokenStart = null;
|
|
15739
15876
|
_currentTokenType = null;
|
|
15740
15877
|
_expansionCaseStack = [];
|
|
15878
|
+
_openDirectiveCount = 0;
|
|
15741
15879
|
_inInterpolation = false;
|
|
15742
15880
|
_preserveLineEndings;
|
|
15743
15881
|
_i18nNormalizeLineEndingsInICUs;
|
|
15744
15882
|
_tokenizeBlocks;
|
|
15745
15883
|
_tokenizeLet;
|
|
15884
|
+
_selectorlessEnabled;
|
|
15746
15885
|
tokens = [];
|
|
15747
15886
|
errors = [];
|
|
15748
15887
|
nonNormalizedIcuExpressions = [];
|
|
@@ -15770,6 +15909,7 @@ class _Tokenizer {
|
|
|
15770
15909
|
this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
|
|
15771
15910
|
this._tokenizeBlocks = options.tokenizeBlocks ?? true;
|
|
15772
15911
|
this._tokenizeLet = options.tokenizeLet ?? true;
|
|
15912
|
+
this._selectorlessEnabled = options.selectorlessEnabled ?? false;
|
|
15773
15913
|
try {
|
|
15774
15914
|
this._cursor.init();
|
|
15775
15915
|
}
|
|
@@ -15838,7 +15978,7 @@ class _Tokenizer {
|
|
|
15838
15978
|
this.handleError(e);
|
|
15839
15979
|
}
|
|
15840
15980
|
}
|
|
15841
|
-
this._beginToken(
|
|
15981
|
+
this._beginToken(41 /* TokenType.EOF */);
|
|
15842
15982
|
this._endToken([]);
|
|
15843
15983
|
}
|
|
15844
15984
|
_getBlockName() {
|
|
@@ -16237,7 +16377,7 @@ class _Tokenizer {
|
|
|
16237
16377
|
this._cursor.advance();
|
|
16238
16378
|
this._endToken([content]);
|
|
16239
16379
|
}
|
|
16240
|
-
_consumePrefixAndName() {
|
|
16380
|
+
_consumePrefixAndName(endPredicate) {
|
|
16241
16381
|
const nameOrPrefixStart = this._cursor.clone();
|
|
16242
16382
|
let prefix = '';
|
|
16243
16383
|
while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
|
|
@@ -16252,41 +16392,64 @@ class _Tokenizer {
|
|
|
16252
16392
|
else {
|
|
16253
16393
|
nameStart = nameOrPrefixStart;
|
|
16254
16394
|
}
|
|
16255
|
-
this._requireCharCodeUntilFn(
|
|
16395
|
+
this._requireCharCodeUntilFn(endPredicate, prefix === '' ? 0 : 1);
|
|
16256
16396
|
const name = this._cursor.getChars(nameStart);
|
|
16257
16397
|
return [prefix, name];
|
|
16258
16398
|
}
|
|
16259
16399
|
_consumeTagOpen(start) {
|
|
16260
16400
|
let tagName;
|
|
16261
16401
|
let prefix;
|
|
16262
|
-
let
|
|
16402
|
+
let closingTagName;
|
|
16403
|
+
let openToken;
|
|
16263
16404
|
try {
|
|
16264
|
-
if (
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
this._cursor.peek() !== $LT &&
|
|
16274
|
-
this._cursor.peek() !== $EOF) {
|
|
16275
|
-
this._consumeAttributeName();
|
|
16405
|
+
if (this._selectorlessEnabled && isSelectorlessNameStart(this._cursor.peek())) {
|
|
16406
|
+
openToken = this._consumeComponentOpenStart(start);
|
|
16407
|
+
[closingTagName, prefix, tagName] = openToken.parts;
|
|
16408
|
+
if (prefix) {
|
|
16409
|
+
closingTagName += `:${prefix}`;
|
|
16410
|
+
}
|
|
16411
|
+
if (tagName) {
|
|
16412
|
+
closingTagName += `:${tagName}`;
|
|
16413
|
+
}
|
|
16276
16414
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16415
|
+
}
|
|
16416
|
+
else {
|
|
16417
|
+
if (!isAsciiLetter(this._cursor.peek())) {
|
|
16418
|
+
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
|
|
16280
16419
|
}
|
|
16420
|
+
openToken = this._consumeTagOpenStart(start);
|
|
16421
|
+
prefix = openToken.parts[0];
|
|
16422
|
+
tagName = closingTagName = openToken.parts[1];
|
|
16281
16423
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16282
16424
|
}
|
|
16283
|
-
this.
|
|
16425
|
+
while (!isAttributeTerminator(this._cursor.peek())) {
|
|
16426
|
+
if (this._selectorlessEnabled && this._cursor.peek() === $AT) {
|
|
16427
|
+
const start = this._cursor.clone();
|
|
16428
|
+
const nameStart = start.clone();
|
|
16429
|
+
nameStart.advance();
|
|
16430
|
+
if (isSelectorlessNameStart(nameStart.peek())) {
|
|
16431
|
+
this._consumeDirective(start, nameStart);
|
|
16432
|
+
}
|
|
16433
|
+
}
|
|
16434
|
+
else {
|
|
16435
|
+
this._consumeAttribute();
|
|
16436
|
+
}
|
|
16437
|
+
}
|
|
16438
|
+
if (openToken.type === 33 /* TokenType.COMPONENT_OPEN_START */) {
|
|
16439
|
+
this._consumeComponentOpenEnd();
|
|
16440
|
+
}
|
|
16441
|
+
else {
|
|
16442
|
+
this._consumeTagOpenEnd();
|
|
16443
|
+
}
|
|
16284
16444
|
}
|
|
16285
16445
|
catch (e) {
|
|
16286
16446
|
if (e instanceof _ControlFlowError) {
|
|
16287
|
-
if (
|
|
16447
|
+
if (openToken) {
|
|
16288
16448
|
// We errored before we could close the opening tag, so it is incomplete.
|
|
16289
|
-
|
|
16449
|
+
openToken.type =
|
|
16450
|
+
openToken.type === 33 /* TokenType.COMPONENT_OPEN_START */
|
|
16451
|
+
? 37 /* TokenType.INCOMPLETE_COMPONENT_OPEN */
|
|
16452
|
+
: 4 /* TokenType.INCOMPLETE_TAG_OPEN */;
|
|
16290
16453
|
}
|
|
16291
16454
|
else {
|
|
16292
16455
|
// When the start tag is invalid, assume we want a "<" as text.
|
|
@@ -16300,13 +16463,13 @@ class _Tokenizer {
|
|
|
16300
16463
|
}
|
|
16301
16464
|
const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
|
|
16302
16465
|
if (contentTokenType === exports.TagContentType.RAW_TEXT) {
|
|
16303
|
-
this._consumeRawTextWithTagClose(
|
|
16466
|
+
this._consumeRawTextWithTagClose(openToken, closingTagName, false);
|
|
16304
16467
|
}
|
|
16305
16468
|
else if (contentTokenType === exports.TagContentType.ESCAPABLE_RAW_TEXT) {
|
|
16306
|
-
this._consumeRawTextWithTagClose(
|
|
16469
|
+
this._consumeRawTextWithTagClose(openToken, closingTagName, true);
|
|
16307
16470
|
}
|
|
16308
16471
|
}
|
|
16309
|
-
_consumeRawTextWithTagClose(
|
|
16472
|
+
_consumeRawTextWithTagClose(openToken, tagName, consumeEntities) {
|
|
16310
16473
|
this._consumeRawText(consumeEntities, () => {
|
|
16311
16474
|
if (!this._attemptCharCode($LT))
|
|
16312
16475
|
return false;
|
|
@@ -16318,23 +16481,79 @@ class _Tokenizer {
|
|
|
16318
16481
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16319
16482
|
return this._attemptCharCode($GT);
|
|
16320
16483
|
});
|
|
16321
|
-
this._beginToken(
|
|
16484
|
+
this._beginToken(openToken.type === 33 /* TokenType.COMPONENT_OPEN_START */
|
|
16485
|
+
? 36 /* TokenType.COMPONENT_CLOSE */
|
|
16486
|
+
: 3 /* TokenType.TAG_CLOSE */);
|
|
16322
16487
|
this._requireCharCodeUntilFn((code) => code === $GT, 3);
|
|
16323
16488
|
this._cursor.advance(); // Consume the `>`
|
|
16324
|
-
this._endToken(
|
|
16489
|
+
this._endToken(openToken.parts);
|
|
16325
16490
|
}
|
|
16326
16491
|
_consumeTagOpenStart(start) {
|
|
16327
16492
|
this._beginToken(0 /* TokenType.TAG_OPEN_START */, start);
|
|
16328
|
-
const parts = this._consumePrefixAndName();
|
|
16493
|
+
const parts = this._consumePrefixAndName(isNameEnd);
|
|
16494
|
+
return this._endToken(parts);
|
|
16495
|
+
}
|
|
16496
|
+
_consumeComponentOpenStart(start) {
|
|
16497
|
+
this._beginToken(33 /* TokenType.COMPONENT_OPEN_START */, start);
|
|
16498
|
+
const parts = this._consumeComponentName();
|
|
16329
16499
|
return this._endToken(parts);
|
|
16330
16500
|
}
|
|
16501
|
+
_consumeComponentName() {
|
|
16502
|
+
const nameStart = this._cursor.clone();
|
|
16503
|
+
while (isSelectorlessNameChar(this._cursor.peek())) {
|
|
16504
|
+
this._cursor.advance();
|
|
16505
|
+
}
|
|
16506
|
+
const name = this._cursor.getChars(nameStart);
|
|
16507
|
+
let prefix = '';
|
|
16508
|
+
let tagName = '';
|
|
16509
|
+
if (this._cursor.peek() === $COLON) {
|
|
16510
|
+
this._cursor.advance();
|
|
16511
|
+
[prefix, tagName] = this._consumePrefixAndName(isNameEnd);
|
|
16512
|
+
}
|
|
16513
|
+
return [name, prefix, tagName];
|
|
16514
|
+
}
|
|
16515
|
+
_consumeAttribute() {
|
|
16516
|
+
this._consumeAttributeName();
|
|
16517
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16518
|
+
if (this._attemptCharCode($EQ)) {
|
|
16519
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16520
|
+
this._consumeAttributeValue();
|
|
16521
|
+
}
|
|
16522
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16523
|
+
}
|
|
16331
16524
|
_consumeAttributeName() {
|
|
16332
16525
|
const attrNameStart = this._cursor.peek();
|
|
16333
16526
|
if (attrNameStart === $SQ || attrNameStart === $DQ) {
|
|
16334
16527
|
throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
|
|
16335
16528
|
}
|
|
16336
16529
|
this._beginToken(14 /* TokenType.ATTR_NAME */);
|
|
16337
|
-
|
|
16530
|
+
let nameEndPredicate;
|
|
16531
|
+
if (this._openDirectiveCount > 0) {
|
|
16532
|
+
// If we're parsing attributes inside of directive syntax, we have to terminate the name
|
|
16533
|
+
// on the first non-matching closing paren. For example, if we have `@Dir(someAttr)`,
|
|
16534
|
+
// `@Dir` and `(` will have already been captured as `DIRECTIVE_NAME` and `DIRECTIVE_OPEN`
|
|
16535
|
+
// respectively, but the `)` will get captured as a part of the name for `someAttr`
|
|
16536
|
+
// because normally that would be an event binding.
|
|
16537
|
+
let openParens = 0;
|
|
16538
|
+
nameEndPredicate = (code) => {
|
|
16539
|
+
if (this._openDirectiveCount > 0) {
|
|
16540
|
+
if (code === $LPAREN) {
|
|
16541
|
+
openParens++;
|
|
16542
|
+
}
|
|
16543
|
+
else if (code === $RPAREN) {
|
|
16544
|
+
if (openParens === 0) {
|
|
16545
|
+
return true;
|
|
16546
|
+
}
|
|
16547
|
+
openParens--;
|
|
16548
|
+
}
|
|
16549
|
+
}
|
|
16550
|
+
return isNameEnd(code);
|
|
16551
|
+
};
|
|
16552
|
+
}
|
|
16553
|
+
else {
|
|
16554
|
+
nameEndPredicate = isNameEnd;
|
|
16555
|
+
}
|
|
16556
|
+
const prefixAndName = this._consumePrefixAndName(nameEndPredicate);
|
|
16338
16557
|
this._endToken(prefixAndName);
|
|
16339
16558
|
}
|
|
16340
16559
|
_consumeAttributeValue() {
|
|
@@ -16365,10 +16584,32 @@ class _Tokenizer {
|
|
|
16365
16584
|
this._requireCharCode($GT);
|
|
16366
16585
|
this._endToken([]);
|
|
16367
16586
|
}
|
|
16587
|
+
_consumeComponentOpenEnd() {
|
|
16588
|
+
const tokenType = this._attemptCharCode($SLASH)
|
|
16589
|
+
? 35 /* TokenType.COMPONENT_OPEN_END_VOID */
|
|
16590
|
+
: 34 /* TokenType.COMPONENT_OPEN_END */;
|
|
16591
|
+
this._beginToken(tokenType);
|
|
16592
|
+
this._requireCharCode($GT);
|
|
16593
|
+
this._endToken([]);
|
|
16594
|
+
}
|
|
16368
16595
|
_consumeTagClose(start) {
|
|
16596
|
+
if (this._selectorlessEnabled) {
|
|
16597
|
+
const clone = start.clone();
|
|
16598
|
+
while (clone.peek() !== $GT && !isSelectorlessNameStart(clone.peek())) {
|
|
16599
|
+
clone.advance();
|
|
16600
|
+
}
|
|
16601
|
+
if (isSelectorlessNameStart(clone.peek())) {
|
|
16602
|
+
this._beginToken(36 /* TokenType.COMPONENT_CLOSE */, start);
|
|
16603
|
+
const parts = this._consumeComponentName();
|
|
16604
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16605
|
+
this._requireCharCode($GT);
|
|
16606
|
+
this._endToken(parts);
|
|
16607
|
+
return;
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16369
16610
|
this._beginToken(3 /* TokenType.TAG_CLOSE */, start);
|
|
16370
16611
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16371
|
-
const prefixAndName = this._consumePrefixAndName();
|
|
16612
|
+
const prefixAndName = this._consumePrefixAndName(isNameEnd);
|
|
16372
16613
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16373
16614
|
this._requireCharCode($GT);
|
|
16374
16615
|
this._endToken(prefixAndName);
|
|
@@ -16524,6 +16765,50 @@ class _Tokenizer {
|
|
|
16524
16765
|
parts.push(this._getProcessedChars(expressionStart, this._cursor));
|
|
16525
16766
|
this._endToken(parts);
|
|
16526
16767
|
}
|
|
16768
|
+
_consumeDirective(start, nameStart) {
|
|
16769
|
+
this._requireCharCode($AT);
|
|
16770
|
+
// Skip over the @ since it's not part of the name.
|
|
16771
|
+
this._cursor.advance();
|
|
16772
|
+
// Capture the rest of the name.
|
|
16773
|
+
while (isSelectorlessNameChar(this._cursor.peek())) {
|
|
16774
|
+
this._cursor.advance();
|
|
16775
|
+
}
|
|
16776
|
+
// Capture the opening token.
|
|
16777
|
+
this._beginToken(38 /* TokenType.DIRECTIVE_NAME */, start);
|
|
16778
|
+
const name = this._cursor.getChars(nameStart);
|
|
16779
|
+
this._endToken([name]);
|
|
16780
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16781
|
+
// Optionally there might be attributes bound to the specific directive.
|
|
16782
|
+
// Stop parsing if there's no opening character for them.
|
|
16783
|
+
if (this._cursor.peek() !== $LPAREN) {
|
|
16784
|
+
return;
|
|
16785
|
+
}
|
|
16786
|
+
this._openDirectiveCount++;
|
|
16787
|
+
this._beginToken(39 /* TokenType.DIRECTIVE_OPEN */);
|
|
16788
|
+
this._cursor.advance();
|
|
16789
|
+
this._endToken([]);
|
|
16790
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16791
|
+
// Capture all the attributes until we hit a closing paren.
|
|
16792
|
+
while (!isAttributeTerminator(this._cursor.peek()) && this._cursor.peek() !== $RPAREN) {
|
|
16793
|
+
this._consumeAttribute();
|
|
16794
|
+
}
|
|
16795
|
+
// Trim any trailing whitespace.
|
|
16796
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16797
|
+
this._openDirectiveCount--;
|
|
16798
|
+
if (this._cursor.peek() !== $RPAREN) {
|
|
16799
|
+
// Stop parsing, instead of throwing, if we've hit the end of the tag.
|
|
16800
|
+
// This can be handled better later when turning the tokens into AST.
|
|
16801
|
+
if (this._cursor.peek() === $GT || this._cursor.peek() === $SLASH) {
|
|
16802
|
+
return;
|
|
16803
|
+
}
|
|
16804
|
+
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
|
|
16805
|
+
}
|
|
16806
|
+
// Capture the closing token.
|
|
16807
|
+
this._beginToken(40 /* TokenType.DIRECTIVE_CLOSE */);
|
|
16808
|
+
this._cursor.advance();
|
|
16809
|
+
this._endToken([]);
|
|
16810
|
+
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
16811
|
+
}
|
|
16527
16812
|
_getProcessedChars(start, end) {
|
|
16528
16813
|
return this._processCarriageReturns(end.getChars(start));
|
|
16529
16814
|
}
|
|
@@ -16639,6 +16924,15 @@ function isBlockNameChar(code) {
|
|
|
16639
16924
|
function isBlockParameterChar(code) {
|
|
16640
16925
|
return code !== $SEMICOLON && isNotWhitespace(code);
|
|
16641
16926
|
}
|
|
16927
|
+
function isSelectorlessNameStart(code) {
|
|
16928
|
+
return code === $_ || (code >= $A && code <= $Z);
|
|
16929
|
+
}
|
|
16930
|
+
function isSelectorlessNameChar(code) {
|
|
16931
|
+
return isAsciiLetter(code) || isDigit(code) || code === $_;
|
|
16932
|
+
}
|
|
16933
|
+
function isAttributeTerminator(code) {
|
|
16934
|
+
return code === $SLASH || code === $GT || code === $LT || code === $EOF;
|
|
16935
|
+
}
|
|
16642
16936
|
function mergeTextTokens(srcTokens) {
|
|
16643
16937
|
const dstTokens = [];
|
|
16644
16938
|
let lastDstToken = undefined;
|
|
@@ -16935,26 +17229,26 @@ let Parser$1 = class Parser {
|
|
|
16935
17229
|
};
|
|
16936
17230
|
class _TreeBuilder {
|
|
16937
17231
|
tokens;
|
|
16938
|
-
|
|
17232
|
+
tagDefinitionResolver;
|
|
16939
17233
|
_index = -1;
|
|
16940
17234
|
// `_peek` will be initialized by the call to `_advance()` in the constructor.
|
|
16941
17235
|
_peek;
|
|
16942
17236
|
_containerStack = [];
|
|
16943
17237
|
rootNodes = [];
|
|
16944
17238
|
errors = [];
|
|
16945
|
-
constructor(tokens,
|
|
17239
|
+
constructor(tokens, tagDefinitionResolver) {
|
|
16946
17240
|
this.tokens = tokens;
|
|
16947
|
-
this.
|
|
17241
|
+
this.tagDefinitionResolver = tagDefinitionResolver;
|
|
16948
17242
|
this._advance();
|
|
16949
17243
|
}
|
|
16950
17244
|
build() {
|
|
16951
|
-
while (this._peek.type !==
|
|
17245
|
+
while (this._peek.type !== 41 /* TokenType.EOF */) {
|
|
16952
17246
|
if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
|
|
16953
17247
|
this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
|
|
16954
|
-
this.
|
|
17248
|
+
this._consumeElementStartTag(this._advance());
|
|
16955
17249
|
}
|
|
16956
17250
|
else if (this._peek.type === 3 /* TokenType.TAG_CLOSE */) {
|
|
16957
|
-
this.
|
|
17251
|
+
this._consumeElementEndTag(this._advance());
|
|
16958
17252
|
}
|
|
16959
17253
|
else if (this._peek.type === 12 /* TokenType.CDATA_START */) {
|
|
16960
17254
|
this._closeVoidElement();
|
|
@@ -16993,6 +17287,13 @@ class _TreeBuilder {
|
|
|
16993
17287
|
this._closeVoidElement();
|
|
16994
17288
|
this._consumeIncompleteLet(this._advance());
|
|
16995
17289
|
}
|
|
17290
|
+
else if (this._peek.type === 33 /* TokenType.COMPONENT_OPEN_START */ ||
|
|
17291
|
+
this._peek.type === 37 /* TokenType.INCOMPLETE_COMPONENT_OPEN */) {
|
|
17292
|
+
this._consumeComponentStartTag(this._advance());
|
|
17293
|
+
}
|
|
17294
|
+
else if (this._peek.type === 36 /* TokenType.COMPONENT_CLOSE */) {
|
|
17295
|
+
this._consumeComponentEndTag(this._advance());
|
|
17296
|
+
}
|
|
16996
17297
|
else {
|
|
16997
17298
|
// Skip all other tokens...
|
|
16998
17299
|
this._advance();
|
|
@@ -17066,9 +17367,9 @@ class _TreeBuilder {
|
|
|
17066
17367
|
if (!exp)
|
|
17067
17368
|
return null;
|
|
17068
17369
|
const end = this._advance();
|
|
17069
|
-
exp.push({ type:
|
|
17370
|
+
exp.push({ type: 41 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
|
|
17070
17371
|
// parse everything in between { and }
|
|
17071
|
-
const expansionCaseParser = new _TreeBuilder(exp, this.
|
|
17372
|
+
const expansionCaseParser = new _TreeBuilder(exp, this.tagDefinitionResolver);
|
|
17072
17373
|
expansionCaseParser.build();
|
|
17073
17374
|
if (expansionCaseParser.errors.length > 0) {
|
|
17074
17375
|
this.errors = this.errors.concat(expansionCaseParser.errors);
|
|
@@ -17106,7 +17407,7 @@ class _TreeBuilder {
|
|
|
17106
17407
|
return null;
|
|
17107
17408
|
}
|
|
17108
17409
|
}
|
|
17109
|
-
if (this._peek.type ===
|
|
17410
|
+
if (this._peek.type === 41 /* TokenType.EOF */) {
|
|
17110
17411
|
this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
|
|
17111
17412
|
return null;
|
|
17112
17413
|
}
|
|
@@ -17121,7 +17422,7 @@ class _TreeBuilder {
|
|
|
17121
17422
|
const parent = this._getContainer();
|
|
17122
17423
|
if (parent != null &&
|
|
17123
17424
|
parent.children.length === 0 &&
|
|
17124
|
-
this.
|
|
17425
|
+
this._getTagDefinition(parent)?.ignoreFirstLf) {
|
|
17125
17426
|
text = text.substring(1);
|
|
17126
17427
|
tokens[0] = { type: token.type, sourceSpan: token.sourceSpan, parts: [text] };
|
|
17127
17428
|
}
|
|
@@ -17152,25 +17453,23 @@ class _TreeBuilder {
|
|
|
17152
17453
|
}
|
|
17153
17454
|
_closeVoidElement() {
|
|
17154
17455
|
const el = this._getContainer();
|
|
17155
|
-
if (el
|
|
17456
|
+
if (el !== null && this._getTagDefinition(el)?.isVoid) {
|
|
17156
17457
|
this._containerStack.pop();
|
|
17157
17458
|
}
|
|
17158
17459
|
}
|
|
17159
|
-
|
|
17160
|
-
const [prefix, name] = startTagToken.parts;
|
|
17460
|
+
_consumeElementStartTag(startTagToken) {
|
|
17161
17461
|
const attrs = [];
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
const fullName = this._getElementFullName(prefix, name, this._getClosestParentElement());
|
|
17462
|
+
const directives = [];
|
|
17463
|
+
this._consumeAttributesAndDirectives(attrs, directives);
|
|
17464
|
+
const fullName = this._getElementFullName(startTagToken, this._getClosestElementLikeParent());
|
|
17166
17465
|
let selfClosing = false;
|
|
17167
17466
|
// Note: There could have been a tokenizer error
|
|
17168
17467
|
// so that we don't get a token for the end tag...
|
|
17169
17468
|
if (this._peek.type === 2 /* TokenType.TAG_OPEN_END_VOID */) {
|
|
17170
17469
|
this._advance();
|
|
17171
17470
|
selfClosing = true;
|
|
17172
|
-
const tagDef = this.
|
|
17173
|
-
if (!(tagDef
|
|
17471
|
+
const tagDef = this._getTagDefinition(fullName);
|
|
17472
|
+
if (!(tagDef?.canSelfClose || getNsPrefix(fullName) !== null || tagDef?.isVoid)) {
|
|
17174
17473
|
this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void, custom and foreign elements can be self closed "${startTagToken.parts[1]}"`));
|
|
17175
17474
|
}
|
|
17176
17475
|
}
|
|
@@ -17182,10 +17481,10 @@ class _TreeBuilder {
|
|
|
17182
17481
|
const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
|
|
17183
17482
|
// Create a separate `startSpan` because `span` will be modified when there is an `end` span.
|
|
17184
17483
|
const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
|
|
17185
|
-
const el = new Element(fullName, attrs, [], span, startSpan, undefined);
|
|
17186
|
-
const
|
|
17187
|
-
|
|
17188
|
-
|
|
17484
|
+
const el = new Element(fullName, attrs, directives, [], span, startSpan, undefined);
|
|
17485
|
+
const parent = this._getContainer();
|
|
17486
|
+
const isClosedByChild = parent !== null && !!this._getTagDefinition(parent)?.isClosedByChild(el.name);
|
|
17487
|
+
this._pushContainer(el, isClosedByChild);
|
|
17189
17488
|
if (selfClosing) {
|
|
17190
17489
|
// Elements that are self-closed have their `endSourceSpan` set to the full span, as the
|
|
17191
17490
|
// element start tag also represents the end tag.
|
|
@@ -17198,6 +17497,73 @@ class _TreeBuilder {
|
|
|
17198
17497
|
this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
|
|
17199
17498
|
}
|
|
17200
17499
|
}
|
|
17500
|
+
_consumeComponentStartTag(startToken) {
|
|
17501
|
+
const componentName = startToken.parts[0];
|
|
17502
|
+
const attrs = [];
|
|
17503
|
+
const directives = [];
|
|
17504
|
+
this._consumeAttributesAndDirectives(attrs, directives);
|
|
17505
|
+
const closestElement = this._getClosestElementLikeParent();
|
|
17506
|
+
const tagName = this._getComponentTagName(startToken, closestElement);
|
|
17507
|
+
const fullName = this._getComponentFullName(startToken, closestElement);
|
|
17508
|
+
const selfClosing = this._peek.type === 35 /* TokenType.COMPONENT_OPEN_END_VOID */;
|
|
17509
|
+
this._advance();
|
|
17510
|
+
const end = this._peek.sourceSpan.fullStart;
|
|
17511
|
+
const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
|
|
17512
|
+
const startSpan = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
|
|
17513
|
+
const node = new Component(componentName, tagName, fullName, attrs, directives, [], span, startSpan, undefined);
|
|
17514
|
+
const parent = this._getContainer();
|
|
17515
|
+
const isClosedByChild = parent !== null &&
|
|
17516
|
+
node.tagName !== null &&
|
|
17517
|
+
!!this._getTagDefinition(parent)?.isClosedByChild(node.tagName);
|
|
17518
|
+
this._pushContainer(node, isClosedByChild);
|
|
17519
|
+
if (selfClosing) {
|
|
17520
|
+
this._popContainer(fullName, Component, span);
|
|
17521
|
+
}
|
|
17522
|
+
else if (startToken.type === 37 /* TokenType.INCOMPLETE_COMPONENT_OPEN */) {
|
|
17523
|
+
this._popContainer(fullName, Component, null);
|
|
17524
|
+
this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
|
|
17525
|
+
}
|
|
17526
|
+
}
|
|
17527
|
+
_consumeAttributesAndDirectives(attributesResult, directivesResult) {
|
|
17528
|
+
while (this._peek.type === 14 /* TokenType.ATTR_NAME */ ||
|
|
17529
|
+
this._peek.type === 38 /* TokenType.DIRECTIVE_NAME */) {
|
|
17530
|
+
if (this._peek.type === 38 /* TokenType.DIRECTIVE_NAME */) {
|
|
17531
|
+
directivesResult.push(this._consumeDirective(this._peek));
|
|
17532
|
+
}
|
|
17533
|
+
else {
|
|
17534
|
+
attributesResult.push(this._consumeAttr(this._advance()));
|
|
17535
|
+
}
|
|
17536
|
+
}
|
|
17537
|
+
}
|
|
17538
|
+
_consumeComponentEndTag(endToken) {
|
|
17539
|
+
const fullName = this._getComponentFullName(endToken, this._getClosestElementLikeParent());
|
|
17540
|
+
if (!this._popContainer(fullName, Component, endToken.sourceSpan)) {
|
|
17541
|
+
const container = this._containerStack[this._containerStack.length - 1];
|
|
17542
|
+
let suffix;
|
|
17543
|
+
if (container instanceof Component && container.componentName === endToken.parts[0]) {
|
|
17544
|
+
suffix = `, did you mean "${container.fullName}"?`;
|
|
17545
|
+
}
|
|
17546
|
+
else {
|
|
17547
|
+
suffix = '. It may happen when the tag has already been closed by another tag.';
|
|
17548
|
+
}
|
|
17549
|
+
const errMsg = `Unexpected closing tag "${fullName}"${suffix}`;
|
|
17550
|
+
this.errors.push(TreeError.create(fullName, endToken.sourceSpan, errMsg));
|
|
17551
|
+
}
|
|
17552
|
+
}
|
|
17553
|
+
_getTagDefinition(nodeOrName) {
|
|
17554
|
+
if (typeof nodeOrName === 'string') {
|
|
17555
|
+
return this.tagDefinitionResolver(nodeOrName);
|
|
17556
|
+
}
|
|
17557
|
+
else if (nodeOrName instanceof Element) {
|
|
17558
|
+
return this.tagDefinitionResolver(nodeOrName.name);
|
|
17559
|
+
}
|
|
17560
|
+
else if (nodeOrName instanceof Component && nodeOrName.tagName !== null) {
|
|
17561
|
+
return this.tagDefinitionResolver(nodeOrName.tagName);
|
|
17562
|
+
}
|
|
17563
|
+
else {
|
|
17564
|
+
return null;
|
|
17565
|
+
}
|
|
17566
|
+
}
|
|
17201
17567
|
_pushContainer(node, isClosedByChild) {
|
|
17202
17568
|
if (isClosedByChild) {
|
|
17203
17569
|
this._containerStack.pop();
|
|
@@ -17205,9 +17571,9 @@ class _TreeBuilder {
|
|
|
17205
17571
|
this._addToParent(node);
|
|
17206
17572
|
this._containerStack.push(node);
|
|
17207
17573
|
}
|
|
17208
|
-
|
|
17209
|
-
const fullName = this._getElementFullName(endTagToken
|
|
17210
|
-
if (this.
|
|
17574
|
+
_consumeElementEndTag(endTagToken) {
|
|
17575
|
+
const fullName = this._getElementFullName(endTagToken, this._getClosestElementLikeParent());
|
|
17576
|
+
if (this._getTagDefinition(fullName)?.isVoid) {
|
|
17211
17577
|
this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
|
|
17212
17578
|
}
|
|
17213
17579
|
else if (!this._popContainer(fullName, Element, endTagToken.sourceSpan)) {
|
|
@@ -17225,7 +17591,8 @@ class _TreeBuilder {
|
|
|
17225
17591
|
let unexpectedCloseTagDetected = false;
|
|
17226
17592
|
for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) {
|
|
17227
17593
|
const node = this._containerStack[stackIndex];
|
|
17228
|
-
|
|
17594
|
+
const nodeName = node instanceof Component ? node.fullName : node.name;
|
|
17595
|
+
if ((nodeName === expectedName || expectedName === null) && node instanceof expectedType) {
|
|
17229
17596
|
// Record the parse span with the element that is being closed. Any elements that are
|
|
17230
17597
|
// removed from the element stack at this point are closed implicitly, so they won't get
|
|
17231
17598
|
// an end source span (as there is no explicit closing element).
|
|
@@ -17235,8 +17602,7 @@ class _TreeBuilder {
|
|
|
17235
17602
|
return !unexpectedCloseTagDetected;
|
|
17236
17603
|
}
|
|
17237
17604
|
// Blocks and most elements are not self closing.
|
|
17238
|
-
if (node instanceof Block ||
|
|
17239
|
-
(node instanceof Element && !this.getTagDefinition(node.name).closedByParent)) {
|
|
17605
|
+
if (node instanceof Block || !this._getTagDefinition(node)?.closedByParent) {
|
|
17240
17606
|
// Note that we encountered an unexpected close tag but continue processing the element
|
|
17241
17607
|
// stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this
|
|
17242
17608
|
// end tag in the stack.
|
|
@@ -17296,6 +17662,31 @@ class _TreeBuilder {
|
|
|
17296
17662
|
new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
|
|
17297
17663
|
return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
|
|
17298
17664
|
}
|
|
17665
|
+
_consumeDirective(nameToken) {
|
|
17666
|
+
const attributes = [];
|
|
17667
|
+
let startSourceSpanEnd = nameToken.sourceSpan.end;
|
|
17668
|
+
let endSourceSpan = null;
|
|
17669
|
+
this._advance();
|
|
17670
|
+
if (this._peek.type === 39 /* TokenType.DIRECTIVE_OPEN */) {
|
|
17671
|
+
// Capture the opening token in the start span.
|
|
17672
|
+
startSourceSpanEnd = this._peek.sourceSpan.end;
|
|
17673
|
+
this._advance();
|
|
17674
|
+
// Cast here is necessary, because TS doesn't know that `_advance` changed `_peek`.
|
|
17675
|
+
while (this._peek.type === 14 /* TokenType.ATTR_NAME */) {
|
|
17676
|
+
attributes.push(this._consumeAttr(this._advance()));
|
|
17677
|
+
}
|
|
17678
|
+
if (this._peek.type === 40 /* TokenType.DIRECTIVE_CLOSE */) {
|
|
17679
|
+
endSourceSpan = this._peek.sourceSpan;
|
|
17680
|
+
this._advance();
|
|
17681
|
+
}
|
|
17682
|
+
else {
|
|
17683
|
+
this.errors.push(TreeError.create(null, nameToken.sourceSpan, 'Unterminated directive definition'));
|
|
17684
|
+
}
|
|
17685
|
+
}
|
|
17686
|
+
const startSourceSpan = new ParseSourceSpan(nameToken.sourceSpan.start, startSourceSpanEnd, nameToken.sourceSpan.fullStart);
|
|
17687
|
+
const sourceSpan = new ParseSourceSpan(startSourceSpan.start, endSourceSpan === null ? nameToken.sourceSpan.end : endSourceSpan.end, startSourceSpan.fullStart);
|
|
17688
|
+
return new Directive(nameToken.parts[0], attributes, sourceSpan, startSourceSpan, endSourceSpan);
|
|
17689
|
+
}
|
|
17299
17690
|
_consumeBlockOpen(token) {
|
|
17300
17691
|
const parameters = [];
|
|
17301
17692
|
while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
|
|
@@ -17386,10 +17777,11 @@ class _TreeBuilder {
|
|
|
17386
17777
|
? this._containerStack[this._containerStack.length - 1]
|
|
17387
17778
|
: null;
|
|
17388
17779
|
}
|
|
17389
|
-
|
|
17780
|
+
_getClosestElementLikeParent() {
|
|
17390
17781
|
for (let i = this._containerStack.length - 1; i > -1; i--) {
|
|
17391
|
-
|
|
17392
|
-
|
|
17782
|
+
const current = this._containerStack[i];
|
|
17783
|
+
if (current instanceof Element || current instanceof Component) {
|
|
17784
|
+
return current;
|
|
17393
17785
|
}
|
|
17394
17786
|
}
|
|
17395
17787
|
return null;
|
|
@@ -17403,18 +17795,57 @@ class _TreeBuilder {
|
|
|
17403
17795
|
parent.children.push(node);
|
|
17404
17796
|
}
|
|
17405
17797
|
}
|
|
17406
|
-
_getElementFullName(
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17798
|
+
_getElementFullName(token, parent) {
|
|
17799
|
+
const prefix = this._getPrefix(token, parent);
|
|
17800
|
+
return mergeNsAndName(prefix, token.parts[1]);
|
|
17801
|
+
}
|
|
17802
|
+
_getComponentFullName(token, parent) {
|
|
17803
|
+
const componentName = token.parts[0];
|
|
17804
|
+
const tagName = this._getComponentTagName(token, parent);
|
|
17805
|
+
if (tagName === null) {
|
|
17806
|
+
return componentName;
|
|
17807
|
+
}
|
|
17808
|
+
return tagName.startsWith(':') ? componentName + tagName : `${componentName}:${tagName}`;
|
|
17809
|
+
}
|
|
17810
|
+
_getComponentTagName(token, parent) {
|
|
17811
|
+
const prefix = this._getPrefix(token, parent);
|
|
17812
|
+
const tagName = token.parts[2];
|
|
17813
|
+
if (!prefix && !tagName) {
|
|
17814
|
+
return null;
|
|
17815
|
+
}
|
|
17816
|
+
else if (!prefix && tagName) {
|
|
17817
|
+
return tagName;
|
|
17818
|
+
}
|
|
17819
|
+
else {
|
|
17820
|
+
// TODO(crisbeto): re-evaluate this fallback. Maybe base it off the class name?
|
|
17821
|
+
return mergeNsAndName(prefix, tagName || 'ng-component');
|
|
17822
|
+
}
|
|
17823
|
+
}
|
|
17824
|
+
_getPrefix(token, parent) {
|
|
17825
|
+
let prefix;
|
|
17826
|
+
let tagName;
|
|
17827
|
+
if (token.type === 33 /* TokenType.COMPONENT_OPEN_START */ ||
|
|
17828
|
+
token.type === 37 /* TokenType.INCOMPLETE_COMPONENT_OPEN */ ||
|
|
17829
|
+
token.type === 36 /* TokenType.COMPONENT_CLOSE */) {
|
|
17830
|
+
prefix = token.parts[1];
|
|
17831
|
+
tagName = token.parts[2];
|
|
17832
|
+
}
|
|
17833
|
+
else {
|
|
17834
|
+
prefix = token.parts[0];
|
|
17835
|
+
tagName = token.parts[1];
|
|
17836
|
+
}
|
|
17837
|
+
prefix = prefix || this._getTagDefinition(tagName)?.implicitNamespacePrefix || '';
|
|
17838
|
+
if (!prefix && parent) {
|
|
17839
|
+
const parentName = parent instanceof Element ? parent.name : parent.tagName;
|
|
17840
|
+
if (parentName !== null) {
|
|
17841
|
+
const parentTagName = splitNsName(parentName)[1];
|
|
17842
|
+
const parentTagDefinition = this._getTagDefinition(parentTagName);
|
|
17843
|
+
if (parentTagDefinition !== null && !parentTagDefinition.preventNamespaceInheritance) {
|
|
17844
|
+
prefix = getNsPrefix(parentName);
|
|
17414
17845
|
}
|
|
17415
17846
|
}
|
|
17416
17847
|
}
|
|
17417
|
-
return
|
|
17848
|
+
return prefix;
|
|
17418
17849
|
}
|
|
17419
17850
|
}
|
|
17420
17851
|
function lastOnStack(stack, element) {
|
|
@@ -17493,11 +17924,11 @@ class WhitespaceVisitor {
|
|
|
17493
17924
|
if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
|
|
17494
17925
|
// don't descent into elements where we need to preserve whitespaces
|
|
17495
17926
|
// but still visit all attributes to eliminate one used as a market to preserve WS
|
|
17496
|
-
const newElement = new Element(element.name, visitAllWithSiblings(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
17927
|
+
const newElement = new Element(element.name, visitAllWithSiblings(this, element.attrs), visitAllWithSiblings(this, element.directives), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
17497
17928
|
this.originalNodeMap?.set(newElement, element);
|
|
17498
17929
|
return newElement;
|
|
17499
17930
|
}
|
|
17500
|
-
const newElement = new Element(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
17931
|
+
const newElement = new Element(element.name, element.attrs, element.directives, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
17501
17932
|
this.originalNodeMap?.set(newElement, element);
|
|
17502
17933
|
return newElement;
|
|
17503
17934
|
}
|
|
@@ -17571,6 +18002,22 @@ class WhitespaceVisitor {
|
|
|
17571
18002
|
visitLetDeclaration(decl, context) {
|
|
17572
18003
|
return decl;
|
|
17573
18004
|
}
|
|
18005
|
+
visitComponent(node, context) {
|
|
18006
|
+
if ((node.tagName && SKIP_WS_TRIM_TAGS.has(node.tagName)) ||
|
|
18007
|
+
hasPreserveWhitespacesAttr(node.attrs)) {
|
|
18008
|
+
// don't descent into elements where we need to preserve whitespaces
|
|
18009
|
+
// but still visit all attributes to eliminate one used as a market to preserve WS
|
|
18010
|
+
const newElement = new Component(node.componentName, node.tagName, node.fullName, visitAllWithSiblings(this, node.attrs), visitAllWithSiblings(this, node.directives), node.children, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.i18n);
|
|
18011
|
+
this.originalNodeMap?.set(newElement, node);
|
|
18012
|
+
return newElement;
|
|
18013
|
+
}
|
|
18014
|
+
const newElement = new Component(node.componentName, node.tagName, node.fullName, node.attrs, node.directives, visitAllWithSiblings(this, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.i18n);
|
|
18015
|
+
this.originalNodeMap?.set(newElement, node);
|
|
18016
|
+
return newElement;
|
|
18017
|
+
}
|
|
18018
|
+
visitDirective(directive, context) {
|
|
18019
|
+
return directive;
|
|
18020
|
+
}
|
|
17574
18021
|
visit(_node, context) {
|
|
17575
18022
|
// `visitAllWithSiblings` provides context necessary for ICU messages to be handled correctly.
|
|
17576
18023
|
// Prefer that over calling `html.visitAll` directly on this visitor.
|
|
@@ -20471,28 +20918,13 @@ class _I18nVisitor {
|
|
|
20471
20918
|
return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
|
|
20472
20919
|
}
|
|
20473
20920
|
visitElement(el, context) {
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
|
|
20482
|
-
context.placeholderToContent[startPhName] = {
|
|
20483
|
-
text: el.startSourceSpan.toString(),
|
|
20484
|
-
sourceSpan: el.startSourceSpan,
|
|
20485
|
-
};
|
|
20486
|
-
let closePhName = '';
|
|
20487
|
-
if (!isVoid) {
|
|
20488
|
-
closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name);
|
|
20489
|
-
context.placeholderToContent[closePhName] = {
|
|
20490
|
-
text: `</${el.name}>`,
|
|
20491
|
-
sourceSpan: el.endSourceSpan ?? el.sourceSpan,
|
|
20492
|
-
};
|
|
20493
|
-
}
|
|
20494
|
-
const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
|
|
20495
|
-
return context.visitNodeFn(el, node);
|
|
20921
|
+
return this._visitElementLike(el, context);
|
|
20922
|
+
}
|
|
20923
|
+
visitComponent(component, context) {
|
|
20924
|
+
return this._visitElementLike(component, context);
|
|
20925
|
+
}
|
|
20926
|
+
visitDirective(directive, context) {
|
|
20927
|
+
throw new Error('Unreachable code');
|
|
20496
20928
|
}
|
|
20497
20929
|
visitAttribute(attribute, context) {
|
|
20498
20930
|
const node = attribute.valueTokens === undefined || attribute.valueTokens.length === 1
|
|
@@ -20566,7 +20998,42 @@ class _I18nVisitor {
|
|
|
20566
20998
|
visitLetDeclaration(decl, context) {
|
|
20567
20999
|
return null;
|
|
20568
21000
|
}
|
|
20569
|
-
|
|
21001
|
+
_visitElementLike(node, context) {
|
|
21002
|
+
const children = visitAll(this, node.children, context);
|
|
21003
|
+
const attrs = {};
|
|
21004
|
+
const visitAttribute = (attr) => {
|
|
21005
|
+
// Do not visit the attributes, translatable ones are top-level ASTs
|
|
21006
|
+
attrs[attr.name] = attr.value;
|
|
21007
|
+
};
|
|
21008
|
+
let nodeName;
|
|
21009
|
+
let isVoid;
|
|
21010
|
+
if (node instanceof Element) {
|
|
21011
|
+
nodeName = node.name;
|
|
21012
|
+
isVoid = getHtmlTagDefinition(node.name).isVoid;
|
|
21013
|
+
}
|
|
21014
|
+
else {
|
|
21015
|
+
nodeName = node.fullName;
|
|
21016
|
+
isVoid = node.tagName ? getHtmlTagDefinition(node.tagName).isVoid : false;
|
|
21017
|
+
}
|
|
21018
|
+
node.attrs.forEach(visitAttribute);
|
|
21019
|
+
node.directives.forEach((dir) => dir.attrs.forEach(visitAttribute));
|
|
21020
|
+
const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(nodeName, attrs, isVoid);
|
|
21021
|
+
context.placeholderToContent[startPhName] = {
|
|
21022
|
+
text: node.startSourceSpan.toString(),
|
|
21023
|
+
sourceSpan: node.startSourceSpan,
|
|
21024
|
+
};
|
|
21025
|
+
let closePhName = '';
|
|
21026
|
+
if (!isVoid) {
|
|
21027
|
+
closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(nodeName);
|
|
21028
|
+
context.placeholderToContent[closePhName] = {
|
|
21029
|
+
text: `</${nodeName}>`,
|
|
21030
|
+
sourceSpan: node.endSourceSpan ?? node.sourceSpan,
|
|
21031
|
+
};
|
|
21032
|
+
}
|
|
21033
|
+
const i18nNode = new TagPlaceholder(nodeName, attrs, startPhName, closePhName, children, isVoid, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
|
|
21034
|
+
return context.visitNodeFn(node, i18nNode);
|
|
21035
|
+
}
|
|
21036
|
+
/**
|
|
20570
21037
|
* Convert, text and interpolated tokens up into text and placeholder pieces.
|
|
20571
21038
|
*
|
|
20572
21039
|
* @param tokens The text and interpolated tokens.
|
|
@@ -20828,15 +21295,74 @@ class I18nMetaVisitor {
|
|
|
20828
21295
|
return new ParseTreeResult(result, this._errors);
|
|
20829
21296
|
}
|
|
20830
21297
|
visitElement(element) {
|
|
21298
|
+
this._visitElementLike(element);
|
|
21299
|
+
return element;
|
|
21300
|
+
}
|
|
21301
|
+
visitComponent(component, context) {
|
|
21302
|
+
this._visitElementLike(component);
|
|
21303
|
+
return component;
|
|
21304
|
+
}
|
|
21305
|
+
visitExpansion(expansion, currentMessage) {
|
|
21306
|
+
let message;
|
|
21307
|
+
const meta = expansion.i18n;
|
|
21308
|
+
this.hasI18nMeta = true;
|
|
21309
|
+
if (meta instanceof IcuPlaceholder) {
|
|
21310
|
+
// set ICU placeholder name (e.g. "ICU_1"),
|
|
21311
|
+
// generated while processing root element contents,
|
|
21312
|
+
// so we can reference it when we output translation
|
|
21313
|
+
const name = meta.name;
|
|
21314
|
+
message = this._generateI18nMessage([expansion], meta);
|
|
21315
|
+
const icu = icuFromI18nMessage(message);
|
|
21316
|
+
icu.name = name;
|
|
21317
|
+
if (currentMessage !== null) {
|
|
21318
|
+
// Also update the placeholderToMessage map with this new message
|
|
21319
|
+
currentMessage.placeholderToMessage[name] = message;
|
|
21320
|
+
}
|
|
21321
|
+
}
|
|
21322
|
+
else {
|
|
21323
|
+
// ICU is a top level message, try to use metadata from container element if provided via
|
|
21324
|
+
// `context` argument. Note: context may not be available for standalone ICUs (without
|
|
21325
|
+
// wrapping element), so fallback to ICU metadata in this case.
|
|
21326
|
+
message = this._generateI18nMessage([expansion], currentMessage || meta);
|
|
21327
|
+
}
|
|
21328
|
+
expansion.i18n = message;
|
|
21329
|
+
return expansion;
|
|
21330
|
+
}
|
|
21331
|
+
visitText(text) {
|
|
21332
|
+
return text;
|
|
21333
|
+
}
|
|
21334
|
+
visitAttribute(attribute) {
|
|
21335
|
+
return attribute;
|
|
21336
|
+
}
|
|
21337
|
+
visitComment(comment) {
|
|
21338
|
+
return comment;
|
|
21339
|
+
}
|
|
21340
|
+
visitExpansionCase(expansionCase) {
|
|
21341
|
+
return expansionCase;
|
|
21342
|
+
}
|
|
21343
|
+
visitBlock(block, context) {
|
|
21344
|
+
visitAll(this, block.children, context);
|
|
21345
|
+
return block;
|
|
21346
|
+
}
|
|
21347
|
+
visitBlockParameter(parameter, context) {
|
|
21348
|
+
return parameter;
|
|
21349
|
+
}
|
|
21350
|
+
visitLetDeclaration(decl, context) {
|
|
21351
|
+
return decl;
|
|
21352
|
+
}
|
|
21353
|
+
visitDirective(directive, context) {
|
|
21354
|
+
return directive;
|
|
21355
|
+
}
|
|
21356
|
+
_visitElementLike(node) {
|
|
20831
21357
|
let message = undefined;
|
|
20832
|
-
if (hasI18nAttrs(
|
|
21358
|
+
if (hasI18nAttrs(node)) {
|
|
20833
21359
|
this.hasI18nMeta = true;
|
|
20834
21360
|
const attrs = [];
|
|
20835
21361
|
const attrsMeta = {};
|
|
20836
|
-
for (const attr of
|
|
21362
|
+
for (const attr of node.attrs) {
|
|
20837
21363
|
if (attr.name === I18N_ATTR) {
|
|
20838
21364
|
// root 'i18n' node attribute
|
|
20839
|
-
const i18n =
|
|
21365
|
+
const i18n = node.i18n || attr.value;
|
|
20840
21366
|
// Generate a new AST with whitespace trimmed, but also generate a map
|
|
20841
21367
|
// to correlate each new node to its original so we can apply i18n
|
|
20842
21368
|
// information to the original node based on the trimmed content.
|
|
@@ -20850,20 +21376,27 @@ class I18nMetaVisitor {
|
|
|
20850
21376
|
// backwards compatibility.
|
|
20851
21377
|
const originalNodeMap = new Map();
|
|
20852
21378
|
const trimmedNodes = this.preserveSignificantWhitespace
|
|
20853
|
-
?
|
|
20854
|
-
: visitAllWithSiblings(new WhitespaceVisitor(false /* preserveSignificantWhitespace */, originalNodeMap),
|
|
21379
|
+
? node.children
|
|
21380
|
+
: visitAllWithSiblings(new WhitespaceVisitor(false /* preserveSignificantWhitespace */, originalNodeMap), node.children);
|
|
20855
21381
|
message = this._generateI18nMessage(trimmedNodes, i18n, setI18nRefs(originalNodeMap));
|
|
20856
21382
|
if (message.nodes.length === 0) {
|
|
20857
21383
|
// Ignore the message if it is empty.
|
|
20858
21384
|
message = undefined;
|
|
20859
21385
|
}
|
|
20860
21386
|
// Store the message on the element
|
|
20861
|
-
|
|
21387
|
+
node.i18n = message;
|
|
20862
21388
|
}
|
|
20863
21389
|
else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
|
|
20864
21390
|
// 'i18n-*' attributes
|
|
20865
21391
|
const name = attr.name.slice(I18N_ATTR_PREFIX.length);
|
|
20866
|
-
|
|
21392
|
+
let isTrustedType;
|
|
21393
|
+
if (node instanceof Component) {
|
|
21394
|
+
isTrustedType = node.tagName === null ? false : isTrustedTypesSink(node.tagName, name);
|
|
21395
|
+
}
|
|
21396
|
+
else {
|
|
21397
|
+
isTrustedType = isTrustedTypesSink(node.name, name);
|
|
21398
|
+
}
|
|
21399
|
+
if (isTrustedType) {
|
|
20867
21400
|
this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
|
|
20868
21401
|
}
|
|
20869
21402
|
else {
|
|
@@ -20888,59 +21421,10 @@ class I18nMetaVisitor {
|
|
|
20888
21421
|
if (!this.keepI18nAttrs) {
|
|
20889
21422
|
// update element's attributes,
|
|
20890
21423
|
// keeping only non-i18n related ones
|
|
20891
|
-
|
|
20892
|
-
}
|
|
20893
|
-
}
|
|
20894
|
-
visitAll(this, element.children, message);
|
|
20895
|
-
return element;
|
|
20896
|
-
}
|
|
20897
|
-
visitExpansion(expansion, currentMessage) {
|
|
20898
|
-
let message;
|
|
20899
|
-
const meta = expansion.i18n;
|
|
20900
|
-
this.hasI18nMeta = true;
|
|
20901
|
-
if (meta instanceof IcuPlaceholder) {
|
|
20902
|
-
// set ICU placeholder name (e.g. "ICU_1"),
|
|
20903
|
-
// generated while processing root element contents,
|
|
20904
|
-
// so we can reference it when we output translation
|
|
20905
|
-
const name = meta.name;
|
|
20906
|
-
message = this._generateI18nMessage([expansion], meta);
|
|
20907
|
-
const icu = icuFromI18nMessage(message);
|
|
20908
|
-
icu.name = name;
|
|
20909
|
-
if (currentMessage !== null) {
|
|
20910
|
-
// Also update the placeholderToMessage map with this new message
|
|
20911
|
-
currentMessage.placeholderToMessage[name] = message;
|
|
21424
|
+
node.attrs = attrs;
|
|
20912
21425
|
}
|
|
20913
21426
|
}
|
|
20914
|
-
|
|
20915
|
-
// ICU is a top level message, try to use metadata from container element if provided via
|
|
20916
|
-
// `context` argument. Note: context may not be available for standalone ICUs (without
|
|
20917
|
-
// wrapping element), so fallback to ICU metadata in this case.
|
|
20918
|
-
message = this._generateI18nMessage([expansion], currentMessage || meta);
|
|
20919
|
-
}
|
|
20920
|
-
expansion.i18n = message;
|
|
20921
|
-
return expansion;
|
|
20922
|
-
}
|
|
20923
|
-
visitText(text) {
|
|
20924
|
-
return text;
|
|
20925
|
-
}
|
|
20926
|
-
visitAttribute(attribute) {
|
|
20927
|
-
return attribute;
|
|
20928
|
-
}
|
|
20929
|
-
visitComment(comment) {
|
|
20930
|
-
return comment;
|
|
20931
|
-
}
|
|
20932
|
-
visitExpansionCase(expansionCase) {
|
|
20933
|
-
return expansionCase;
|
|
20934
|
-
}
|
|
20935
|
-
visitBlock(block, context) {
|
|
20936
|
-
visitAll(this, block.children, context);
|
|
20937
|
-
return block;
|
|
20938
|
-
}
|
|
20939
|
-
visitBlockParameter(parameter, context) {
|
|
20940
|
-
return parameter;
|
|
20941
|
-
}
|
|
20942
|
-
visitLetDeclaration(decl, context) {
|
|
20943
|
-
return decl;
|
|
21427
|
+
visitAll(this, node.children, message);
|
|
20944
21428
|
}
|
|
20945
21429
|
/**
|
|
20946
21430
|
* Parse the general form `meta` passed into extract the explicit metadata needed to create a
|
|
@@ -27357,15 +27841,22 @@ function isAnimationLabel(name) {
|
|
|
27357
27841
|
return name[0] == '@';
|
|
27358
27842
|
}
|
|
27359
27843
|
function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
|
|
27360
|
-
|
|
27361
|
-
|
|
27362
|
-
|
|
27363
|
-
|
|
27364
|
-
|
|
27365
|
-
|
|
27366
|
-
|
|
27367
|
-
|
|
27368
|
-
|
|
27844
|
+
let ctxs;
|
|
27845
|
+
const nameToContext = (elName) => registry.securityContext(elName, propName, isAttribute);
|
|
27846
|
+
if (selector === null) {
|
|
27847
|
+
ctxs = registry.allKnownElementNames().map(nameToContext);
|
|
27848
|
+
}
|
|
27849
|
+
else {
|
|
27850
|
+
ctxs = [];
|
|
27851
|
+
CssSelector.parse(selector).forEach((selector) => {
|
|
27852
|
+
const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
|
|
27853
|
+
const notElementNames = new Set(selector.notSelectors
|
|
27854
|
+
.filter((selector) => selector.isElementSelector())
|
|
27855
|
+
.map((selector) => selector.element));
|
|
27856
|
+
const possibleElementNames = elementNames.filter((elName) => !notElementNames.has(elName));
|
|
27857
|
+
ctxs.push(...possibleElementNames.map(nameToContext));
|
|
27858
|
+
});
|
|
27859
|
+
}
|
|
27369
27860
|
return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
|
|
27370
27861
|
}
|
|
27371
27862
|
/**
|
|
@@ -28450,6 +28941,17 @@ const BINDING_DELIMS = {
|
|
|
28450
28941
|
EVENT: { start: '(', end: ')' },
|
|
28451
28942
|
};
|
|
28452
28943
|
const TEMPLATE_ATTR_PREFIX = '*';
|
|
28944
|
+
// TODO(crisbeto): any other tag names that shouldn't be allowed here?
|
|
28945
|
+
const UNSUPPORTED_SELECTORLESS_TAGS = new Set([
|
|
28946
|
+
'link',
|
|
28947
|
+
'style',
|
|
28948
|
+
'script',
|
|
28949
|
+
'ng-template',
|
|
28950
|
+
'ng-container',
|
|
28951
|
+
'ng-content',
|
|
28952
|
+
]);
|
|
28953
|
+
// TODO(crisbeto): any other attributes that should not be allowed here?
|
|
28954
|
+
const UNSUPPORTED_SELECTORLESS_DIRECTIVE_ATTRS = new Set(['ngProjectAs', 'ngNonBindable']);
|
|
28453
28955
|
function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
|
|
28454
28956
|
const transformer = new HtmlAstToIvyAst(bindingParser, options);
|
|
28455
28957
|
const ivyNodes = visitAll(transformer, htmlNodes, htmlNodes);
|
|
@@ -28513,52 +29015,8 @@ class HtmlAstToIvyAst {
|
|
|
28513
29015
|
}
|
|
28514
29016
|
// Whether the element is a `<ng-template>`
|
|
28515
29017
|
const isTemplateElement = isNgTemplate(element.name);
|
|
28516
|
-
const parsedProperties =
|
|
28517
|
-
const
|
|
28518
|
-
const variables = [];
|
|
28519
|
-
const references = [];
|
|
28520
|
-
const attributes = [];
|
|
28521
|
-
const i18nAttrsMeta = {};
|
|
28522
|
-
const templateParsedProperties = [];
|
|
28523
|
-
const templateVariables = [];
|
|
28524
|
-
// Whether the element has any *-attribute
|
|
28525
|
-
let elementHasInlineTemplate = false;
|
|
28526
|
-
for (const attribute of element.attrs) {
|
|
28527
|
-
let hasBinding = false;
|
|
28528
|
-
const normalizedName = normalizeAttributeName(attribute.name);
|
|
28529
|
-
// `*attr` defines template bindings
|
|
28530
|
-
let isTemplateBinding = false;
|
|
28531
|
-
if (attribute.i18n) {
|
|
28532
|
-
i18nAttrsMeta[attribute.name] = attribute.i18n;
|
|
28533
|
-
}
|
|
28534
|
-
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
|
28535
|
-
// *-attributes
|
|
28536
|
-
if (elementHasInlineTemplate) {
|
|
28537
|
-
this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
|
|
28538
|
-
}
|
|
28539
|
-
isTemplateBinding = true;
|
|
28540
|
-
elementHasInlineTemplate = true;
|
|
28541
|
-
const templateValue = attribute.value;
|
|
28542
|
-
const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
|
|
28543
|
-
const parsedVariables = [];
|
|
28544
|
-
const absoluteValueOffset = attribute.valueSpan
|
|
28545
|
-
? attribute.valueSpan.start.offset
|
|
28546
|
-
: // If there is no value span the attribute does not have a value, like `attr` in
|
|
28547
|
-
//`<div attr></div>`. In this case, point to one character beyond the last character of
|
|
28548
|
-
// the attribute name.
|
|
28549
|
-
attribute.sourceSpan.start.offset + attribute.name.length;
|
|
28550
|
-
this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIvyAst */);
|
|
28551
|
-
templateVariables.push(...parsedVariables.map((v) => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
|
|
28552
|
-
}
|
|
28553
|
-
else {
|
|
28554
|
-
// Check for variables, events, property bindings, interpolation
|
|
28555
|
-
hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
|
|
28556
|
-
}
|
|
28557
|
-
if (!hasBinding && !isTemplateBinding) {
|
|
28558
|
-
// don't include the bindings as attributes as well in the AST
|
|
28559
|
-
attributes.push(this.visitAttribute(attribute));
|
|
28560
|
-
}
|
|
28561
|
-
}
|
|
29018
|
+
const { attributes, boundEvents, references, variables, templateVariables, elementHasInlineTemplate, parsedProperties, templateParsedProperties, i18nAttrsMeta, } = this.prepareAttributes(element.attrs, isTemplateElement);
|
|
29019
|
+
const directives = this.extractDirectives(element);
|
|
28562
29020
|
let children;
|
|
28563
29021
|
if (preparsedElement.nonBindable) {
|
|
28564
29022
|
// The `NonBindableVisitor` may need to return an array of nodes for blocks so we need
|
|
@@ -28573,44 +29031,24 @@ class HtmlAstToIvyAst {
|
|
|
28573
29031
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
|
28574
29032
|
const selector = preparsedElement.selectAttr;
|
|
28575
29033
|
const attrs = element.attrs.map((attr) => this.visitAttribute(attr));
|
|
28576
|
-
parsedElement = new Content(selector, attrs, children, element.sourceSpan, element.i18n);
|
|
29034
|
+
parsedElement = new Content(selector, attrs, children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
28577
29035
|
this.ngContentSelectors.push(selector);
|
|
28578
29036
|
}
|
|
28579
29037
|
else if (isTemplateElement) {
|
|
28580
29038
|
// `<ng-template>`
|
|
28581
|
-
const attrs = this.
|
|
28582
|
-
parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [
|
|
29039
|
+
const attrs = this.categorizePropertyAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
|
29040
|
+
parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, directives, [
|
|
28583
29041
|
/* no template attributes */
|
|
28584
29042
|
], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
28585
29043
|
}
|
|
28586
29044
|
else {
|
|
28587
|
-
const attrs = this.
|
|
28588
|
-
parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
29045
|
+
const attrs = this.categorizePropertyAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
|
29046
|
+
parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, directives, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
28589
29047
|
}
|
|
28590
29048
|
if (elementHasInlineTemplate) {
|
|
28591
29049
|
// If this node is an inline-template (e.g. has *ngFor) then we need to create a template
|
|
28592
29050
|
// node that contains this node.
|
|
28593
|
-
|
|
28594
|
-
// node for matching against content projection selectors.
|
|
28595
|
-
const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
|
|
28596
|
-
const templateAttrs = [];
|
|
28597
|
-
attrs.literal.forEach((attr) => templateAttrs.push(attr));
|
|
28598
|
-
attrs.bound.forEach((attr) => templateAttrs.push(attr));
|
|
28599
|
-
const hoistedAttrs = parsedElement instanceof Element$1
|
|
28600
|
-
? {
|
|
28601
|
-
attributes: parsedElement.attributes,
|
|
28602
|
-
inputs: parsedElement.inputs,
|
|
28603
|
-
outputs: parsedElement.outputs,
|
|
28604
|
-
}
|
|
28605
|
-
: { attributes: [], inputs: [], outputs: [] };
|
|
28606
|
-
// For <ng-template>s with structural directives on them, avoid passing i18n information to
|
|
28607
|
-
// the wrapping template to prevent unnecessary i18n instructions from being generated. The
|
|
28608
|
-
// necessary i18n meta information will be extracted from child elements.
|
|
28609
|
-
const i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n;
|
|
28610
|
-
const name = parsedElement instanceof Template ? null : parsedElement.name;
|
|
28611
|
-
parsedElement = new Template(name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [
|
|
28612
|
-
/* no references */
|
|
28613
|
-
], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n);
|
|
29051
|
+
parsedElement = this.wrapInTemplate(parsedElement, templateParsedProperties, templateVariables, i18nAttrsMeta, isTemplateElement, isI18nRootElement);
|
|
28614
29052
|
}
|
|
28615
29053
|
if (isI18nRootElement) {
|
|
28616
29054
|
this.inI18nBlock = false;
|
|
@@ -28674,6 +29112,43 @@ class HtmlAstToIvyAst {
|
|
|
28674
29112
|
}
|
|
28675
29113
|
return new LetDeclaration$1(decl.name, value, decl.sourceSpan, decl.nameSpan, decl.valueSpan);
|
|
28676
29114
|
}
|
|
29115
|
+
visitComponent(component) {
|
|
29116
|
+
const isI18nRootElement = isI18nRootNode(component.i18n);
|
|
29117
|
+
if (isI18nRootElement) {
|
|
29118
|
+
if (this.inI18nBlock) {
|
|
29119
|
+
this.reportError('Cannot mark a component as translatable inside of a translatable section. Please remove the nested i18n marker.', component.sourceSpan);
|
|
29120
|
+
}
|
|
29121
|
+
this.inI18nBlock = true;
|
|
29122
|
+
}
|
|
29123
|
+
if (component.tagName !== null && UNSUPPORTED_SELECTORLESS_TAGS.has(component.tagName)) {
|
|
29124
|
+
this.reportError(`Tag name "${component.tagName}" cannot be used as a component tag`, component.startSourceSpan);
|
|
29125
|
+
return null;
|
|
29126
|
+
}
|
|
29127
|
+
const { attributes, boundEvents, references, templateVariables, elementHasInlineTemplate, parsedProperties, templateParsedProperties, i18nAttrsMeta, } = this.prepareAttributes(component.attrs, false);
|
|
29128
|
+
const directives = this.extractDirectives(component);
|
|
29129
|
+
let children;
|
|
29130
|
+
if (component.attrs.find((attr) => attr.name === 'ngNonBindable')) {
|
|
29131
|
+
// The `NonBindableVisitor` may need to return an array of nodes for blocks so we need
|
|
29132
|
+
// to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
|
|
29133
|
+
// a new array.
|
|
29134
|
+
children = visitAll(NON_BINDABLE_VISITOR, component.children).flat(Infinity);
|
|
29135
|
+
}
|
|
29136
|
+
else {
|
|
29137
|
+
children = visitAll(this, component.children, component.children);
|
|
29138
|
+
}
|
|
29139
|
+
const attrs = this.categorizePropertyAttributes(component.tagName, parsedProperties, i18nAttrsMeta);
|
|
29140
|
+
let node = new Component$1(component.componentName, component.tagName, component.fullName, attributes, attrs.bound, boundEvents, directives, children, references, component.sourceSpan, component.startSourceSpan, component.endSourceSpan, component.i18n);
|
|
29141
|
+
if (elementHasInlineTemplate) {
|
|
29142
|
+
node = this.wrapInTemplate(node, templateParsedProperties, templateVariables, i18nAttrsMeta, false, isI18nRootElement);
|
|
29143
|
+
}
|
|
29144
|
+
if (isI18nRootElement) {
|
|
29145
|
+
this.inI18nBlock = false;
|
|
29146
|
+
}
|
|
29147
|
+
return node;
|
|
29148
|
+
}
|
|
29149
|
+
visitDirective() {
|
|
29150
|
+
return null;
|
|
29151
|
+
}
|
|
28677
29152
|
visitBlockParameter() {
|
|
28678
29153
|
return null;
|
|
28679
29154
|
}
|
|
@@ -28750,8 +29225,8 @@ class HtmlAstToIvyAst {
|
|
|
28750
29225
|
}
|
|
28751
29226
|
return relatedBlocks;
|
|
28752
29227
|
}
|
|
28753
|
-
|
|
28754
|
-
|
|
29228
|
+
/** Splits up the property attributes depending on whether they're static or bound. */
|
|
29229
|
+
categorizePropertyAttributes(elementName, properties, i18nPropsMeta) {
|
|
28755
29230
|
const bound = [];
|
|
28756
29231
|
const literal = [];
|
|
28757
29232
|
properties.forEach((prop) => {
|
|
@@ -28771,6 +29246,65 @@ class HtmlAstToIvyAst {
|
|
|
28771
29246
|
});
|
|
28772
29247
|
return { bound, literal };
|
|
28773
29248
|
}
|
|
29249
|
+
prepareAttributes(attrs, isTemplateElement) {
|
|
29250
|
+
const parsedProperties = [];
|
|
29251
|
+
const boundEvents = [];
|
|
29252
|
+
const variables = [];
|
|
29253
|
+
const references = [];
|
|
29254
|
+
const attributes = [];
|
|
29255
|
+
const i18nAttrsMeta = {};
|
|
29256
|
+
const templateParsedProperties = [];
|
|
29257
|
+
const templateVariables = [];
|
|
29258
|
+
// Whether the element has any *-attribute
|
|
29259
|
+
let elementHasInlineTemplate = false;
|
|
29260
|
+
for (const attribute of attrs) {
|
|
29261
|
+
let hasBinding = false;
|
|
29262
|
+
const normalizedName = normalizeAttributeName(attribute.name);
|
|
29263
|
+
// `*attr` defines template bindings
|
|
29264
|
+
let isTemplateBinding = false;
|
|
29265
|
+
if (attribute.i18n) {
|
|
29266
|
+
i18nAttrsMeta[attribute.name] = attribute.i18n;
|
|
29267
|
+
}
|
|
29268
|
+
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
|
29269
|
+
// *-attributes
|
|
29270
|
+
if (elementHasInlineTemplate) {
|
|
29271
|
+
this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
|
|
29272
|
+
}
|
|
29273
|
+
isTemplateBinding = true;
|
|
29274
|
+
elementHasInlineTemplate = true;
|
|
29275
|
+
const templateValue = attribute.value;
|
|
29276
|
+
const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
|
|
29277
|
+
const parsedVariables = [];
|
|
29278
|
+
const absoluteValueOffset = attribute.valueSpan
|
|
29279
|
+
? attribute.valueSpan.start.offset
|
|
29280
|
+
: // If there is no value span the attribute does not have a value, like `attr` in
|
|
29281
|
+
//`<div attr></div>`. In this case, point to one character beyond the last character of
|
|
29282
|
+
// the attribute name.
|
|
29283
|
+
attribute.sourceSpan.start.offset + attribute.name.length;
|
|
29284
|
+
this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIvyAst */);
|
|
29285
|
+
templateVariables.push(...parsedVariables.map((v) => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
|
|
29286
|
+
}
|
|
29287
|
+
else {
|
|
29288
|
+
// Check for variables, events, property bindings, interpolation
|
|
29289
|
+
hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
|
|
29290
|
+
}
|
|
29291
|
+
if (!hasBinding && !isTemplateBinding) {
|
|
29292
|
+
// don't include the bindings as attributes as well in the AST
|
|
29293
|
+
attributes.push(this.visitAttribute(attribute));
|
|
29294
|
+
}
|
|
29295
|
+
}
|
|
29296
|
+
return {
|
|
29297
|
+
attributes,
|
|
29298
|
+
boundEvents,
|
|
29299
|
+
references,
|
|
29300
|
+
variables,
|
|
29301
|
+
templateVariables,
|
|
29302
|
+
elementHasInlineTemplate,
|
|
29303
|
+
parsedProperties,
|
|
29304
|
+
templateParsedProperties,
|
|
29305
|
+
i18nAttrsMeta,
|
|
29306
|
+
};
|
|
29307
|
+
}
|
|
28774
29308
|
parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
|
|
28775
29309
|
const name = normalizeAttributeName(attribute.name);
|
|
28776
29310
|
const value = attribute.value;
|
|
@@ -28869,6 +29403,81 @@ class HtmlAstToIvyAst {
|
|
|
28869
29403
|
const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan, attribute.valueTokens ?? null);
|
|
28870
29404
|
return hasBinding;
|
|
28871
29405
|
}
|
|
29406
|
+
extractDirectives(node) {
|
|
29407
|
+
const elementName = node instanceof Component ? node.tagName : node.name;
|
|
29408
|
+
const directives = [];
|
|
29409
|
+
const seenDirectives = new Set();
|
|
29410
|
+
for (const directive of node.directives) {
|
|
29411
|
+
let invalid = false;
|
|
29412
|
+
for (const attr of directive.attrs) {
|
|
29413
|
+
if (attr.name.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
|
29414
|
+
invalid = true;
|
|
29415
|
+
this.reportError(`Shorthand template syntax "${attr.name}" is not supported inside a directive context`, attr.sourceSpan);
|
|
29416
|
+
}
|
|
29417
|
+
else if (UNSUPPORTED_SELECTORLESS_DIRECTIVE_ATTRS.has(attr.name)) {
|
|
29418
|
+
invalid = true;
|
|
29419
|
+
this.reportError(`Attribute "${attr.name}" is not supported in a directive context`, attr.sourceSpan);
|
|
29420
|
+
}
|
|
29421
|
+
}
|
|
29422
|
+
if (!invalid && seenDirectives.has(directive.name)) {
|
|
29423
|
+
invalid = true;
|
|
29424
|
+
this.reportError(`Cannot apply directive "${directive.name}" multiple times on the same element`, directive.sourceSpan);
|
|
29425
|
+
}
|
|
29426
|
+
if (invalid) {
|
|
29427
|
+
continue;
|
|
29428
|
+
}
|
|
29429
|
+
const { attributes, parsedProperties, boundEvents, references, i18nAttrsMeta } = this.prepareAttributes(directive.attrs, false);
|
|
29430
|
+
const { bound: inputs } = this.categorizePropertyAttributes(elementName, parsedProperties, i18nAttrsMeta);
|
|
29431
|
+
for (const input of inputs) {
|
|
29432
|
+
if (input.type !== exports.BindingType.Property && input.type !== exports.BindingType.TwoWay) {
|
|
29433
|
+
invalid = true;
|
|
29434
|
+
this.reportError('Binding is not supported in a directive context', input.sourceSpan);
|
|
29435
|
+
}
|
|
29436
|
+
}
|
|
29437
|
+
if (invalid) {
|
|
29438
|
+
continue;
|
|
29439
|
+
}
|
|
29440
|
+
seenDirectives.add(directive.name);
|
|
29441
|
+
directives.push(new Directive$1(directive.name, attributes, inputs, boundEvents, references, directive.sourceSpan, directive.startSourceSpan, directive.endSourceSpan, undefined));
|
|
29442
|
+
}
|
|
29443
|
+
return directives;
|
|
29444
|
+
}
|
|
29445
|
+
wrapInTemplate(node, templateProperties, templateVariables, i18nAttrsMeta, isTemplateElement, isI18nRootElement) {
|
|
29446
|
+
// We need to hoist the attributes of the node to the template for content projection purposes.
|
|
29447
|
+
const attrs = this.categorizePropertyAttributes('ng-template', templateProperties, i18nAttrsMeta);
|
|
29448
|
+
const templateAttrs = [];
|
|
29449
|
+
attrs.literal.forEach((attr) => templateAttrs.push(attr));
|
|
29450
|
+
attrs.bound.forEach((attr) => templateAttrs.push(attr));
|
|
29451
|
+
const hoistedAttrs = {
|
|
29452
|
+
attributes: [],
|
|
29453
|
+
inputs: [],
|
|
29454
|
+
outputs: [],
|
|
29455
|
+
};
|
|
29456
|
+
if (node instanceof Element$1 || node instanceof Component$1) {
|
|
29457
|
+
hoistedAttrs.attributes.push(...node.attributes);
|
|
29458
|
+
hoistedAttrs.inputs.push(...node.inputs);
|
|
29459
|
+
hoistedAttrs.outputs.push(...node.outputs);
|
|
29460
|
+
}
|
|
29461
|
+
// For <ng-template>s with structural directives on them, avoid passing i18n information to
|
|
29462
|
+
// the wrapping template to prevent unnecessary i18n instructions from being generated. The
|
|
29463
|
+
// necessary i18n meta information will be extracted from child elements.
|
|
29464
|
+
const i18n = isTemplateElement && isI18nRootElement ? undefined : node.i18n;
|
|
29465
|
+
let name;
|
|
29466
|
+
if (node instanceof Component$1) {
|
|
29467
|
+
name = node.tagName;
|
|
29468
|
+
}
|
|
29469
|
+
else if (node instanceof Template) {
|
|
29470
|
+
name = null;
|
|
29471
|
+
}
|
|
29472
|
+
else {
|
|
29473
|
+
name = node.name;
|
|
29474
|
+
}
|
|
29475
|
+
return new Template(name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, [
|
|
29476
|
+
// Do not copy over the directives.
|
|
29477
|
+
], templateAttrs, [node], [
|
|
29478
|
+
// Do not copy over the references.
|
|
29479
|
+
], templateVariables, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, i18n);
|
|
29480
|
+
}
|
|
28872
29481
|
_visitTextWithInterpolation(value, sourceSpan, interpolatedTokens, i18n) {
|
|
28873
29482
|
const valueNoNgsp = replaceNgsp(value);
|
|
28874
29483
|
const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan, interpolatedTokens);
|
|
@@ -28919,7 +29528,8 @@ class NonBindableVisitor {
|
|
|
28919
29528
|
const children = visitAll(this, ast.children, null);
|
|
28920
29529
|
return new Element$1(ast.name, visitAll(this, ast.attrs),
|
|
28921
29530
|
/* inputs */ [],
|
|
28922
|
-
/* outputs */ [],
|
|
29531
|
+
/* outputs */ [],
|
|
29532
|
+
/* directives */ [], children,
|
|
28923
29533
|
/* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
28924
29534
|
}
|
|
28925
29535
|
visitComment(comment) {
|
|
@@ -28955,6 +29565,17 @@ class NonBindableVisitor {
|
|
|
28955
29565
|
visitLetDeclaration(decl, context) {
|
|
28956
29566
|
return new Text$3(`@let ${decl.name} = ${decl.value};`, decl.sourceSpan);
|
|
28957
29567
|
}
|
|
29568
|
+
visitComponent(ast, context) {
|
|
29569
|
+
const children = visitAll(this, ast.children, null);
|
|
29570
|
+
return new Element$1(ast.fullName, visitAll(this, ast.attrs),
|
|
29571
|
+
/* inputs */ [],
|
|
29572
|
+
/* outputs */ [],
|
|
29573
|
+
/* directives */ [], children,
|
|
29574
|
+
/* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
29575
|
+
}
|
|
29576
|
+
visitDirective(directive, context) {
|
|
29577
|
+
return null;
|
|
29578
|
+
}
|
|
28958
29579
|
}
|
|
28959
29580
|
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
|
28960
29581
|
function normalizeAttributeName(attrName) {
|
|
@@ -29730,6 +30351,7 @@ class Scope {
|
|
|
29730
30351
|
}
|
|
29731
30352
|
}
|
|
29732
30353
|
visitElement(element) {
|
|
30354
|
+
element.directives.forEach((node) => node.visit(this));
|
|
29733
30355
|
// `Element`s in the template may have `Reference`s which are captured in the scope.
|
|
29734
30356
|
element.references.forEach((node) => this.visitReference(node));
|
|
29735
30357
|
// Recurse into the `Element`'s children.
|
|
@@ -29737,6 +30359,7 @@ class Scope {
|
|
|
29737
30359
|
this.elementsInScope.add(element);
|
|
29738
30360
|
}
|
|
29739
30361
|
visitTemplate(template) {
|
|
30362
|
+
template.directives.forEach((node) => node.visit(this));
|
|
29740
30363
|
// References on a <ng-template> are defined in the outer scope, so capture them before
|
|
29741
30364
|
// processing the template's child scope.
|
|
29742
30365
|
template.references.forEach((node) => this.visitReference(node));
|
|
@@ -29791,6 +30414,12 @@ class Scope {
|
|
|
29791
30414
|
visitLetDeclaration(decl) {
|
|
29792
30415
|
this.maybeDeclare(decl);
|
|
29793
30416
|
}
|
|
30417
|
+
visitComponent(component) {
|
|
30418
|
+
throw new Error('TODO');
|
|
30419
|
+
}
|
|
30420
|
+
visitDirective(directive) {
|
|
30421
|
+
throw new Error('TODO');
|
|
30422
|
+
}
|
|
29794
30423
|
// Unused visitors.
|
|
29795
30424
|
visitBoundAttribute(attr) { }
|
|
29796
30425
|
visitBoundEvent(event) { }
|
|
@@ -29892,6 +30521,10 @@ class DirectiveBinder {
|
|
|
29892
30521
|
// First, determine the HTML shape of the node for the purpose of directive matching.
|
|
29893
30522
|
// Do this by building up a `CssSelector` for the node.
|
|
29894
30523
|
const cssSelector = createCssSelectorFromNode(node);
|
|
30524
|
+
// TODO(crisbeto): account for selectorless directives here.
|
|
30525
|
+
if (node.directives.length > 0) {
|
|
30526
|
+
throw new Error('TODO');
|
|
30527
|
+
}
|
|
29895
30528
|
// Next, use the `SelectorMatcher` to get the list of directives on the node.
|
|
29896
30529
|
const directives = [];
|
|
29897
30530
|
this.matcher.match(cssSelector, (_selector, results) => directives.push(...results));
|
|
@@ -29991,6 +30624,12 @@ class DirectiveBinder {
|
|
|
29991
30624
|
visitContent(content) {
|
|
29992
30625
|
content.children.forEach((child) => child.visit(this));
|
|
29993
30626
|
}
|
|
30627
|
+
visitComponent(component) {
|
|
30628
|
+
throw new Error('TODO');
|
|
30629
|
+
}
|
|
30630
|
+
visitDirective(directive) {
|
|
30631
|
+
throw new Error('TODO');
|
|
30632
|
+
}
|
|
29994
30633
|
// Unused visitors.
|
|
29995
30634
|
visitVariable(variable) { }
|
|
29996
30635
|
visitReference(reference) { }
|
|
@@ -30121,6 +30760,7 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
30121
30760
|
// Visit the inputs, outputs, and children of the element.
|
|
30122
30761
|
element.inputs.forEach(this.visitNode);
|
|
30123
30762
|
element.outputs.forEach(this.visitNode);
|
|
30763
|
+
element.directives.forEach(this.visitNode);
|
|
30124
30764
|
element.children.forEach(this.visitNode);
|
|
30125
30765
|
element.references.forEach(this.visitNode);
|
|
30126
30766
|
}
|
|
@@ -30128,6 +30768,7 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
30128
30768
|
// First, visit inputs, outputs and template attributes of the template node.
|
|
30129
30769
|
template.inputs.forEach(this.visitNode);
|
|
30130
30770
|
template.outputs.forEach(this.visitNode);
|
|
30771
|
+
template.directives.forEach(this.visitNode);
|
|
30131
30772
|
template.templateAttrs.forEach(this.visitNode);
|
|
30132
30773
|
template.references.forEach(this.visitNode);
|
|
30133
30774
|
// Next, recurse into the template.
|
|
@@ -30145,6 +30786,12 @@ class TemplateBinder extends RecursiveAstVisitor {
|
|
|
30145
30786
|
this.symbols.set(reference, this.rootNode);
|
|
30146
30787
|
}
|
|
30147
30788
|
}
|
|
30789
|
+
visitComponent(component) {
|
|
30790
|
+
throw new Error('TODO');
|
|
30791
|
+
}
|
|
30792
|
+
visitDirective(directive) {
|
|
30793
|
+
throw new Error('TODO');
|
|
30794
|
+
}
|
|
30148
30795
|
// Unused template visitors
|
|
30149
30796
|
visitText(text) { }
|
|
30150
30797
|
visitTextAttribute(attribute) { }
|
|
@@ -31197,7 +31844,7 @@ class _Visitor {
|
|
|
31197
31844
|
this._init(_VisitorMode.Merge, interpolationConfig);
|
|
31198
31845
|
this._translations = translations;
|
|
31199
31846
|
// Construct a single fake root element
|
|
31200
|
-
const wrapper = new Element('wrapper', [], nodes, undefined, undefined, undefined);
|
|
31847
|
+
const wrapper = new Element('wrapper', [], [], nodes, undefined, undefined, undefined);
|
|
31201
31848
|
const translatedNode = wrapper.visit(this, null);
|
|
31202
31849
|
if (this._inI18nBlock) {
|
|
31203
31850
|
this._reportError(nodes[nodes.length - 1], 'Unclosed block');
|
|
@@ -31283,7 +31930,41 @@ class _Visitor {
|
|
|
31283
31930
|
return text;
|
|
31284
31931
|
}
|
|
31285
31932
|
visitElement(el, context) {
|
|
31286
|
-
this.
|
|
31933
|
+
return this._visitElementLike(el, context);
|
|
31934
|
+
}
|
|
31935
|
+
visitAttribute(attribute, context) {
|
|
31936
|
+
throw new Error('unreachable code');
|
|
31937
|
+
}
|
|
31938
|
+
visitBlock(block, context) {
|
|
31939
|
+
visitAll(this, block.children, context);
|
|
31940
|
+
}
|
|
31941
|
+
visitBlockParameter(parameter, context) { }
|
|
31942
|
+
visitLetDeclaration(decl, context) { }
|
|
31943
|
+
visitComponent(component, context) {
|
|
31944
|
+
return this._visitElementLike(component, context);
|
|
31945
|
+
}
|
|
31946
|
+
visitDirective(directive, context) {
|
|
31947
|
+
throw new Error('unreachable code');
|
|
31948
|
+
}
|
|
31949
|
+
_init(mode, interpolationConfig) {
|
|
31950
|
+
this._mode = mode;
|
|
31951
|
+
this._inI18nBlock = false;
|
|
31952
|
+
this._inI18nNode = false;
|
|
31953
|
+
this._depth = 0;
|
|
31954
|
+
this._inIcu = false;
|
|
31955
|
+
this._msgCountAtSectionStart = undefined;
|
|
31956
|
+
this._errors = [];
|
|
31957
|
+
this._messages = [];
|
|
31958
|
+
this._inImplicitNode = false;
|
|
31959
|
+
this._createI18nMessage = createI18nMessageFactory(interpolationConfig, DEFAULT_CONTAINER_BLOCKS,
|
|
31960
|
+
// When dropping significant whitespace we need to retain whitespace tokens or
|
|
31961
|
+
// else we won't be able to reuse source spans because empty tokens would be
|
|
31962
|
+
// removed and cause a mismatch.
|
|
31963
|
+
/* retainEmptyTokens */ !this._preserveSignificantWhitespace,
|
|
31964
|
+
/* preserveExpressionWhitespace */ this._preserveSignificantWhitespace);
|
|
31965
|
+
}
|
|
31966
|
+
_visitElementLike(node, context) {
|
|
31967
|
+
this._mayBeAddBlockChildren(node);
|
|
31287
31968
|
this._depth++;
|
|
31288
31969
|
const wasInI18nNode = this._inI18nNode;
|
|
31289
31970
|
const wasInImplicitNode = this._inImplicitNode;
|
|
@@ -31292,9 +31973,10 @@ class _Visitor {
|
|
|
31292
31973
|
// Extract:
|
|
31293
31974
|
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
|
31294
31975
|
// - ICU messages
|
|
31295
|
-
const
|
|
31976
|
+
const nodeName = node instanceof Component ? node.tagName : node.name;
|
|
31977
|
+
const i18nAttr = _getI18nAttr(node);
|
|
31296
31978
|
const i18nMeta = i18nAttr ? i18nAttr.value : '';
|
|
31297
|
-
const isImplicit = this._implicitTags.some((tag) =>
|
|
31979
|
+
const isImplicit = this._implicitTags.some((tag) => nodeName === tag) &&
|
|
31298
31980
|
!this._inIcu &&
|
|
31299
31981
|
!this._isInTranslatableSection;
|
|
31300
31982
|
const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
|
|
@@ -31302,29 +31984,29 @@ class _Visitor {
|
|
|
31302
31984
|
if (!this._isInTranslatableSection && !this._inIcu) {
|
|
31303
31985
|
if (i18nAttr || isTopLevelImplicit) {
|
|
31304
31986
|
this._inI18nNode = true;
|
|
31305
|
-
const message = this._addMessage(
|
|
31306
|
-
translatedChildNodes = this._translateMessage(
|
|
31987
|
+
const message = this._addMessage(node.children, i18nMeta);
|
|
31988
|
+
translatedChildNodes = this._translateMessage(node, message);
|
|
31307
31989
|
}
|
|
31308
31990
|
if (this._mode == _VisitorMode.Extract) {
|
|
31309
31991
|
const isTranslatable = i18nAttr || isTopLevelImplicit;
|
|
31310
31992
|
if (isTranslatable)
|
|
31311
|
-
this._openTranslatableSection(
|
|
31312
|
-
visitAll(this,
|
|
31993
|
+
this._openTranslatableSection(node);
|
|
31994
|
+
visitAll(this, node.children);
|
|
31313
31995
|
if (isTranslatable)
|
|
31314
|
-
this._closeTranslatableSection(
|
|
31996
|
+
this._closeTranslatableSection(node, node.children);
|
|
31315
31997
|
}
|
|
31316
31998
|
}
|
|
31317
31999
|
else {
|
|
31318
32000
|
if (i18nAttr || isTopLevelImplicit) {
|
|
31319
|
-
this._reportError(
|
|
32001
|
+
this._reportError(node, 'Could not mark an element as translatable inside a translatable section');
|
|
31320
32002
|
}
|
|
31321
32003
|
if (this._mode == _VisitorMode.Extract) {
|
|
31322
32004
|
// Descend into child nodes for extraction
|
|
31323
|
-
visitAll(this,
|
|
32005
|
+
visitAll(this, node.children);
|
|
31324
32006
|
}
|
|
31325
32007
|
}
|
|
31326
32008
|
if (this._mode === _VisitorMode.Merge) {
|
|
31327
|
-
const visitNodes = translatedChildNodes ||
|
|
32009
|
+
const visitNodes = translatedChildNodes || node.children;
|
|
31328
32010
|
visitNodes.forEach((child) => {
|
|
31329
32011
|
const visited = child.visit(this, context);
|
|
31330
32012
|
if (visited && !this._isInTranslatableSection) {
|
|
@@ -31334,48 +32016,29 @@ class _Visitor {
|
|
|
31334
32016
|
}
|
|
31335
32017
|
});
|
|
31336
32018
|
}
|
|
31337
|
-
this._visitAttributesOf(
|
|
32019
|
+
this._visitAttributesOf(node);
|
|
31338
32020
|
this._depth--;
|
|
31339
32021
|
this._inI18nNode = wasInI18nNode;
|
|
31340
32022
|
this._inImplicitNode = wasInImplicitNode;
|
|
31341
32023
|
if (this._mode === _VisitorMode.Merge) {
|
|
31342
|
-
|
|
31343
|
-
|
|
32024
|
+
if (node instanceof Element) {
|
|
32025
|
+
return new Element(node.name, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
|
|
32026
|
+
}
|
|
32027
|
+
else {
|
|
32028
|
+
return new Component(node.componentName, node.tagName, node.fullName, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
|
|
32029
|
+
}
|
|
31344
32030
|
}
|
|
31345
32031
|
return null;
|
|
31346
32032
|
}
|
|
31347
|
-
visitAttribute(attribute, context) {
|
|
31348
|
-
throw new Error('unreachable code');
|
|
31349
|
-
}
|
|
31350
|
-
visitBlock(block, context) {
|
|
31351
|
-
visitAll(this, block.children, context);
|
|
31352
|
-
}
|
|
31353
|
-
visitBlockParameter(parameter, context) { }
|
|
31354
|
-
visitLetDeclaration(decl, context) { }
|
|
31355
|
-
_init(mode, interpolationConfig) {
|
|
31356
|
-
this._mode = mode;
|
|
31357
|
-
this._inI18nBlock = false;
|
|
31358
|
-
this._inI18nNode = false;
|
|
31359
|
-
this._depth = 0;
|
|
31360
|
-
this._inIcu = false;
|
|
31361
|
-
this._msgCountAtSectionStart = undefined;
|
|
31362
|
-
this._errors = [];
|
|
31363
|
-
this._messages = [];
|
|
31364
|
-
this._inImplicitNode = false;
|
|
31365
|
-
this._createI18nMessage = createI18nMessageFactory(interpolationConfig, DEFAULT_CONTAINER_BLOCKS,
|
|
31366
|
-
// When dropping significant whitespace we need to retain whitespace tokens or
|
|
31367
|
-
// else we won't be able to reuse source spans because empty tokens would be
|
|
31368
|
-
// removed and cause a mismatch.
|
|
31369
|
-
/* retainEmptyTokens */ !this._preserveSignificantWhitespace,
|
|
31370
|
-
/* preserveExpressionWhitespace */ this._preserveSignificantWhitespace);
|
|
31371
|
-
}
|
|
31372
32033
|
// looks for translatable attributes
|
|
31373
32034
|
_visitAttributesOf(el) {
|
|
31374
32035
|
const explicitAttrNameToValue = {};
|
|
31375
|
-
const implicitAttrNames = this._implicitAttrs[el.name] || [];
|
|
32036
|
+
const implicitAttrNames = this._implicitAttrs[el instanceof Component ? el.tagName || '' : el.name] || [];
|
|
31376
32037
|
el.attrs
|
|
31377
|
-
.filter((attr) => attr.name.startsWith(_I18N_ATTR_PREFIX))
|
|
31378
|
-
.forEach((attr) =>
|
|
32038
|
+
.filter((attr) => attr instanceof Attribute && attr.name.startsWith(_I18N_ATTR_PREFIX))
|
|
32039
|
+
.forEach((attr) => {
|
|
32040
|
+
explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] = attr.value;
|
|
32041
|
+
});
|
|
31379
32042
|
el.attrs.forEach((attr) => {
|
|
31380
32043
|
if (attr.name in explicitAttrNameToValue) {
|
|
31381
32044
|
this._addMessage([attr], explicitAttrNameToValue[attr.name]);
|
|
@@ -31448,16 +32111,15 @@ class _Visitor {
|
|
|
31448
32111
|
return [];
|
|
31449
32112
|
}
|
|
31450
32113
|
// translate the attributes of an element and remove i18n specific attributes
|
|
31451
|
-
_translateAttributes(
|
|
31452
|
-
const attributes = el.attrs;
|
|
32114
|
+
_translateAttributes(node) {
|
|
31453
32115
|
const i18nParsedMessageMeta = {};
|
|
31454
|
-
|
|
32116
|
+
const translatedAttributes = [];
|
|
32117
|
+
node.attrs.forEach((attr) => {
|
|
31455
32118
|
if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
|
|
31456
32119
|
i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] = _parseMessageMeta(attr.value);
|
|
31457
32120
|
}
|
|
31458
32121
|
});
|
|
31459
|
-
|
|
31460
|
-
attributes.forEach((attr) => {
|
|
32122
|
+
node.attrs.forEach((attr) => {
|
|
31461
32123
|
if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) {
|
|
31462
32124
|
// strip i18n specific attributes
|
|
31463
32125
|
return;
|
|
@@ -31475,11 +32137,11 @@ class _Visitor {
|
|
|
31475
32137
|
translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */));
|
|
31476
32138
|
}
|
|
31477
32139
|
else {
|
|
31478
|
-
this._reportError(
|
|
32140
|
+
this._reportError(node, `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
|
|
31479
32141
|
}
|
|
31480
32142
|
}
|
|
31481
32143
|
else {
|
|
31482
|
-
this._reportError(
|
|
32144
|
+
this._reportError(node, `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
|
|
31483
32145
|
}
|
|
31484
32146
|
}
|
|
31485
32147
|
else {
|
|
@@ -31488,6 +32150,9 @@ class _Visitor {
|
|
|
31488
32150
|
});
|
|
31489
32151
|
return translatedAttributes;
|
|
31490
32152
|
}
|
|
32153
|
+
_translateDirectives(node) {
|
|
32154
|
+
return node.directives.map((dir) => new Directive(dir.name, this._translateAttributes(dir), dir.sourceSpan, dir.startSourceSpan, dir.endSourceSpan));
|
|
32155
|
+
}
|
|
31491
32156
|
/**
|
|
31492
32157
|
* Add the node as a child of the block when:
|
|
31493
32158
|
* - we are in a block,
|
|
@@ -31563,7 +32228,7 @@ function _isClosingComment(n) {
|
|
|
31563
32228
|
return !!(n instanceof Comment && n.value && n.value === '/i18n');
|
|
31564
32229
|
}
|
|
31565
32230
|
function _getI18nAttr(p) {
|
|
31566
|
-
return p.attrs.find((attr) => attr.name === _I18N_ATTR) || null;
|
|
32231
|
+
return (p.attrs.find((attr) => attr instanceof Attribute && attr.name === _I18N_ATTR) || null);
|
|
31567
32232
|
}
|
|
31568
32233
|
function _parseMessageMeta(i18n) {
|
|
31569
32234
|
if (!i18n)
|
|
@@ -31597,7 +32262,7 @@ var FactoryTarget;
|
|
|
31597
32262
|
* @description
|
|
31598
32263
|
* Entry point for all public APIs of the compiler package.
|
|
31599
32264
|
*/
|
|
31600
|
-
new Version('20.0.0-next.
|
|
32265
|
+
new Version('20.0.0-next.6');
|
|
31601
32266
|
|
|
31602
32267
|
//////////////////////////////////////
|
|
31603
32268
|
// THIS FILE HAS GLOBAL SIDE EFFECT //
|