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

推荐订阅源

博客园 - 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.7: Improved formatting consistency and new plugin features! 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.6: Experimental fast CLI and new OXC and Hermes plugins!
Sosuke Suzuki · 2025-06-23 · via Prettier Blog

This release includes several important feature additions that we're excited to share with you.

First, we're shipping a new experimental high-performance CLI behind a feature flag (--experimental-cli). This CLI was previously only available in prettier@next, but now you can enable it simply by using a flag. We encourage you to try it out and share your feedback! If you are interested in the internal implementation, please read Prettier's CLI: Performance Deep Dive by Fabio.

Additionally, we're releasing two new official plugins: @prettier/plugin-oxc and @prettier/plugin-hermes. These plugins are provided separately from Prettier's core.

We want to extend our heartfelt gratitude to everyone who made this amazing release possible: @fabiospampinato, @43081j, and @pralkarz along with the new CLI contributors, @boshen and @overlookmotel along with other OXC contributors, the Flow and Hermes teams at Meta. Thank you all for your incredible contributions!

We're excited to see how these new features enhance your development experience. Happy formatting!

Highlights

CLI

Support experimental CLI (#17151, #17396 by @fisker)

You may have already heard of or used our new performance improved CLI. From Prettier 3.6, you can now use it without installing unstable v4 version.

# Run CLI with `--experimental-cli`

prettier . --check --experimental-cli

# Or use environment variable `PRETTIER_EXPERIMENTAL_CLI=1`

PRETTIER_EXPERIMENTAL_CLI=1 prettier . --check

JavaScript

Added a new official plugin @prettier/plugin-oxc (#17472, #17483 by @fisker)

@prettier/plugin-oxc is based on OXC(A fast JavaScript and TypeScript parser in Rust).

This plugin includes two new parsers oxc (JavaScript syntax) and oxc-ts (TypeScript syntax), to use this plugin:

  1. Install the plugin

    yarn add --dev prettier @prettier/plugin-oxc

  2. Add the following to your .prettierrc file

    plugins:

    - "@prettier/plugin-oxc"

Due to package size limitations, this plugin is not included in the prettier package, it needs to be installed separately.

For more information, check the package homepage.

Many thanks to the OXC team(@boshen, @overlookmotel, and other contributors).

Flow

Added a new official plugin @prettier/plugin-hermes (#17520 by @fisker)

@prettier/plugin-hermes is based on Hermes JS Engine.

This plugin includes a new parser hermes (Flow syntax), to use this plugin:

  1. Install the plugin

    yarn add --dev prettier @prettier/plugin-hermes

  2. Add the following to your .prettierrc file

    plugins:

    - "@prettier/plugin-hermes"

Due to package size limitations, this plugin is not included in the prettier package, it needs to be installed separately.

We plan to make this as the default parser for Flow syntax support in v4, we'll also remove babel-flow parser in v4, please give it a try.

For more information, check the package homepage.

Many thanks to the Hermes team.

Other Changes

JavaScript

Add parentheses to SequenceExpression in ReturnStatement and ExpressionStatement (#17085 by @TYKevin)

// Input

function a() {

return ( a, b)

}

(a(), b());

// Prettier 3.5

function a() {

return a, b;

}

a(), b();

// Prettier 3.6

function a() {

return (a, b);

}

(a(), b());

Add parentheses to AssignmentExpression in class property keys (#17145 by @fisker)

Previously we only add parentheses to AssignmentExpression in object keys, but not in class property keys. Thanks to Biome for bringing our attention to this inconsistency.

// Input

a = {

[(x = "key")]: 1,

}

class A {

[(x = "property")] = 1;

[(x = "method")]() {}

}

// Prettier 3.5

a = {

[(x = "key")]: 1,

};

class A {

[x = "property"] = 1;

[(x = "method")]() {}

}

// Prettier 3.6

a = {

[(x = "key")]: 1,

};

class A {

[(x = "property")] = 1;

[(x = "method")]() {}

}

Add parentheses to numbers in optional member expression (#17190 by @fisker)

There is an inconsistency when formatting member expression where the object is a number before Prettier 3.6.

When using babel parser(and other Babel based parsers), we print the number as unparenthesized, when using typescript parser(and other ESTree parsers), we print it as parenthesized.

Technically parentheses are not needed, but if we print it as 1?.toString() and later users realize it's unnecessary to use ?., users can't simply remove the question mark because 1.toString() will raise a SyntaxError, for this reason, we decide to always put parentheses around it.

// Input

(1)?.toString();

(1.5)?.toString();

// Prettier 3.5 (--parser=babel)

1?.toString();

1.5?.toString();

// Prettier 3.5 (--parser=typescript)

(1)?.toString();

(1.5)?.toString();

// Prettier 3.6

(1)?.toString();

(1.5)?.toString();

Removed support for experimental Records & Tuples (#17363 by @fisker)

The ES proposal JavaScript Records & Tuples Proposal has been withdrawn.

Preserve spaces between CSS words and embedded expression (#17398 by @sosukesuzuki)

// Input

const Heading = styled.h1`

font-size: var(--font-size-h${level});

`;

// Prettier 3.5

const Heading = styled.h1`

font-size: var(--font-size-h ${level});

`;

// Prettier 3.6

const Heading = styled.h1`

font-size: var(--font-size-h${level});

`;

Fix inconsistent assignment format (#17469 by @fisker)

// Input

didScheduleRenderPhaseUpdateDuringThisPassFoo = didScheduleRenderPhaseUpdate = true

// Prettier 3.5 (--parser=babel)

didScheduleRenderPhaseUpdateDuringThisPassFoo =

didScheduleRenderPhaseUpdate = true;

// Prettier 3.5 (--parser=typescript)

didScheduleRenderPhaseUpdateDuringThisPassFoo = didScheduleRenderPhaseUpdate =

true;

// Prettier 3.6

didScheduleRenderPhaseUpdateDuringThisPassFoo =

didScheduleRenderPhaseUpdate = true;

Fix inconsistent member chain format (#17470 by @fisker)

// Input

s.get(u)?.trigger({ triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123 });

// Prettier 3.5 (--parser=babel)

s.get(u)?.trigger({

triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123,

});

// Prettier 3.5 (--parser=typescript)

s

.get(u)

?.trigger({ triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123 });

// Prettier 3.6

s.get(u)?.trigger({

triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123,

});

Fix optional chaining as computed key (#17486 by @fisker)

// Input

const a = { [y?.z]() {} };

class A { [y?.z]() {} };

// Prettier 3.5

const a = { [y?.z]?() {} };

class A {

[y?.z]?() {}

}

// Prettier 3.6

const a = { [y?.z]() {} };

class A {

[y?.z]() {}

}

Support type cast comments for acorn and meriyah parser (#17491, #17566 by @ArnaudBarre, #17600 by #fisker)

This was previously only supported by the Babel parser.

// Input

/** @type {MyType} */ (x).foo;

// Prettier 3.5 (--parser=acorn|meriyah)

/** @type {MyType} */ x.foo;

// Prettier 3.6

/** @type {MyType} */ (x).foo;

Fix unstable comment format in tagged template literal (#17510 by @fisker)

// Input

foo

// Comment

`x`

// Prettier 3.5 (First format)

foo// Comment

`x`;

// Prettier 3.5 (Second format)

foo // Comment

`x`;

// Prettier 3.6

foo // Comment

`x`;

Improve consistency for JSX in optional method call (#17616 by @seiyab)

// Input

<SuspendyTree>

<div style={{ height: 200, overflow: "scroll" }}>

{Array(20)

.fill()

?.map((_, i) => (

<h2 key={i}>{i + 1}</h2>

))}

</div>

</SuspendyTree>;

// Prettier 3.5 (ESTree based parsers like espree and typescript)

<SuspendyTree>

<div style={{ height: 200, overflow: "scroll" }}>

{Array(20)

.fill()

?.map((_, i) => <h2 key={i}>{i + 1}</h2>)}

</div>

</SuspendyTree>;

// Prettier 3.5 (babel and babel-ts parser)

<SuspendyTree>

<div style={{ height: 200, overflow: "scroll" }}>

{Array(20)

.fill()

?.map((_, i) => (

<h2 key={i}>{i + 1}</h2>

))}

</div>

</SuspendyTree>;

// Prettier 3.6 (parsers of both types)

<SuspendyTree>

<div style={{ height: 200, overflow: "scroll" }}>

{Array(20)

.fill()

?.map((_, i) => (

<h2 key={i}>{i + 1}</h2>

))}

</div>

</SuspendyTree>;

TypeScript

Support import type attribute in TSImportType (#16881 by @fisker)

// Input

type A = import("foo", {with: {type: "json"}})

// Prettier 3.5

type A = import("foo")

// Prettier 3.6

type A = import("foo", { with: { type: "json" } });

Fix comments in logical expression and intersection type (#17193 by @fisker)

// Input

export type ErrorLike =

SerializedProps<Error> &

// cause is a new addition to Error that is not yet available in all runtimes. We have added

// it to try and pinpoint additional reasoning for failures such as Node's fetch.

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

{ cause?: unknown };

// Prettier 3.5

export type ErrorLike =

SerializedProps<Error> & // cause is a new addition to Error that is not yet available in all runtimes. We have added

// it to try and pinpoint additional reasoning for failures such as Node's fetch.

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

{ cause?: unknown };

// Prettier 3.5 (second format)

export type ErrorLike =

SerializedProps<Error> & // it to try and pinpoint additional reasoning for failures such as Node's fetch. // cause is a new addition to Error that is not yet available in all runtimes. We have added

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

{ cause?: unknown };

// Prettier 3.6

export type ErrorLike = SerializedProps<Error> &

// cause is a new addition to Error that is not yet available in all runtimes. We have added

// it to try and pinpoint additional reasoning for failures such as Node's fetch.

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

{ cause?: unknown };

Improve new line detect in mapped type (#17498 by @fisker)

// Input

type A = { readonly

[A in B]: T}

// Prettier 3.5

type A = {

readonly [A in B]: T;

};

// Prettier 3.6

type A = { readonly [A in B]: T };

Don't print extra semicolon after prettier-ignored index-signature (#17538 by @sosukesuzuki)

// Input

type foo = {

// prettier-ignore

[key: string]: bar;

};

// Prettier 3.5

type foo = {

// prettier-ignore

[key: string]: bar;;

};

// Prettier 3.6

type foo = {

// prettier-ignore

[key: string]: bar;

};

Flow

Fix missing parentheses in ConditionalTypeAnnotation (#17196 by @fisker)

// Input

type T<U> = 'a' | ('b' extends U ? 'c' : empty);

type T<U> = 'a' & ('b' extends U ? 'c' : empty);

// Prettier 3.5

type T<U> = "a" | "b" extends U ? "c" : empty;

type T<U> = "a" & "b" extends U ? "c" : empty;

// Prettier 3.6

type T<U> = "a" | ("b" extends U ? "c" : empty);

type T<U> = "a" & ("b" extends U ? "c" : empty);

JSON

Allow format comment-only JSONC files (#17269 by @fisker)

// Input

// Comment

// Prettier 3.5

SyntaxError: Unexpected token (1:11)

> 1 | // Comment

| ^

// Prettier 3.6

// Comment

Forbid parenthesized expressions (#17598 by @fisker)

// Input

[1, (2)]

// Prettier 3.5

[1, 2]

// Prettier 3.6

SyntaxError: 'ParenthesizedExpression' is not allowed in JSON. (1:5)

> 1 | [1, (2)]

| ^^^

CSS

Support @utility directive for Tailwind (#17362 by @sosukesuzuki)

This change supports @utility directive for Tailwind CSS V4.

/* Input */

@utility tab-* {

tab-size: --value(--tab-size-*);

}

/* Prettier 3.5 */

@utility tab-* {

tab-size: --value(--tab-size- *);

}

/* Prettier 3.6 */

@utility tab-* {

tab-size: --value(--tab-size-*);

}

Remove extra indentation for :has pseudo call (#17541 by @sosukesuzuki)

/* Input */

li:has(

path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"]

) {

display: none;

}

/* Prettier 3.5 */

li:has(

path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"]

) {

display: none;

}

/* Prettier 3.6 */

li:has(

path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"]

) {

display: none;

}

Less

Fix function argument incorrectly lowercased (#17502 by @fisker)

// Input

.what {

.make-modifier(1A, "1a.png");

.make-modifier(AA, "1a.png");

}

// Prettier 3.5

.what {

.make-modifier(1a, "1a.png");

.make-modifier(AA, "1a.png");

}

// Prettier 3.6

.what {

.make-modifier(1A, "1a.png");

.make-modifier(AA, "1a.png");

}

HTML

Fix formatting when tag name is an object prototype property (#17501 by @fisker)

<!-- Input -->

<constructor>

text

</constructor>

<!-- Prettier 3.5 -->

TypeError: Vn(...).startsWith is not a function

<!-- Prettier 3.6 -->

<constructor> text </constructor>

Angular

Support TemplateLiteral introduced in Angular 19.2 (#17238 by @fisker)

Angular 19.2 added support for TemplateLiteral.

<!-- Input -->

<div>{{ `Hello, ${

getName('world')}` }}</div>

<!-- Prettier 3.5 -->

<div>

{{ `Hello, ${

getName('world')}` }}

</div>

<!-- Prettier 3.6 -->

<div>{{ `Hello, ${getName("world")}` }}</div>

Remove extra colon after track in angular @for control-flow (#17280 by @claudio-herger)

// Input

@for (item of items; let i = $index; let count = $count; track block) {}

// Prettier 3.5

@for (item of items; let i = $index; let count = $count; track: block) {}

// Prettier 3.6

@for (item of items; let i = $index; let count = $count; track block) {}

Support Angular 20 (#17534 by @fisker)

// Input

{{

( (a in (b)))

}}

{{

( (tag ` a ${ b } \u0063 `))

}}

{{

( (` a ${ b } \u0063 `))

}}

{{ void(1 + 2) }}

// Prettier 3.5

The new syntax is not correctly recognized.

// Prettier 3.6

{{ a in b }}

{{ tag` a ${b} \u0063 ` }}

{{ ` a ${b} \u0063 ` }}

{{ void (1 + 2) }}

MJML

Enabling CSS formatting within <mj-style> tag (#17338 by @iryusa)

<!-- Input -->

<mj-style>

.hello {

color: blue;

border: 1px solid blue;

font-size:12px;

} p { font-size: 14px; }

</mj-style>

<!-- Prettier 3.5 -->

<mj-style>

.hello { color: blue; border: 1px solid blue; font-size:12px; } p { font-size:

14px; }

</mj-style>

<!-- Prettier 3.6 -->

<mj-style>

.hello {

color: blue;

border: 1px solid blue;

font-size: 12px;

}

p {

font-size: 14px;

}

</mj-style>

Correctly parse <mj-style> and <mj-raw> (#17400 by @fisker)

<!-- Input -->

<mj-style>

a::before {

content: "</p>";

}

</mj-style>

<!-- Prettier 3.5 -->

SyntaxError: Unexpected closing tag "p".

<!-- Prettier 3.6 -->

Correctly parsed as CSS.

Markdown

Fix adjacent markdown syntax in blockquote (#16596 by @fiji-flo)

<!-- Input -->

> `x`

> `y`

> _x_

> _y_

> [foo](http://foo)

> [bar](http://bar)

> `this` behaves

> `correctly`

<!-- Prettier 3.5 -->

> `x` > `y`

> _x_ > _y_

> [foo](http://foo) > [bar](http://bar)

> `this` behaves `correctly`

<!-- Prettier 3.6 -->

> `x` `y`

> _x_ _y_

> [foo](http://foo) [bar](http://bar)

> `this` behaves `correctly`

Fix markdown inserts unexpected newline in lists (#16637 by @byplayer)

<!-- Input -->

- Level 1

- Level 1-1

- Level 2

<!-- Prettier 3.5 -->

- Level 1

- Level 1-1

- Level 2

<!-- Prettier 3.6 -->

- Level 1

- Level 1-1

- Level 2

Fix strong emphasis (#17143 by @fiji-flo)

Most markdown implementations don't support 1**_2_**3 so prefer 1***2***3.

<!-- Input -->

1***2***3

1**_2_**3

<!-- Prettier 3.5 -->

1**_2_**3

1**_2_**3

<!-- Prettier 3.6 -->

1***2***3

1***2***3

YAML

Do not add line break before empty map or sequence (#16074 by @BapRx)

# Input

---

myDict: {}

# comment

myList: []

# comment

# Prettier 3.5

---

myDict:

{}

# comment

myList:

[]

# comment

# Prettier 3.6

---

myDict: {}

# comment

myList: []

# comment

API

Accept URL in plugins option (#17166 by @fisker)

plugins option now accepts URL with file: protocol or a url string that starts with file: in all public APIs.

// `URL`

await prettier.check("foo", {

parser: "my-cool-parser",

plugins: [new URL("./path/to/plugin.js", import.meta.url)],

});

await prettier.format("foo", {

parser: "my-cool-parser",

plugins: [new URL("./path/to/plugin.js", import.meta.url)],

});

await prettier.formatWithCursor("foo", {

parser: "my-cool-parser",

cursorOffset: 2,

plugins: [new URL("./path/to/plugin.js", import.meta.url)],

});

await prettier.getFileInfo("/path/to/file", {

plugins: [new URL("./path/to/plugin.js", import.meta.url)],

});

await prettier.getSupportInfo({

plugins: [new URL("./path/to/plugin.js", import.meta.url)],

});

// URL string

await prettier.check("foo", {

parser: "my-cool-parser",

plugins: ["file:///path/to/plugin.js"],

});

await prettier.format("foo", {

parser: "my-cool-parser",

plugins: ["file:///path/to/plugin.js"],

});

await prettier.formatWithCursor("foo", {

parser: "my-cool-parser",

cursorOffset: 2,

plugins: ["file:///path/to/plugin.js"],

});

await prettier.getFileInfo("/path/to/file", {

plugins: ["file:///path/to/plugin.js"],

});

await prettier.getSupportInfo({

plugins: ["file:///path/to/plugin.js"],

});

Accept URL as custom config file in resolveConfig (#17167 by @fisker)

prettier.resolveConfig() now accepts an URL with file: protocol or a url string that starts with file: as custom config file location.

// `URL`

await prettier.resolveConfig("path/to/file", {

config: new URL("/path/to/prettier-config-file", import.meta.url),

});

// URL string

await prettier.resolveConfig("path/to/file", {

config: "file:///path/to/prettier-config-file",

});

Stop interpret *.frag files as JavaScript files (#17178 by @fisker)

*.frag was interpreted as JavaScript files, but .frag is also used in GLSL(OpenGL Shading Language). It causes error when Prettier try to format them as JavaScript files.

Since Prettier 3.6, *.frag files except *.start.frag, *.end.frag, start.frag, and end.frag are no longer treated as JavaScript files.

If you have JavaScript files with .frag that do not match the patterns mentioned above, you can config with overrides.

export default {

overrides: {

files: "**/*.frag",

options: {

parser: "babel",

},

},

};

Add isSupported function support for languages API (#17331 by @JounQin, #17490 by @fisker)

Previously, languages API for custom plugins only supported inferring parser based on the file basename or extension.

Prettier 3.6 added isSupported: (options: { filepath: string }) => boolean function to allow plugin check if file is supported based on the full path (eg: files in a specific directory).

note

Prettier can not ensure that filepath exists on disk.
When using from APIs(eg: prettier.format()), Prettier can not ensure it's a valid path either.

If no isSupported provided, it just behaves the same way as before.

export const languages = [

{

name: "foo",

parsers: ["foo"],

isSupported: ({ filepath }) => filepath.includes(".foo"),

},

];

Add mjml parser (#17339 by @fisker)

We already support MJML in previous version with html parser, in order to distinguish MJML-specific a new mjml parser added.

Ignore files with --check-ignore-pragma (#17344 by @wnayes)

Individual files can now opt out of formatting via @noformat or @noprettier "pragma" comments at the top of the file.

To enable this feature, use the new option --check-ignore-pragma (checkIgnorePragma via configuration or API).

Language plugins can implement support for this feature. Most built-in parsers, including JavaScript (TypeScript), CSS, HTML, JSON, Markdown (MDX), YAML, and GraphQL, were updated to support this feature.

/**

* @noformat

*/

export default matrix(

1, 0, 0,

0, 1, 0,

0, 0, 1

);

Fix plugin loading in prettier.getFileInfo() (#17548 by @fisker)

In previous version, prettier.getFileInfo() only read parser config from .prettierrc, but doesn't load plugins to infer parser from plugin languages, Prettier 3.6 fixed it.

// prettier-plugin-foo

export const languages = [

{

parsers: ["foo"],

extensions: [".foo"],

},

];

# .prettierrc

plugins:

- prettier-plugin-foo

prettier --file-info file.foo

# Prettier 3.5

{ "ignored": false, "inferredParser": null }

# Prettier 3.6

{ "ignored": false, "inferredParser": "foo" }

Allow plugin to override builtin parsers when inferring parser (#17549 by @fisker)

Previously when inferring parser for file, builtin plugins are checked first, so plugins are not able to override parsers for files like .js.

// prettier-plugin-foo

export const languages = [

{

parsers: ["foo"],

extensions: [".js"],

},

];

// prettier.config.js

import * as prettierPluginFoo from "prettier-plugin-foo";

export default {

plugins: [prettierPluginFoo],

};

prettier --file-info file.js

# Prettier 3.5

{ "ignored": false, "inferredParser": "babel" }

# Prettier 3.6

{ "ignored": false, "inferredParser": "foo" }

CLI

Forbid use --config and --no-config together (#12221 by @Balastrong)

$ prettier --config=.prettierrc --no-config .

[error] Cannot use --no-config and --config together.

Ignore file modified time when --cache-strategy=content (#17438 by @fisker)

In previous version, when using --cache-strategy=content, if the file modified time changed, it still gets re-formatted even the file content didn't change, Prettier 3.6 fixed it.

Fix result message for files can not be formatted (#17505 by @fisker)

touch unknown

prettier --check unknown

# Prettier 3.5

Checking formatting...

unknown

[error] No parser could be inferred for file "</path/to/unknown>".

All matched files use Prettier code style!

# Prettier 3.6

Checking formatting...

unknown

[error] No parser could be inferred for file "</path/to/unknown>".

Error occurred when checking code style in the above file.

Fix exitCode when parser cannot infer (#17505 by @fisker)

touch unknown

prettier --check unknown > /dev/null;echo $?

# Prettier 3.5

[error] No parser could be inferred for file "</path/to/unknown>".

0

# Prettier 3.6

[error] No parser could be inferred for file "</path/to/unknown>".

2

Miscellaneous

Fix embedded format with cursorOffset (#17254 by @fisker)

<!-- Input (--cursor-offset=1) -->

# Angular note

```typescript

import {Component} from '@angular/core';

@Component({

selector: 'app-root',

standalone: true,

imports: [],

template: `

<h1>

{{ title }}</h1>

`,

styleUrls: ['./app.component.css'],

})

export class AppComponent {

title = 'default';

}

```

<!-- Prettier 3.5 -->

Error: There are too many 'cursor' in doc.

<!-- Prettier 3.6 -->

# Angular note

```typescript

import { Component } from "@angular/core";

@Component({

selector: "app-root",

standalone: true,

imports: [],

template: `

<h1>

{{ title }}

</h1>

`,

styleUrls: ["./app.component.css"],

})

export class AppComponent {

title = "default";

}

```