Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins!
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:
-
Install the plugin
yarn add --dev prettier @prettier/plugin-oxc
-
Add the following to your
.prettierrc
fileplugins:
- "@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:
-
Install the plugin
yarn add --dev prettier @prettier/plugin-hermes
-
Add the following to your
.prettierrc
fileplugins:
- "@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-ignore
d 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).
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";
}
```