Angular 21.1: Support consecutive switch cases (#18593)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-01-15 05:14:58 +08:00
1 parent b8af9d5153
commit 9464003348
6 files changed
+213 -16

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
#### Add support for multiple switch cases (#18593 by @fisker)
This feature added in Angular v21.1.
<!-- prettier-ignore -->
```html
<!-- Input -->
@switch (foo) {
@case (0)
@case (1) {
<div>case 0 or 1</div>
}
}
<!-- Prettier stable -->
SyntaxError: Incomplete block "case". If you meant to write the @ character, you should use the "&#64;" HTML entity instead. (2:3)
<!-- Prettier main -->
@switch (a) {
@case (0)
@case (1) {
<div>case 0 or 1</div>
}
}
```
+1 -1
View File
@@ -56,7 +56,7 @@
"acorn": "8.15.0",
"acorn-jsx": "5.3.2",
"angular-estree-parser": "15.2.0",
"angular-html-parser": "10.2.1",
"angular-html-parser": "10.3.0",
"camelcase": "9.0.0",
"ci-info": "4.3.1",
"cjk-regex": "3.4.0",
+25 -10
View File
@@ -24,18 +24,20 @@ function printAngularControlFlowBlock(path, options, print) {
docs.push(" (", group(print("parameters")), ")");
}
docs.push(" {");
if (!isSwitchFallthroughCase(node)) {
docs.push(" {");
const shouldPrintCloseBracket = shouldCloseBlock(node);
if (node.children.length > 0) {
node.firstChild.hasLeadingSpaces = true;
node.lastChild.hasTrailingSpaces = true;
docs.push(indent([hardline, printChildren(path, options, print)]));
if (shouldPrintCloseBracket) {
docs.push(hardline, "}");
const shouldPrintCloseBracket = shouldCloseBlock(node);
if (node.children.length > 0) {
node.firstChild.hasLeadingSpaces = true;
node.lastChild.hasTrailingSpaces = true;
docs.push(indent([hardline, printChildren(path, options, print)]));
if (shouldPrintCloseBracket) {
docs.push(hardline, "}");
}
} else if (shouldPrintCloseBracket) {
docs.push("}");
}
} else if (shouldPrintCloseBracket) {
docs.push("}");
}
return group(docs, { shouldBreak: true });
@@ -48,6 +50,19 @@ function shouldCloseBlock(node) {
);
}
const isSwitchCaseBlock = (node) =>
node?.kind === "angularControlFlowBlock" &&
(node.name === "case" || node.name === "default");
// https://github.com/angular/angular/commit/0ad3adc7c6d4094f1e3432a3f2e3bdc9862cb4fa#diff-77a6f285c6ea13d6644ef635e7495e71134d1141af2650cb9ae5631ff1f38bf2R263
// https://github.com/prettier/prettier/issues/18563#issuecomment-3728354491
function isSwitchFallthroughCase(node) {
return (
isSwitchCaseBlock(node) &&
node.endSourceSpan &&
node.endSourceSpan.start.offset === node.endSourceSpan.end.offset
);
}
function isPreviousBlockUnClosed(path) {
const { previous } = path;
return (
@@ -526,6 +526,120 @@ printWidth: 80
================================================================================
`;
exports[`multiple-switch-cases.html format 1`] = `
====================================options=====================================
parsers: ["angular"]
printWidth: 80
| printWidth
=====================================input======================================
<!-- https://github.com/angular/angular/pull/66210 -->
@switch (expr) {
@case ( 'one')
@case ( 'two') {
{{ oneOrTwo()}}
}
@case ( 'three') {
{{ three()}}
}
}
@switch (expr) {
@case (1)
@case (2) {
{{oneOrTwo() }}
}
@case (3 )
@default {
{{default() }}
}
}
<div>
{{message}}
@switch (value()) {
@case ( 0) @case(1 ) {
case 01
}
@case (2) {
case 2
}
@default {
default
}
}
</div>
@switch(a){@default @case(2){<div>default before case</div>}}
@switch(a){@case(1) @case(2){} @case(3) {<div>3</div>}}
@switch(a){@case(1) @case(2) {<!-- comment -->}}
=====================================output=====================================
<!-- https://github.com/angular/angular/pull/66210 -->
@switch (expr) {
@case ("one")
@case ("two") {
{{ oneOrTwo() }}
}
@case ("three") {
{{ three() }}
}
}
@switch (expr) {
@case (1)
@case (2) {
{{ oneOrTwo() }}
}
@case (3)
@default {
{{ default() }}
}
}
<div>
{{ message }}
@switch (value()) {
@case (0)
@case (1) {
case 01
}
@case (2) {
case 2
}
@default {
default
}
}
</div>
@switch (a) {
@default
@case (2) {
<div>default before case</div>
}
}
@switch (a) {
@case (1)
@case (2) {}
@case (3) {
<div>3</div>
}
}
@switch (a) {
@case (1)
@case (2) {
<!-- comment -->
}
}
================================================================================
`;
exports[`switch.html format 1`] = `
====================================options=====================================
parsers: ["angular"]
@@ -0,0 +1,43 @@
<!-- https://github.com/angular/angular/pull/66210 -->
@switch (expr) {
@case ( 'one')
@case ( 'two') {
{{ oneOrTwo()}}
}
@case ( 'three') {
{{ three()}}
}
}
@switch (expr) {
@case (1)
@case (2) {
{{oneOrTwo() }}
}
@case (3 )
@default {
{{default() }}
}
}
<div>
{{message}}
@switch (value()) {
@case ( 0) @case(1 ) {
case 01
}
@case (2) {
case 2
}
@default {
default
}
}
</div>
@switch(a){@default @case(2){<div>default before case</div>}}
@switch(a){@case(1) @case(2){} @case(3) {<div>3</div>}}
@switch(a){@case(1) @case(2) {<!-- comment -->}}
+5 -5
View File
@@ -2892,10 +2892,10 @@ __metadata:
languageName: node
linkType: hard
"angular-html-parser@npm:10.2.1":
version: 10.2.1
resolution: "angular-html-parser@npm:10.2.1"
checksum: 10/873d049c902d31423b42f2e3c006e991d8dbb3697ae4bc5c8bea0fa7db9f13aae4560e69ee5c8d5e9039094c921a016d0256f8b0e27151eecd2281c98217bc94
"angular-html-parser@npm:10.3.0":
version: 10.3.0
resolution: "angular-html-parser@npm:10.3.0"
checksum: 10/97078879db8f53fc9645d2cd8c748c9eb3770790ec96f249bd96e0ab9293f65506b7facd201c17f2f18884e82550f3c362972e7b3a5448b0e1fb2a6938e9ef4d
languageName: node
linkType: hard
@@ -8379,7 +8379,7 @@ __metadata:
acorn: "npm:8.15.0"
acorn-jsx: "npm:5.3.2"
angular-estree-parser: "npm:15.2.0"
angular-html-parser: "npm:10.2.1"
angular-html-parser: "npm:10.3.0"
base64-arraybuffer-es6: "npm:3.1.0"
browserslist: "npm:4.28.1"
browserslist-to-esbuild: "npm:2.1.1"