Prettier 3.1:新增实验性三元表达式格式化方案与 Angular 控制流语法!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本次更新重新为嵌套三元表达式添加了缩进,并新增了 --experimental-ternaries 标志来尝试一种创新的"好奇三元"格式,该格式能更好地适应深层嵌套条件表达式。在年底默认启用该格式前,我们热切期待您通过反馈表单提供宝贵意见!
同时新增了对 Angular v17 控制流语法的支持。语法详情请阅读Angular 官方发布说明。
如果您认可 Prettier 的价值并希望支持我们的工作,请考虑通过 我们的 OpenCollective 直接赞助,或赞助我们依赖的项目如 typescript-eslint、remark 和 Babel。感谢您持续的支持!
重要更新
JavaScript
为嵌套三元表达式恢复缩进 (#9559 by @rattrayalex)
// Input
const message =
i % 3 === 0 && i % 5 === 0
? "fizzbuzz"
: i % 3 === 0
? "fizz"
: i % 5 === 0
? "buzz"
: String(i);
// Prettier 3.0
const message =
i % 3 === 0 && i % 5 === 0
? "fizzbuzz"
: i % 3 === 0
? "fizz"
: i % 5 === 0
? "buzz"
: String(i);
// Prettier 3.1
const message =
i % 3 === 0 && i % 5 === 0
? "fizzbuzz"
: i % 3 === 0
? "fizz"
: i % 5 === 0
? "buzz"
: String(i);
实验性三元表达式格式:好奇三元之谜 (#13183 by @rattrayalex)
该功能通过 --experimental-ternaries 标志启用。
我们将多行三元表达式中的 ? 移至首行末尾而非次行开头,并实施多项关联调整。
虽然初看可能略显奇特,但测试表明开发者使用数小时后,普遍认为该格式显著提升了嵌套三元表达式的可读性与实用性。
本次更新解决了我们高票反馈的议题,同时规避了原解决方案可能引发的其他问题。
详情请参阅博客文章《好奇三元表达式之谜》。
示例
// "Questioning" ternaries for simple ternaries:
const content =
children && !isEmptyChildren(children) ?
render(children)
: renderDefaultChildren();
// "Case-style" ternaries for chained ternaries:
const message =
i % 3 === 0 && i % 5 === 0 ? "fizzbuzz"
: i % 3 === 0 ? "fizz"
: i % 5 === 0 ? "buzz"
: String(i);
// Smoothly transitions between "case-style" and "questioning" when things get complicated:
const reactRouterResult =
children && !isEmptyChildren(children) ? children
: props.match ?
component ? React.createElement(component, props)
: render ? render(props)
: null
: null
支持 Babel 7.23.0 新增语法 (#15485, #15486, #15487, #15488 by @sosukesuzuki)
现已支持 Babel 7.23.0 引入的新 JavaScript 语法!
源码阶段导入 (Source Phase Imports)
详见 https://github.com/tc39/proposal-source-phase-imports
import source x from "mod";
延迟导入求值 (Deferred Import Evaluation)
详见 https://github.com/tc39/proposal-defer-import-eval
import defer * as ns from "mod";
可选链式赋值 (Optional Chaining Assignments)
详见 https://github.com/tc39/proposal-optional-chaining-assignment
maybeObj?.prop1 = value;
Angular
支持 Angular 控制流语法 (#15606 by @DingWeizhe, @fisker)
新增对 Angular 17 内置控制流的支持。如果您发现任何问题,请随时向我们反馈。
有关控制流语法的更多详情,请参阅官方博客文章。
https://blog.angular.io/introducing-angular-v17-4d7033312e4b
其他变更
JavaScript
修复括号与函数体之间的注释格式 (#15326 by @fisker)
// Input
function function_declaration()
// this is a function
{
return 42
}
(function function_expression()
// this is a function
{
return 42
})();
// Prettier 3.0
function function_declaration() {
// this is a function
return 42;
}
(function function_expression() // this is a function
{
return 42;
})();
// Prettier 3.1
function function_declaration() {
// this is a function
return 42;
}
(function function_expression() {
// this is a function
return 42;
})();
// Input
function function_declaration()
// this is a function
{
return 42
}
export default function()
// this is a function
{
return 42
}
// Prettier 3.0
TypeError: Cannot read properties of null (reading 'range')
// Prettier 3.1
function function_declaration() {
// this is a function
return 42;
}
export default function () {
// this is a function
return 42;
}
消除 instanceof 和 in 运算符左侧一元表达式的歧义 (#15468 by @lucacasonato)
现在会在 instanceof 和 in 表达式左侧的一元表达式周围添加括号,以区分左侧一元表达式与应用于整个二元表达式的一元运算符。
这有助于避免常见错误:用户本意是写 !("x" in y) 却误写为 !"x" in y(实际会被解析为无意义的 (!"x") in y)。
// Input
!"x" in y;
!("x" in y);
// Prettier 3.0
!"x" in y;
!("x" in y);
// Prettier 3.1
(!"x") in y;
!("x" in y);
修复 styled components 插值中选择器的大小写问题 (#15472 by @lucasols)
// Input
const StyledComponent = styled.div`
margin-right: -4px;
${Container}.isExpanded & {
transform: rotate(-180deg);
}
`;
const StyledComponent2 = styled.div`
margin-right: -4px;
${abc}.camelCase + ${def}.camelCase & {
transform: rotate(-180deg);
}
`;
// Prettier 3.0
const StyledComponent = styled.div`
margin-right: -4px;
${Container}.isexpanded & {
transform: rotate(-180deg);
}
`;
const StyledComponent2 = styled.div`
margin-right: -4px;
${abc}.camelcase + ${def}.camelCase & {
transform: rotate(-180deg);
}
`;
// Prettier 3.1 -- same as input
统一包含转义字符的字符串格式化 (#15525 by @sosukesuzuki)
// Input
export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 =
goog.getMsg("That's all we know");
export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 =
goog.getMsg("That\'s all we know");
// Prettier 3.0
export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 =
goog.getMsg("That's all we know");
export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg(
"That's all we know",
);
// Prettier 3.1
export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 =
goog.getMsg("That's all we know");
export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 =
goog.getMsg("That's all we know");
改进左侧可能换行的赋值语句格式 (#15547 by @sosukesuzuki)
// Input
params["redirectTo"] =
`${window.location.pathname}${window.location.search}${window.location.hash}`;
// Prettier 3.0
params[
"redirectTo"
] = `${window.location.pathname}${window.location.search}${window.location.hash}`;
// Prettier 3.1
params["redirectTo"] =
`${window.location.pathname}${window.location.search}${window.location.hash}`;
TypeScript
修复最后一个参数属性后的注释不稳定问题 (#15324 by @fisker)
// Input
class Class {
constructor(
private readonly paramProp: Type,
// comment
) {
}
}
// Prettier 3.0
class Class {
constructor(private readonly paramProp: Type) // comment
{}
}
// Prettier 3.0 (Second format)
class Class {
constructor(
private readonly paramProp: Type, // comment
) {}
}
// Prettier 3.1
class Class {
constructor(
private readonly paramProp: Type,
// comment
) {}
}
支持在带有 as const 注解的模板字面量中进行嵌入式格式化 (#15408 by @sosukesuzuki)
// Input
const GQL_QUERY_WITH_CONST = /* GraphQL */ `
query S { shop }
` as const;
// Prettier 3.0
const GQL_QUERY_WITH_CONST = /* GraphQL */ `
query S { shop }
` as const;
// Prettier 3.1
const GQL_QUERY_WITH_CONST = /* GraphQL */ `
query S {
shop
}
` as const;
修复联合类型最后一个操作数的注释打印问题 (#15409 by @sosukesuzuki)
// Input
type Foo1 = (
| "thing1" // Comment1
| "thing2" // Comment2
)[]; // Final comment1
type Foo2 = (
| "thing1" // Comment1
| "thing2" // Comment2
) & Bar; // Final comment2
// Prettier 3.0
type Foo1 = (
| "thing1" // Comment1
| "thing2"
)[]; // Comment2 // Final comment1
type Foo2 = (
| "thing1" // Comment1
| "thing2"
) & // Comment2
Bar; // Final comment2
// Prettier 3.1
type Foo1 = (
| "thing1" // Comment1
| "thing2" // Comment2
)[]; // Final comment1
type Foo2 = (
| "thing1" // Comment1
| "thing2" // Comment2
) &
Bar; // Final comment2
在 satisfies / as 表达式语句中为特定关键字标识符保留必需括号 (#15514 by @seiyab)
// Input
(type) satisfies never;
// Prettier 3.0
type satisfies never;
// Prettier 3.1
(type) satisfies never;
Flow
支持 Flow 中的 as 和 satisfies 表达式 (#15130 by @gkz)
// Input
const x = y as T;
// Prettier 3.0
// <error: unsupported>
// Prettier 3.1
const x = y as T;
支持在 Flow 的 JSX 开始元素上使用类型参数 (#15429 by @SamChou19815)
// Input
<Foo<bar> />;
// Prettier 3.0
<Foo />;
// Prettier 3.1
<Foo<bar> />;
支持在 typeof 后使用类型参数 (#15466 by @sosukesuzuki)
支持自 Flow v0.127.0 起新增的 typeof 语法后类型参数:
type Foo = typeof MyGenericClass<string, number>;
SCSS
修复带前导破折号的 SCSS 函数调用不分割问题 (#15370 by @auvred)
/* Input */
div {
width: -double(-double(3));
}
/* Prettier 3.0 */
div {
width: -double(- double(3));
}
/* Prettier 3.1 */
div {
width: -double(-double(3));
}
HTML
修复 menu 和 marquee 元素的格式化问题 (#15334 by @fisker)
<!-- Input -->
<menu><li><button onclick="copy()">Copy</button></li>
<li><button onclick="cut()">Cut</button></li>
<li><button onclick="paste()">Paste</button></li></menu>
<marquee
direction="down"
width="250"
height="200"
behavior="alternate"
style="border:solid"><marquee behavior="alternate"> This text will bounce </marquee></marquee>
<!-- Prettier 3.0 -->
<menu
><li><button onclick="copy()">Copy</button></li>
<li><button onclick="cut()">Cut</button></li>
<li><button onclick="paste()">Paste</button></li></menu
>
<marquee
direction="down"
width="250"
height="200"
behavior="alternate"
style="border: solid"
><marquee behavior="alternate"> This text will bounce </marquee></marquee
>
<!-- Prettier 3.1 -->
<menu>
<li><button onclick="copy()">Copy</button></li>
<li><button onclick="cut()">Cut</button></li>
<li><button onclick="paste()">Paste</button></li>
</menu>
<marquee
direction="down"
width="250"
height="200"
behavior="alternate"
style="border: solid"
>
<marquee behavior="alternate">This text will bounce</marquee>
</marquee>
Markdown
在 Markdown URL 中对 < 和 > 进行编码 (#15400 by @vivekjoshi556)
<!-- Input -->
[link](https://www.google.fr/()foo->bar)
<!-- Prettier 3.0 -->
[link](<https://www.google.fr/()foo->bar>)
<!-- Prettier 3.1 -->
[link](<https://www.google.fr/()foo-%3Ebar>)
<!-- Input -->
foo->bar>)
<!-- Prettier 3.0 -->
foo->bar>)
<!-- Prettier 3.1 -->
foo-%3Ebar>)
禁止在日文假名与 COMBINING KATAKANA-HIRAGANA (SEMI-)VOICED SOUND MARK 之间换行 (#15411 by @tats-u)
此 PR 修复了 #15410。
日语中的半浊音假名字符可以拆分为两个代码点。例如,以下平假名字符 /ka/ 可以表示为:
が (U+304C) → か (U+304B) + ゙ (U+3099) → が (U+304C U+3099)
大多数用户不会使用或遇到这样的表达方式,除了在 macOS 的文件路径中。然而,有些字符只能以这种方式表示。一些日语文本需要区分 /ŋa̠/(尽管如今有不少日本人不再使用)和常见的 /ga/,会使用 "か゚" (U+304B U+309A) 这种表达方式。
nasalか゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚
以上 Markdown 在 Prettier 3.0 中的格式化效果如下:
nasalか゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚け
゚こ゚
半浊音符号会换到下一行,这是不正确的。通过此 PR,源代码 Markdown 现在被格式化为:
nasalか゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚け゚こ゚か゚き゚く゚
け゚こ゚
半浊音符号现在会紧贴在平假名"け"后面。
API
在 prettier.{resolveConfig,resolveConfigFile,getFileInfo}() 中接受 URL (#15332, #15354, #15360, #15364 by @fisker)
prettier.resolveConfig()、prettier.resolveConfigFile() 和 prettier.getFileInfo() 现在接受带有 file: 协议的 URL 或以 file:// 开头的 URL 字符串。
// `URL`
await prettier.resolveConfig(new URL("./path/to/file", import.meta.url));
await prettier.resolveConfigFile(new URL("./path/to/file", import.meta.url));
await prettier.getFileInfo(new URL("./path/to/file", import.meta.url));
await prettier.getFileInfo("/path/to/file", {
ignorePath: new URL("./.eslintignore", import.meta.url),
});
// URL string
await prettier.resolveConfig("file:///path/to/file");
await prettier.resolveConfigFile("file:///path/to/file");
await prettier.getFileInfo("file:///path/to/file");
await prettier.getFileInfo("/path/to/file", {
ignorePath: "file:///path/to/.eslintignore",
});
CLI
仅处理插件支持的文件 (#15433 by @sosukesuzuki)
在 Prettier 3.0 中,通过 CLI 指定目录时,仅会处理带有默认支持扩展名的文件。
在以下场景中,不仅 foo.js 应该被格式化,foo.astro 同样需要被格式化:
# Prettier 3.0 version
$ ls .
foo.js foo.astro
$ cat .prettierrc
{ "plugins": ["prettier-plugin-astro"] }
$ prettier --write .
foo.js 20ms
通过此更新,现在 foo.js 和 foo.astro 都将被格式化:
# Prettier 3.1 branch
$ prettier --write .
foo.js 20ms
foo.astro 32ms
您现在可以用 prettier . 替代 prettier "**/*" --ignore-unknown,因为两者现已等效。
在 CLI --write 中显示 (unchanged) 关键字以提高可访问性 (#15467 by @ADTC)
此前,已更改文件与未更改文件的唯一区别在于文件名的灰色显示。如下方示例所示,当颜色信息缺失时,我们无法区分 a.js 和 b.js。通过添加 (unchanged) 关键字,现在无需依赖颜色即可明确区分。
prettier --write .
# Prettier 3.0
a.js 0ms
b.js 0ms
c.js 0ms (cached)
# Prettier 3.1
a.js 0ms
b.js 0ms (unchanged)
c.js 0ms (unchanged) (cached)
修复格式化包含特殊字符的文件名时报错的问题 (#15597 by @fisker)
prettier "[with-square-brackets].js" --list
# Prettier 3.0
[error] Explicitly specified file was ignored due to negative glob patterns: "[with-square-brackets].js".
# Prettier 3.1
[with-square-brackets].js
