Skip to content

Commit 44d3dae

Browse files
committed
feat(language-service): add support for @boundary blocks
Add support for the new `@boundary` and `@error` control flow blocks in the Angular Language Service. This includes: - Updating outlining spans to handle boundary blocks correctly. - Adding classification visitor methods for semantic tokens. - Adding template target visitor methods for navigation and hover support. - Updating the TextMate grammar to recognize `@boundary` and the `when` clause.
1 parent 3ffeb11 commit 44d3dae

5 files changed

Lines changed: 46 additions & 1 deletion

File tree

packages/core/test/render3/error_boundary_spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
EnvironmentInjector,
77
Input,
88
signal,
9+
ErrorHandler,
910
} from '@angular/core';
1011
import {TestBed, ComponentFixture} from '@angular/core/testing';
1112
import {ɵɵdefineComponent} from '../../src/render3/definition';

packages/language-service/src/outlining_spans.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
TmplAstNode,
1717
TmplAstRecursiveVisitor,
1818
TmplAstSwitchBlockCase,
19+
TmplAstBoundaryBlock,
1920
tmplAstVisitAll,
2021
} from '@angular/compiler';
2122
import {isExternalResource, isNamedClassDeclaration, NgCompiler} from '@angular/compiler-cli';
@@ -90,6 +91,8 @@ class BlockVisitor extends TmplAstRecursiveVisitor {
9091
node instanceof TmplAstBlockNode &&
9192
// Omit `IfBlock` because we include the branches individually
9293
!(node instanceof TmplAstIfBlock) &&
94+
// Omit `BoundaryBlock` because we include the branches individually
95+
!(node instanceof TmplAstBoundaryBlock) &&
9396
// Omit `SwitchBlockCase` because we include the groups
9497
!(node instanceof TmplAstSwitchBlockCase)
9598
) {

packages/language-service/src/semantic_tokens.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import {
3838
TmplAstUnknownBlock,
3939
TmplAstVariable,
4040
TmplAstVisitor,
41+
TmplAstBoundaryBlock,
42+
TmplAstBoundaryErrorBlock,
4143
} from '@angular/compiler';
4244
import {NgCompiler, PotentialDirective} from '@angular/compiler-cli';
4345

@@ -200,6 +202,15 @@ class ClassificationVisitor implements TmplAstVisitor {
200202
this.visitAll(block.children);
201203
}
202204

205+
visitBoundaryBlock(block: TmplAstBoundaryBlock) {
206+
this.visitAll(block.children);
207+
this.visitAll(block.errorBlocks);
208+
}
209+
210+
visitBoundaryErrorBlock(block: TmplAstBoundaryErrorBlock) {
211+
this.visitAll(block.children);
212+
}
213+
203214
visitTemplate(template: TmplAstTemplate) {
204215
this.visitAll(template.children);
205216
}

packages/language-service/src/template_target.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ import {
5050
TmplAstUnknownBlock,
5151
TmplAstVariable,
5252
TmplAstViewportDeferredTrigger,
53+
TmplAstBoundaryBlock,
54+
TmplAstBoundaryErrorBlock,
5355
tmplAstVisitAll,
5456
TmplAstVisitor,
5557
} from '@angular/compiler';
@@ -698,6 +700,17 @@ class TemplateTargetVisitor implements TmplAstVisitor {
698700
this.visitAll(block.children);
699701
}
700702

703+
visitBoundaryBlock(block: TmplAstBoundaryBlock) {
704+
this.visitAll(block.children);
705+
this.visitAll(block.errorBlocks);
706+
}
707+
708+
visitBoundaryErrorBlock(block: TmplAstBoundaryErrorBlock) {
709+
block.expression && this.visitBinding(block.expression);
710+
block.errorAlias && this.visit(block.errorAlias);
711+
this.visitAll(block.children);
712+
}
713+
701714
visitUnknownBlock(block: TmplAstUnknownBlock) {}
702715

703716
visitLetDeclaration(decl: TmplAstLetDeclaration) {

vscode-ng-language-service/syntaxes/template-blocks.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"name": "keyword.control.block.transition.ng"
1313
},
1414
"block": {
15-
"begin": "(@)(if|else if|else|defer|placeholder|loading|error|switch|for|empty)(?:\\s*)",
15+
"begin": "(@)(if|else if|else|defer|placeholder|loading|error|boundary|switch|for|empty)(?:\\s*)",
1616
"beginCaptures": {
1717
"1": {
1818
"patterns": [
@@ -108,6 +108,9 @@
108108
{
109109
"include": "#blockExpressionTrackClause"
110110
},
111+
{
112+
"include": "#blockExpressionWhenClause"
113+
},
111114
{
112115
"include": "expression.ng"
113116
}
@@ -119,6 +122,20 @@
119122
}
120123
}
121124
},
125+
"blockExpressionWhenClause": {
126+
"begin": "\\bwhen\\b",
127+
"beginCaptures": {
128+
"0": {
129+
"name": "keyword.control.when.ng"
130+
}
131+
},
132+
"end": "(?=[$)])|(?<=;)",
133+
"patterns": [
134+
{
135+
"include": "expression.ng"
136+
}
137+
]
138+
},
122139
"blockExpressionOfClause": {
123140
"begin": "([_$[:alpha:]][_$[:alnum:]]*)\\s+(of)\\b",
124141
"beginCaptures": {

0 commit comments

Comments
 (0)