Prettier 3.6:实验性快速 CLI 及全新 OXC 与 Hermes 插件!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本次发布包含多个重要功能更新,我们非常高兴能与您分享。
首先,我们推出了一项实验性高性能 CLI 功能(通过 --experimental-cli 标志启用)。此前该 CLI 仅在 prettier@next 中可用,现在您只需使用一个标志即可启用。我们鼓励您尝试并提供反馈!如果您对其内部实现感兴趣,请阅读 Fabio 撰写的 Prettier CLI 性能深度解析。
此外,我们发布了两个新的官方插件:@prettier/plugin-oxc 和 @prettier/plugin-hermes。这些插件独立于 Prettier 核心包提供。
我们要衷心感谢所有促成此次精彩发布的贡献者:@fabiospampinato、@43081j 和 @pralkarz 以及新 CLI 的贡献者;OXC 贡献者 @boshen、@overlookmotel 及其他成员;以及 Meta 的 Flow 和 Hermes 团队。感谢所有人的卓越贡献!
期待这些新功能能提升您的开发体验。祝您代码格式化愉快!
重要更新
CLI
支持实验性 CLI (#17151, #17396 by @fisker)
您可能已听说或使用过我们性能大幅提升的新版 CLI。从 Prettier 3.6 开始,您无需安装不稳定的 v4 版本即可使用。
# Run CLI with `--experimental-cli`
prettier . --check --experimental-cli
# Or use environment variable `PRETTIER_EXPERIMENTAL_CLI=1`
PRETTIER_EXPERIMENTAL_CLI=1 prettier . --check
JavaScript
新增官方插件 @prettier/plugin-oxc (#17472, #17483 by @fisker)
@prettier/plugin-oxc 基于 OXC(使用 Rust 编写的高性能 JavaScript/TypeScript 解析器)。
该插件包含两个新解析器:oxc(JavaScript 语法)和 oxc-ts(TypeScript 语法),使用方法如下:
-
安装插件
yarn add --dev prettier @prettier/plugin-oxc -
在
.prettierrc文件中添加配置plugins:
- "@prettier/plugin-oxc"
由于包体积限制,此插件未包含在 prettier 主包中,需要单独安装。
更多信息请参见插件主页。
特别感谢 OXC 团队(@boshen、@overlookmotel 及其他贡献者)。
Flow
新增官方插件 @prettier/plugin-hermes (#17520 by @fisker)
@prettier/plugin-hermes 基于 Hermes JS 引擎。
此插件包含一个新的解析器 hermes(用于 Flow 语法),使用方式如下:
-
安装插件
yarn add --dev prettier @prettier/plugin-hermes -
在
.prettierrc文件中添加以下内容:plugins:
- "@prettier/plugin-hermes"
由于包体积限制,此插件未包含在 prettier 主包中,需要单独安装。
我们计划在 v4 版本中将其作为 Flow 语法的默认解析器,同时将移除 babel-flow 解析器,请尝试使用。
更多信息,请查看插件主页。
衷心感谢 Hermes 团队。
其他变更
JavaScript
在 ReturnStatement 和 ExpressionStatement 中为 SequenceExpression 添加括号 (#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());
在类属性键中为 AssignmentExpression 添加括号 (#17145 by @fisker)
此前我们仅在对象键中为 AssignmentExpression 添加括号,而未在类属性键中添加。感谢 Biome 让我们注意到这一不一致性。
// 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")]() {}
}
在可选成员表达式中为数字添加括号 (#17190 by @fisker)
在 Prettier 3.6 之前,当成员表达式的对象为数字时,格式化存在不一致性。
使用 babel 解析器(以及其他基于 Babel 的解析器)时,我们会将数字打印为无括号形式;而使用 typescript 解析器(以及其他 ESTree 解析器)时,则会添加括号。
从技术上讲,括号并非必需,但如果我们将其打印为 1?.toString(),而用户后来发现无需使用 ?.,则无法直接删除问号,因为 1.toString() 会引发 SyntaxError。因此,我们决定始终为其添加括号。
// 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();
移除对实验性 Records & Tuples 的支持 (#17363 by @fisker)
ES 提案 JavaScript Records & Tuples Proposal 已被撤回。
保留 CSS 单词与嵌入表达式之间的空格 (#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});
`;
修复赋值格式不一致问题 (#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;
修复成员链格式不一致问题 (#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,
});
修复可选链作为计算键的问题 (#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]() {}
}
为 acorn 和 meriyah 解析器支持类型转换注释 (#17491, #17566 by @ArnaudBarre, #17600 by #fisker)
此前该功能仅由 Babel 解析器支持。
// Input
/** @type {MyType} */ (x).foo;
// Prettier 3.5 (--parser=acorn|meriyah)
/** @type {MyType} */ x.foo;
// Prettier 3.6
/** @type {MyType} */ (x).foo;
修复带标签模板字符串中的注释格式不稳定问题 (#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`;
提升可选方法调用中 JSX 格式的一致性 (#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
在 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" } });
修复逻辑表达式和交集类型中的注释问题 (#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 };
改进映射类型中的换行检测 (#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 };
避免在 prettier-ignore 标记的索引签名后打印多余分号 (#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
修复 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
允许格式化仅含注释的 JSONC 文件 (#17269 by @fisker)
// Input
// Comment
// Prettier 3.5
SyntaxError: Unexpected token (1:11)
> 1 | // Comment
| ^
// Prettier 3.6
// Comment
禁止使用带括号的表达式 (#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
支持 Tailwind 的 @utility 指令 (#17362 by @sosukesuzuki)
此项变更支持 Tailwind CSS V4 的 @utility 指令。
/* 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-*);
}
移除 :has 伪类调用的额外缩进 (#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
修复函数参数被错误转换为小写的问题 (#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
修复当标签名是对象原型属性时的格式化问题 (#17501 by @fisker)
<!-- Input -->
<constructor>
text
</constructor>
<!-- Prettier 3.5 -->
TypeError: Vn(...).startsWith is not a function
<!-- Prettier 3.6 -->
<constructor> text </constructor>
Angular
支持 Angular 19.2 中引入的 TemplateLiteral (#17238 by @fisker)
Angular 19.2 增加了对 TemplateLiteral 的支持。
<!-- Input -->
<div>{{ `Hello, ${
getName('world')}` }}</div>
<!-- Prettier 3.5 -->
<div>
{{ `Hello, ${
getName('world')}` }}
</div>
<!-- Prettier 3.6 -->
<div>{{ `Hello, ${getName("world")}` }}</div>
移除 Angular @for 控制流中 track 后面的额外冒号 (#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) {}
支持 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
支持在 <mj-style> 标签内格式化 CSS (#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>
正确解析 <mj-style> 和 <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
修复块引用中相邻 Markdown 语法的问题 (#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`
修复 Markdown 在列表中意外插入换行的问题 (#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
修复粗体强调格式问题 (#17143 by @fiji-flo)
大多数 Markdown 实现不支持 1**_2_**3,因此改用 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
避免在空的映射或序列前添加换行 (#16074 by @BapRx)
# Input
---
myDict: {}
# comment
myList: []
# comment
# Prettier 3.5
---
myDict:
{}
# comment
myList:
[]
# comment
# Prettier 3.6
---
myDict: {}
# comment
myList: []
# comment
API
在 plugins 选项中接受 URL (#17166 by @fisker)
plugins 选项现在在所有公共 API 中接受带有 file: 协议的 URL 或以 file: 开头的 URL 字符串。
// `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"],
});
接受在 resolveConfig 中使用 URL 作为自定义配置文件 (#17167 by @fisker)
prettier.resolveConfig() 现在接受使用 URL(需为 file: 协议)或以 file: 开头的 URL 字符串作为自定义配置文件路径。
// `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",
});
停止将 *.frag 文件识别为 JavaScript 文件 (#17178 by @fisker)
此前 *.frag 文件被识别为 JavaScript 文件,但 .frag 扩展名也用于 GLSL(OpenGL 着色语言),导致 Prettier 尝试将其格式化为 JavaScript 时出错。
自 Prettier 3.6 起,除 *.start.frag、*.end.frag、start.frag 和 end.frag 之外的 *.frag 文件不再被视为 JavaScript 文件。
如果您的 JavaScript 文件使用了不匹配上述模式的 .frag 扩展名,可通过 overrides 配置覆盖此行为。
export default {
overrides: {
files: "**/*.frag",
options: {
parser: "babel",
},
},
};
为 languages API 添加 isSupported 函数支持 (#17331 by @JounQin, #17490 by @fisker)
此前自定义插件的 languages API 仅支持通过文件基本名或扩展名推断解析器。
Prettier 3.6 新增了 isSupported: (options: { filepath: string }) => boolean 函数,允许插件根据完整路径(例如特定目录中的文件)检查文件是否受支持。
Prettier 无法保证 filepath 在磁盘上实际存在。
通过 API(如 prettier.format())调用时,也无法保证该路径有效。
若未提供 isSupported 函数,其行为将与之前版本保持一致。
export const languages = [
{
name: "foo",
parsers: ["foo"],
isSupported: ({ filepath }) => filepath.includes(".foo"),
},
];
新增 mjml 解析器 (#17339 by @fisker)
此前版本已通过 html 解析器支持 MJML,为区分 MJML 特定语法,现新增专用 mjml 解析器。
通过 --check-ignore-pragma 忽略文件 (#17344 by @wnayes)
单个文件现在可通过在文件顶部添加 @noformat 或 @noprettier 的 "pragma" 注释来跳过格式化。
启用此功能需使用新选项 --check-ignore-pragma(或通过配置文件/API 的 checkIgnorePragma 选项)。
语言插件可实现该功能支持。大多数内置解析器(包括 JavaScript(TypeScript)、CSS、HTML、JSON、Markdown(MDX)、YAML 和 GraphQL)均已更新支持此功能。
/**
* @noformat
*/
export default matrix(
1, 0, 0,
0, 1, 0,
0, 0, 1
);
修复 prettier.getFileInfo() 中的插件加载问题 (#17548 by @fisker)
在先前版本中,prettier.getFileInfo() 仅从 .prettierrc 读取 parser 配置,但未加载插件来通过插件的 languages 推断解析器。Prettier 3.6 已修复此问题。
// 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" }
允许插件在推断解析器时覆盖内置解析器 (#17549 by @fisker)
先前在推断文件解析器时,内置插件会被优先检查,导致第三方插件无法覆盖 .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
禁止同时使用 --config 和 --no-config (#12221 by @Balastrong)
$ prettier --config=.prettierrc --no-config .
[error] Cannot use --no-config and --config together.
当 --cache-strategy=content 时忽略文件修改时间 (#17438 by @fisker)
在先前版本中,使用 --cache-strategy=content 时,即使文件内容未改变,只要修改时间变化就会重新格式化。Prettier 3.6 已修复此问题。
修复无法格式化文件的提示信息 (#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.
修复解析器无法推断时的 exitCode (#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
其他改进
修复 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";
}
```
