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

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
M
MIT News - Artificial intelligence
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
aimingoo的专栏
aimingoo的专栏
博客园 - 三生石上(FineUI控件)
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
F
Full Disclosure
G
Google Developers Blog
罗磊的独立博客
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
A
About on SuperTechFans
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
GbyAI
GbyAI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
The Register - Security
The Register - Security
U
Unit 42
D
Docker
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
博客园_首页
Google DeepMind News
Google DeepMind News

Prettier Blog

Prettier 3.8: Support for Angular v21.1 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.7: Improved formatting consistency and new plugin features!
Fisker Cheung · 2025-11-27 · via Prettier Blog

We are excited to announce Prettier 3.7! This release focuses on polishing the TypeScript and Flow experience, specifically by aligning the formatting of classes and interfaces to be more consistent and predictable. We also want your opinion on the upcoming change to fix inconsistent opening brace print logic of class and interface body.

Additionally, we also fixed lots of bugs, added support for new features in Angular 21 and Graphql 16.12, added Front Matter support to Handlebars.

For plugin developers, we've added new APIs to give you more control over comment attachment and handling of ignored nodes.

If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on. Thank you for your continued support!

Highlights

TypeScript

Fix the inconsistent printing between class and interface (#18094, #18091, #18215 by @fisker)

In this release, we've focused heavily on improving consistency between Class and Interface formatting. Previously, these two similar constructs were printed quite differently, leading to visual inconsistencies. We've aligned their formatting rules to provide a more predictable and cleaner output.

// Input

interface MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

>

extends A, B {}

declare class MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

>

implements A, B {}

// Prettier 3.6

interface MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

> extends A,

B {}

declare class MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

>

implements A, B {}

// Prettier 3.7

interface MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

>

extends A, B {}

declare class MarkDef<

M extends string | Mark = Mark,

ES extends ExprRef | SignalRef = ExprRef | SignalRef,

>

implements A, B {}

Align interface heritages print with class

// Input

export interface AreaConfig<ES extends ExprRef | SignalRef>

extends MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>

implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

// Prettier 3.6

export interface AreaConfig<ES extends ExprRef | SignalRef>

extends MarkConfig<ES>,

PointOverlayMixins<ES>,

LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>

implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

// Prettier 3.7

export interface AreaConfig<ES extends ExprRef | SignalRef>

extends MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>

implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

Align single heritage print with super class

// Input

class ExtendsLongOneWithGenerics

extends

Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine,

> {}

class ExtendsLongOneWithGenerics

implements

Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine,

> {}

interface ExtendsLongOneWithGenerics

extends

Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine,

> {}

// Prettier 3.6

class ExtendsLongOneWithGenerics extends Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

class ExtendsLongOneWithGenerics

implements

Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

interface ExtendsLongOneWithGenerics

extends Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

// Prettier 3.7

class ExtendsLongOneWithGenerics extends Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

class ExtendsLongOneWithGenerics implements Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

interface ExtendsLongOneWithGenerics extends Bar<

SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,

ToBreakLineToBreakLineToBreakLine

> {}

Inconsistent opening brace print logic of class and interface body

In Prettier v2.3, to improve visual separation between class head and body, we started to print the opening { of the class body on a new line when the class has multiple heritages.

// Prettier 2.2

class loooooooooooooooooooong

extends looooooooooooooooooong

implements loooooooooooooooooooong {

property: string;

}

// Prettier 2.3

class loooooooooooooooooooong

extends looooooooooooooooooong

implements loooooooooooooooooooong

{

property: string;

}

However, not everyone is happy with this change.

Let us know what you think about applying this change to interfaces by leaving a comment on this issue.

If you have a better solution for this issue, we'll be happy to discuss it too.

Unless a better solution comes along, we'll align the interface body print with the one for the class body in Prettier v4.

// Input

declare class loooooooooooooooooooong

implements looooooooooooooooooong, loooooooooooooooooooong {

property: string;

}

interface loooooooooooooooooooong

extends looooooooooooooooooong, loooooooooooooooooooong {

property: string;

}

// Prettier 3.7

declare class loooooooooooooooooooong

implements looooooooooooooooooong, loooooooooooooooooooong

{

property: string;

}

interface loooooooooooooooooooong

extends looooooooooooooooooong, loooooooooooooooooooong { // <-- This

property: string;

}

These changes also affect Flow syntax

Other Changes

JavaScript

Allow break import attributes into multiple lines (#17329 by @fisker)

// Input

import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with {

BABEL_8_BREAKING: "false",

USE_ESM: "true", IS_STANDALONE: "false" };

// Prettier 3.6

import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with { BABEL_8_BREAKING: "false", USE_ESM: "true", IS_STANDALONE: "false" };

// Prettier 3.7

import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with {

BABEL_8_BREAKING: "false",

USE_ESM: "true",

IS_STANDALONE: "false",

};

Add support for "Discard Bindings" proposal (#17708 by @fisker)

The Stage 2 proposal "Discard Bindings" is now supported via Babel. Also keep in mind our policy on non-standardized syntax before using this proposed syntax feature with Prettier.

const [void] = x;

const {x:void} = x;

Fix inconsistent comment format (#17723 by @fisker)

// Input

if (

true

// This is a really complicated part of the condition, so we need a big ol'

// comment here to explain it.

&& flibble.blibble.blobble?.bloo

) {

doThings();

}

// Prettier 3.6 (--parser=typescript --experimental-operator-position=start)

if (

true

&& // This is a really complicated part of the condition, so we need a big ol'

// comment here to explain it.

flibble.blibble.blobble?.bloo

) {

doThings();

}

// Prettier 3.6 (--parser=babel --experimental-operator-position=start)

if (

true

// This is a really complicated part of the condition, so we need a big ol'

// comment here to explain it.

&& flibble.blibble.blobble?.bloo

) {

doThings();

}

// Prettier 3.7

if (

true

// This is a really complicated part of the condition, so we need a big ol'

// comment here to explain it.

&& flibble.blibble.blobble?.bloo

) {

doThings();

}

Add additional Playwright test functions (#17876 by @BPScott)

Prettier already avoids changing indentation for test functions when you add .skip to them. It now also treats the Playwright functions test.fixme, test.describe.skip and test.describe.fixme similar to test.skip.

// Input

test.fixme("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

test.describe.skip("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

test.describe.fixme("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

// Prettier 3.6

test.fixme(

"does something really long and complicated so I have to write a very long name for the test",

() => {

// code

},

);

test.describe.skip(

"does something really long and complicated so I have to write a very long name for the test",

() => {

// code

},

);

test.describe.fixme(

"does something really long and complicated so I have to write a very long name for the test",

() => {

// code

},

);

// Prettier 3.7

test.fixme("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

test.describe

.skip("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

test.describe

.fixme("does something really long and complicated so I have to write a very long name for the test", () => {

// code

});

Avoid break {import,require.resolve,require.resolve.paths,import.meta.resolve}() with long module name (#17882, #17908 by @kovsu & @fisker)

// Input

const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const b = require.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const c = require.resolve.paths("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const d = await import("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module")

const e = import.meta.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

// Prettier 3.6

const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const b = require.resolve(

"./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",

);

const c = require.resolve.paths(

"./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",

);

const d = await import(

"./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module"

);

const e = import.meta.resolve(

"./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",

);

// Prettier 3.7

const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const b =

require.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const c = require.resolve

.paths("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const d =

await import("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const e = import.meta

.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

Improve comment handing inside if statement (#17998 by @fisker)

// Input

if (foo) // comment

{

doThing();

} else // comment for else

{

doSomethingElse();

}

// Prettier 3.6

if (foo) {

// comment

doThing();

} // comment for else

else {

doSomethingElse();

}

// Prettier 3.7

if (foo) // comment

{

doThing();

} else // comment for else

{

doSomethingElse();

}

Improve require() call with comments (#18037 by @fisker)

// Input

require(

// Comment

"foo"

);

// Prettier 3.6

require(// Comment

"foo");

// Prettier 3.7

require(

// Comment

"foo",

);

Remove indention in logical expression in Boolean() call (#18087 by @kovsu)

Reduce diff when changing a condition to an opposite value, or change between !! and Boolean().

// Input

const foo = Boolean(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition

);

const bar = !!(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition

);

// Prettier 3.6

const foo = Boolean(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition,

);

const bar = !!(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition

);

// Prettier 3.7

const foo = Boolean(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition

);

const bar = !!(

a_long_long_condition ||

a_long_long_long_condition ||

a_long_long_long_condition

);

Fix comments handling for for-statements (#18099 by @fisker, @sosukesuzuki)

// Input

for (x of y)

// Comment

bar();

// Prettier 3.6

// Comment

for (x of y) bar();

// Prettier 3.7

for (x of y)

// Comment

bar();

Improve comment printing around empty statement (#18108 by @fisker)

// Input

for (

index = 0;

doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;

index ++

) /* No op */;

// Prettier 3.6

for (

index = 0;

doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;

index++ /* No op */

);

// Prettier 3.7

for (

index = 0;

doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;

index++

) /* No op */ ;

Fix inconsistent comment print between class methods and object methods (#18147 by @fisker)

// Input

class x {

method() // Class method

{

return 1

}

}

const object = {

method() // Object method

{

return 1

}

}

// Prettier 3.6

class x {

method() { // Class method

return 1;

}

}

const object = {

method() {

// Object method

return 1;

},

};

// Prettier 3.7

class x {

method() {

// class method

return 1;

}

}

const object = {

method() {

// object method

return 1;

},

};

Add missing parentheses in bitwise operators (#18163 by @fs0414)

// Input

1 << (bit % 8);

1 >> (bit - 8);

// Prettier 3.6

1 << bit % 8;

1 >> (bit - 8);

// Prettier 3.7

1 << (bit % 8);

1 >> (bit - 8);

Fix inconsistent break for array literals (#18172 by @Dunqing, @fisker)

// Input

assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides___(-1, -1), [1]);

assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [1, 2]);

// Prettier 3.6

assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides___(-1, -1), [

1,

]);

assert.deepStrictEqual(

linesCollection.getViewLinesIndentGuides(-1, -1),

[1, 2],

);

// Prettier 3.7

assert.deepStrictEqual(

linesCollection.getViewLinesIndentGuides___(-1, -1),

[1],

);

assert.deepStrictEqual(

linesCollection.getViewLinesIndentGuides(-1, -1),

[1, 2],

);

Fix inconsistent logical expression print (#18205 by @fisker)

// Input

fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b

);

new Fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b

);

// Prettier 3.6

fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b,

);

new Fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b,

);

// Prettier 3.7

fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b,

);

new Fn(

a &&

a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition

? a

: b,

);

Fix inconsistent print between CallExpression and NewExpression (#18206 by @fisker)

// Input

TelemetryTrustedValue(

instance.capabilities.get(

TerminalCapability?.PromptTypeDetection

)?.promptType

)

new TelemetryTrustedValue(

instance.capabilities.get(

TerminalCapability?.PromptTypeDetection

)?.promptType

)

// Prettier 3.6

TelemetryTrustedValue(

instance.capabilities.get(TerminalCapability?.PromptTypeDetection)

?.promptType,

);

new TelemetryTrustedValue(

instance.capabilities.get(

TerminalCapability?.PromptTypeDetection,

)?.promptType,

);

// Prettier 3.7

TelemetryTrustedValue(

instance.capabilities.get(TerminalCapability?.PromptTypeDetection)

?.promptType,

);

new TelemetryTrustedValue(

instance.capabilities.get(TerminalCapability?.PromptTypeDetection)

?.promptType,

)

Remove redundant parentheses around JSX element (#18243 by @fisker)

// Input

new A(

<div>

<div></div>

</div>

)

// Prettier 3.6

new A(

(

<div>

<div></div>

</div>

),

);

// Prettier 3.7

new A(

<div>

<div></div>

</div>,

);

Improve formatting of logical expression as callee of new expression (#18245 by @fisker)

// Input

a = new (

a_long_long_long_long_condition || a_long_long_long_long_condition || a_long_long_long_long_condition

)();

// Prettier 3.6

a = new (a_long_long_long_long_condition ||

a_long_long_long_long_condition ||

a_long_long_long_long_condition)();

// Prettier 3.7

a = new (

a_long_long_long_long_condition ||

a_long_long_long_long_condition ||

a_long_long_long_long_condition

)();

Remove empty line in for statement without "update" (#18300 by @fisker)

// Input

for ( let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;i < len;) {}

// Prettier 3.6

for (

let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;

i < len;

) {}

// Prettier 3.7

for (

let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;

i < len;

) {}

Improve super class format (#18325 by @fisker)

// Input

class EnsureNoDisposablesAreLeakedInTestSuiteSuite extends eslint.Rule.RuleModule {};

// Prettier 3.6

class EnsureNoDisposablesAreLeakedInTestSuiteSuite extends eslint.Rule

.RuleModule {}

// Prettier 3.7

class EnsureNoDisposablesAreLeakedInTestSuiteSuite

extends eslint.Rule.RuleModule {}

TypeScript

Fix misplacement of comments after arrow (#17421 by @o-m12a, @t-mangoe)

// Input

export const test = (): any => /* first line

second line

*/

null;

// Prettier 3.6

export const test = (): any /* first line

second line

*/ => null;

// Prettier 3.6 (Second format)

SyntaxError: Unexpected token (1:22)

> 1 | export const test = (): any /* first line

| ^

2 | second line

3 | */ => null;

4 |

// Prettier 3.7

export const test = (): any =>

/* first line

second line

*/

null;

Add missing parentheses to arrow function in instantiation expression (#17724 by @fisker)

// Input

void (<_T extends never>() => {})<never>;

// Prettier 3.6

void <_T extends never>() => {}<never>;

// Prettier 3.7

void (<_T extends never>() => {})<never>;

Fix TSMappedType format (#17785 by @fisker)

// Input (--parser=babel-ts)

export type A = B extends { C?: { [D in infer E]?: F } } ? G : H

// Prettier 3.6

TypeError: Cannot read properties of undefined (reading 'startsWith')

// Prettier 3.7

export type A = B extends { C?: { [D in infer E]?: F } } ? G : H;

Print trailing comma in TSImportType options (#17798 by @fisker)

Trailing comma in import type attribute wasn't allowed before TypeScript v5.9, now the bug has been fixed.

// Input

type A = import("foo", {

with:{

type:'json',

} // <- Should be a comma here

})

// Prettier 3.6

type A = import("foo", {

with: {

type: "json",

} // <- Should be a comma here

});

// Prettier 3.7

type A = import("foo", {

with: {

type: "json",

}, // <- Should be a comma here

});

Improve CommonJS module require() with comments (#18035 by @fisker)

// Input

import foo = require(

// Comment

"foo"

);

// Prettier 3.6

import foo = require(// Comment

"foo");

// Prettier 3.7

import foo = require(

// Comment

"foo"

);

Line breaking after = in type parameters (#18043 by @fisker)

// Input

export type OuterType2<

LongerLongerLongerLongerInnerType = LongerLongerLongerLongerLongerLongerLongerLongerOtherType

> = { a: 1 };

// Prettier 3.6

export type OuterType2<

LongerLongerLongerLongerInnerType = LongerLongerLongerLongerLongerLongerLongerLongerOtherType,

> = { a: 1 };

// Prettier 3.7

export type OuterType2<

LongerLongerLongerLongerInnerType =

LongerLongerLongerLongerLongerLongerLongerLongerOtherType,

> = { a: 1 };

Remove unexpected blank line before union types (#18109 by @jspereiramoura, @fisker)

// Input

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

type A = // comment

Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.6

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

type A = // comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.7

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

type A = // comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

This change also affect Flow syntax

Fix inconsistent comment printing between typescript and flow parser (#18110 by @fisker)

// Input

interface A {

a: // Comment

B;

b: // Comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

c: // Comment

& Fooo1000

& Baz2000

& BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

}

// Prettier 3.6 (--parser=typescript)

interface A {

a: // Comment

B;

b: // Comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

c: // Comment

Fooo1000 &

Baz2000 &

BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

}

// Prettier 3.6 (--parser=flow)

interface A {

a: B; // Comment

b: // Comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

c: Fooo1000 & // Comment

Baz2000 &

BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

}

// Prettier 3.7 (Same output for `--parser=typescript` and `--parser=flow`)

interface A {

a: B; // Comment

b: // Comment

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

c: // Comment

Fooo1000 &

Baz2000 &

BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

}

Fix missing semicolon before call signatures (#18118 by @fisker)

// Input

interface A {

foo;

<T>(): T;

}

type B = {

foo;

<T>(): T;

}

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

interface A {

foo

<T>(): T

}

type B = {

foo

<T>(): T

}

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

interface A {

foo<T>(): T

}

type B = {

foo<T>(): T

}

// Prettier 3.7

interface A {

foo;

<T>(): T

}

type B = {

foo;

<T>(): T

}

Fix inconsistent print of as const between flow and typescript parsers (#18161 by @fisker)

// Input

1 as /* comment */ const;

// Prettier 3.6 (--parser=typescript)

1 as /* comment */ const;

// Prettier 3.6 (--parser=flow)

1 /* comment */ as const;

// Prettier 3.7 (Same output for `--parser=typescript` and `--parser=flow`)

1 /* comment */ as const;

Fix comment around as/satisfies expression (#18162 by @fisker)

// Input

1 as /*

comment

*/

const;

// Prettier 3.6 (First format)

1 /*

comment

*/ as const;

// Prettier 3.6 (Second format)

SyntaxError: Unexpected keyword or identifier. (3:4)

1 | 1 /*

2 | comment

> 3 | */ as const;

| ^

4 |

// Prettier 3.7

1 as const /*

comment

*/;

Fix miss aligned union type (#18165 by @fisker)

// Input

interface I {

elements: // comment

| [string, ExpressionNode, ExpressionNode]

| [string, ExpressionNode, ExpressionNode, ObjectExpression]

}

// Prettier 3.6

interface I {

elements: // comment

| [string, ExpressionNode, ExpressionNode]

| [string, ExpressionNode, ExpressionNode, ObjectExpression];

}

// Prettier 3.7

interface I {

elements: // comment

| [string, ExpressionNode, ExpressionNode]

| [string, ExpressionNode, ExpressionNode, ObjectExpression];

}

Remove extra empty line in union type (#18197 by @Dunqing)

// Input

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.6

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.7

type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

| Fooo1000

| Baz2000

| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

Flow

Add basic support for "match" syntax (#17681 by @fisker)

// Input

const e = match (a) {

1 => true,

'foo' => false,

2 => {obj: 'literal'},

};

// Prettier 3.6

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

> 1 | const e = match (a) {

| ^

2 | 1 => true,

3 | 'foo' => false,

4 | 2 => {obj: 'literal'},

// Prettier 3.7

const e = match (a) {

1 => true,

"foo" => false,

2 => { obj: "literal" },

};

Add support for opaque type with lower and upper bound (#17792 by @SamChou19815)

// Input

opaque type Counter super empty extends Box<T> = Container<T>;

opaque type Counter super Box<T> = Container<T>;

declare opaque type Counter super empty extends Box<T>;

declare opaque type Counter super Box<T>;

// Prettier 3.6

SyntaxError: Unexpected identifier, expected the token `=` (1:21)

// Prettier 3.7

opaque type Counter super empty extends Box<T> = Container<T>;

opaque type Counter super Box<T> = Container<T>;

declare opaque type Counter super empty extends Box<T>;

declare opaque type Counter super Box<T>;

CSS

Handle attribute selector with case-sensitive and uppercase case-insensitive flags (#17841, #17865 by @kovsu)

/* Input */

[type=a s],

[type=a S],

[type=a I] {

list-style-type: lower-alpha;

}

/* Prettier 3.6 */

[type="a s"],

[type="a S"],

[type="a I"] {

list-style-type: lower-alpha;

}

/* Prettier 3.7 */

[type="a" s],

[type="a" S],

[type="a" I] {

list-style-type: lower-alpha;

}

Fix crash when formatting special custom properties (#17899 by @fisker)

/* Input */

:root {

--l: , #000;

}

/* Prettier 3.6 */

TypeError: Cannot read properties of undefined (reading 'value')

/* Prettier 3.7 */

:root {

--l: , #000;

}

Fix selector been lowercased incorrectly inside css modules (#17929 by @kovsu)

/* Input */

:export {

nest: {

myColor: blue;

}

myColor: red;

}

/* Prettier 3.6 */

:export {

nest: {

mycolor: blue;

}

myColor: red;

}

/* Prettier 3.7 */

:export {

nest: {

myColor: blue;

}

myColor: red;

}

Fix formatting of CSS selectors contains // (#17938 by @kovsu)

/* Input */

a[href="http://example.com"] {

color: red;

}

/* Prettier 3.6 */

a[href="http://example.com"]

{

color: red;

}

/* Prettier 3.7 */

a[href="http://example.com"] {

color: red;

}

Remove unexpected space between font size and line height (#18114 by @kovsu)

/* Input */

a {

font: var(--size)/1;

}

/* Prettier 3.6 */

a {

font: var(--size) / 1;

}

/* Prettier 3.7 */

a {

font: var(--size)/1;

}

Fix extra indent for CSS comma-separated values after a block comment (#18228 by @seiyab)

/* Input */

.foo {

background-image:

linear-gradient(to top, blue, red 100%),

/* texture */

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);

}

/* Prettier 3.6 */

.foo {

background-image:

linear-gradient(to top, blue, red 100%),

/* texture */

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);

}

/* Prettier 3.7 */

.foo {

background-image:

linear-gradient(to top, blue, red 100%),

/* texture */

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),

repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);

}

SCSS

Fix parentheses space problem in mixin argument (#17836 by @kovsu)

// Input

.foo {

@include bar('A (B)');

}

// Prettier 3.6

.foo {

@include bar('A( B)');

}

// Prettier 3.7

.foo {

@include bar('A (B)');

}

Fix formatting of space-separated values (#17903 by @kovsu)

// Input

.foo {

@include transition(min-height ($spacer/2) ease-in-out);

}

// Prettier 3.6

.foo {

@include transition(min-height($spacer/2) ease-in-out);

}

// Prettier 3.7

.foo {

@include transition(min-height ($spacer/2) ease-in-out);

}

Less

Fix variable name being lowercased incorrectly (#17820 by @kovsu)

// Input

@fooBackground:line-gradient(#f00);

a {

background: @fooBackground;

}

// Prettier 3.6

@foobackground:line-gradient (#f00);

a {

background: @fooBackground;

}

// Prettier 3.7

@fooBackground: line-gradient(#f00);

a {

background: @fooBackground;

}

Keep property/variable accessors tight (#17983 by @kovsu)

// Input

.average(@x, @y) {

@result: ((@x + @y) / 2);

}

div {

padding: .average(16px, 50px) [ @result ];

}

// Prettier 3.6

.average(@x, @y) {

@result: ((@x + @y) / 2);

}

div {

padding: .average(16px, 50px) [ @result];

}

// Prettier 3.7

.average(@x, @y) {

@result: ((@x + @y) / 2);

}

div {

padding: .average(16px, 50px)[@result];

}

HTML

Support format allow attribute of iframe element (#17879 by @kovsu)

<!-- Input -->

<iframe allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>

<!-- Prettier 3.6 -->

<iframe allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>

<!-- Prettier 3.7 -->

<iframe

allow="

layout-animations 'none';

unoptimized-images 'none';

oversized-images 'none';

sync-script 'none';

sync-xhr 'none';

unsized-media 'none';

"

></iframe>

Format inline event handler (#17909 by @kovsu)

<!-- Input -->

<button

type="button"

onclick="console .log( 'Hello, this is my old-fashioned event handler!')"

>Press me</button>

<!-- Prettier 3.6 -->

<button

type="button"

onclick="console .log( 'Hello, this is my old-fashioned event handler!')"

>

Press me

</button>

<!-- Prettier 3.7 -->

<button

type="button"

onclick="console.log('Hello, this is my old-fashioned event handler!')"

>

Press me

</button>

Angular

Support Angular 21 (#17722, #18294 by @fisker)

Angular 20.1 added support for new assignment operators. Angular 21 added support for regular expression.

<!-- Input -->

<b (click)="

a ??= b">{{ /\d+/g}}</b>

<!-- Prettier 3.6 -->

<b

(click)="

a ??= b"

>{{ /\d+/g}}</b

>

<!-- Prettier 3.7 -->

<b (click)="a ??= b">{{ /\d+/g }}</b>

Fix comments get duplicated in interpolation (#17862 by @fisker)

<!-- Input -->

{{a() // comment}}

<!-- Prettier 3.6 -->

{{ a(// comment) // comment }}

<!-- Prettier 3.7 -->

{{

a() // comment

}}

Fix formatting of "non-null assertion" (#18047 by @fisker)

<!-- Input -->

{{ foo?.bar!.baz }}

<!-- Prettier 3.6 -->

{{ (foo?.bar)!.baz }}

<!-- Prettier 3.7 -->

{{ foo?.bar!.baz }}

Ember / Handlebars

Added Front Matter support to Handlebars (#17781 by @Codezilluh)

Front matter can now be used in Handlebars.

---

title: My page title

keywords:

- word

- other word

---

<h1>{{title}}</h1>

<ul>

{{#each keywords}}

<li>{{this}}</li>

{{/each}}

</ul>

Preserve else if syntax for custom helpers (#17856 by @kovsu)

{{! Input }}

{{#animated-if this.foo}}

foo content

{{else if (this.bar)}}

bar content

{{/animated-if}}

{{! Prettier 3.6 }}

{{#animated-if this.foo}}

foo content

{{else}}{{#if (this.bar)}}

bar content

{{/if}}{{/animated-if}}

{{! Prettier 3.7 }}

{{#animated-if this.foo}}

foo content

{{else if (this.bar)}}

bar content

{{/animated-if}}

Remove extra blank lines in <style> tags (#18065 by @kovsu, @fisker)

{{! Input }}

<style>

#foo {

color: red;

}

</style>

{{! Prettier 3.6 (--html-whitespace-sensitivity=ignore) }}

<style>

#foo {

color: red;

}

</style>

{{! Prettier 3.7 (--html-whitespace-sensitivity=ignore) }}

<style>

#foo {

color: red;

}

</style>

Don't force elements to break with --html-whitespace-sensitivity=ignore (#18133 by @fisker)

{{! Input }}

<div> </div>

{{! Prettier 3.6 (--html-whitespace-ensitivity=ignore) }}

<div>

</div>

{{! Prettier 3.7 (--html-whitespace-ensitivity=ignore) }}

<div></div>

GraphQL

Support "executable descriptions" (#18214 by @fisker)

# Input

"Description"

query {

node {

id

}

}

# Prettier 3.6

SyntaxError: Syntax Error: Unexpected description, descriptions are supported only on type definitions. (1:1)

> 1 | "Description"

| ^

2 | query {

3 | node {

4 | id

# Prettier 3.7

"Description"

query {

node {

id

}

}

Markdown

Improve emoji size measurement (#17813 by @seiyab)

This change improves table alignment in all languages.

<!-- Input -->

| | |

| :-: | :-: |

| ✔ | ✘ |

| ✘ | ✔ |

| ✔ | ✘ |

<!-- Input -->

| | |

| :-: | :-: |

| ✔ | ✘ |

| ✘ | ✔ |

| ✔ | ✘ |

<!-- Prettier 3.7 -->

| | |

| :-: | :-: |

| ✔ | ✘ |

| ✘ | ✔ |

| ✔ | ✘ |

Infer TOML parser for Front Matter (#17965 by @kovsu)

TOML Front Matter can be processed by the appropriate plugin if any. Works for HTML and CSS files too.

Fix strong emphasis format (#18010 by @yin1999)

This is a supplementary fix for #17143, where the original PR could not determine whether the contents on the left and right sides were both words.

<!-- Input -->

1***2***3

1**_2_**3

<!-- Prettier 3.6 -->

1**_2_**3

1**_2_**3

<!-- Prettier 3.7 -->

1***2***3

1***2***3

MDX

Fix import and export parsing (#17996 by @kovsu & @fisker)

{/* Input */}

- import is a word in lists

- export is a word in lists, too!

{/* Prettier 3.6 */}

- import is a word in list

s

- export is a word in lists, too

!

{/* Prettier 3.7 */}

- import is a word in lists

- export is a word in lists, too!

YAML

Preserve empty line between map and comment (#17843 by @kovsu)

# Input

only: issues

# Comment

# Prettier 3.6

only: issues

# Comment

# Prettier 3.7

only: issues

# Comment

Preserve explicit document end marker (#18296 by @fisker)

# Input

a: a

---

b: b

...

c: c

...

---

d: d

# Prettier 3.6

a: a

---

b: b

---

c: c

---

d: d

# Prettier 3.7

a: a

---

b: b

...

c: c

...

---

d: d

Use explicit key style for flow-mapping keys with trailing comments (#18324 by @kovsu, @fisker)

# Input

{ "foo" # comment

:bar }

# Prettier 3.6

{ "foo": bar } # comment

# Prettier 3.7

{ ? "foo" # comment

: bar }

API

Allow plugin.parser.preprocess() to return a Promise (#17679 by @fisker)

Align with plugin.printer.preprocess(), which allows to return a Promise.

We still suggest move your async work into plugin.parser.parse(), which already allow to return a Promise, we may remove support for plugin.parser.preprocess() in future.

Allow AstPath#call() to access property of nullish properties (#17860 by @fisker)

Previously, to check for a possible non-existent child node, we had to ensure the node existed first.

const isFoo = path.call(() => path.node?.type === "Foo", "foo", "bar");

// Uncaught TypeError: Cannot read properties of undefined (reading 'bar')

We have to

const isFoo =

path.node.foo?.bar &&

path.call(() => path.node?.type === "Foo", "foo", "bar");

Since Prettier 3.7, accessing a property of nullish properties no longer throws errors.

Pass ancestors to plugin.printer.canAttachComment() (#18055 by @fisker)

This prevent attaching comments to a specific child of node.

For example in this JavaScript code const object = {property};, the Identifier node (property) appears as both Property.key and Property.value in the AST, obviously it can only print once, if the comment is attached to the non-printable child the comment will get lost.

Plugins can now avoid this by adding a canAttachComment like this:

export const canAttachComment = (node, [parent]) =>

!(

parent?.type === "Property" &&

parent.shorthand &&

parent.key === node &&

parent.key !== parent.value

);

export const print = (path, options, print) => {

const { node } = path;

switch (node.type) {

case "Property":

if (node.shorthand) {

return print("value");

}

// ...

}

};

Add support for plugin.printer.printPrettierIgnored() (#18070 by @fisker)

For a node with prettier-ignore comment, Prettier prints the text of the node directly. However, this may cause problems, for example, if the node needs to be parenthesized or needs to print a leading semicolon to prevent ASI issue in --no-semi mode.

Since Prettier 3.7, plugins can add a printPrettierIgnored() function to the printer to customize the prettier-ignored node print process. This function uses the extract same signature as plugin.printer.print()

Allow plugin to provide an estree printer (#18072 by @fisker)

Previously, if a plugin wanted to make a plugin with an estree printer that outputs different code based on the built-in one, the plugin needed to provide both parsers and printers. Prettier 3.7 allows a plugin to create a plugin that only provides an estree printer.

CLI

Avoid creating node_modules/.cache/ directory when --cache is not enabled (#18124 by @chiawendt)

Running prettier . without --cache no longer creates an empty node_modules/.cache/ directory.