NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #256 most downloaded on npm
Prettier is an opinionated code formatter
Last release 11 days ago
23 Sep 2026
Release timing varies
gaps range from 8 days to 5 months
Nearly every release is documented
notes for 59 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
10 years old
198 releases · first in 2017
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
diff
Nothing published for this version
Nothing published for this version
Nothing published for this version
Markdown: Fix text with $ been incorrectly parsed as math syntax ( #20140 by @fisker )
$ been incorrectly parsed as math syntax (#20140 by @fisker)<!-- prettier-ignore -->
<!-- Input -->
**Uses $FOO** from `a.sh` and `b.sh`, plus `$BAR` from `c.sh`, before anything else runs here.
<!-- Prettier 3.9.8 -->
**Uses $FOO** from `a.sh` and `b.sh`, plus `$BAR`from`c.sh`, before anything else runs here.
<!-- Prettier 3.9.9 -->
**Uses $FOO** from `a.sh` and `b.sh`, plus `$BAR` from `c.sh`, before anything else runs here.
Markdown: Don't let Liquid objects interrupt paragraphs ( #20087 by @seiyab )
<!-- prettier-ignore -->
<!-- Input -->
If `module` is not a [`WebAssembly.Module`](/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module) object instance, a
{{jsxref("TypeError")}} is thrown.
<!-- Prettier 3.9.7 -->
If `module` is not a [`WebAssembly.Module`](/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module) object instance, a
{{jsxref("TypeError")}} is thrown.
<!-- Prettier 3.9.8 -->
If `module` is not a [`WebAssembly.Module`](/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module) object instance, a
{{jsxref("TypeError")}} is thrown.
Support Angular 22.2 Fix regressions in v3.9 🔗 Changelog
<!-- prettier-ignore -->
<!-- Input -->
- [x] short first line.
second paragraph at six spaces that wraps
onto another line here.
<!-- Prettier 3.9.6 -->
- [x] short first line.
second paragraph at six spaces that wraps
onto another line here.
<!-- Prettier 3.9.7 -->
- [x] short first line.
second paragraph at six spaces that wraps
onto another line here.
<!-- prettier-ignore -->
// Input
const foo = html`
<div>${getText({
value,
})}</div>
`;
// Prettier 3.9.6 (first format)
const foo = html`
<div>
${getText({
value,
})}
</div>
`;
// Prettier 3.9.6 (second format)
const foo = html`
<div>
${getText({
value,
})}
</div>
`;
// Prettier 3.9.7
const foo = html`
<div>
${getText({
value,
})}
</div>
`;
<!-- prettier-ignore -->
<!-- Input -->
| Argument | Type |
| -------- | ---- |
{% set default_params = {
"model": ["str"],
} %}
<!-- Prettier 3.9.6 -->
| Argument | Type |
| ------------------------- | ---- |
| {% set default_params = { |
"model": ["str"],
} %}
<!-- Prettier 3.9.7 -->
| Argument | Type |
| -------- | ---- |
{% set default_params = {
"model": ["str"],
} %}
Since 3.9.0, single-tilde spans like H~2~O were rewritten to double tildes, turning subscript syntax into strike-through. Only double tildes are treated that way now, matching GitHub.
<!-- prettier-ignore -->
<!-- Input -->
H~2~O
<!-- Prettier 3.9.6 -->
H~~2~~O
<!-- Prettier 3.9.7 -->
H~2~O
> characters (#19802 by @seiyab)<!-- prettier-ignore -->
<!-- Input -->
> **test**\>
<!-- Prettier 3.9.6 -->
> **test**>\>
<!-- Prettier 3.9.7 -->
> **test**\>
A setext heading spanning multiple lines inside a blockquote kept the > marker of its continuation lines as literal text.
<!-- prettier-ignore -->
<!-- Input -->
> Multi
> Line
> ===
<!-- Prettier 3.9.6 -->
> Multi > Line
> ===
<!-- Prettier 3.9.7 -->
> Multi
> Line
> ===
<!-- prettier-ignore -->
<!-- Input -->
1. Enable images:
<p align="center">
<img alt="example">
</p>
<!-- Prettier 3.9.6 (--tab-width=4) -->
1. Enable images:
<p align="center">
<img alt="example">
</p>
<!-- Prettier 3.9.7 (--tab-width=4) -->
1. Enable images:
<p align="center">
<img alt="example">
</p>
@boundary error boundaries (#20014 by @Yahiro025)<!-- prettier-ignore -->
<!-- Input -->
@boundary {
<complex-chart [data]="data"/>
}
@error (let err) {
<p>{{err.message}}</p>
}
<!-- Prettier 3.9.6 -->
SyntaxError: Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.) (6:1)
<!-- Prettier 3.9.7 -->
@boundary {
<complex-chart [data]="data" />
} @error (let err) {
<p>{{ err.message }}</p>
}
Preserve quotes for methods named new ( #19621 by @kovsu )
new (#19621 by @kovsu)<!-- prettier-ignore -->
// Input
interface Container {
"new"(id: string): number;
}
// Prettier 3.9.5
interface Container {
new(id: string): number;
}
// Prettier 3.9.6
interface Container {
"new"(id: string): number;
}
import defer (#19624, #19675 by @fisker)<!-- prettier-ignore -->
// Input
import defer * as foo from "foo";
// Prettier 3.9.5
import * as foo from "foo";
// Prettier 3.9.6
import defer * as foo from "foo";
@prettier/plugin-yuku (#19628, #19629 by @fisker)@prettier/plugin-yuku is powered by Yuku (A high-performance JavaScript/TypeScript compiler toolchain written in Zig).
This plugin includes two new parsers: yuku (JavaScript syntax) and yuku-ts (TypeScript syntax).
To use this plugin:
Install the plugin:
yarn add --dev prettier @prettier/plugin-yuku
Add it to your .prettierrc:
plugins:
- "@prettier/plugin-yuku"
Due to package size limitations, this plugin is not bundled with the main prettier package and must be installed separately.
For more information, check the package homepage.
Big thanks to @arshad-yaseen for his excellent work.
🔗 Changelog
CommonMark parsers only support ordered list item numbers up to 999,999,999.
With this change, Prettier now caps the ordered list item number at 999,999,999 to ensure that the output is correctly parsed as an ordered list by CommonMark parsers. Numbers larger than 999,999,999 are not parsed as list item numbers and are left unchanged in the output:
<!-- prettier-ignore -->
<!-- Input -->
999999998. text
999999998. text
999999998. text
999999998. text
1234567890123456789012) text
<!-- Prettier 3.9.4 -->
999999998. text
999999999. text
1000000000. text
1000000001. text
1234567890123456789012) text
<!-- Prettier 3.9.5 -->
999999998. text
999999999. text
999999999. text
999999999. text
1234567890123456789012) text
Do not remove <> from an inline link or image with an empty URL and a title, as this removal would change its interpretation.
<!-- prettier-ignore -->
<!-- Input -->
[link](<> "title")
<!-- Prettier 3.9.4 -->
[link]( "title")
<!-- Prettier 3.9.5 -->
[link](<> "title")
[ in map lookups (#19503 by @kovsu)<!-- prettier-ignore -->
// Input
.foo {
color: #theme[ primary];
color: #theme[@name];
color: #theme[@@name];
}
// Prettier 3.9.4
.foo {
color: #theme[ primary];
color: #theme[ @name];
color: #theme[ @@name];
}
// Prettier 3.9.5
.foo {
color: #theme[primary];
color: #theme[@name];
color: #theme[@@name];
}
type() with + (#19516 by @bigandy)This fixes the addition space before + in CSS type() declaration. For example type(<number>+) was being converted into type(<number> +) which is invalid CSS and does not work.
<!-- prettier-ignore -->
/* Input */
div {
border-radius: attr(br type(<length>+));
}
/* Prettier 3.9.4 */
div {
border-radius: attr(br type(<length> +));
}
/* Prettier 3.9.5 */
div {
border-radius: attr(br type(<length>+));
}
<!-- prettier-ignore -->
// Input
a {
box-shadow + : 0 0 1px #000;
}
// Prettier 3.9.4
a {
box-shadow+ : 0 0 1px #000;
}
// Prettier 3.9.5
a {
box-shadow+: 0 0 1px #000;
}
<!-- prettier-ignore -->
<!-- Input -->
[[Foo:Bar]]
<!-- Prettier 3.9.4 -->
[[Foo]]
<!-- Prettier 3.9.5 -->
[[Foo:Bar]]
type import/export specifiers (#19565 by @kirkwaiblinger)<!-- prettier-ignore -->
// Input
export { type /* comment */ T } from "foo";
import { type /* comment */ T } from "foo";
// Prettier 3.9.4
Error: Comment "comment" was not printed. Please report this error!
// Prettier 3.9.5
export { type /* comment */ T } from "foo";
import { type /* comment */ T } from "foo";
placement property (#19567 by @Janther)Prettier@3.9.0 deleted an undocumented property on comments, which was already used by plugins, comment.placement is now available again after comment attach.
<!-- prettier-ignore -->
// Input
declare module "foo" {}
// Prettier 3.9.4
declare module "foo" {
}
// Prettier 3.9.5
declare module "foo" {}
<!-- prettier-ignore -->
<!-- Input -->
@switch (state.mode) {
@default never(state);
}
<!-- Prettier 3.9.4 -->
@switch (state.mode) {
@default never;
}
<!-- Prettier 3.9.5 -->
@switch (state.mode) {
@default never(state);
}
<!-- prettier-ignore -->
// Input
foo<{
// comment
[key in keyof Foo]: number
}>();
// Prettier 3.9.4
foo<
{
// comment
[key in keyof Foo]: number;
}
>();
// Prettier 3.9.5
foo<{
// comment
[key in keyof Foo]: number;
}>();
<!-- prettier-ignore -->
// Input
/* a *//* b */
/* a */* {
color: red;
}
// Prettier 3.9.4
/* a */
/* b */
/* a * {
color: red;
}
// Prettier 3.9.5
/* a */ /* b */
/* a */
* {
color: red;
}
SwitchStatement (#19581 by @fisker)<!-- prettier-ignore -->
// Input
switch (foo) {
// comment
}
// Prettier 3.9.4
switch (
foo
// comment
) {
}
// Prettier 3.9.5
switch (foo) {
// comment
}
<!-- prettier-ignore -->
// Input
var foo = {
/* comment */
};
type Foo = {
/* comment */
};
// Prettier 3.9.4
var foo = {/* comment */};
type Foo = { /* comment */ };
// Prettier 3.9.5
var foo = {/* comment */};
type Foo = {/* comment */};
Angular: Format @content(name) -> @content (name) to align with other block syntax ( #19499 by @fisker )
@content(name) -> @content (name) to align with other block syntax (#19499 by @fisker)<!-- prettier-ignore -->
<!-- Input -->
<FancyButton [label]="title">
@content (icon) {
<span>Icon!</span>
}
@content (description) {
<span>Description text</span>
}
<span>Other children</span>
</FancyButton>
<!-- Prettier 3.9.3 -->
<FancyButton [label]="title">
@content(icon) {
<span>Icon!</span>
}
@content(description) {
<span>Description text</span>
}
<span>Other children</span>
</FancyButton>
<!-- Prettier 3.9.4 -->
<FancyButton [label]="title">
@content (icon) {
<span>Icon!</span>
}
@content (description) {
<span>Description text</span>
}
<span>Other children</span>
</FancyButton>
Markdown: Fix unexpected removal of characters in liquid syntax ( #19489 by @seiyab )
<!-- prettier-ignore -->
// Input
<!-- Input -->
{{ page.title
}} text
<!-- Prettier 3.9.1 -->
{{ page.title
text
<!-- Prettier 3.9.3 -->
{{ page.title
}} text
Extensively used within the Ember ecosystem, decorators with declare on class fields will ignore the babel parser error and allow Prettier to format the code without breaking it.
<!-- prettier-ignore -->
// Input
export default class ProjectStatusComponent extends Component<ProjectStatusSig> {
@service declare server: ServerService;
}
// Prettier 3.9.1
// SyntaxError: Decorators can't be used with a declare field. (2:3)
// 1 | export default class ProjectStatusComponent extends Component<ProjectStatusSig> {
//> 2 | @service declare server: ServerService;
// | ^
// 3 | }
// Prettier 3.9.3
export default class ProjectStatusComponent extends Component<ProjectStatusSig> {
@service declare server: ServerService;
}
Nothing published for this version
CLI: Fix ignored file has been cached incorrectly ( #19483 by @kovsu )
Bug details https://github.com/prettier/prettier/issues/18016
🔗 Prettier 3.9: Major parser upgrades and Formatting improvements
Fix Flow variance annotation print ( #19022 by @marcoww6 )
readonly as a variance annotation (#19022 by @marcoww6)Flow now accepts readonly as a property variance annotation, equivalent to + (covariant/read-only).
<!-- prettier-ignore -->
// Input
type T = {
readonly foo: string,
};
// Prettier 3.8.4
SyntaxError
// Prettier 3.8.5
type T = {
readonly foo: string,
};
Markdown: Fix blank lines between list items and nested sub-lists being removed in Markdown/MDX ( #17746 by @byplayer )
Prettier was removing blank lines between list items and their nested sub-lists, converting loose lists into tight lists and changing their semantic meaning.
<!-- prettier-ignore -->
<!-- Input -->
- a
- b
- c
- d
<!-- Prettier 3.8.3 -->
- a
- b
- c
- d
<!-- Prettier 3.8.4 -->
- a
- b
- c
- d
SCSS: Prevent trailing comma in if() function ( #18471 by @kovsu )
if() function (#18471 by @kovsu)<!-- prettier-ignore -->
// Input
$value: if(sass(false): 1; else: -1);
// Prettier 3.8.2
$value: if(
sass(false): 1; else: -1,
);
// Prettier 3.8.3
$value: if(sass(false): 1; else: -1);
- Support Angular v21.2 🔗 Changelog
Exhaustive typechecking with @default never;
<!-- prettier-ignore -->
<!-- Input -->
@switch (foo) {
@case (1) {}
@default never;
}
<!-- Prettier 3.8.1 -->
SyntaxError: Incomplete block "default never". If you meant to write the @ character, you should use the "@" HTML entity instead. (3:3)
<!-- Prettier 3.8.2 -->
@switch (foo) {
@case (1) {}
@default never;
}
arrow function and instanceof expressions.
<!-- prettier-ignore -->
<!-- Input -->
@let fn = (a) => a? 1:2;
{{ fn ( a instanceof b)}}
<!-- Prettier 3.8.1 -->
@let fn = (a) => a? 1:2;
{{ fn ( a instanceof b)}}
<!-- Prettier 3.8.2 -->
@let fn = (a) => (a ? 1 : 2);
{{ fn(a instanceof b) }}
Include available printers in plugin type declarations (#18706 by @porada)
printers in plugin type declarations (#18706 by @porada)<!-- prettier-ignore -->
// Input
import * as prettierPluginEstree from "prettier/plugins/estree";
// Prettier 3.8.0
// Property 'printers' does not exist on type 'typeof import("prettier/plugins/estree")'. ts(2339)
prettierPluginEstree.printers.estree; //=> any
// Prettier 3.8.1
prettierPluginEstree.printers.estree; //=> Printer
prettierPluginEstree.printers["estree-json"]; //=> Printer
🔗 Release note "Prettier 3.8: Support for Angular v21.1"
Fix comment in union type gets duplicated by @fisker in https://github.com/prettier/prettier/pull/18393
<!-- prettier-ignore -->
<!-- Input -->
<div foo={bar}> </div>
<!-- Prettier 3.7.3 (--embedded-language-formatting off) -->
<div foo="{bar}"></div>
<!-- Prettier 3.7.4 (--embedded-language-formatting off) -->
<div foo={bar}></div>
<!-- prettier-ignore -->
// Input
type Foo = (/** comment */ a | b) | c;
// Prettier 3.7.3
type Foo = /** comment */ (/** comment */ a | b) | c;
// Prettier 3.7.4
type Foo = /** comment */ (a | b) | c;
<!-- prettier-ignore -->
// Input
type X = (A | B) & (
// comment
A | B
);
// Prettier 3.7.3 (first format)
type X = (A | B) &
(// comment
A | B);
// Prettier 3.7.3 (second format)
type X = (
| A
| B // comment
) &
(A | B);
// Prettier 3.7.4
type X = (A | B) &
// comment
(A | B);
Fix prettier.getFileInfo() change that breaks VSCode extension by @fisker in https://github.com/prettier/prettier/pull/18375
prettier.getFileInfo() change that breaks VSCode extension by @fisker in https://github.com/prettier/prettier/pull/18375prettier.getFileInfo() change that breaks VSCode extension (#18375 by @fisker)An internal refactor accidentally broke the VSCode extension plugin loading.
Fix string print when switching quotes by @fisker in https://github.com/prettier/prettier/pull/18351
<!-- prettier-ignore -->
// Input
console.log("A descriptor\\'s .kind must be \"method\" or \"field\".")
// Prettier 3.7.1
console.log('A descriptor\\'s .kind must be "method" or "field".');
// Prettier 3.7.2
console.log('A descriptor\\\'s .kind must be "method" or "field".');
<!-- prettier-ignore -->
// Input
const html = /* HTML */ ` <div class="${styles.banner}"></div> `;
// Prettier 3.7.1
const html = /* HTML */ ` <div class=${styles.banner}></div> `;
// Prettier 3.7.2
const html = /* HTML */ ` <div class="${styles.banner}"></div> `;
<!-- prettier-ignore -->
// Input
export type XXX = {
// tbd
};
// Prettier 3.7.1
export type XXX = { // tbd };
// Prettier 3.7.2
export type XXX = {
// tbd
};
Fix performance regression in doc printer (#18342 by @fisker)
Prettier 3.7.0 can be very slow when formatting big files, the regression has been fixed.
diff 🔗 Release note
Add missing blank line around code block by @fisker in https://github.com/prettier/prettier/pull/17675
<!-- prettier-ignore -->
<!-- Input -->
1. Some text, and code block below, with newline after code block
```yaml
---
foo: bar
```
1. Another
2. List
<!-- Prettier 3.6.1 -->
1. Some text, and code block below, with newline after code block
```yaml
---
foo: bar
```
1. Another
2. List
<!-- Prettier 3.6.2 -->
1. Some text, and code block below, with newline after code block
```yaml
---
foo: bar
```
1. Another
2. List
Fix "Warning: File descriptor 39 closed but not opened in unmanaged mode" error when running --experimental-cli
--experimental-cli<!-- prettier-ignore -->
// Input
export const version: string;
// Prettier 3.6.0 (--parser=babel-ts)
SyntaxError: Unexpected token (1:21)
> 1 | export const version: string;
| ^
// Prettier 3.6.0 (--parser=oxc-ts)
SyntaxError: Missing initializer in const declaration (1:14)
> 1 | export const version: string;
| ^^^^^^^^^^^^^^^
// Prettier 3.6.1
export const version: string;
When reading a file to infer the interpreter from a shebang, we use the
n-readlines library to read the first line in order to get the shebang.
This library closes files when it reaches EOF, and we later try close the same
files again. We now close files only if n-readlines did not already close
them.
🔗 Release note "Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins!"
🔗 Changelog
ConditionalTypeAnnotation (#17196 by @fisker)<!-- prettier-ignore -->
// Input
type T<U> = 'a' | ('b' extends U ? 'c' : empty);
type T<U> = 'a' & ('b' extends U ? 'c' : empty);
// Prettier 3.5.2
type T<U> = "a" | "b" extends U ? "c" : empty;
type T<U> = "a" & "b" extends U ? "c" : empty;
// Prettier 3.5.3
type T<U> = "a" | ("b" extends U ? "c" : empty);
type T<U> = "a" & ("b" extends U ? "c" : empty);
🔗 Changelog
module-sync condition (#17156 by @fisker)In Prettier 3.5.0, we added module-sync condition to package.json, so that require("prettier") can use ESM version, but turns out it doesn't work if CommonJS and ESM plugins both imports builtin plugins. To solve this problem, we decide simply remove the module-sync condition, so require("prettier") will still use the CommonJS version, we'll revisit until require(ESM) feature is more stable.
🔗 Changelog
Prettier 3.5 uses a different cache format than previous versions, Prettier 3.5.0 crashes when reading existing cache file, Prettier 3.5.1 fixed the problem.
Prettier now supports the dockercompose and github-actions-workflow languages in Visual Studio Code.
diff 🔗 Release note
🔗 Changelog
Prettier doesn't treat U+30A0 & U+30FB as Japanese. U+30FB is commonly used in Japanese to represent the delimitation of first and last names of non-Japanese people or “and”. The following “C言語・C++・Go・Rust” means “C language & C++ & Go & Rust” in Japanese.
<!-- prettier-ignore -->
<!-- Input (--prose-wrap=never) -->
C言
語
・
C++
・
Go
・
Rust
<!-- Prettier 3.4.1 -->
C言語・ C++ ・ Go ・ Rust
<!-- Prettier 3.4.2 -->
C言語・C++・Go・Rust
U+30A0 can be used as the replacement of the - in non-Japanese names (e.g. “Saint-Saëns” (Charles Camille Saint-Saëns) can be represented as “サン゠サーンス” in Japanese), but substituted by ASCII hyphen (U+002D) or U+FF1D (full width hyphen) in many cases (e.g. “サン=サーンス” or “サン=サーンス”).
<!-- prettier-ignore -->
// Input
class A {
@decorator
/**
* The method description
*
*/
async method(foo: Foo, bar: Bar) {
console.log(foo);
}
}
// Prettier 3.4.1
class A {
@decorator
async /**
* The method description
*
*/
method(foo: Foo, bar: Bar) {
console.log(foo);
}
}
// Prettier 3.4.2
class A {
@decorator
/**
* The method description
*
*/
async method(foo: Foo, bar: Bar) {
console.log(foo);
}
}
This bug fix is not language-specific. You may see similar change in any languages. This fixes regression in 3.4.0 so change caused by it should yield same formatting as 3.3.3.
<!-- prettier-ignore -->
// Input
<div>
foo
<span>longlonglonglonglonglonglonglonglonglonglonglonglonglonglongl foo</span>
, abc
</div>;
// Prettier 3.4.1 (first)
<div>
foo
<span>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglongl foo
</span>, abc
</div>;
// Prettier 3.4.1 (second)
<div>
foo
<span>longlonglonglonglonglonglonglonglonglonglonglonglonglonglongl foo</span>
, abc
</div>;
// Prettier 3.4.2
<div>
foo
<span>longlonglonglonglonglonglonglonglonglonglonglonglonglonglongl foo</span>
, abc
</div>;
🔗 Changelog
v-on (#16887 by @fisker)<!-- prettier-ignore -->
<!-- Input -->
<template>
<button @click="foo += 2">Click</button>
</template>
<!-- Prettier 3.4.0 -->
<template>
<button @click="(foo += 2)">Click</button>
</template>
<!-- Prettier 3.4.1 -->
<template>
<button @click="foo += 2">Click</button>
</template>
diff 🔗 Release note
🔗 Changelog
This change adds clarity to operator precedence.
<!-- prettier-ignore -->
// Input
foo ? bar ?? foo : baz;
foo ?? bar ? a : b;
a ? b : foo ?? bar;
// Prettier 3.3.2
foo ? bar ?? foo : baz;
foo ?? bar ? a : b;
a ? b : foo ?? bar;
// Prettier 3.3.3
foo ? (bar ?? foo) : baz;
(foo ?? bar) ? a : b;
a ? b : (foo ?? bar);
Prevent parentheses around member expressions or tagged template literals from being removed to follow the stricter parsing rules of TypeScript 5.5.
<!-- prettier-ignore -->
// Input
@(foo`tagged template`)
class X {}
// Prettier 3.3.2
@foo`tagged template`
class X {}
// Prettier 3.3.3
@(foo`tagged template`)
class X {}
@let declaration syntax (#16474 by @sosukesuzuki)Adds support for Angular v18 @let declaration syntax.
Please see the following code example. The @let declaration allows you to define local variables within the template:
<!-- prettier-ignore -->
@let name = 'Frodo';
<h1>Dashboard for {{name}}</h1>
Hello, {{name}}
For more details, please refer to the excellent blog post by the Angular Team: Introducing @let in Angular.
We also appreciate the Angular Team for kindly answering our questions to implement this feature.
🔗 Changelog
@ (#16358 by @Princeyadav05)<!-- prettier-ignore -->
{{! Input }}
<div>{{@x.y.z}}</div>
{{! Prettier 3.3.1 }}
<div>{{@x}}</div>
{{! Prettier 3.3.2 }}
<div>{{@x.y.z}}</div>
🔗 Changelog
<!-- prettier-ignore -->
<!-- Input -->
---
foo:
- bar1
- bar2
- bar3
---
Markdown
<!-- Prettier 3.3.0 -->
---
foo:
- bar1
- bar2
- bar3
---
Markdown
<!-- Prettier 3.3.1 -->
---
foo:
- bar1
- bar2
- bar3
---
Markdown
<!-- prettier-ignore -->
<!-- Input -->
---yaml
title: Hello
slug: home
---
<!-- Prettier 3.3.0 -->
---
title: Hello
slug: home
---
<!-- Prettier 3.3.1 -->
---yaml
title: Hello
slug: home
---
<!-- prettier-ignore -->
// Input
import something from "./some-very-very-very-very-very-very-very-very-long-path.json" with { type: "json" };
// Prettier 3.3.0
import something from "./some-very-very-very-very-very-very-very-very-long-path.json" with { type:
"json" };
// Prettier 3.3.1
import something from "./some-very-very-very-very-very-very-very-very-long-path.json" with { type: "json" };
diff 🔗 Release note
🔗 Changelog
Angular v17 supports single string inline styles.
<!-- prettier-ignore -->
// Input
@Component({
template: `<div>...</div>`,
styles: `h1 { color: blue; }`,
})
export class AppComponent {}
// Prettier 3.2.4
@Component({
template: `<div>...</div>`,
styles: `h1 { color: blue; }`,
})
export class AppComponent {}
// Prettier 3.2.5
@Component({
template: `<div>...</div>`,
styles: `
h1 {
color: blue;
}
`,
})
export class AppComponent {}
Computed template should not be considered as Angular component template
<!-- prettier-ignore -->
// Input
const template = "foobar";
@Component({
[template]: `<h1>{{ hello }}</h1>`,
})
export class AppComponent {}
// Prettier 3.2.4
const template = "foobar";
@Component({
[template]: `<h1>{{ hello }}</h1>`,
})
export class AppComponent {}
// Prettier 3.2.5
const template = "foobar";
@Component({
[template]: `<h1>{{ hello }}</h1>`,
})
export class AppComponent {}
"json" parser for tsconfig.json by default (#16012 by @sosukesuzuki)In v3.2.0, we introduced "jsonc" parser which adds trailing comma by default.
When adding a new parser we also define how it will be used based on the linguist-languages data.
tsconfig.json is a special file used by TypeScript, it uses .json file extension, but it actually uses the JSON with Comments syntax. However, we found that there are many third-party tools not recognize it correctly because of the confusing .json file extension.
We decide to treat it as a JSON file for now to avoid the extra configuration step.
To keep using the "jsonc" parser for your tsconfig.json files, add the following to your .prettierrc file
{
"overrides": [
{
"files": ["tsconfig.json", "jsconfig.json"],
"options": {
"parser": "jsonc"
}
}
]
}
<!-- prettier-ignore -->
# Prettier 3.2.4
prettier --file-info tsconfig.json
{ "ignored": false, "inferredParser": "jsonc" }
# Prettier 3.2.5
prettier --file-info tsconfig.json
{ "ignored": false, "inferredParser": "json" }
Fix .eslintrc.json format #15947
.eslintrc.json format #15947Files like .eslintrc.json were incorrectly formatted as JSONC files.
<!-- prettier-ignore -->
// Input
prettier --file-info .eslintrc.json
{ "ignored": false, "inferredParser": "jsonc" }
// Prettier 3.2.4
prettier --file-info .eslintrc.json
{ "ignored": false, "inferredParser": "json" }
Format tsconfig.json file with jsonc parser #15927
tsconfig.json file with jsonc parser #15927<!-- prettier-ignore -->
// Input
1++;
// Prettier 3.2.2
1++;
// Prettier 3.2.3
SyntaxError: Invalid left-hand side expression in unary operation (1:1)
> 1 | 1++;
| ^
<!-- prettier-ignore -->
// Input
try {} catch (error = 1){}
// Prettier 3.2.2
try {
} catch (error) {}
// Prettier 3.2.3
SyntaxError: Catch clause variable cannot have an initializer. (1:23)
> 1 | try {} catch (error = 1){}
| ^
<!-- prettier-ignore -->
// Prettier 3.2.2
prettier --file-info tsconfig.json
{ "ignored": false, "inferredParser": "json" }
// Prettier 3.2.3
prettier --file-info tsconfig.json
{ "ignored": false, "inferredParser": "jsonc" }
🔗 Changelog
For example this code would crash before:
<!-- prettier-ignore -->
<style {...spread}>{`.{}`}</style>
<!-- prettier-ignore -->
// Input
a(() => {}, c?.d());
// Prettier 3.2.1
TypeError: Cannot read properties of undefined (reading 'type')
// Prettier 3.2.2
a(() => {}, c?.d());
🔗 Changelog
<!-- prettier-ignore -->
// Input
test().test2().test2(thing?.something);
// Prettier 3.2.0
TypeError: Cannot read properties of undefined (reading 'type')
// Prettier 3.2.1
test().test2().test2(thing?.something);
diff 🔗 Release note
🔗 Changelog
Previously, we start search for config files from the filePath as a directory, if it happened to be a directory and contains config file, it will be used by mistake.
├─ .prettierrc
└─ test.js (A directory)
└─ .prettierrc
// Prettier 3.1.0
await prettier.resolveConfigFile(new URL("./test.js", import.meta.url));
// <CWD>/test.js/.prettierrc
// Prettier 3.1.1
await prettier.resolveConfigFile(new URL("./test.js", import.meta.url));
// <CWD>/.prettierrc
--no-error-on-unmatched-pattern (#15533 by @sanmai-NL)Since Prettier v3, we stopped following symbolic links, however in some use cases, the symbolic link patterns can't be filtered out, and there is no way to prevent Prettier from throwing errors.
In Prettier 3.1.1, you can use --no-error-on-unmatched-pattern to simply skip symbolic links.
useTabs is true (#15662 by @auvred)<!-- prettier-ignore -->
// Input
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee
? fffffffffffffff
: gggggggggggggggg;
// Prettier 3.1.0
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee
? fffffffffffffff
: gggggggggggggggg;
// Prettier 3.1.1
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee
? fffffffffffffff
: gggggggggggggggg;
The Prettier config file search performance has been improved by more effective cache strategy.
<!-- prettier-ignore -->
// Input
const {
foo,
// bar
// baz
}: Foo = expr;
// Prettier 3.1.0
const {
foo1,
} // bar
// baz
: Foo = expr;
// Prettier 3.1.0 second output
const {
foo1, // bar
} // baz
: Foo = expr;
// Prettier 3.1.1
const {
foo1,
// bar
// baz
}: Foo = expr;
TypeScript 5.3 supports the latest updates to the import attributes proposal.
import something from "./something.json" with { type: "json" };
The cursorOffset option has in fact been compatible with rangeStart/rangeEnd for over 5 years, thanks to work by @ds300. However, Prettier's documentation (including the CLI --help text) continued to claim otherwise, falsely. The documentation is now fixed.
from keyword in empty import statements (#15756 by @fisker)<!-- prettier-ignore -->
// Input
import { } from 'foo';
import { /* comment */ } from 'bar';
// Prettier 3.1.0
import {} from "foo";
import /* comment */ "bar";
// Prettier 3.1.1
import {} from "foo";
import {} from /* comment */ "bar";
<!-- prettier-ignore -->
// Input
import foo from "foo" with {};
import bar from "bar" assert {};
// Prettier 3.1.0
import foo from "foo";
import bar from "bar";
// Prettier 3.1.1
import foo from "foo" with {};
import bar from "bar" assert {};
diff 🔗 Release note
🔗 Changelog
preferUnplugged: true to package.json (#15169 by @fisker and @so1ve)Prettier v3 uses dynamic imports, user will need to unplug Prettier when Yarn's PnP mode is enabled, add preferUnplugged: true to package.json, so Yarn will install Prettier as unplug by default.
require() (#15233 by @fisker)If an external shared config package is used, and the package exports don't have require or default export.
In Prettier 3.0.2 Prettier fails when attempt to require() the package, and throws an error.
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in <packageName>/package.json
require() to break (#15256 by @fisker)<!-- prettier-ignore -->
// Input
const plugin = require(
global.STANDALONE
? path.join(__dirname, "../standalone.js")
: path.join(__dirname, "..")
);
// Prettier 3.0.2
const plugin = require(global.STANDALONE
? path.join(__dirname, "../standalone.js")
: path.join(__dirname, ".."));
// Prettier 3.0.3
const plugin = require(
global.STANDALONE
? path.join(__dirname, "../standalone.js")
: path.join(__dirname, "..")
);
ts code blocks (#15286 by @sosukesuzuki)<!-- prettier-ignore -->
<!-- Input -->
```ts
const foo = <T>() => {}
```
<!-- Prettier 3.0.2 -->
```ts
const foo = <T,>() => {}
```
<!-- Prettier 3.0.3 -->
```ts
const foo = <T>() => {}
```
using / await using declaration (#15321 by @sosukesuzuki)Support for the upcoming Explicit Resource Management feature in ECMAScript. using / await using declaration
<!-- prettier-ignore -->
{
using foo = new Foo();
await using bar = new Bar();
}
🔗 Changelog
= of assignment if RHS is poorly breakable AwaitExpression or YieldExpression (#15204 by @seiyab)<!-- prettier-ignore -->
// Input
const { section, rubric, authors, tags } = await utils.upsertCommonData(mainData);
// Prettier 3.0.1
const { section, rubric, authors, tags } = await utils.upsertCommonData(
mainData,
);
// Prettier 3.0.2
const { section, rubric, authors, tags } =
await utils.upsertCommonData(mainData);
<!-- prettier-ignore -->
/* Input */
$foo: (
'property': (),
// comment 1
// comment 2
)
/* Prettier 3.0.1 */
$foo: (
"property": (),
// comment 1
// comment 2,
);
/* Prettier 3.0.2 */
$foo: (
"property": (),
// comment 1
// comment 2
);
declare and export keywords for nested namespace (#15249 by @sosukesuzuki)<!-- prettier-ignore -->
// Input
declare namespace abc1.def {}
export namespace abc2.def {}
// Prettier 3.0.1
namespace abc1.def {}
namespace abc2.def {}
// Prettier 3.0.2
declare namespace abc1.def {}
export namespace abc2.def {}
🔗 Changelog
<!-- prettier-ignore -->
// <|> is the cursor position
/* Input */
// All messages are represented in JSON.
// So, the prettier.py controls a subprocess which spawns "node {this_file}".
import {<|> } from "fs"
/* Prettier 3.0.0 */
// All messages are represented in JSON.
// So, the prettier.py <|>controls a subprocess which spawns "node {this_file}".
import {} from "fs"
/* Prettier 3.0.1 */
// All messages are represented in JSON.
// So, the prettier.py controls a subprocess which spawns "node {this_file}".
import {<|>} from "fs"
Add export {} in plugins/estree.d.ts to fix the "File is not a module" error
<!-- prettier-ignore -->
// Input
function fn() {
return (
/**
* @type {...}
*/ expression
)
}
// Prettier 3.0.0
function fn() {
return /**
* @type {...}
*/ expression;
}
// Prettier 3.0.1
function fn() {
return (
/**
* @type {...}
*/ expression
);
}
https://blog.vuejs.org/posts/vue-3-3#generic-components
<!-- prettier-ignore -->
<!-- Input -->
<script setup lang="ts" generic="T extends Type1 & Type2 & (Type3 | Type4), U extends string | number | boolean"></script>
<!-- Prettier 3.0.0 -->
<script
setup
lang="ts"
generic="T extends Type1 & Type2 & (Type3 | Type4), U extends string | number | boolean"
></script>
<!-- Prettier 3.0.1 -->
<script
setup
lang="ts"
generic="
T extends Type1 & Type2 & (Type3 | Type4),
U extends string | number | boolean
"
></script>
IfStatement (#15076 by @fisker)<!-- prettier-ignore -->
function a(b) {
if (b) return 1; // comment
else return 2;
}
/* Prettier 3.0.0 */
Error: Comment "comment" was not printed. Please report this error!
/* Prettier 3.0.1 */
function a(b) {
if (b) return 1; // comment
else return 2;
}
printer.preprocess (#15123 by @so1ve)export interface Printer<T = any> {
// ...
+ preprocess?:
+ | ((ast: T, options: ParserOptions<T>) => T | Promise<T>)
+ | undefined;
}
getVisitorKeys method type definition for Printer (#15125 by @auvred)const printer: Printer = {
print: () => [],
getVisitorKeys(node, nonTraversableKeys) {
return ["body"];
},
};
readonly array properties of AST Node (#15127 by @auvred)<!-- prettier-ignore -->
// Input
interface TestNode {
readonlyArray: readonly string[];
}
declare const path: AstPath<TestNode>;
path.map(() => "", "readonlyArray");
// Prettier 3.0.0
interface TestNode {
readonlyArray: readonly string[];
}
declare const path: AstPath<TestNode>;
path.map(() => "", "readonlyArray");
// ^ Argument of type '"readonlyArray"' is not assignable to parameter of type '"regularArray"'. ts(2345)
// Prettier 3.0.1
interface TestNode {
readonlyArray: readonly string[];
}
declare const path: AstPath<TestNode>;
path.map(() => "", "readonlyArray");
<!-- prettier-ignore -->
// Input
div {
margin: - func();
}
// Prettier 3.0.0
div {
margin: -func();
}
// Prettier 3.0.1
div {
margin: - func();
}
Your coding agent can read these notes before it upgrades. Set up the MCP server →