From 787cd875b08ef789d2fa203ea1fc4242a1fde587 Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Tue, 24 Feb 2026 19:28:52 +0100 Subject: [PATCH] refactor(vscode-extension): Add support for exhaustive type check in the syntax `@default never` will be considered a keyword on its own. (cherry picked from commit db11e74b3d23053c148dd6535099a5a53aaf7fb1) --- .../syntaxes/src/template-blocks.ts | 12 ++++++++- .../syntaxes/template-blocks.json | 24 ++++++++++++++++- .../syntaxes/test/data/template-blocks.html | 5 ++++ .../test/data/template-blocks.html.snap | 26 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/vscode-ng-language-service/syntaxes/src/template-blocks.ts b/vscode-ng-language-service/syntaxes/src/template-blocks.ts index e341c44d5fe..a8b5f74cc2f 100644 --- a/vscode-ng-language-service/syntaxes/src/template-blocks.ts +++ b/vscode-ng-language-service/syntaxes/src/template-blocks.ts @@ -39,7 +39,7 @@ export const TemplateBlocks: GrammarDefinition = { 2: {name: 'keyword.control.block.kind.ng'}, }, patterns: [{include: '#blockExpression'}], - end: /(?=@|{)/, + end: /(?=@|{|})/, name: 'control.block.case.header.ng', }, caseBlock: { @@ -48,6 +48,15 @@ export const TemplateBlocks: GrammarDefinition = { end: /(?<=\})/, name: 'control.block.case.ng', }, + caseExhaustive: { + match: /(@)(default\s+never)\s*(;)/, + captures: { + 1: {patterns: [{include: '#transition'}]}, + 2: {name: 'keyword.control.block.kind.ng'}, + 3: {name: 'punctuation.terminator.statement.ng'}, + }, + name: 'control.block.case.ng', + }, blockExpression: { begin: /\(/, beginCaptures: { @@ -105,6 +114,7 @@ export const TemplateBlocks: GrammarDefinition = { }, contentName: 'control.block.body.ng', patterns: [ + {include: '#caseExhaustive'}, {include: '#caseBlock'}, {include: 'text.html.derivative'}, {include: 'template.ng'}, diff --git a/vscode-ng-language-service/syntaxes/template-blocks.json b/vscode-ng-language-service/syntaxes/template-blocks.json index cc49bfdf64d..55b5bb8888c 100644 --- a/vscode-ng-language-service/syntaxes/template-blocks.json +++ b/vscode-ng-language-service/syntaxes/template-blocks.json @@ -55,7 +55,7 @@ "include": "#blockExpression" } ], - "end": "(?=@|{)", + "end": "(?=@|{|})", "name": "control.block.case.header.ng" }, "caseBlock": { @@ -71,6 +71,25 @@ "end": "(?<=\\})", "name": "control.block.case.ng" }, + "caseExhaustive": { + "match": "(@)(default\\s+never)\\s*(;)", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.block.kind.ng" + }, + "3": { + "name": "punctuation.terminator.statement.ng" + } + }, + "name": "control.block.case.ng" + }, "blockExpression": { "begin": "\\(", "beginCaptures": { @@ -160,6 +179,9 @@ }, "contentName": "control.block.body.ng", "patterns": [ + { + "include": "#caseExhaustive" + }, { "include": "#caseBlock" }, diff --git a/vscode-ng-language-service/syntaxes/test/data/template-blocks.html b/vscode-ng-language-service/syntaxes/test/data/template-blocks.html index 287d58a0e76..e43a1a5d1af 100644 --- a/vscode-ng-language-service/syntaxes/test/data/template-blocks.html +++ b/vscode-ng-language-service/syntaxes/test/data/template-blocks.html @@ -18,6 +18,11 @@ } } +@switch(aOrb) { + @case(a) {} + @default never; +} + @if (a==b) { hello } @else { goodbye } @if (a==b) { diff --git a/vscode-ng-language-service/syntaxes/test/data/template-blocks.html.snap b/vscode-ng-language-service/syntaxes/test/data/template-blocks.html.snap index 320fa528f5f..bc3c7dc51e1 100644 --- a/vscode-ng-language-service/syntaxes/test/data/template-blocks.html.snap +++ b/vscode-ng-language-service/syntaxes/test/data/template-blocks.html.snap @@ -104,6 +104,32 @@ >} #^ template.blocks.ng control.block.ng punctuation.definition.block.ts > +>@switch(aOrb) { +#^ template.blocks.ng control.block.ng keyword.control.block.transition.ng +# ^^^^^^ template.blocks.ng control.block.ng keyword.control.block.kind.ng +# ^ template.blocks.ng control.block.ng meta.brace.round.ts +# ^^^^ template.blocks.ng control.block.ng control.block.expression.ng variable.other.readwrite.ts +# ^ template.blocks.ng control.block.ng meta.brace.round.ts +# ^ template.blocks.ng control.block.ng +# ^ template.blocks.ng control.block.ng punctuation.definition.block.ts +> @case(a) {} +#^^^^ template.blocks.ng control.block.ng control.block.body.ng +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng keyword.control.block.transition.ng +# ^^^^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng keyword.control.block.kind.ng +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng meta.brace.round.ts +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng control.block.expression.ng variable.other.readwrite.ts +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng meta.brace.round.ts +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng control.block.case.header.ng +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng punctuation.definition.block.ts +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng punctuation.definition.block.ts +> @default never; +#^^^^ template.blocks.ng control.block.ng control.block.body.ng +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng keyword.control.block.transition.ng +# ^^^^^^^^^^^^^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng keyword.control.block.kind.ng +# ^ template.blocks.ng control.block.ng control.block.body.ng control.block.case.ng punctuation.terminator.statement.ng +>} +#^ template.blocks.ng control.block.ng punctuation.definition.block.ts +> >@if (a==b) { hello } @else { goodbye } #^ template.blocks.ng control.block.ng keyword.control.block.transition.ng # ^^ template.blocks.ng control.block.ng keyword.control.block.kind.ng