Prettier 2.1:新增 --embedded-language-formatting 选项以及 JavaScript/TypeScript 新功能!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本次发布新增了 --embedded-language-formatting 选项,支持 JavaScript/TypeScript 新特性,并包含大量错误修复与改进!
重要更新
API
新增 --embedded-language-formatting={auto,off} 选项 (#7875 by @bakkot, #8825 by @fisker)
当 Prettier 检测到您在其他文件的字符串中嵌入了它可识别的代码格式(例如 JavaScript 中标签名为 html 的模板字符串或 Markdown 代码块),默认会尝试格式化这些代码。
有时此行为可能不受欢迎,因为它可能改变代码行为。该选项允许您在默认行为(auto)和完全禁用此功能(off)之间切换。此设置适用于 Prettier 支持的所有包含嵌入式代码的语言,不限于 JavaScript。
// Input
html`
<p>
I am expecting this to come out exactly like it went in.
`;
// using --embedded-language-formatting=auto (or omitting this option)
html`
<p>
I am expecting this to come out exactly like it went in.
</p>
`;
// using --embedded-language-formatting=off
html`
<p>
I am expecting this to come out exactly like it went in.
`;
TypeScript
支持 TypeScript 4.0
带标签的元组元素 (#8885 by @fisker, #8982 by @sosukesuzuki)
// Input
type Range = [start: number, end: number];
// Prettier 2.0
SyntaxError: Unexpected token, expected "," (1:20)
> 1 | type Range = [start: number, end: number];
// Prettier 2.1
type Range = [start: number, end: number];
短路赋值运算符 (#8982 by @sosukesuzuki)
// Input
a ||= b;
// Prettier 2.0
SyntaxError: Expression expected. (1:5)
> 1 | a ||= b;
// Prettier 2.1
a ||= b;
catch 子句的类型注解 (#8805 by @fisker)
// Input
try {} catch (e: any) {}
// Prettier 2.0
try {
} catch (e) {}
// Prettier 2.1
try {
} catch (e: any) {}
其他变更
JavaScript
支持 F# 和智能管道操作符提案 (#6319 by @sosukesuzuki, @thorn0, #7979 by @sosukesuzuki)
F# 风格管道:
// Input
promises |> await;
// Output (Prettier 2.0)
SyntaxError: Unexpected token (1:18)
> 1 | promises |> await;
| ^
// Output (Prettier 2.1)
promises |> await;
智能管道:
// Input
5 |> # * 2
// Output (Prettier 2.0)
SyntaxError: Unexpected character '#' (1:6)
> 1 | 5 |> # * 2
| ^
// Output (Prettier 2.1)
5 |> # * 2
修复行尾注释后跟随尾随空格的问题 (#8069 by @shisama)
如果注释行包含尾部空格,Prettier 无法正确识别其为行尾注释。
// Input
var a = { /* extra whitespace --> */
b };
var a = { /* no whitespace --> */
b };
// Prettier 2.0
var a = {
/* extra whitespace --> */
b,
};
var a = {
/* no whitespace --> */ b,
};
// Prettier 2.1
var a = {
/* extra whitespace --> */ b,
};
var a = {
/* no whitespace --> */ b,
};
修复 styled-components 模板字面量中注入表达式解析不一致问题 (#8097 by @thecodrr)
// Input
const SingleConcat = styled.div`
${something()}
& > ${Child}:not(:first-child) {
margin-left:5px;
}
`
const MultiConcats = styled.div`
${something()}
& > ${Child}${Child2}:not(:first-child) {
margin-left:5px;
}
`
const SeparatedConcats = styled.div`
font-family: "${a}", "${b}";
`
// Prettier 2.0 -- same as input
// Prettier 2.1
const SingleConcat = styled.div`
${something()}
& > ${Child}:not(:first-child) {
margin-left: 5px;
}
`;
const MultiConcats = styled.div`
${something()}
& > ${Child}${Child2}:not(:first-child) {
margin-left: 5px;
}
`;
const SeparatedConcats = styled.div`
font-family: "${a}", "${b}";
`;
修复对象尾部逗号在最后一个属性被忽略的问题 (#8111 by @fisker)
// Input
const foo = {
// prettier-ignore
bar: "baz"
}
// Prettier 2.0
const foo = {
// prettier-ignore
bar: "baz"
};
// Prettier 2.1
const foo = {
// prettier-ignore
bar: "baz",
};
保留包含转义序列的对象键值原始格式 (#8160 by @fisker)
// Input
const a = {
"\u2139": 'why "\\u2139" converted to "i"?',
};
// Prettier 2.0
const a = {
ℹ: 'why "\\u2139" converted to "i"?',
};
// Prettier 2.1
const a = {
"\u2139": 'why "\\u2139" is converted to "i"?',
};
修复 CSS-in-JS 中减号后多余空格问题 (#8255 by @thorn0)
// Input
css`
color: var(--global--color--${props.color});
`
// Prettier 2.0
css`
color: var(--global--color-- ${props.color});
`;
// Prettier 2.1
css`
color: var(--global--color--${props.color});
`;
修复类声明/表达式中 extends 部分的注释格式 (#8312 by @thorn0)
// Input
class a extends a // comment
{
constructor() {}
}
// Prettier 2.0
class a extends a // comment {
constructor() {}
}
// Prettier 2.1
class a extends a { // comment
constructor() {}
}
禁止在 Jest 的 test.each 模板字符串中包装数组 (#8354 by @yogmel)
// Input
test.each`
a | b | c
${1} | ${[{ start: 1, end: 3 },{ start: 15, end: 20 },]} | ${[]}
`("example test", ({a, b, c}) => {})
// Prettier 2.0
test.each`
a | b | c
${1} | ${[
{ start: 1, end: 3 },
{ start: 15, end: 20 }
]} | ${[]}
`("example test", ({ a, b, c }) => {});
// Prettier 2.1
test.each`
a | b | c
${1} | ${[{ start: 1, end: 3 }, { start: 15, end: 20 }]} | ${[]}
`("example test", ({ a, b, c }) => {});
支持在包含 shebang 的文件中使用 insertPragma 和 requirePragma (#8376 by @fisker)
// `--insert-pragma`
// Input
#!/usr/bin/env node
hello
.world();
// Prettier 2.0
SyntaxError: Unexpected token (3:1)
1 | /** @format */
2 |
> 3 | #!/usr/bin/env node
| ^
4 | hello
5 | .world();
// Prettier 2.1
#!/usr/bin/env node
/** @format */
hello.world();
// `--require-pragma`
// Input
#!/usr/bin/env node
/**
* @format
*/
hello
.world();
// Prettier 2.0
#!/usr/bin/env node
/**
* @format
*/
hello
.world();
// Prettier 2.1
#!/usr/bin/env node
/**
* @format
*/
hello.world();
修复范围格式化的缩进问题 (#8410 by @thorn0)
> echo -e "export default class Foo{\n/**/\n}" | prettier --range-start 16 --range-end 31 --parser babel
// Prettier 2.0
export default class Foo {
/**/
}
// Prettier 2.1
export default class Foo {
/**/
}
改进范围格式化的源元素检测机制 (#8419 by @thorn0)
此前并非所有语句类型都能被正确检测(参阅 Prettier 文档了解范围格式化工作原理)。
// Input
for (const element of list) { /* ... */ }
// ^^^^^^^^^^^^^^^^^^^^^^ ← range
// Prettier 2.0
for (const element of list) { /* ... */ }
// Prettier 2.1
for (const element of list) {
/* ... */
}
支持 in 运算符中的私有字段 (#8431 by @sosukesuzuki)
支持 Stage 2 提案 Private Fields in in。
// Input
#prop in obj;
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #prop in obj;
| ^
2 |
// Prettier 2.1
#prop in obj;
支持 ES 模块属性和 JSON 模块 (#8436 by @fisker)
支持 Stage 2 提案 ES Module Attributes and JSON modules。
// Input
import foo from "foo.json" with type: "json";
// Prettier 2.0
SyntaxError: Unexpected token, expected ";" (1:28)
> 1 | import foo from "foo.json" with type: "json";
| ^
// Prettier 2.1
import foo from "foo.json" with type: "json";
支持记录(Record)和元组(Tuple)语法 (#8453 by @fisker)
支持 Stage 2 提案 JavaScript Records & Tuples Proposal。
仅支持 #[]/#{} 语法,不支持 {| |} / [| |] 语法。
元组示例
// Input
#[1, 2, 3]
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #[1, 2, 3]
| ^
// Prettier 2.1
#[1, 2, 3];
记录示例
// Input
#{
a: 1,
b: 2,
c: 3,
}
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #{
| ^
2 | a: 1,
3 | b: 2,
4 | c: 3,
// Prettier 2.1
#{
a: 1,
b: 2,
c: 3,
};
自动为位于 "<" 左侧的 JSX 元素包裹括号 (#8461 by @sosukesuzuki)
// Input
(<div/>) < 5;
// Prettier 2.0
<div/> < 5;
// Prettier 2.0 second output
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (1:9)
> 1 | <div /> < 5;
| ^
2 |
// Prettier 2.1
(<div />) < 5;
修复含尾部注释的二元表达式缩进问题 (#8476 by @sosukesuzuki)
// Input
a +
a + // comment
a;
// Prettier 2.0
a +
a + // comment
a;
// Prettier 2.1
a +
a + // comment
a;
修复二元表达式中注释位置不稳定的问题 (#8491 by @thorn0)
// Input
Math.min(
(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight)
) - devsite_footer_height,
0,
)
// Prettier 2.0 (first output)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Prettier 2.0 (second output)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Prettier 2.1 (first and second outputs)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Input
const topOfDescriptionBox =
Layout.window.width + // Images are 1:1 aspect ratio, full screen width
Layout.headerHeight;
// Prettier 2.0 (first output)
const topOfDescriptionBox =
Layout.window.width + Layout.headerHeight; // Images are 1:1 aspect ratio, full screen width
// Prettier 2.0 (second output)
const topOfDescriptionBox = Layout.window.width + Layout.headerHeight; // Images are 1:1 aspect ratio, full screen width
// Prettier 2.1 (first and second outputs)
const topOfDescriptionBox =
Layout.window.width + // Images are 1:1 aspect ratio, full screen width
Layout.headerHeight;
对数字键名添加/移除引号 (#8508 by @lydell)
当对象键名是标识符时,Prettier 会移除其引号。现在当键名是数字时,Prettier 同样会移除其引号。
若配置 quoteProps: "consistent",Prettier 还会为数字键名添加引号,确保所有属性都使用引号。
// Input
x = {
"a": null,
"1": null,
};
// Prettier 2.0
x = {
a: null,
"1": null,
};
// Prettier 2.1
x = {
a: null,
1: null,
};
Prettier 仅处理"简单"数字(如 1 和 123.5)。以下转换不会执行,因其可能引发意外结果:
1e2 -> "100"
0b10 -> "10"
1_000 -> "1000"
1.0 -> "1"
0.99999999999999999 -> "1"
999999999999999999999 -> "1e+21"
2n -> "2"
"1e+100" -> 1e100
(请勿使用易混淆的数字作为对象键名!)
请注意:Prettier 仅在 "babel" 解析器下移除数字键名的引号。在 TypeScript 中此操作不完全安全。
条件类型中优先保留"?"符号前的行首注释 (#8557 by @sosukesuzuki)
// Input
type A = B extends T
? // comment
foo
: bar;
// Prettier 2.0
type A = B extends T // comment
? foo
: bar;
// Prettier 2.1
type A = B extends T
? // comment
foo
: bar;
当三元表达式中含有多行块注释时自动换行 (#8592 by @sosukesuzuki)
// Input
test
? /* comment
comment
*/
foo
: bar;
// Prettier 2.0
test ? /* comment
comment
*/ foo : bar;
// Prettier 2.1
test
? /* comment
comment
*/
foo
: bar;
修复类方法间注释对位置不稳定的问题 (#8731 by @fisker)
// Input
class C {
ma() {} /* D */ /* E */
mb() {}
}
// Prettier 2.0
class C {
ma() {} /* E */ /* D */
mb() {}
}
// Prettier 2.0 (Second format)
class C {
ma() {} /* D */ /* E */
mb() {}
}
// Prettier 2.1
class C {
ma() {} /* D */ /* E */
mb() {}
}
修复重复的 prettier-ignore 注释问题 (#8742 by @fisker)
// Input
a = <div {.../* prettier-ignore */{}}/>
a = <div {...{}/* prettier-ignore */}/>
// Prettier 2.0
a = <div {/* prettier-ignore */ .../* prettier-ignore */ {}} />;
a = <div {...{} /* prettier-ignore */ /* prettier-ignore */} />;
// Prettier 2.1
a = <div {.../* prettier-ignore */ {}} />;
a = <div {...{} /* prettier-ignore */} />;
支持 Decimal 提案 (#8901 by @fisker)
支持 Stage-1 提案 Decimal Proposal。
// Input
0.3m;
// Prettier 2.0
SyntaxError: Identifier directly after number (1:4)
> 1 | 0.3m;
// Prettier 2.1
0.3m;
为 yield JSX 表达式添加括号 (#9011 by @fisker)
在 v2.0.0 版本中我们移除了 yield JSX 的括号,该方案适用于多数解析器,但 ESLint 解析时会报错(参见相关 issue)。
// Input
function* f() {
yield <div>generator</div>
}
// Prettier 2.0
function* f() {
yield <div>generator</div>
}
// Prettier 2.1
function* f() {
yield (<div>generator</div>);
}
TypeScript
修复 babel-ts 解析器对 (a:b) 的语法错误处理 (#8046 by @thorn0)
此前该代码能被解析且不报错,但在打印阶段会抛出错误,且错误信息包含不友好的堆栈跟踪。现在解析器会直接抛出规范的语法错误。
// Input
(a:b)
// Prettier 2.0
[error] test.ts: Error: unknown type: "TSTypeCastExpression"
[error] ... [a long stack trace here] ...
// Prettier 2.1
[error] test.ts: SyntaxError: Did not expect a type annotation here. (1:2)
[error] > 1 | (a:b)
[error] | ^
[error] 2 |
为字符串字面量添加括号以避免被识别为指令 (#8422 by @thorn0)
Prettier 会自动为语句位置的字符串字面量添加括号包裹,因为否则当这些字符串出现在函数或程序顶部时会被解释为指令,从而改变程序行为。虽然对于不在函数或程序首行的字符串来说这在技术上并非必要,但统一添加括号能保持一致性并有助于发现潜在错误。例如可参考Twitter上的这个讨论。
此前该功能在 typescript 解析器中未能完全生效,仅原本带括号的字符串能保留括号。
// Input
f();
'use foo';
('use bar');
// Prettier 2.0
f();
"use foo";
("use bar");
// Prettier 2.1
f();
("use foo");
("use bar");
支持 TypeScript 3.9 对可选链与非空断言的破坏性变更 (#8450 by @sosukesuzuki)
详见 https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#breaking-changes
// Input
(a?.b)!.c;
// Prettier 2.0
a?.b!.c;
// Prettier 2.1
(a?.b)!.c;
Flow
修复函数类型参数包含可为空参数的情况 (#8365 by @fisker)
// Input
let f: <A>(
((?A) => B),
) => B;
// Prettier 2.0
let f: <A>((?A) => B) => B;
// Prettier 2.0 (Second format)
SyntaxError: Unexpected token (1:12)
> 1 | let f: <A>((?A) => B) => B;
// Prettier 2.1
let f: <A>(((?A) => B)) => B;
修复 Flow Enum 的默认导出格式 (#8768 by @gkz)
当默认导出 Flow Enum 时,不再添加尾部分号。
// Input
export default enum B {}
// Prettier 2.0
export default enum B {};
// Prettier 2.1
export default enum B {}
CSS
避免因 @规则末尾注释导致代码中断 (#7009 by @evilebottnawi)
/* Input */
@at-root .foo
// .bar
{
}
/* Prettier 2.0 */
@at-root .foo
// .bar {
}
/* Prettier 2.1 */
@at-root .foo
// .bar
{
}
修复 url() 未加引号内容的处理问题 (#7592 by @mattiacci)
改进 CSS/SCSS/Less 中未加引号 URL 内容的处理机制。虽然未彻底解决底层解析问题,但至少确保 Prettier 不会修改 URL 内容。
/* Input */
@import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap);
@import url(//fonts.googleapis.com/css?family=#{ get-font-family('Roboto') }:100,300,500,700,900&display=swap);
.validUnquotedUrls{
background: url(data/+0ThisShouldNotBeLowerCased);
background: url(https://foo/A*3I8oSY6AKRMAAAAAAAAAAABkARQnAQ);
background: url(https://example.com/some/quite,long,url,with,commas.jpg);
}
/* Prettier 2.0 */
@import url(
https://fonts.googleapis.com/css?family=Roboto:100,
300,
400,
500,
700,
900&display=swap
);
@import url(
//fonts.googleapis.com/css?family=#{get-font-family("Roboto")}:100,
300,
500,
700,
900&display=swap
);
.validUnquotedUrls {
background: url(data/+0thisshouldnotbelowercased);
background: url(https://foo/A*3i8osy6akrmaaaaaaaaaaabkarqnaq);
background: url(https://example.com/some/quite, long, url, with, commas.jpg);
}
/* Prettier 2.1 */
@import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap);
@import url(//fonts.googleapis.com/css?family=#{ get-font-family('Roboto') }:100,300,500,700,900&display=swap);
.validUnquotedUrls{
background: url(data/+0ThisShouldNotBeLowerCased);
background: url(https://foo/A*3I8oSY6AKRMAAAAAAAAAAABkARQnAQ);
background: url(https://example.com/some/quite,long,url,with,commas.jpg);
}
修复 CSS 网格线名转义冒号后多余空格问题 (#8535 by @boyenn)
/* Input */
.grid {
grid-template-rows:
[row-1-00\:00] auto;
}
/* Prettier 2.0 */
.grid {
grid-template-rows: [row-1-00\: 00] auto;
}
/* Prettier 2.1 */
.grid {
grid-template-rows: [row-1-00\:00] auto;
}
支持 @supports selector(<custom-selector>) 语法 (#8545 by @boyenn)
/* Input */
@supports selector(:focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
/* Prettier 2.0 */
@supports selector(: focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
/* Prettier 2.1 */
@supports selector(:focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
改进任意参数的处理机制 (#8567, #8566 by @boyenn)
当传递任意参数时,Prettier 不再在函数后意外添加额外空格。 使用行内数字列表作为任意参数时,Prettier 不再破坏代码结构。
/* Input */
body {
test: function($list...);
foo: bar(returns-list($list)...);
background-color: rgba(50 50 50 50...);
}
/* Prettier 2.0 */
body {
test: function($list...);
foo: bar(returns-list($list) ...);
background-color: rgba(50 50 50 50..);
}
/* Prettier 2.1 */
body {
test: function($list...);
foo: bar(returns-list($list)...);
background-color: rgba(50 50 50 50...);
}
SCSS
修复 SCSS 注释后行级缩进异常问题 (#7844 by @boyenn)
此前 Prettier 在 SCSS 映射中的注释后行会添加额外缩进,现已修复此问题。
/* Input */
$my-map: (
'foo': 1, // Foo
'bar': 2, // Bar
);
/* Prettier 2.0 */
$my-map: (
"foo": 1,
// Foo
"bar": 2,
// Bar
);
/* Prettier 2.1 */
$my-map: (
"foo": 1,
// Foo
"bar": 2,
// Bar
);
修复属性与值间行内注释的格式问题 (#8366 by @fisker)
// Input
a {
color: // comment
red;
}
// Prettier 2.0
a {
color: // comment red;
}
// Prettier 2.1
a {
color: // comment
red;
}
修复省略尾部引号时文件末尾注释丢失问题 (#8675 by @fisker)
// Input
@mixin foo() {
a {
color: #f99;
}
}
@include foo() /* comment*/
// Prettier 2.0
@mixin foo() {
a {
color: #f99;
}
}
@include foo();
// Prettier 2.1
@mixin foo() {
a {
color: #f99;
}
}
@include foo(); /* comment*/
Less
修复 :extend 伪类选择器 (#8178 by @fisker)
此前该选择器被解析为值,现已被正确识别为选择器。
// Input
.hello {
&:extend(.input[type="checkbox"]:checked ~ label)}
// Prettier 2.0
.hello {
&:extend(.input[type= "checkbox" ]: checked ~label);
}
// Prettier 2.1
.hello {
&:extend(.input[type="checkbox"]:checked ~ label);
}
修复包含 /* 的行内注释 (#8360 by @fisker)
当行内注释包含 /* 时,部分其他注释未能正确输出。
// Input
@import "a";
// '/*' <-- this breaks formatting
@import 'b';
/* block */
/*no-space block*/
// Prettier 2.0
@import "a";
// '/*' <-- this breaks formatting
@import "b";
@import 'b
@import 'b';
/* bl
// Prettier 2.1
@import "a";
// '/*' <-- this breaks formatting
@import "b";
/* block */
/*no-space block*/
HTML
单行样式属性省略尾部分号 (#8013 by @bschlenk)
<!-- Input -->
<div style="margin: 0; padding: 20px"></div>
<div style="margin: 0; padding: 20px; position: relative; display: inline-block; color: blue"></div>
<!-- Prettier 2.0 -->
<div style="margin: 0; padding: 20px;"></div>
<div
style="
margin: 0;
padding: 20px;
position: relative;
display: inline-block;
color: blue;
"
></div>
<!-- Prettier 2.1 -->
<div style="margin: 0; padding: 20px"></div>
<div
style="
margin: 0;
padding: 20px;
position: relative;
display: inline-block;
color: blue;
"
></div>
保留 HTML 中的非 ASCII 空白字符 (#8137 by @fisker)
诸如 U+00A0、U+2005 等非 ASCII 空白字符在 HTML 中不被视为空白符,不应被移除。
// Prettier 2.0
[...require("prettier").format("<i> \u2005 </i>", { parser: "html" })]
.slice(3, -5)
.map((c) => c.charCodeAt(0).toString(16));
// -> [ '20' ]
// `U+2005` is removed
// Prettier 2.1
[...require("prettier").format("<i> \u2005 </i>", { parser: "html" })]
.slice(3, -5)
.map((c) => c.charCodeAt(0).toString(16));
// -> [ '20', '2005', '20' ]
支持传统 HTML 式注释的 script 块 (#8173 by @fisker, #8394 by @fisker)
此前我们将 HTML <script> 块解析为 "module"(ECMAScript 模块语法),这导致无法解析以 <!-- 开头的注释(即 HTML 式注释),现在我们将 <script> 块解析为 "script",除非这个 <script>
-
type="module" -
type="text/babel"且data-type="module"(由 babel@v7.10.0 引入)
<!-- Input -->
<SCRIPT>
<!--
alert("hello" + ' world!')
//--></SCRIPT>
<!-- Prettier 2.0 -->
SyntaxError: Unexpected token (2:1)
1 |
> 2 | <!--
| ^
3 | alert("hello" + ' world!')
4 | //-->
<!-- Prettier 2.1 -->
<script>
<!--
alert("hello" + " world!");
//-->
</script>
将 <select> 视为行内块元素,将 <optgroup>/<option> 视为块元素 (#8275 by @thorn0, #8620 by @fisker)
现在 Prettier 能安全地在 select、option 和 optgroup 标签内添加空白符。
<!-- Input -->
<select><option>Blue</option><option>Green</option><optgroup label="Darker"><option>Dark Blue</option><option>Dark Green</option></optgroup></select>
<!-- Prettier 2.0 -->
<select
><option>Blue</option
><option>Green</option
><optgroup label="Darker"
><option>Dark Blue</option><option>Dark Green</option></optgroup
></select
>
<!-- Prettier 2.1 -->
<select>
<option>Blue</option>
<option>Green</option>
<optgroup label="Darker">
<option>Dark Blue</option>
<option>Dark Green</option>
</optgroup>
</select>
修复 srcset 中带逗号的 URL 解析 (#8359 by @fisker)
<!-- Input -->
<img
srcset="
_20200401_145009_szrhju_c_scale,w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,w_1400.jpg 1400w"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
>
<!-- Prettier 2.0 -->
<img
srcset="
_20200401_145009_szrhju_c_scale,
w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,
w_1400.jpg 1400w
"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
/>
<!-- Prettier 2.1 -->
<img
srcset="
_20200401_145009_szrhju_c_scale,w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,w_1400.jpg 1400w
"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
/>
支持 <script type="text/html> (#8371 by @sosukesuzuki)
<!-- Input -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
<!-- Prettier 2.0 -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
<!-- Prettier 2.1 -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
支持动态语言的前置元数据 (#8381 by @fisker)
支持前置元数据中的动态语言检测,该功能同样适用于 css、less、scss 和 markdown 解析器。
<!-- Input -->
---my-awsome-language
title: Title
description: Description
---
<h1>
prettier</h1>
<!-- Prettier 2.0 -->
---my-awsome-language title: Title description: Description ---
<h1>
prettier
</h1>
<!-- Prettier 2.1 -->
---my-awsome-language
title: Title
description: Description
---
<h1>
prettier
</h1>
纯文本内容周围不保留换行符 (#8614 by @fisker)
此前,Prettier 总是保留内联节点周围的换行符(即内联元素、文本、插值)。总体而言,Prettier 会尽可能避免依赖原始格式,但在两种情况下将内联节点折叠为单行是不可取的:类列表内容和条件结构(如 Vue 中的 v-if/v-else)。由于未能找到检测这些情况的可靠方法,因此采取了这种折衷方案。然而事实证明,对于纯文本内容而言,这种规则放宽并无必要,只会导致格式混乱不一致。
<!-- Input -->
<div>
Hello, world!
</div>
<div>
Hello, {{ username }}!
</div>
<!-- Prettier 2.0 -->
<div>
Hello, world!
</div>
<div>Hello, {{ username }}!</div>
<!-- Prettier 2.1 -->
<div>Hello, world!</div>
<div>Hello, {{ username }}!</div>
识别已知 HTML 标签 (#8621 by @fisker)
<!-- Input -->
<div>before<details><summary>summary long long long long </summary>details</details>after</div>
<div>before<dialog open>dialog long long long long long long long long </dialog>after</div>
<div>before<object data="horse.wav"><param name="autoplay" value="true"/><param name="autoplay" value="true"/></object>after</div>
<!-- Prettier 2.0 -->
<div>
before<details><summary>summary long long long long </summary>details</details
>after
</div>
<div>
before<dialog open>dialog long long long long long long long long </dialog
>after
</div>
<div>
before<object data="horse.wav"
><param name="autoplay" value="true" /><param
name="autoplay"
value="true" /></object
>after
</div>
<!-- Prettier 2.1 -->
<div>
before
<details>
<summary>summary long long long long</summary>
details
</details>
after
</div>
<div>
before
<dialog open>dialog long long long long long long long long</dialog>
after
</div>
<div>
before<object data="horse.wav">
<param name="autoplay" value="true" />
<param name="autoplay" value="true" /></object
>after
</div>
修复以空元素作为末子元素的格式问题 (#8643 by @ikatyang)
<!-- Input -->
<video controls width="250">
<source src="/media/examples/flower.webm"
type="video/webm">
<source src="/media/examples/flower.mp4"
type="video/mp4"
></video>text after
<!-- Prettier 2.0 -->
<video controls width="250">
<source src="/media/examples/flower.webm" type="video/webm" />
<source src="/media/examples/flower.mp4" type="video/mp4" /></video
>text after
<!-- Prettier 2.1 -->
<video controls width="250">
<source src="/media/examples/flower.webm" type="video/webm" />
<source src="/media/examples/flower.mp4" type="video/mp4" /></video
>text after
Vue
优化 Vue SFC 根块格式化 (#8023 by @sosukesuzuki, #8465 by @fisker)
现支持使用内置解析器和插件格式化所有语言块(包括带 lang 属性的自定义块)。
<!-- Input -->
<template lang="pug">
div.text( color = "primary", disabled ="true" )
</template>
<i18n lang="json">
{
"hello": 'prettier',}
</i18n>
<!-- Prettier 2.0 -->
<template lang="pug">
div.text( color = "primary", disabled ="true" )
</template>
<i18n lang="json">
{
"hello": 'prettier',}
</i18n>
<!-- Prettier 2.1 -->
<template lang="pug">
.text(color="primary", disabled="true")
</template>
<i18n lang="json">
{
"hello": "prettier"
}
</i18n>
此示例需安装 @prettier/plugin-pug。
改进自定义块解析 (#8153 by @sosukesuzuki)
<!-- Input -->
<custom lang="javascript">
const foo = "</";
</custom>
<!-- Prettier 2.0 -->
SyntaxError: Unexpected character """ (2:19)
[error] 1 | <custom lang="javascript">
[error] > 2 | const foo = "</";
[error] | ^
[error] 3 | </custom>
<!-- Prettier 2.1 -->
<custom lang="javascript">
const foo = "</";
</custom>
修复大写 HTML 标签导致的格式错误 (#8280 by @fisker)
<!-- Input -->
<!doctype html><HTML></HTML>
<!-- Prettier 2.0 -->
<!DOCTYPE html>><HTML></HTML>
<!-- Prettier 2.1 -->
<!DOCTYPE html><HTML></HTML>
修复 Vue SFC 单行 template 格式异常 (#8325 by @sosukesuzuki)
<!-- Input -->
<template><p>foo</p><div>foo</div></template>
<!-- Prettier 2.0 -->
<template
><p>foo</p>
<div>foo</div></template
>
<!-- Prettier 2.1 -->
<template>
<p>foo</p>
<div>foo</div>
</template>
支持 Vue DOM 模板 (#8326 by @sosukesuzuki)
使用 vue 解析 HTML 时,将模板作为 HTML 解析。
<!-- Input -->
<!DOCTYPE html>
<html>
<body STYLE="color: #333">
<DIV id="app">
<DIV>First Line</DIV><DIV>Second Line</DIV>
</DIV>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {}
},
});
</script>
</body>
</html>
<!-- Prettier 2.0 -->
<!DOCTYPE html>
<html>
<body STYLE="color: #333">
<DIV id="app"> <DIV>First Line</DIV><DIV>Second Line</DIV> </DIV>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {};
},
});
</script>
</body>
</html>
<!-- Prettier 2.1 -->
<!DOCTYPE html>
<html>
<body style="color: #333">
<div id="app">
<div>First Line</div>
<div>Second Line</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {};
},
});
</script>
</body>
</html>
优化 DOM 模板中大写 HTML 标签的格式化 (#8337 by @sosukesuzuki)
<!-- Input -->
<!DOCTYPE html><HTML>
<body>
<div v-if="foo === 'foo'">
</div>
<script>
new Vue({el: '#app'})
</script>
</body>
</HTML>
<!-- Prettier 2.0 -->
<!DOCTYPE html>
<HTML>
<body>
<div v-if="foo === 'foo'">
</div>
<script>
new Vue({el: '#app'})
</script>
</body>
</HTML>
<!-- Prettier 2.1 -->
<!DOCTYPE html>
<HTML>
<body>
<div v-if="foo === 'foo'"></div>
<script>
new Vue({ el: "#app" });
</script>
</body>
</HTML>
修复带括号插值的格式问题 (#8747 by @fisker)
<!-- Input -->
<template>
<span>{{(a|| b)}} {{z&&(a&&b)}}</span>
</template>
<!-- Prettier 2.0 -->
<template>
<span>{{(a|| b)}} {{z&&(a&&b)}}</span>
</template>
<!-- Prettier 2.1 -->
<template>
<span>{{ a || b }} {{ z && a && b }}</span>
</template>
修复命名插槽简写值未格式化的问题 (#8839 by @wenfangdu)
<!-- Input -->
<template>
<div #default="{foo:{bar:{baz}}}"></div>
</template>
<!-- Prettier 2.0 -->
<template>
<div #default="{foo:{bar:{baz}}}"></div>
</template>
<!-- Prettier 2.1 -->
<template>
<div #default="{ foo: { bar: { baz } } }"></div>
</template>
Angular
修复可选链与计算属性及 this 的处理问题 (#8253 by @thorn0, #7942 by @fisker,通过 angular-estree-parser 修复 by @ikatyang)
<!-- Input -->
{{ a?.b[c] }}
{{ a ( this )}}
<!-- Prettier 2.0 -->
{{ (a?.b)[c] }}
{{ a ( this )}}
<!-- Prettier 2.1 -->
{{ a?.b[c] }}
{{ a(this) }}
保留对象字面量中管道符的括号以兼容 AngularJS 1.x (#8254 by @thorn0)
<!-- Input -->
<div ng-style="{ 'color': ('#222' | darken)}"></div>
<!-- Prettier 2.0 -->
<div ng-style="{ color: '#222' | darken }"></div>
<!-- Prettier 2.1 -->
<div ng-style="{ 'color': ('#222' | darken)}"></div>
Handlebars (alpha)
在复杂属性值场景中遵循 singleQuote 选项 (#8375 by @dcyriller)
{{!-- Input --}}
<a href='/{{url}}'></a>
<a href="/{{url}}"></a>
<a href='url'></a>
<a href="url"></a>
{{!-- Prettier 2.0 --}}
<a href="/{{url}}"></a>
<a href="/{{url}}"></a>
<a href='url'></a>
<a href='url'></a>
{{!-- Prettier 2.1 --}}
<a href='/{{url}}'></a>
<a href='/{{url}}'></a>
<a href='url'></a>
<a href='url'></a>
修复元素内部经典组件的格式化问题 (#8593 by @mikoscz)
{{!-- Input --}}
<div>
{{classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
{{!-- Prettier 2.0 --}}
<div>
{{
classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
{{!-- Prettier 2.1 --}}
<div>
{{classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
支持通过反斜杠转义 Mustache 语法 (#8634 by @dcyriller)
{{!-- Input --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}
{{!-- Prettier 2.0 --}}
{{mustache}}
\{{mustache}}
\\{{mustache}}
{{!-- Prettier 2.1 --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}
仅格式化属性中的类名 (#8677 by @dcyriller)
{{!-- Input --}}
<div class=' class '></div>
<div title=' other attribute '></div>
{{!-- Prettier 2.0 --}}
<div class="class"></div>
<div title="other attribute"></div>
{{!-- Prettier 2.1 --}}
<div class="class"></div>
<div title=" other attribute "></div>
GraphQL
优化 GraphQL 片段指令的换行处理 (#7721 by @sasurau4)
# Input
fragment TodoList_list on TodoList @argumentDefinitions(
count: {type: "Int", defaultValue: 10},
) {
title
}
# Prettier 2.0
fragment TodoList_list on TodoList
@argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
title
}
# Prettier 2.1
fragment TodoList_list on TodoList
@argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
title
}
修复接口之间的注释格式 (#8006 by @fisker)
# Input
type Type1 implements
A &
# comment 1
B
# comment 2
& C {a: a}
# Prettier 2.0
type Type1 implements A & # comment 1
B & # comment 2
C {
a: a
}
# Prettier 2.0 (Second format)
type Type1 implements A & B & C { # comment 1 # comment 2
a: a
}
# Prettier 2.1
type Type1 implements A &
# comment 1
B &
# comment 2
C {
a: a
}
允许接口实现其他接口 (#8007 by @fisker)
# Input
interface Resource implements Node {
id: ID!
url: String
}
# Prettier 2.0
interface Resource {
id: ID!
url: String
}
# Prettier 2.1
interface Resource implements Node {
id: ID!
url: String
}
Markdown
将 remark-parse 更新至 v8 版本 (#8140 by @saramarcondes, @fisker, @thorn0)
Prettier 使用的 Markdown 解析器 remark 迎来了姗姗来迟的更新(5.0.0 → 8.0.2,详见 remark 更新日志)。此次更新修复了大量旧有 bug,特别是与解析制表符缩进列表项相关的问题。
请注意,新版本在解析脚注时更为严格(这是一个未在任何规范中定义的语法扩展)。此前 Prettier 会解析(并根据 --tab-width 选项输出)使用任意数量空格缩进的多行脚注。新版本仅识别缩进 4 个空格的多行脚注。由于该语法非标准,此变更不被视为破坏性更新。但若您恰巧使用了此功能,建议在升级 Prettier 前使用旧版本配合 --tab-width=4 参数调整文件中的脚注格式以兼容新版本。
正确格式化包含变体选择器(Variation Selector)的中日韩语句 (#8511 by @ne-sachirou)
<!-- Input -->
麻󠄁羽󠄀‼️
<!-- Prettier 2.0 -->
麻 󠄁 羽 󠄀 ‼️
<!-- Prettier 2.1 -->
麻󠄁羽󠄀‼️
YAML
修复使用 prettier-ignore 时的格式不稳定问题 (#8355 by @fisker)
# Input
# prettier-ignore
---
prettier: true
...
hello: world
# Prettier 2.0
# prettier-ignore
---
prettier: true
---
hello: world
# Prettier 2.0 (Second format)
# prettier-ignore
---
prettier: true
---
hello: world
# Prettier 2.1
# prettier-ignore
---
prettier: true
---
hello: world
保留注释中的空行 (#8356 by @fisker)
# Input
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
# Prettier 2.0
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
# Prettier 2.1
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
更新 yaml 和 yaml-unist-parser 依赖 (#8386 by @fisker,修复来自 yaml-unist-parser by @ikatyang)
-
yaml: 修复块级标量中缩进空行的显式错误 -
yaml-unist-parser: 修复:文档头结束标记位置误判问题
# Input
# --- comments ---
# Prettier 2.0
--- # --- comments ---
# Prettier 2.1
# --- comments ---
# Input
empty block scalar: >
# comment
# Prettier 2.0
empty block scalar: >
# comment
# Prettier 2.1
SyntaxError: Block scalars with more-indented leading empty lines must use an explicit indentation indicator (1:21)
> 1 | empty block scalar: >
| ^
> 2 |
| ^^
> 3 | # comment
| ^^^^^^^^^^^
修复 YAML 内联扩展语法解析错误 (#8888 by @fisker, @evilebottnawi,修复来自 yaml-unist-parser by @ikatyang)
# Input
foo:
<<: &anchor
K1: "One"
K2: "Two"
bar:
<<: *anchor
K3: "Three"
# Prettier 2.0
SyntaxError: Merge nodes can only have Alias nodes as values (2:2)
1 | foo:
> 2 | <<: &anchor
| ^^^^^^^^^^^
> 3 | K1: "One"
| ^^^^^^^^^^^^
> 4 | K2: "Two"
| ^^^^^^^^^^^^
> 5 |
| ^
6 | bar:
7 | <<: *anchor
8 | K3: "Three"
# Prettier 2.1
foo:
<<: &anchor
K1: "One"
K2: "Two"
bar:
<<: *anchor
K3: "Three"
API
将插件解析器加入 parser 选项 (#8390 by @thorn0)
当插件定义语言时,该语言指定的解析器现在会自动添加到 parser 选项的有效值列表中。
此功能对编辑器集成或其他需要可用解析器列表的应用程序非常实用。
npm install --save-dev --save-exact prettier @prettier/plugin-php
const hasPhpParser = prettier
.getSupportInfo()
.options.find((option) => option.name === "parser")
.choices.map((choice) => choice.value)
.includes("php"); // false in Prettier 2.0, true in Prettier 2.1
修复 prettier.getFileInfo() 方法 (#8548, #8551, #8585 by @fisker)
-
当传递
{resolveConfig: true}时,inferredParser应为配置文件解析出的解析器,先前版本对内置解析器支持的文件可能返回错误结果 -
当同时传递
{resolveConfig: true}和{ignorePath: "a/file/in/different/dir"}时,inferredParser结果可能不正确 -
若给定
filePath被忽略,inferredParser现在始终返回null
$ echo {"parser":"flow"}>.prettierrc
$ node -p "require('prettier').getFileInfo.sync('./foo.js', {resolveConfig: true})"
# Prettier 2.0
# { ignored: false, inferredParser: 'babel' }
# Prettier 2.1
# { ignored: false, inferredParser: 'flow' }
$ echo ignored.js>>.prettierignore
$ node -p "require('prettier').getFileInfo.sync('./ignored.js')"
# Prettier 2.0
# { ignored: true, inferredParser: 'babel' }
# Prettier 2.1
# { ignored: true, inferredParser: null }
修复深层目录文件的 editorConfig 解析 (#8591 by @fisker)
先前版本无法为深层目录文件(距离项目根目录超过9层,详见 #5705)正确解析 .editorconfig。
支持 .cjs 和 .json5 配置文件 (#8890, #8957 by @fisker)
新增配置文件格式:
-
.prettierrc.json5 -
.prettierrc.cjs -
prettier.config.cjs
修复含 BOM 的文件范围格式错误 (#8936 by @fisker)
当文件包含 BOM 时,先前版本会错误计算实际范围值。
const text = "\uFEFF" + "foo = 1.0000;bar = 1.0000;";
// ^^^^^^^^^^^^^ Range
const result = require("prettier")
.format(text, {
parser: "babel",
rangeStart: 1,
rangeEnd: 13,
})
// Visualize BOM
.replace("\uFEFF", "<<BOM>>")
// Visualize EOL
.replace("\n", "<<EOL>>");
console.log(result);
// Prettier 2.0
// -> <<BOM>>foo = 1.0;<<EOL>>bar = 1.0;
// ^^^^^^^^^ This part should not be formatted
// Prettier 2.1
// -> <<BOM>>foo = 1.0;bar = 1.0000;
CLI
修复含 CJK 字符或表情符号的文件名未正确忽略的问题 (#8098 by @fisker)
// Prettier 2.0
$ echo "dir" > .prettierignore
$ prettier **/*.js -l
dir/😁.js
dir/中文.js
not-ignored.js
// Prettier 2.1
$ echo "dir" > .prettierignore
$ prettier **/*.js -l
not-ignored.js
--file-info 命令现支持读取 .prettierrc 配置并兼容 --no-config 参数 (#8586, #8830 by @fisker)
$ echo {"parser":"ninja"}>.prettierrc
# Prettier 2.0
$ prettier --file-info file.js
# { "ignored": false, "inferredParser": "babel" }
$ prettier --file-info file.js --no-config
# { "ignored": false, "inferredParser": "babel" }
# Prettier 2.1
$ prettier --file-info file.js
# { "ignored": false, "inferredParser": "ninja" }
$ prettier --file-info file.js --no-config
# { "ignored": false, "inferredParser": "babel" }
新增 --ignore-unknown(别名 -u)标志 (#8829 by @fisker)
# Prettier 2.0
npx prettier * --check
Checking formatting...
foo.unknown[error] No parser could be inferred for file: foo.unknown
All matched files use Prettier code style!
# Prettier 2.1
npx prettier * --check --ignore-unknown
Checking formatting...
All matched files use Prettier code style!
为 --write 选项添加 -w 短命令别名 (#8833 by @fisker)
# Prettier 2.0
$ prettier index.js -w
[warn] Ignored unknown option -w. Did you mean -_?
"use strict";
module.exports = require("./src/index");
# Prettier 2.1
$ prettier index.js -w
index.js 30ms
停止为未知选项建议 -_ 写法 (#8934 by @fisker)
# Prettier 2.0
$ prettier foo.js -a
[warn] Ignored unknown option -a. Did you mean -_?
# Prettier 2.1
$ prettier foo.js -a
[warn] Ignored unknown option -a. Did you mean -c?
