Merge branch 'v3.8.x'

# Conflicts:
#	src/language-markdown/embed.js
#	tests/format/misc/errors/front-matter/__snapshots__/format.test.js.snap
This commit is contained in:
fisker committed 2026-01-15 08:10:20 +08:00
commit 01d1469c84
13 files changed
+204 -34

No files matched your search

+154
View File
@@ -0,0 +1,154 @@
---
authors: "fisker"
title: "Prettier 3.8: Support for Angular v21.1"
---
We're excited to announce that Prettier now fully supports the fresh features landing in Angular v21.1 (released today 🎉)!
This update brings cleaner, more expressive templates with:
- Consecutive `@case` statements in `@switch` blocks.
- Spread elements (`...`) in array literals, object literals, and function calls inside templates.
We've also added the ability to format Angular syntax beautifully inside Markdown code blocks.
If you find Prettier valuable and want to help us keep pace with fast-moving frameworks like Angular, please consider [sponsoring us on OpenCollective](https://opencollective.com/prettier) or supporting the projects we rely on. Thank you for being part of this community — your support means a lot!
<!-- truncate -->
## Highlights
### Angular
#### Support for consecutive switch cases ([#18593](https://github.com/prettier/prettier/pull/18593) by [@fisker](https://github.com/fisker)) {#change-18593}
<!-- prettier-ignore -->
```html
<!-- Input -->
@switch (userRole) {
@case ('admin')
@case ('moderator') {
<p>Welcome, boss! Full access.</p>
}
@case ('user') { <p>Standard access</p> }
@default { <p>Guest view</p> }
}
<!-- Prettier 3.7 -->
SyntaxError: Incomplete block "case". If you meant to write the @ character, you should use the "&#64;" HTML entity instead. (2:3)
<!-- Prettier 3.8 -->
@switch (userRole) {
@case ("admin")
@case ("moderator") {
<p>Welcome, boss! Full access.</p>
}
@case ("user") {
<p>Standard access</p>
}
@default {
<p>Guest view</p>
}
}
```
#### Support for spread elements ([#18596](https://github.com/prettier/prettier/pull/18596), [#18636](https://github.com/prettier/prettier/pull/18636) by [@prettier](https://github.com/prettier)) {#change-18596}
<!-- prettier-ignore -->
```html
<!-- Input -->
<MyComponent
[array]="[ ...foo, ...bar]"
[object]="{...bar, ...extra }"
[call]="call( ...baz)"
/>
<!-- Prettier 3.7 -->
<MyComponent
[array]="[ ...foo, ...bar]"
[object]="{...bar, ...extra }"
[call]="call( ...baz)"
/>
<!-- Prettier 3.8 -->
<MyComponent
[array]="[...foo, ...bar]"
[object]="{ ...bar, ...extra }"
[call]="call(...baz)"
/>
```
## Other Changes
### Angular
#### Don't print attribute values that are single template or string literals on new lines ([#18378](https://github.com/prettier/prettier/pull/18378) by [@ravindUwU](https://github.com/ravindUwU)) {#change-18378}
<!-- prettier-ignore -->
```html
<!-- Input -->
<component
[property]="`
template
literal
`"
/>
<!-- Prettier 3.7 -->
<component
[property]="
`
template
literal
`
"
/>
<!-- Prettier 3.8 -->
<component
[property]="`
template
literal
`"
/>
```
### Markdown
#### Support formatting Angular syntax in code block ([#18519](https://github.com/prettier/prettier/pull/18519) by [@fisker](https://github.com/fisker)) {#change-18519}
<!-- prettier-ignore -->
````md
<!-- Input -->
```angular-ts
@Component({
selector: 'app-root',
template: `<div
>Welcome to {{
Angular}}! </div>`,
})
export class App {}
```
```angular-html
<div
>Welcome to {{
Angular}}! </div>
```
<!-- Prettier 3.7 -->
Same as input
<!-- Prettier 3.8 -->
```angular-ts
@Component({
selector: "app-root",
template: `<div>Welcome to {{ Angular }}!</div>`,
})
export class App {}
```
```angular-html
<div>Welcome to {{ Angular }}!</div>
```
````
@@ -21,7 +21,7 @@ Required options:
- **[`parser`](options.md#parser) (or [`filepath`](options.md#file-path))**: One of these options has to be specified for Prettier to know which parser to use.
- **`plugins`**: Unlike the `format` function from the [Node.js-based API](api.md#prettierformatsource-options), this function doesn’t load plugins automatically. The `plugins` option is required because all the parsers included in the Prettier package come as plugins (for reasons of file size). These plugins are files in [https://unpkg.com/browse/prettier@3.7.4/plugins](https://unpkg.com/browse/prettier@3.7.4/plugins). Note that `estree` plugin should be loaded when printing JavaScript, TypeScript, Flow, or JSON.
- **`plugins`**: Unlike the `format` function from the [Node.js-based API](api.md#prettierformatsource-options), this function doesn’t load plugins automatically. The `plugins` option is required because all the parsers included in the Prettier package come as plugins (for reasons of file size). These plugins are files in [https://unpkg.com/browse/prettier@3.8.0/plugins](https://unpkg.com/browse/prettier@3.8.0/plugins). Note that `estree` plugin should be loaded when printing JavaScript, TypeScript, Flow, or JSON.
You need to load the ones that you’re going to use and pass them to `prettier.format` using the `plugins` option.
@@ -32,8 +32,8 @@ See below for examples.
### Global
```html
<script src="https://unpkg.com/prettier@3.7.4/standalone.js"></script>
<script src="https://unpkg.com/prettier@3.7.4/plugins/graphql.js"></script>
<script src="https://unpkg.com/prettier@3.8.0/standalone.js"></script>
<script src="https://unpkg.com/prettier@3.8.0/plugins/graphql.js"></script>
<script>
(async () => {
const formatted = await prettier.format("type Query { hello: String }", {
@@ -50,8 +50,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
```html
<script type="module">
import * as prettier from "https://unpkg.com/prettier@3.7.4/standalone.mjs";
import * as prettierPluginGraphql from "https://unpkg.com/prettier@3.7.4/plugins/graphql.mjs";
import * as prettier from "https://unpkg.com/prettier@3.8.0/standalone.mjs";
import * as prettierPluginGraphql from "https://unpkg.com/prettier@3.8.0/plugins/graphql.mjs";
const formatted = await prettier.format("type Query { hello: String }", {
parser: "graphql",
@@ -64,8 +64,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
```js
define([
"https://unpkg.com/prettier@3.7.4/standalone.js",
"https://unpkg.com/prettier@3.7.4/plugins/graphql.js",
"https://unpkg.com/prettier@3.8.0/standalone.js",
"https://unpkg.com/prettier@3.8.0/plugins/graphql.js",
], async (prettier, ...plugins) => {
const formatted = await prettier.format("type Query { hello: String }", {
parser: "graphql",
@@ -96,8 +96,8 @@ This syntax doesn’t necessarily work in the browser, but it can be used when b
<TabItem value="module" label="Module worker">
```js
import * as prettier from "https://unpkg.com/prettier@3.7.4/standalone.mjs";
import * as prettierPluginGraphql from "https://unpkg.com/prettier@3.7.41/plugins/graphql.mjs";
import * as prettier from "https://unpkg.com/prettier@3.8.0/standalone.mjs";
import * as prettierPluginGraphql from "https://unpkg.com/prettier@3.8.01/plugins/graphql.mjs";
const formatted = await prettier.format("type Query { hello: String }", {
parser: "graphql",
@@ -110,8 +110,8 @@ const formatted = await prettier.format("type Query { hello: String }", {
```js
importScripts(
"https://unpkg.com/prettier@3.7.4/standalone.js",
"https://unpkg.com/prettier@3.7.4/plugins/graphql.js",
"https://unpkg.com/prettier@3.8.0/standalone.js",
"https://unpkg.com/prettier@3.8.0/plugins/graphql.js",
);
(async () => {
@@ -131,9 +131,9 @@ If you want to format [embedded code](options.md#embedded-language-formatting),
```html
<script type="module">
import * as prettier from "https://unpkg.com/prettier@3.7.4/standalone.mjs";
import * as prettierPluginBabel from "https://unpkg.com/prettier@3.7.4/plugins/babel.mjs";
import * as prettierPluginEstree from "https://unpkg.com/prettier@3.7.4/plugins/estree.mjs";
import * as prettier from "https://unpkg.com/prettier@3.8.0/standalone.mjs";
import * as prettierPluginBabel from "https://unpkg.com/prettier@3.8.0/plugins/babel.mjs";
import * as prettierPluginEstree from "https://unpkg.com/prettier@3.8.0/plugins/estree.mjs";
console.log(
await prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
@@ -149,10 +149,10 @@ The HTML code embedded in JavaScript stays unformatted because the `html` parser
```html
<script type="module">
import * as prettier from "https://unpkg.com/prettier@3.7.4/standalone.mjs";
import * as prettierPluginBabel from "https://unpkg.com/prettier@3.7.4/plugins/babel.mjs";
import * as prettierPluginEstree from "https://unpkg.com/prettier@3.7.4/plugins/estree.mjs";
import * as prettierPluginHtml from "https://unpkg.com/prettier@3.7.4/plugins/html.mjs";
import * as prettier from "https://unpkg.com/prettier@3.8.0/standalone.mjs";
import * as prettierPluginBabel from "https://unpkg.com/prettier@3.8.0/plugins/babel.mjs";
import * as prettierPluginEstree from "https://unpkg.com/prettier@3.8.0/plugins/estree.mjs";
import * as prettierPluginHtml from "https://unpkg.com/prettier@3.8.0/plugins/html.mjs";
console.log(
await prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {