惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
美团技术团队
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
L
LangChain Blog
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 叶小钗
Engineering at Meta
Engineering at Meta
腾讯CDC
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
有赞技术团队
有赞技术团队
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
博客园 - 司徒正美
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
C
Check Point Blog
小众软件
小众软件
V
Visual Studio Blog
V
V2EX
F
Full Disclosure
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
罗磊的独立博客
人人都是产品经理
人人都是产品经理
量子位
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
博客园_首页
Y
Y Combinator Blog
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
Recorded Future
Recorded Future
G
Google Developers Blog
Vercel News
Vercel News
大猫的无限游戏
大猫的无限游戏
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
爱范儿
爱范儿
Jina AI
Jina AI

Prettier Blog

Prettier 3.8: Support for Angular v21.1 Prettier 3.7: Improved formatting consistency and new plugin features! Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins! Prettier 3.5: New objectWrap option, experimentalOperatorPosition option and TS config file support! Prettier 3.4: A lot of bug fixes Prettier 3.3: New Flow features and a lot of bug fixes Prettier 3.2: Support JSONC and Angular’s ICU expression Prettier's CLI: A Performance Deep Dive $20k Bounty was Claimed! Prettier 3.1: New experimental ternaries formatting and Angular control flow syntax! A curious case of the ternaries Prettier 3.0: Hello, ECMAScript Modules! Prettier 2.8: improve --cache CLI option and TypeScript 4.9 satisfies operator! Prettier 2.7: new --cache CLI option and TypeScript 4.7 syntax! Prettier 2.6: new singleAttributePerLine option and new JavaScript features! Prettier begins paying maintainers Prettier 2.5: TypeScript 4.5 and MDX v2 comment syntax! Prettier 2.4: new bracketSameLine option and TypeScript 4.4 support! Prettier 2.3. In which assignments are consistent, short keys non-breaking, and Handlebars official Prettier for Ruby goes v1.0 🎉
Prettier 3.9: Major parser upgrades and Formatting improvements
Fisker Cheung · 2026-06-27 · via Prettier Blog

We are excited to announce Prettier 3.9!

This release brings major parser upgrades for Markdown, YAML, Flow, GraphQL, and Angular, along with formatting improvements for JavaScript and TypeScript (particularly in --no-semi mode).

If you find Prettier valuable, please consider sponsoring us on OpenCollective or supporting the upstream projects we rely on. Your contributions help us keep improving the tool for everyone.

Thank you for your continued support! ❤️

A reminder, when Prettier is installed or updated, it’s strongly recommended to specify the exact version in package.json: "prettier": "3.9.0", not "prettier": "^3.9.0".

If you use @prettier/plugin-oxc or @prettier/plugin-hermes, don't forget upgrade them to ensure the new formatting rules are applied.

Highlights

Markdown

Upgrade parser to latest micromark (#18277 by @seiyab, @j-f1, @fisker)

We've upgraded Prettier's Markdown parser from the outdated remark-parse v8 to the modern micromark v4. This upgrade significantly enhances CommonMark and GFM compliance, resolves numerous long-standing parsing bugs, and lays a stronger foundation for future enhancements.

Huge thanks to @seiyab, @j-f1, and everyone else who contributed to this long-awaited improvement for their tremendous effort in driving this major upgrade!

Note: While the core Markdown parser has been upgraded, the MDX parser upgrade is not yet complete. If you're familiar with the unified ecosystem, micromark, or MDX, we'd love your help to finish the migration — contributions are very welcome!

YAML

Update dependency yaml to v2 (#18419 by @ota-meshi, @fisker)

The YAML parser has been upgraded to use yaml v2, which fixes many long standing parse issues.

Thanks to excellent work on the yaml-unist-parser side by @ota-meshi.

GraphQL

Support GraphQL.js v17 (#19171 by @YBJ0000, #19297 by @fisker)

Prettier now fully supports newer syntax features from GraphQL.js v17, including directives on directive definitions, fragment arguments, and other enhancements.

Fragment arguments

# Input

fragment variableProfilePic on User {

...dynamicProfilePic(size: $size)

}

# Prettier 3.8

SyntaxError: Syntax Error: Expected Name, found "(". (2:23)

# Prettier 3.9

fragment variableProfilePic on User {

...dynamicProfilePic(size: $size)

}

Directives on directive definitions (and extend directive extensions)

# Input

directive @a @b on QUERY

extend directive @a @b

# Prettier 3.8

Error: Syntax Error: Expected "on", found "@".

# Prettier 3.9

directive @a @b on QUERY

extend directive @a @b

Flow

New Rust-based Flow parser (#19398 by @SamChou19815)

Prettier now uses the new Rust-based Flow parser (oxidized) released by the Flow team, which improves performance for Flow-typed code.

In local parser-only benchmarks, the new parser parsed Prettier's valid Flow fixtures in 266.4ms median time, compared with 422.6ms for the old parser, and parsed flow_parser.js in 1298.0ms, compared with 2269.6ms.

Other Changes

JavaScript

Stabilize comment around break and continue in no-semi mode (#7161 by @thorn0, @fisker)

// Input

for (;;) {

if (condition) {

break; // breaking comment

(possibleArray || []).sort()

}

}

// Prettier 3.8 (--no-semi, first format)

for (;;) {

if (condition) {

break // breaking comment

;(possibleArray || []).sort()

}

}

// Prettier 3.8 (--no-semi, second format)

for (;;) {

if (condition) {

break // breaking comment

;(possibleArray || []).sort()

}

}

// Prettier 3.9 (--no-semi, both first and second format)

for (;;) {

if (condition) {

break; // breaking comment

(possibleArray || []).sort();

}

}

Remove redundant parentheses in "return statement" (#18142 by @fisker)

// Input

function sequenceExpressionInside() {

return ( // Reason for a

a, b

);

}

// Prettier 3.8

function sequenceExpressionInside() {

return (

// Reason for a

(a, b)

);

}

// Prettier 3.9

function sequenceExpressionInside() {

return (

// Reason for a

a, b

);

}

Fix alignment in embedded template interpolations (#18380 by @fisker)

// Input

string = `

.class {

flex-direction: column${

long_cond && long_cond && long_cond

? "-reverse" :

""

};

}

`;

css = css`

.class {

flex-direction: column${

long_cond && long_cond && long_cond

? "-reverse" :

""

};

}

`;

// Prettier 3.8

string = `

.class {

flex-direction: column${

long_cond && long_cond && long_cond ? "-reverse" : ""

};

}

`;

css = css`

.class {

flex-direction: column${long_cond && long_cond && long_cond

? "-reverse"

: ""};

}

`;

// Prettier 3.9

string = `

.class {

flex-direction: column${

long_cond && long_cond && long_cond ? "-reverse" : ""

};

}

`;

css = css`

.class {

flex-direction: column${

long_cond && long_cond && long_cond ? "-reverse" : ""

};

}

`;

Avoid linebreaks in embedded template interpolations (#18380 by @fisker)

// Input

string = /* Comment */ `

<div>${long_cond && long_cond && long_cond && long_cond && long_cond ? "content" : ""}</div>

`;

html = /* HTML */ `

<div>${long_cond && long_cond && long_cond && long_cond && long_cond ? "content" : ""}</div>

`;

// Prettier 3.8

string = /* Comment */ `

<div>${long_cond && long_cond && long_cond && long_cond && long_cond ? "content" : ""}</div>

`;

html = /* HTML */ `

<div>

${long_cond && long_cond && long_cond && long_cond && long_cond

? "content"

: ""}

</div>

`;

// Prettier 3.9

string = /* Comment */ `

<div>${long_cond && long_cond && long_cond && long_cond && long_cond ? "content" : ""}</div>

`;

html = /* HTML */ `

<div>

${long_cond && long_cond && long_cond && long_cond && long_cond ? "content" : ""}

</div>

`;

Improve logical not expression print (#18397, #18401 by @fisker)

  • Fixed inner logical expression can be double parenthesized in some case.
  • Inline the expression in if/while/do..while condition, to reduce diff when changing condition to negated value.

// Input

if (!(

// `import("foo")`

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

)) {

} else if (

// `import("foo")`

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

) {

}

// Prettier 3.8

if (

!(

// `import("foo")`

(

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

)

)

) {

} else if (

// `import("foo")`

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

) {

}

// Prettier 3.9

if (!(

// `import("foo")`

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

)) {

} else if (

// `import("foo")`

node.type === "ImportExpression" ||

// `type foo = import("foo")`

node.type === "TSImportType"

) {

}

This code example above is a real world case right here in the Prettier codebase

Remove unexpected space inserted before expression in CSS selectors (#18460 by @kovsu)

// Input

css`foo:${bar} {}`

// Prettier 3.8

css`

foo: ${bar} {

}

`;

// Prettier 3.9

css`

foo:${bar} {

}

`;

Keep iife function comments in parentheses (#18538 by @fisker)

// Input

const a = (

/**

* @param {number} foo

* @return {number}

*/

function (foo) {

return foo + 1;

}

)(1);

// Prettier 3.8

const a = /**

* @param {number} foo

* @return {number}

*/

(function (foo) {

return foo + 1;

})(1);

// Prettier 3.9

const a = (

/**

* @param {number} foo

* @return {number}

*/

function (foo) {

return foo + 1;

}

)(1);

Fix comment print for parenthesized callee (#18540 by @fisker)

// Input

const a = (

function(){}

/* comment for callee */

)(),

b = (

function(){}

)(/* comment for call */)

// Prettier 3.8

const a = (function () {})(),

/* comment for callee */

b = (function () {})(/* comment for call */);

// Prettier 3.9

const a = (

function () {}

/* comment for callee */

)(),

b = (function () {})(/* comment for call */);

Preserve trailing double spaces in JSDoc (#18594 by @seiyab)

Some tools treat these spaces as meaningful.

await prettier.format("/**\n * With 2 spaces \n */", { parser: "babel" });

/* Prettier 3.8 */

// -> '/**\n * With 2 spaces\n */\n'

/* Prettier 3.9 */

// -> '/**\n * With 2 spaces \n */\n'

// ^^ space preserved

Drop support for the old "import assertions" syntax (#18611 by @fisker)

import assertions (using the assert keyword) is an old version of the current import attributes proposal.

// Old (deprecated)

import foo from "./foo.json" assert { type: "json" };

// Current standard

import foo from "./foo.json" with { type: "json" };

Babel 8 completely removed support for the legacy assert syntax (the old parser plugin is gone). Without Babel parser support, Prettier can no longer reliably parse or format code using import ... assert { ... }.

Please migrate to the with syntax.

- import foo from "./foo.json" assert { type: "json" };

+ import foo from "./foo.json" with { type: "json" };

See also Prettier's disclaimer about non-standard syntax.

Improve comment handling around empty call argument list (#18615 by @fisker)

// Input

call

// line comment

();

call(// line comment

);

call(

// line comment

);

call

/* block comment */

();

call(/* block comment */

);

call(

/* block comment */

);

// Prettier 3.8

call();

// line comment

call(); // line comment

call();

// line comment

call();

/* block comment */

call /* block comment */();

call();

/* block comment */

// Prettier 3.9

call

// line comment

();

call(

// line comment

);

call(

// line comment

);

call

/* block comment */

();

call(/* block comment */);

call(/* block comment */);

Fix unstable comment in call expression (#18615 by @fisker)

// Input

foo =

call(

/* call argument */);

// Prettier 3.8 (First format)

foo =

call();

/* call argument */

// Prettier 3.8 (Second format)

foo = call();

/* call argument */

// Prettier 3.9

foo = call(/* call argument */);

Allow empty call expression argument list with long comments to break (#18615 by @fisker)

// Input

call(/* a long long long long long long long long long long long long comment */);

array = [/* a long long long long long long long long long long long long comment */];

object = {/* a long long long long long long long long long long long long comment */};

// Prettier 3.8

call(/* a long long long long long long long long long long long long comment */);

array = [

/* a long long long long long long long long long long long long comment */

];

object = {

/* a long long long long long long long long long long long long comment */

};

// Prettier 3.9

call(

/* a long long long long long long long long long long long long comment */

);

array = [

/* a long long long long long long long long long long long long comment */

];

object = {

/* a long long long long long long long long long long long long comment */

};

Don't force empty array and object with short comments to break (#18617 by @fisker)

// Input

const array = [/* comment */]

const object = {/* comment */}

// Prettier 3.8

const array = [

/* comment */

];

const object = {

/* comment */

};

// Prettier 3.9

const array = [/* comment */];

const object = {/* comment */};

Fix dangling comment print in function parameters (#18623 by @fisker)

// Input

fn = function(

// comment

) {}

arrow = (

// comment

) => {}

// Prettier 3.8

fn = function () // comment

{};

arrow = () =>

// comment

{};

// Prettier 3.9

fn = function (

// comment

) {};

arrow = (

// comment

) => {};

Fix inconsistent comment attach between NewExpression and CallExpression (#18669 by @fisker)

// Input

foo( // comment

bar

);

new Foo( // comment

bar

);

// Prettier 3.8

foo(

// comment

bar,

);

new Foo(bar); // comment

// Prettier 3.9

foo(

// comment

bar,

);

new Foo(

// comment

bar,

);

Fix missing parentheses around optional chaining (#18720 by @fisker)

// Input

(a?.b()).c();

// Prettier 3.8

a?.b().c();

// Prettier 3.9

(a?.b()).c();

Fix range format on variable declaration (#18734, #18740 by @fisker)

// Input

let i ="format me!" ;

// ^^^^^^^^^^^^^^ Range

// Prettier 3.8

let i = "format me!"; ;

// Prettier 3.9

let i = "format me!";

Improve blank line detection between statements (#18736 by @fisker)

// Input

const exports = text

.matchAll(/(?<=\n)exports\.(?<specifier>\w+) = \k<specifier>;/g)

.map((match) => match.groups.specifier)

.toArray()

;

foo();

// Prettier 3.8 (--no-semi)

const exports = text

.matchAll(/(?<=\n)exports\.(?<specifier>\w+) = \k<specifier>;/g)

.map((match) => match.groups.specifier)

.toArray();

foo();

// Prettier 3.9

const exports = text

.matchAll(/(?<=\n)exports\.(?<specifier>\w+) = \k<specifier>;/g)

.map((match) => match.groups.specifier)

.toArray();

foo();

Preserve empty line before ; in no-semi mode (#18736, #18737 by @fisker)

// Input

a

;[].b()

// Prettier 3.8 (--no-semi)

a

;[].b()

// Prettier 3.9

a

;[].b()

Print leading semicolon before type cast comments (#18751 by @fisker)

// Input

;/** @type {string[]} */ (['foo', 'bar']).forEach(doStuff)

// Prettier 3.8 (--no-semi, first format)

/** @type {string[]} */ ;(["foo", "bar"]).forEach(doStuff)

// Prettier 3.8 (--no-semi, second format)

/** @type {string[]} */ ;["foo", "bar"].forEach(doStuff)

// Prettier 3.9 (--no-semi)

;/** @type {string[]} */ (["foo", "bar"]).forEach(doStuff)

Prevent moving comments after arrow into parameters (#18775 by @fisker)

// Input

KEYPAD_NUMBERS.map(num => ( // Buttons 0-9

<div />

));

const createIdFilter =

(foo) => /** @param {string} id */

(id) => id;

// Prettier 3.8

KEYPAD_NUMBERS.map(

(

num // Buttons 0-9

) => <div />

);

const createIdFilter = (foo /** @param {string} id */) => (id) => id;

// Prettier 3.9

KEYPAD_NUMBERS.map((num) => (

// Buttons 0-9

<div />

));

const createIdFilter = (foo) => /** @param {string} id */ (id) => id;

Fix comments above else (#18813 by @fisker)

// Input

/* Case 1 */

if (1) {

}

/* Case 2 */

else if (2) {

}

// Prettier 3.8

/* Case 1 */

if (1) {

} else if (2) {

/* Case 2 */

}

// Prettier 3.9

/* Case 1 */

if (1) {

}

/* Case 2 */

else if (2) {

}

Fix "comment not printed" error in debugger statement (#18840 by @fisker)

// Input

debugger // Comment

;

// Prettier 3.8

Error: Comment "comment" was not printed. Please report this error!

// Prettier 3.9

debugger; // Comment

Improve do..while print in no-semi mode (#18851 by @fisker)

// Input

do {

doStuff()

} while (1)

// comment

;[foo, bar].forEach(doStuff)

// Prettier 3.8

do {

doStuff()

} while (

1

// comment

)

;[foo, bar].forEach(doStuff)

// Prettier 3.9

do {

doStuff()

} while (1)

// comment

;[foo, bar].forEach(doStuff)

Fix duplicated comments in empty branches with experimentalTernaries (#18963 by @kovsu)

// Input

condition ? ifTrue

: [

// Hello, world!

];

// Prettier 3.8 (--experimental-ternaries)

condition ? ifTrue

// Hello, world!

: (

[

// Hello, world!

]

);

// Prettier 3.9 (--experimental-ternaries)

condition ? ifTrue : (

[

// Hello, world!

]

);

Preserve blank lines between JSX attributes (#19161 by @Poliklot)

Prettier now keeps one existing blank line between JSX attributes, consistent with how it preserves blank lines in many other places. Multiple blank lines are still collapsed to one.

// Input

<Button

type="submit"

variant="primary"

size="large"

disabled={isSubmitting}

onClick={handleSubmit}

/>;

// Prettier 3.8

<Button

type="submit"

variant="primary"

size="large"

disabled={isSubmitting}

onClick={handleSubmit}

/>;

// Prettier 3.9

<Button

type="submit"

variant="primary"

size="large"

disabled={isSubmitting}

onClick={handleSubmit}

/>;

Fix multiline JSDoc-style comment alignment in assignments (#19180 by @kovsu)

// Input

const foo = /**

* comment

*/ bar;

// Prettier 3.8

const foo = /**

* comment

*/ bar;

// Prettier 3.9

const foo =

/**

* comment

*/ bar;

Remove space in for statement without "update" expression (#19188 by @Poliklot)

// Input

for (initialize;;) {}

for (; condition;) {}

// Prettier 3.8

for (initialize; ; ) {}

for (; condition; ) {}

// Prettier 3.9

for (initialize; ;) {}

for (; condition;) {}

Fix unstable comment in arrow function with sequence expression body (#19253 by @itsybitsybootsy)

// Input

const fn = () => (a, b, c /* abc */);

// Prettier 3.8

const fn = () => (a, b, c) /* abc */;

// Prettier 3.9

const fn = () => (a, b, c /* abc */);

Fix unstable comment in arrow function with assignment expression body (#19262 by @itsybitsybootsy)

// Input

const fn = () => (a = b /* abc */);

// Prettier 3.8

const fn = () => (a = b) /* abc */;

// Prettier 3.9

const fn = () => (a = b /* abc */);

Keep trailing comments inside the parentheses of a sequence or assignment expression (#19263 by @sarathfrancis90)

// Input

const x = (a, b, c /* comment */);

const y = (a = b /* comment */);

// Prettier 3.8

const x = (a, b, c) /* comment */;

const y = (a = b) /* comment */;

// Prettier 3.9

const x = (a, b, c /* comment */);

const y = (a = b /* comment */);

Improve formatting of comments in objects (#19310 by @fisker)

// Input

const P = {/** X */

Y: "z",

}

// Prettier 3.8

const P = {

/** X */ Y: "z",

};

// Prettier 3.9

const P = {

/** X */

Y: "z",

};

TypeScript

Fix linebreak in member chain (#17251 by @fisker)

// Input

model = types

.model({ something: mxSomething })

.volatile<| "a" | "b">(() => [

annularThingamabobWrapper,

octahedralWeevilService,

cantileveredRhubarbProcessor,

annularPlatypusGenerator,

]);

// Prettier 3.8

model = types

.model({ something: mxSomething })

.volatile<

"a" | "b"

>(() => [annularThingamabobWrapper, octahedralWeevilService, cantileveredRhubarbProcessor, annularPlatypusGenerator]);

// Prettier 3.9

model = types

.model({ something: mxSomething })

.volatile<"a" | "b">(() => [

annularThingamabobWrapper,

octahedralWeevilService,

cantileveredRhubarbProcessor,

annularPlatypusGenerator,

]);

Fix formatting for new expression with type cast (#18507 by @fisker)

// Input

new (require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P)({

rootDir: dir,

});

(

require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P

)({

rootDir: dir,

});

// Prettier 3.8

new (require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P)({

rootDir: dir,

});

(

require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P

)({

rootDir: dir,

});

// Prettier 3.9

new (

require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P

)({

rootDir: dir,

});

(

require("./webpack/plugins/next-trace-entrypoints-plugin")

.TraceEntryPointsPlugin as P

)({

rootDir: dir,

});

Fix line comments jumping past member expression lookups (#18522 by @ulrichstark)

Line comments between a member expression object and property were incorrectly moved past subsequent content like as expressions.

// Input

function getClassNameFromPrototypeMethod(container) {

return ((container // a

.left as PropertyAccessExpression) // b

.expression as PropertyAccessExpression) // c

.expression; // d

}

// Prettier 3.8

function getClassNameFromPrototypeMethod(container) {

return (

(

container.left as PropertyAccessExpression // a

).expression as PropertyAccessExpression // b

).expression; // c // d

}

// Prettier 3.9

function getClassNameFromPrototypeMethod(container) {

return (

(

container // a

.left as PropertyAccessExpression

) // b

.expression as PropertyAccessExpression

) // c

.expression; // d

}

Fix inconsistent formatting of arrow function (#18589 by @fisker)

// Input

a.map(() => ({

name,

}));

a.map(():A => ({

name,

}));

a.map(():{A} => ({

name,

}));

// Prettier 3.8

a.map(() => ({

name,

}));

a.map(

(): A => ({

name,

}),

);

a.map((): { A } => ({

name,

}));

// Prettier 3.9

a.map(() => ({

name,

}));

a.map((): A => ({

name,

}));

a.map((): { A } => ({

name,

}));

Improve comment print inside type arguments (#18619 by @fisker)

// Input

foo<

// Comment

Type

>(

// Comment

value

)

foo<

Type // Comment

>(

)

// Prettier 3.8

foo<// Comment

Type>(

// Comment

value,

);

foo<Type>(); // Comment

// Prettier 3.9

foo<

// Comment

Type

>(

// Comment

value,

);

foo<

Type // Comment

>();

Fix conditional type comment indentation (#18644 by @lindsaycode05)

// Input

type T = any extends B

// Comment

// Multiline comment

? undefined | NonNullable<B>[foo]

: B[foo];

// Prettier 3.8

type T = any extends B

? // Comment

// Multiline comment

undefined | NonNullable<B>[foo]

: B[foo];

// Prettier 3.9

type T = any extends B

? // Comment

// Multiline comment

undefined | NonNullable<B>[foo]

: B[foo];

Fix inconsistent formatting of class superClass (#18652, #18659 by @fisker)

// Input

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName

extends foo.bar.Baz {}

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName

extends foo.bar.Baz! {}

// Prettier 3.8

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName

extends foo.bar.Baz {}

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName extends (foo

.bar.Baz!) {}

// Prettier 3.9

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName

extends foo.bar.Baz {}

class ALongLongLongLongLongLongLongLongLongLongLongLongClassName

extends foo.bar.Baz! {}

Consistent print non-null assertions (#18654 by @fisker)

// Input

const corners = baseCorners.map((corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset))!,

);

const corners = baseCorners.map((corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset)),

);

// Prettier 3.8

const corners = baseCorners.map(

(corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset))!,

);

const corners = baseCorners.map((corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset)),

);

// Prettier 3.9

const corners = baseCorners.map((corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset))!,

);

const corners = baseCorners.map((corner) =>

curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset)),

);

// Input

isEqual(a?.map(([t, _]) => t?.id)!, b?.map(([t, _]) => t?.id));

isEqual(a?.map(([t, _]) => t?.id)!, b?.map(([t, _]) => t?.id)!);

// Prettier 3.8

isEqual(

a?.map(([t, _]) => t?.id)!,

b?.map(([t, _]) => t?.id),

);

isEqual(a?.map(([t, _]) => t?.id)!, b?.map(([t, _]) => t?.id)!);

// Prettier 3.9

isEqual(

a?.map(([t, _]) => t?.id)!,

b?.map(([t, _]) => t?.id),

);

isEqual(

a?.map(([t, _]) => t?.id)!,

b?.map(([t, _]) => t?.id)!,

);

Preserve non-null assertion around optional chaining (#18661 by @fisker)

// Input

(a?.b!).c;

(a?.b)!.c;

(a?.b!)!.c;

// Prettier 3.8

(a?.b)!.c;

(a?.b)!.c;

a?.b!!.c;

// Prettier 3.9

(a?.b!).c;

(a?.b)!.c;

(a?.b!)!.c;

Respect quoteProps option when printing enum keys (#18700, #18703 by @fisker)

// Input

enum E {

A1 = 0,

"A2" = 1,

"A-3" = 2,

}

// Prettier 3.8

enum E {

A1 = 0,

"A2" = 1,

"A-3" = 2,

}

// Prettier 3.9 (--quote-props=as-needed)

enum E {

A1 = 0,

A2 = 1,

"A-3" = 2,

}

// Prettier 3.9 (--quote-props=consistent)

enum E {

"A1" = 0,

"A2" = 1,

"A-3" = 2,

}

Respect quoteProps in method signature (#18702 by @fisker)

// Input

type T = {

method1(): string;

"method2"(): string;

"method-3"(): string;

};

// Prettier 3.8

type T = {

method1(): string;

"method2"(): string;

"method-3"(): string;

};

// Prettier 3.9 (--quote-props=as-needed)

type T = {

method1(): string;

method2(): string;

"method-3"(): string;

};

// Prettier 3.9 (--quote-props=consistent)

type T = {

"method1"(): string;

"method2"(): string;

"method-3"(): string;

};

Keep comments in mapped type inline (#18731 by @fisker)

// Input

type B = {

/* comment */ [b in B]: string

};

// Prettier 3.8

type B = {

/* comment */

[b in B]: string;

};

// Prettier 3.9

type B = {

/* comment */ [b in B]: string;

};

Print semicolon before type assertion in no-semi mode (#18738 by @fisker)

// Input

a;

<b>c;

// Prettier 3.8 (--no-semi, first format)

a

<b>c

// Prettier 3.8 (--no-semi, second format)

a < b > c

// Prettier 3.9 (--no-semi)

a

;<b>c

Add parentheses to conditional types in type parameter constraint (#18760 by @kovsu)

// Input

const foo = <Foo extends (Bar extends Baz ? A : B)>() => true;

// Prettier 3.8

const foo = <Foo extends Bar extends Baz ? A : B>() => true;

// Prettier 3.9

const foo = <Foo extends (Bar extends Baz ? A : B)>() => true;

Fix printing comment for the last operand of union types (#18798 by @fisker)

// Input

type Foo2 = (

| "thing1" // Comment1

| "thing2" // Comment2

) & Bar; // Final comment2

type Foo2 = (

| "thing1" // Comment1

| "thing2" // Comment2

) | Bar; // Final comment2

// Prettier 3.8

type Foo2 = (

| "thing1" // Comment1

| "thing2" // Comment2

) &

Bar; // Final comment2

type Foo2 =

| (

| "thing1" // Comment1

| "thing2"

) // Comment2

| Bar; // Final comment2

// Prettier 3.9

type Foo2 = (

| "thing1" // Comment1

| "thing2" // Comment2

) &

Bar; // Final comment2

type Foo2 =

| (

| "thing1" // Comment1

| "thing2" // Comment2

)

| Bar; // Final comment2

Don't break union type when it can fit (#18827 by @fisker)

// Input

type Browser = "chromium" | "webkit" | "firefox" | "chromium-msedge" | "chromium-chrome";

// Prettier 3.8

type Browser =

| "chromium"

| "webkit"

| "firefox"

| "chromium-msedge"

| "chromium-chrome";

// Prettier 3.9

type Browser =

"chromium" | "webkit" | "firefox" | "chromium-msedge" | "chromium-chrome";

Remove extra indention for union type in conditional type (#18827 by @fisker)

// Input

type A = T extends "arrow"

? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"]

: never;

// Prettier 3.8

type A = T extends "arrow"

?

| ExcalidrawArrowElement["startBinding"]

| ExcalidrawElbowArrowElement["startBinding"]

: never;

// Prettier 3.9

type A = T extends "arrow"

? | ExcalidrawArrowElement["startBinding"]

| ExcalidrawElbowArrowElement["startBinding"]

: never;

Align JSDoc before union type elements (#18833 by @fisker)

// Input

type A =

|

/**

* Comment

*/

a

| (b | c);

type A2 =

|

// comment

a

| (b | c);

// Prettier 3.8

type A =

| /**

* Comment

*/

a

| (b | c);

type A2 =

| // comment

a

| (b | c);

// Prettier 3.9

type A =

| /**

* Comment

*/

a

| (b | c);

type A2 =

| // comment

a

| (b | c);

Prevent moving comment in class properties (#18837 by @fisker)

// Input

class foo {

bar () /* bar */;

baz /* baz */ ();

}

// Prettier 3.8

class foo {

bar /* bar */();

baz /* baz */();

}

// Prettier 3.9

class foo {

bar(); /* bar */

baz /* baz */();

}

Fix trailing comment in abstract method parameters (#19200 by @itsybitsybootsy)

// Input

abstract class Foo {

abstract method(

param1: number,

// param2: number,

): void;

}

// Prettier 3.8

abstract class Foo {

abstract method(param1: number) // param2: number,

: void;

}

// Prettier 3.9

abstract class Foo {

abstract method(

param1: number,

// param2: number,

): void;

}

Avoid unnecessary semicolon before call signatures in no-semi mode (#19212 by @fisker)

// Input

export interface MyInterface {

someMethod: (a: number) => Promise<number>

anotherMethod: (a: string) => Promise<string>

(a: string): Promise<string>

}

// Prettier 3.8 (--no-semi)

export interface MyInterface {

someMethod: (a: number) => Promise<number>

anotherMethod: (a: string) => Promise<string>;

(a: string): Promise<string>

}

// Prettier 3.9

export interface MyInterface {

someMethod: (a: number) => Promise<number>

anotherMethod: (a: string) => Promise<string>

(a: string): Promise<string>

}

Preserve comment position after = in type alias declarations (#19410 by @WhoamiI00)

// Input

type A =

/* 1 */ | /* 2 */ (

/* 3 */ | /* 4 */ {

key: string;

}

);

// Prettier 3.8

type A /* 2 */ = /* 1 */ /* 3 */ /* 4 */ {

key: string;

};

// Prettier 3.9

type A = /* 1 */ /* 2 */ /* 3 */ /* 4 */ {

key: string;

};

Fix missing parentheses around instantiation expression (#19442 by @fisker)

// Input

async function* f() {

makeRecord = (yield* makeRecordFactory)<ManualValue>;

makeRecord = (yield makeRecordFactory)<ManualValue>;

makeRecord = (await makeRecordFactory)<ManualValue>;

}

// Prettier 3.8

async function* f() {

makeRecord = yield* makeRecordFactory<ManualValue>;

makeRecord = yield makeRecordFactory<ManualValue>;

makeRecord = await makeRecordFactory<ManualValue>;

}

// Prettier 3.9

async function* f() {

makeRecord = (yield* makeRecordFactory)<ManualValue>;

makeRecord = (yield makeRecordFactory)<ManualValue>;

makeRecord = (await makeRecordFactory)<ManualValue>;

}

Flow

Fix parenthesis for optional function as return type (#11004, #19331 by @vjeux, @fisker)

// Input

const fn = (a: number): ?((string) => string) => {

return a > 0 ? (s) => `${s}: ${a}` : null;

};

// Prettier 3.8

const fn = (a: number): ?(string) => string => {

return a > 0 ? (s) => `${s}: ${a}` : null;

};

// Prettier 3.9

const fn = (a: number): ?((string) => string) => {

return a > 0 ? (s) => `${s}: ${a}` : null;

};

Add support for Flow match instance patterns and Flow records (#18511 by @gkz)

// Input

record R {

num: number,

}

const x = R {num: 1};

const label = match (x) {

R {num: 0} => "zero",

R {num: 1} => "one",

R {const num} => `${num} items`,

}

// Prettier 3.8

// Unsupported

// Prettier 3.9

// Same as input

Improve comment format in inexact tuples (#18616 by @fisker)

// Input

type A = [// comment

...];

type B = [/* comment */...];

// Prettier 3.8

type A = [...

// comment

];

type B = [...

/* comment */

];

// Prettier 3.9

type A = [

...// comment

];

type B = [.../* comment */];

Fix dangling comment print in components (#18629 by @fisker)

// Input

component A(

// comment

) {}

component B(/* comment */) {}

// Prettier 3.8

component A() // comment

{}

component B /* comment */() {}

// Prettier 3.9

component A(

// comment

) {}

component B(/* comment */) {}

Fix dangling comment print in hooks (#18630 by @fisker)

// Input

hook A(

// comment

) {}

declare hook B(// comment

): void

type C = hook (// comment

)=> void

// Prettier 3.8

hook A() // comment

{}

declare hook B(): // comment

void;

type C = hook () => // comment

void;

// Prettier 3.9

hook A(

// comment

) {}

declare hook B(

// comment

): void;

type C = hook (

// comment

) => void;

Support implicit declared functions and components (#18690 by @fisker)

// Input

declare module "foo" {

function greet(name: string): string;

component Button(label: string);

}

// Prettier 3.8

SyntaxError: Unexpected token `;`, expected the token `{` (2:39)

// Prettier 3.9

<Same as input>

Improve long mapped type to across multiple line (#18779 by @kovsu)

// Input

type MappedType = {

[KeyType in ValueType extends string ? VeryLongStringTypeNameHere : VeryLongNumberTypeNameHere]: KeyType

}

// Prettier 3.8

type MappedType = {

[KeyType in ValueType extends string

? VeryLongStringTypeNameHere

: VeryLongNumberTypeNameHere]: KeyType,

};

// Prettier 3.9

type MappedType = {

[

KeyType in ValueType extends string

? VeryLongStringTypeNameHere

: VeryLongNumberTypeNameHere

]: KeyType,

};

Add parentheses support for keyof type operator (#18801 by @marcoww6)

// Input

type T1 = (keyof Foo)[];

type T2 = (keyof Foo)["bar"];

// Prettier 3.8

type T1 = keyof Foo[];

type T2 = keyof Foo["bar"];

// Prettier 3.9

type T1 = (keyof Foo)[];

type T2 = (keyof Foo)["bar"];

Support literal initializers and multiple declarations in DeclareVariable (#18929 by @fisker)

// Input

declare const x: string, y: number;

declare const s = 'foo';

// Prettier 3.8

SyntaxError: Unexpected token `,`, expected the token `;` (1:24)

// Prettier 3.9

declare const x: string, y: number;

declare const s = "foo";

Print async keyword for component declarations (#19053 by @mvitousek)

// Input

async component MyAsyncComponent() {}

// Prettier 3.8

component MyAsyncComponent() {}

// Prettier 3.9

async component MyAsyncComponent() {}

Add support for writeonly, in, and out variance modifiers (#19102 by @marcoww6)

Support new Flow variance syntax: writeonly on object type properties/indexers, and in T/out T on type parameters.

// Input

type T = {writeonly foo: string};

type Contravariant<in T> = T;

type Covariant<out T> = T;

// Prettier 3.8

// SyntaxError

// Prettier 3.9

type T = { writeonly foo: string };

type Contravariant<in T> = T;

type Covariant<out T> = T;

Do not expand object type with inline comments (#19287 by @fisker)

// Input

type T = {|/* comment */|};

// Prettier 3.8

type T = {|

/* comment */

|};

// Prettier 3.9

type T = {| /* comment */ |};

Preserve Flow comment syntax (#19398 by @SamChou19815)

Preserves Flow comment syntax annotations instead of printing them as regular Flow syntax.

// Input

function foo<T>(bar /*: T[] */, baz /*: T */) /*: S */ {}

// Prettier 3.8

function foo<T>(bar: T[], baz: T): S {}

// Prettier 3.9

function foo<T>(bar /*: T[] */, baz /*: T */) /*: S */ {}

JSON

Preserve number and string representation in json-stringify parser (#18405 by @fisker)

Previous versions of Prettier json-stringify parser used JSON.stringify() to print numbers and strings. This led to the loss of the original value representation in a few rare cases. For example, extremely large or small numbers were rounded, and some special characters were unescaped. Technically, these transformations do not change how JSON values are read, but they are not something a formatter is concerned about. Prettier 3.9 now keeps the original representation, even if it can be simplified.

// Input

[

"\u00FF",

1e9999,

0.4e669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006,

-9223372036854775809,

1e3,

{

1e3: 1,

1e999999999999999999999999999999: 1,

1: 1

}

]

// Prettier 3.8

[

"ÿ",

null,

null,

-9223372036854776000,

1000,

{

"1000": 1,

"Infinity": 1,

"1": 1

}

]

// Prettier 3.9

[

"\u00FF",

1e9999,

0.4e669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006,

-9223372036854775809,

1e3,

{

1e3: 1,

1e999999999999999999999999999999: 1,

"1": 1

}

]

CSS

Fix line breaks when css attribute values contain literal newlines (#18605 by @kovsu)

/* Input */

div span[foo="a long long long long long long long long\

long long long long attritbute value"] {

}

/* Prettier 3.8 */

div

span[foo="a long long long long long long long long\

long long long long attritbute value"] {

}

/* Prettier 3.9 */

div span[foo="a long long long long long long long long\

long long long long attritbute value"] {

}

SCSS

Prevent adding trailing comma in math expression within function arguments (#18530 by @kovsu)

// Input

@include container($foo: 2 * ($bar + $baz));

// Prettier 3.8

@include container(

$foo: 2 *

(

$bar + $baz,

)

);

// Prettier 3.9

@include container($foo: 2 * ($bar + $baz));

Fix comment print in maps (#18535 by @kovsu)

// Input

$map: (

// comment

);

// Prettier 3.8

$map: (// comment);

// Prettier 3.9

$map: (

// comment

);

Avoid adding trailing comma to parenthesized scalars (#19091 by @cyphercodes)

// Input

.a { background-color: rgba($color: (#808080), $alpha: 0.9); }

// Prettier 3.8

.a {

background-color: rgba(

$color: (

#808080,

),

$alpha: 0.9

);

}

// Prettier 3.9

.a {

background-color: rgba($color: (#808080), $alpha: 0.9);

}

Remove space before ; delimiter in SCSS if() function (#19384 by @kovsu)

// Input

$value: if(sass($x): 1 ; else: 2);

// Prettier 3.8

$value: if(sass($x): 1 ; else: 2);

// Prettier 3.9

$value: if(sass($x): 1; else: 2);

HTML

Fix a bug around unicode in front matter (#18453 by @seiyab)

<!-- Input -->

---

title: 😄

---

<!-- comment -->

<!-- Prettier 3.8 -->

---

title: 😄

---

<!-- comment --

<!-- Prettier 3.9 -->

---

title: 😄

---

<!-- comment -->

Fix closing tag of pre-like elements being split across lines (#19046 by @kovsu)

<!-- Input -->

<div>

<pre>

Content

</pre>

</div>

<!-- Prettier 3.8 -->

<div>

<pre>

Content

</pre

>

</div>

<!-- Prettier 3.9 -->

<div>

<pre>

Content

</pre>

</div>

Keep an inline comment attached to the preceding node (#19304 by @kovsu)

<!-- Input -->

<p><b>x</b><!-- comment --></p>

<!-- Prettier 3.8 -->

<p>

<b>x</b

><!-- comment -->

</p>

<!-- Prettier 3.9 -->

<p><b>x</b><!-- comment --></p>

Angular

Support @content block (#19431 by @fisker)

<!-- Input -->

<FancyButton [label]="title">

@content(icon) {

<span>Icon</span>

}

@content(description) {

<span>Description text</span>

}

<span>Other children</span>

</FancyButton>

<!-- Prettier 3.8 -->

SyntaxError: Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.) (9:15)

<!-- Prettier 3.9 -->

<FancyButton [label]="title">

@content(icon) {

<span>Icon!</span>

}

@content(description) {

<span>Description text</span>

}

<span>Other children</span>

</FancyButton>

Support comments in html element (#19465 by @fisker)

<!-- Input -->

<div

// comment 0

/* comment 1 */

attr1="value1"

/*

comment 2

spanning multiple lines

*/

attr2="value2"

></div>

<!-- Prettier 3.8 -->

<div attr1="value1" attr2="value2"></div>

<!-- Prettier 3.9 -->

<div

// comment 0

/* comment 1 */

attr1="value1"

/*

comment 2

spanning multiple lines

*/

attr2="value2"

></div>

GraphQL

Fix crash with comment only object value (#18581 by @fisker)

# Input

query {

search(filters: {

# TODO

}) {

id

}

}

# Prettier 3.8

Error: Comment "TODO" was not printed. Please report this error!

# Prettier 3.9

query {

search(

filters: {

# TODO

}

) {

id

}

}

Allow interfaces to break (#18582 by @fisker)

# Input

type Foo implements InterfaceOne & InterfaceTwo & InterfaceThree & InterfaceFour & InterfaceFive & InterfaceSix {

id: ID!

}

# Prettier 3.8

type Foo implements InterfaceOne & InterfaceTwo & InterfaceThree & InterfaceFour & InterfaceFive & InterfaceSix {

id: ID!

}

# Prettier 3.9

type Foo implements InterfaceOne &

InterfaceTwo &

InterfaceThree &

InterfaceFour &

InterfaceFive &

InterfaceSix {

id: ID!

}

Fix crash with comment only list value (#19422 by @fisker)

# Input

query {

a(x: [

# only comment

])

}

# Prettier 3.8

Error: Comment "only comment" was not printed. Please report this error!

# Prettier 3.9

query {

a(

x: [

# only comment

]

)

}

Markdown

Fix Markdown emphasis near non-breaking space (#17424 by @rkdfx)

Underscore-style emphasis adjacent to a Unicode whitespace (e.g. non-breaking space) was being rewritten to asterisks, because the surrounding text was treated as a regular word.

<!-- Input -->

- _REPORTED_ — message received;

- _NEEDSINFO_ — additional info needed;

<!-- Prettier 3.8 -->

- *REPORTED* — message received;

- *NEEDSINFO* — additional info needed;

<!-- Prettier 3.9 -->

- _REPORTED_ — message received;

- _NEEDSINFO_ — additional info needed;

Support setext headings (#18473 by @fisker)

<!-- Input -->

Setext Heading 1

================

Setext Heading 2

----------------

Multiline

Setext

Heading

-------

<!-- Prettier 3.8 -->

# Setext Heading 1

## Setext Heading 2

Multiline

Setext

Heading

---

<!-- Prettier 3.9 -->

Setext Heading 1

================

Setext Heading 2

----------------

Multiline

Setext

Heading

-------

Treat U+3000 as CJK punctuation-equivalent and make sure to recognize U+FF5E as CJK punctuation again in Markdown prose wrap (#18656 by @tats-u)

We improved the text wrapping in Markdown written in Chinese and Japanese by treating some non Unicode punctuation characters as equivalent to CJK punctuation. A part of this was assumed to have been introduced in 3.5.0 (#16832), but it was not fully implemented and not noticed until now due to insufficient test cases.

await prettier.format(

"U+3000\u{3000}\nU+301C\u{301C}\nU+FF5E\u{FF5E}\nU+1F221\u{1F221} 测试 Test テスト\n",

{ parser: "markdown", proseWrap: "always" },

);

/* Prettier 3.8 */

// -> 'U+3000  U+301C〜U+FF5E~ U+1F221🈡 测试 Test テスト\n'

//  ^ extra space  ^ extra space

/* Prettier 3.9 */

// -> 'U+3000 U+301C〜U+FF5E~U+1F221🈡 测试 Test テスト\n'

Fix CJK line break loss near list-like numbers (#18867 by @it-education-md)

Avoid collapsing line breaks before list-like numbers followed by CJK characters (e.g. 3.中).

<!-- Input -->

1.a

2.b

3.中

<!-- Prettier 3.8 -->

1.a

2.b 3.中

<!-- Prettier 3.9 -->

1.a

2.b

3.中

Fix extra blank line between a list and an indented code block (#19154 by @YBJ0000)

Prettier forced two blank lines whenever an indented code block followed a list. The extra blank line is never semantically required and contradicts Prettier's usual behavior of collapsing consecutive blank lines into a single one.

<!-- Input -->

- one

two

<!-- Prettier 3.8 -->

- one

two

<!-- Prettier 3.9 -->

- one

two

Support formatting LWC (Lightning Web Components) syntax in code block (#19291 by @fisker)

<!-- Input -->

```lwc

<test-this attr={test}>

Awesome </test-this>

```

<!-- Prettier 3.8 -->

Same as input

<!-- Prettier 3.9 -->

```lwc

<test-this attr={test}> Awesome </test-this>

```

Escape unindented indented pseudo setext headers (#19350 by @tats-u)

Indented lines composed of only = or - were previously unindented without being escaped, which caused them to be mistakenly parsed as setext headers. With this change, Prettier now escapes such lines to prevent the misinterpretation:

Check parse results on CommonMark playground

<!-- Input -->

Not a header

===

Not a header

---

Not a list item or a header

-

<!-- Prettier 3.8 -->

Not a header

===

Not a header

---

Not a list item or a header -

<!-- Prettier 3.9 -->

Not a header

\===

Not a header

\---

Not a list item or a header

\-

YAML

Fix mapping format when the key wraps (#18330 by @kovsu)

# Input

long long long long long long long long long long long long long long long long long long key: bar

# Prettier 3.8 (--prose-wrap=always)

long long long long long long long long long long long long long long long long

long long key: bar

# Prettier 3.9 (--prose-wrap=always)

? long long long long long long long long long long long long long long long

long long long key

: bar

Fix block value ends with whitespace (#18331 by @kovsu)

import { inspect } from "node:util";

import * as prettier from "prettier";

const input = "foo: |\n x\n ";

const output = await prettier.format(input, { parser: "yaml" });

console.log(inspect(output));

// Prettier 3.8

//-> 'foo: |\n x\n\n'

// Prettier 3.9

//-> 'foo: |\n x\n'

Preserve empty line after block scalar (#19205 by @seirl)

# Input

foo: >

a

b

bar: baz

qux: quux

# Prettier 3.8

foo: >

a

b

bar: baz

qux: quux

# Prettier 3.9

foo: >

a

b

bar: baz

qux: quux

CLI

Fix crashes on formatting directory names that have special characters (#18452 by @fisker)

prettier . --check

# Prettier 3.8

[error] Invalid configuration for file "<CWD>\test\username[repo-name]\.editorconfig":

[error] Invalid regular expression: /^(?=.)username[repo-name]$/: Range out of order in character class

# Prettier 3.9

Checking formatting...

[warn] test/username[repo-name]/test.js

[warn] Code style issues found in the above file. Run Prettier with --write to fix.

Stop searching for EditorConfig files above Git worktrees (#18891 by @seiyab)

Prettier now treats a .git file as a project root marker, in addition to a .git directory. This prevents EditorConfig settings from a parent directory from being applied when formatting files inside Git worktrees or submodules.

Fix --cache-strategy content not working (#18914 by @paulofduarte)

file-entry-cache v11 renamed the useChecksum option to useCheckSum. Prettier was still passing the old casing, so content-based cache comparison was silently disabled and only file size was compared.

Fix formatting file with a leading quote (") in the name (#19315 by @kovsu)

prettier --check '".md'

# Prettier 3.8

Checking formatting...

[error] Explicitly specified file was ignored due to negative glob patterns: "".md".

# Prettier 3.9

Checking formatting...

[warn] ".md

[warn] Code style issues found in the above file. Run Prettier with --write to fix.

Update experimental cli (#19381, #19415 by @Simomson, @43081j, @fisker)

Full changelog:

Miscellaneous

Update Printer interface (#19014 by @Janther)

export interface Printer<T = any> {

// ...

- print: (AstPath<T>) => Doc,

+ print: (

+ selector?: string | number | Array<string | number> | AstPath<T>,

+ args?: unknown,

+ ) => Doc,

// ...

}