Prettier 1.19:期待已久的 Vue 选项、TypeScript 3.7 及全新 JavaScript 特性
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本次发布包含期待已久的 --vue-indent-script-and-style 选项,支持 TypeScript 3.7 及多项前沿 JavaScript 语法,更不用说海量错误修复与改进!
重要更新
Vue
新增 --vue-indent-script-and-style (#6157 by @kamilic)
全新选项 --vue-indent-script-and-style 用于控制是否缩进 Vue 文件中 <script> 和 <style> 标签内的代码。部分开发者(如 Vue 作者)为节省缩进层级选择不缩进,但这可能破坏编辑器的代码折叠功能。此项更新解决了我们迄今评论量最高的问题,将大幅提升 Vue 开发者的编辑体验!
TypeScript
支持 TypeScript 3.7 (#6657 by @cryrivers)
Prettier 1.19 支持即将发布的 TypeScript 3.7 引入的新语法特性:
(注:为支持 TypeScript 3.7 的依赖升级导致从 GitHub 直接安装时不再兼容 Node.js 6。通过 npm 安装的 Prettier 仍支持 Node.js 4。)
可选链
// Input
const longChain = obj?.a?.b?.c?.d?.e?.f?.g;
const longChainCallExpression = obj.a?.(a,b,c).b?.(a,b,c).c?.(a,b,c).d?.(a,b,c).e?.(a,b,c).f?.(a,b,c)
// Prettier 1.19
const longChain = obj?.a?.b?.c?.d?.e?.f?.g;
const longChainCallExpression = obj
.a?.(a, b, c)
.b?.(a, b, c)
.c?.(a, b, c)
.d?.(a, b, c)
.e?.(a, b, c)
.f?.(a, b, c);
空值合并
// Input
const cond = null;
const result = cond??'a';
const longChain = cond??cond??cond??'b';
// Prettier 1.19
const cond = null;
const result = cond ?? "a";
const longChain = cond ?? cond ?? cond ?? "b";
断言函数
// Input
function assertsString(x: any): asserts x {console.assert(typeof x === 'string');}
function assertsStringWithGuard(x: any): asserts x is string {console.assert(typeof x === 'string');}
// Prettier 1.19
function assertsString(x: any): asserts x {
console.assert(typeof x === "string");
}
function assertsStringWithGuard(x: any): asserts x is string {
console.assert(typeof x === "string");
}
类字段的 declare 修饰符
// Input
class B {p: number;}
class C extends B {declare p: 256 | 1000;}
// Prettier 1.19
class B {
p: number;
}
class C extends B {
declare p: 256 | 1000;
}
JavaScript
支持部分应用语法 (#6397 by @JounQin)
// Input
const addOne = add(1, ?); // apply from the left
addOne(2); // 3
const addTen = add(?, 10); // apply from the right
addTen(2); // 12
// with pipeline
let newScore = player.score
|> add(7, ?)
|> clamp(0, 100, ?); // shallow stack, the pipe to `clamp` is the same frame as the pipe to `add`.
// Prettier 1.18
SyntaxError: Unexpected token (1:23)
> 1 | const addOne = add(1, ?); // apply from the left
| ^
2 | addOne(2); // 3
3 |
4 | const addTen = add(?, 10); // apply from the right
// Prettier 1.19
const addOne = add(1, ?); // apply from the left
addOne(2); // 3
const addTen = add(?, 10); // apply from the right
addTen(2); // 12
// with pipeline
let newScore = player.score |> add(7, ?) |> clamp(0, 100, ?); // shallow stack, the pipe to \`clamp\` is the same frame as the pipe to \`add\`.
通过函数字面量参数识别函数组合 (#6033 by @brainkim)
此前我们通过硬编码的函数式编程相关名称(如 compose、flow、pipe 等)来识别代码中的函数组合与链式调用模式。这种做法确保 Prettier 不会将类似下方调用 pipe 的代码放在同一行(即使未超出列宽限制):
source$
.pipe(
filter(x => x % 2 === 0),
map(x => x + x),
scan((acc, x) => acc + x, 0),
)
.subscribe(x => console.log(x));
然而该启发式方法因误报问题饱受诟病——匹配硬编码名称的函数或方法调用总被拆分为多行,即使调用中不含函数参数(参见 #5769、#5969)。对多数开发者而言,这种仅凭名称拆解函数的做法既令人意外又非最优解。
新版启发式方法通过检测函数字面量来识别函数组合。该方法在保留原有换行行为的同时,基本消除了旧版方法导致的误报问题。
欢迎试用并随时反馈意见!
// Input
eventStore.update(id, _.flow(updater, incrementVersion));
// Prettier 1.18
eventStore.update(
id,
_.flow(
updater,
incrementVersion
)
);
// Prettier 1.19
eventStore.update(id, _.flow(updater, incrementVersion));
特定场景下支持存在解析错误时仍执行格式化 (#6816 by @thorn0 及 Babel 团队)
我们更新了 Babel 解析器至最新版本,并因此获得了一个很棒的功能。现在 Prettier 能够在某些情况下即使代码存在错误也能进行格式化,这将使您的编码体验更加流畅。随着 Babel 改进其错误恢复解析模式,这一功能将随时间推移变得更加强大。更多详情请参阅 Babel 7.7.0 博客文章!
// Input
let a = {
__proto__ : x,
__proto__ : y
}
let a = 2
// Prettier 1.18
SyntaxError: Redefinition of __proto__ property (3:3)
1 | let a = {
2 | __proto__ : x,
> 3 | __proto__ : y
| ^
4 | }
5 | let a = 2
// Prettier 1.19
let a = {
__proto__: x,
__proto__: y
};
let a = 2;
其他变更
TypeScript
修复可选计算类字段和方法 (#6657 by @cryrivers, #6673 by @thorn0)
当键名是复杂表达式时问题仍然存在,但以下情况已修复:
// Input
class Foo {
[bar]?: number;
protected [s]?() {}
}
// Prettier 1.18
class Foo {
[bar]: number;
protected [s?]() {};
}
// Prettier 1.19
class Foo {
[bar]?: number;
protected [s]?() {}
}
修复带类型参数的 JSX 元素名称后注释丢失问题 (#6209 by @duailibe)
// Input
const comp = (
<Foo<number>
// This comment goes missing
value={4}
>
Test
</Foo>
);
// Prettier 1.18
const comp = <Foo<number> value={4}>Test</Foo>;
// Prettier 1.19
const comp = (
<Foo<number>
// This comment goes missing
value={4}
>
Test
</Foo>
);
修复在 JSX 文本中使用 // 导致的崩溃 (#6289 by @duailibe)
本次更新修复了 TypeScript 解析器处理含双斜线 (//) 的 JSX 文本的能力。在先前版本中,这种情况会导致 Prettier 崩溃。
单次格式化即可正确处理长单行映射类型 (#6420 by @sosukesuzuki)
先前当 Prettier 格式化长单行映射类型时,它会折行但不会添加分号,直到您再次运行 Prettier,这违反了 Prettier 的幂等性原则。现在 Prettier 在首次运行时就会添加分号。
// Input
type FooBar<T> = { [P in keyof T]: T[P] extends Something ? Something<T[P]> : T[P] }
// Prettier 1.18
type FooBar<T> = {
[P in keyof T]: T[P] extends Something ? Something<T[P]> : T[P]
};
// Prettier 1.19
type FooBar<T> = {
[P in keyof T]: T[P] extends Something ? Something<T[P]> : T[P];
};
在变量声明的类型注解中保持类型参数内联 (#6467 by @sosukesuzuki)
// Input
const fooooooooooooooo: SomeThing<boolean> = looooooooooooooooooooooooooooooongNameFunc();
// Prettier 1.18
const fooooooooooooooo: SomeThing<
boolean
> = looooooooooooooooooooooooooooooongNameFunc();
// Prettier 1.19
const fooooooooooooooo: SomeThing<boolean> = looooooooooooooooooooooooooooooongNameFunc();
修复类型周围多余括号被错误移除的情况 (#6604 by @sosukesuzuki)
// Input
type A = 0 extends ((1 extends 2 ? 3 : 4)) ? 5 : 6;
type B = ((0 extends 1 ? 2 : 3)) extends 4 ? 5 : 6;
type C = ((number | string))["toString"];
type D = ((keyof T1))["foo"];
// Prettier 1.18
type A = 0 extends 1 extends 2 ? 3 : 4 ? 5 : 6;
type B = 0 extends 1 ? 2 : 3 extends 4 ? 5 : 6;
type C = number | string["toString"];
type D = keyof T1["foo"];
// Prettier 1.19
type A = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6;
type B = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6;
type C = (number | string)["toString"];
type D = (keyof T1)["foo"];
在需要时保留 JSX 周围的括号以避免语法错误 (#6640 by @sosukesuzuki)
// Input
(<a />).toString();
// Prettier 1.18
<a />.toString():
// Prettier 1.19
(<a />).toString();
启用 no-semi 选项时保留类属性前的分号 (#6728 by @sosukesuzuki)
先前尝试重新格式化 Prettier 的输出会导致语法错误。
// Input
export class User {
id: number = 2;
[key: string]: any
}
// Prettier 1.18
export class User {
id: number = 2
[key: string]: any
}
// Prettier 1.19
export class User {
id: number = 2;
[key: string]: any
}
改进含 as 类型表达式的参数展开方式 (#6471 by @mattleff)
先前当 Prettier 格式化包含 as 类型表达式或类型断言的调用表达式时,它会折行处理。现在 Prettier 会依据 as 类型或类型断言中的表达式来决定是否折行。
// Input
const bar = [1,2,3].reduce((carry, value) => {
return [...carry, value];
}, ([] as unknown) as number[]);
// Prettier 1.18
const bar = [1, 2, 3].reduce(
(carry, value) => {
return [...carry, value];
},
([] as unknown) as number[]
);
// Prettier 1.19
const bar = [1,2,3].reduce((carry, value) => {
return [...carry, value];
}, ([] as unknown) as number[]);
TypeScript/Flow
修复元组内联合类型的缩进问题 (#6381 by @squidfunk, #6605 by @thorn0)
// Input
type A = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
type B = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD,
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
type C = [
| [AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD]
| [AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD]
]
// Prettier 1.18
type A = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
];
type B = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD,
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
];
type C = [
| [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
| [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
];
// Prettier 1.19
type A = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
];
type B = [
(
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
),
(
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
)
];
type C = [
| [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
| [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]
];
修复类似 useEffect 函数调用中的注释移位问题 (#6270 by @sosukesuzuki)
此修复解决了以下场景的 bug:当函数调用的首个参数是箭头函数,第二个参数是数组表达式(如 React 的 useEffect)。
若在第二个参数前一行存在注释,Prettier 会错误地将其移至上一行并破坏缩进。
该 bug 仅在使用 Flow 和 TypeScript 解析器时出现。
// Input
useEffect(
() => {
console.log("some code", props.foo);
},
// eslint-disable-line react-hooks/exhaustive-deps
[]
);
// Prettier 1.18
useEffect(() => {
console.log("some code", props.foo);
}, // eslint-disable-line react-hooks/exhaustive-deps
[]);
// Prettier 1.19
useEffect(
() => {
console.log("some code", props.foo);
},
// eslint-disable-line react-hooks/exhaustive-deps
[]
);
在联合类型后将右括号置于新行 (#6307 by @sosukesuzuki)
// Input
const foo = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (
| string
| undefined
)[];
// Prettier 1.18
const foo = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (
| string
| undefined)[];
// Prettier 1.19
const foo = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (
| string
| undefined
)[];
Flow
新增枚举支持 (#6833 by @gkz)
// Input
enum E of string {
A = "a",
B = "b",
}
// Prettier 1.19
enum E of string {
A = "a",
B = "b",
}
为含有嵌套在 ObjectTypeAnnotation 中的 FunctionTypeAnnotation 的箭头函数返回类型添加括号 (#6717 by @sosukesuzuki)
这是针对 Flow 解析器 bug 的临时解决方案。缺少括号会导致解析器报错。
// Input
const example1 = (): { p: (string => string) } => (0: any);
// Prettier 1.18
const example1 = (): { p: string => string } => (0: any);
// Prettier 1.19
const example1 = (): ({ p: string => string }) => (0: any);
JavaScript
当数组元素包含多个元素/属性时,对数组的数组/对象进行换行处理 (#6694 by @sosukesuzuki)
这将使你的 new Map 和 Jest 的 test.each 调用格式化得更美观。
// Input
test.each([
{ a: "1", b: 1 },
{ a: "2", b: 2 },
{ a: "3", b: 3 }
])("test", ({ a, b }) => {
expect(Number(a)).toBe(b);
});
[[0, 1, 2], [0, 1, 2]];
new Map([
[A, B],
[C, D],
[E, F],
[G, H],
[I, J],
[K, L],
[M, N]
]);
// Prettier 1.18
test.each([{ a: "1", b: 1 }, { a: "2", b: 2 }, { a: "3", b: 3 }])(
"test",
({ a, b }) => {
expect(Number(a)).toBe(b);
}
);
[[0, 1, 2], [0, 1, 2]]
new Map([[A, B], [C, D], [E, F], [G, H], [I, J], [K, L], [M, N]]);
// Prettier 1.19
test.each([
{ a: "1", b: 1 },
{ a: "2", b: 2 },
{ a: "3", b: 3 }
])("test", ({ a, b }) => {
expect(Number(a)).toBe(b);
});
[
[0, 1, 2],
[0, 1, 2]
];
new Map([
[A, B],
[C, D],
[E, F],
[G, H],
[I, J],
[K, L],
[M, N]
]);
更新 ?? 运算符优先级以匹配 stage 3 提案 (#6404 by @vjeux, #6863 by @jridgewell)
我们已更新 Prettier 对空值合并运算符的支持,使其不再允许直接包含在 && 或 || 运算中或被其包含,这与规范更新保持一致。
// Input
(foo ?? bar) || baz;
(foo || bar) ?? baz;
// Prettier 1.18
foo ?? bar || baz;
foo || bar ?? baz;
// Prettier 1.19
(foo ?? bar) || baz;
(foo || bar) ?? baz;
请注意,由于我们已更新支持此规范变更的解析器版本,缺少括号的代码现在会抛出解析错误。
相同运算符的逻辑表达式不再强制要求括号 (#6864 by @jridgewell)
// Input
foo && (bar && baz);
foo || (bar || baz);
foo ?? (bar ?? baz);
// Prettier 1.18
foo && (bar && baz);
foo || (bar || baz);
foo ?? (bar ?? baz);
// Prettier 1.19
foo && bar && baz;
foo || bar || baz;
foo ?? bar ?? baz;
优化 new 调用的括号可读性 (#6412 by @bakkot)
// Input
var a = new (x().y)();
var a = new (x().y.z)();
var a = new (x().y().z)();
// Prettier 1.18
var a = new (x()).y();
var a = new (x()).y.z();
var a = new (x().y()).z();
// Prettier 1.19
var a = new (x().y)();
var a = new (x().y.z)();
var a = new (x().y().z)();
保留一元表达式中带注释的括号 (#6217 by @sosukesuzuki)
// Input
!(
/* foo */
foo
);
!(
foo // foo
);
// Prettier 1.18
!/* foo */
foo;
!foo; // foo
// Prettier 1.19
!(/* foo */ foo);
!(
foo // foo
);
停止移动带标签模板字符串内部的注释 (#6236 by @sosukesuzuki)
// Input
foo //comment
`
`;
// Prettier 1.18
foo` // comment
`;
// Prettier 1.19
foo // comment
`
`;
修复解构箭头函数参数中的空行破坏缩进和幂等性问题 (#6301 & #6382 by @sosukesuzuki)
此前,当包含对象模式的箭头函数作为参数传递给函数调用时,Prettier 会产生异常的缩进格式,同时破坏幂等性。详见 #6294。
// Input
foo(
({
a,
b
}) => {}
);
// Prettier 1.18
foo(({ a,
b }) => {});
// Prettier 1.19
foo(
({
a,
b
}) => {}
);
修复带参数装饰器的对象解构格式化 (#6411 by @sosukesuzuki)
// Input
class Class {
method(
@decorator
{ foo }
) {}
}
// Prettier 1.18
class Class {
method(@decorator
{
foo
}) {}
}
// Prettier 1.19
class Class {
method(
@decorator
{ foo }
) {}
}
处理函数参数中带类型注解的空对象模式 (#6438 by @bakkot)
// Input
const f = ({}: MyVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongType) => {};
function g({}: Foo) {}
// Prettier 1.18
const f = ({
,
}: MyVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongType) => {};
function g({ }: Foo) {}
// Prettier 1.19
const f = ({}: MyVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongType) => {};
function g({}: Foo) {}
函数调用内的二元表达式后,将右括号置于新行 (#6441 by @sosukesuzuki)
// Input
(
aaaaaaaaaaaaaaaaaaaaaaaaa &&
bbbbbbbbbbbbbbbbbbbbbbbbb &&
ccccccccccccccccccccccccc &&
ddddddddddddddddddddddddd &&
eeeeeeeeeeeeeeeeeeeeeeeee
)();
// Prettier 1.18
(aaaaaaaaaaaaaaaaaaaaaaaaa &&
bbbbbbbbbbbbbbbbbbbbbbbbb &&
ccccccccccccccccccccccccc &&
ddddddddddddddddddddddddd &&
eeeeeeeeeeeeeeeeeeeeeeeee)();
// Prettier 1.19
(
aaaaaaaaaaaaaaaaaaaaaaaaa &&
bbbbbbbbbbbbbbbbbbbbbbbbb &&
ccccccccccccccccccccccccc &&
ddddddddddddddddddddddddd &&
eeeeeeeeeeeeeeeeeeeeeeeee
)();
修复长命名导出的格式化问题 (#6446 by @sosukesuzuki)
现在,Prettier 对命名导出的格式化方式与命名导入保持一致。
// Input
export { fooooooooooooooooooooooooooooooooooooooooooooooooo } from "fooooooooooooooooooooooooooooo";
// Prettier 1.18
export {
fooooooooooooooooooooooooooooooooooooooooooooooooo
} from "fooooooooooooooooooooooooooooo";
// Prettier 1.19
export { fooooooooooooooooooooooooooooooooooooooooooooooooo } from "fooooooooooooooooooooooooooooo";
修复带注释的多行可选链式调用的错误格式化 (#6506 by @sosukesuzuki)
// Input
return a
.b()
.c()
// Comment
?.d()
// Prettier 1.18
return a
.b()
.c()
?.// Comment
d();
// Prettier 1.19
return (
a
.b()
.c()
// Comment
?.d()
);
修复 switch 语句中不一致的缩进 (#6514 by @sosukesuzuki)
// Input
switch ($veryLongAndVeryVerboseVariableName && $anotherVeryLongAndVeryVerboseVariableName) {
}
switch ($longButSlightlyShorterVariableName && $anotherSlightlyShorterVariableName) {
}
// Prettier 1.18
switch (
$veryLongAndVeryVerboseVariableName &&
$anotherVeryLongAndVeryVerboseVariableName
) {
}
switch (
$longButSlightlyShorterVariableName && $anotherSlightlyShorterVariableName
) {
}
// Prettier 1.19
switch (
$veryLongAndVeryVerboseVariableName &&
$anotherVeryLongAndVeryVerboseVariableName
) {
}
switch (
$longButSlightlyShorterVariableName &&
$anotherSlightlyShorterVariableName
) {
}
支持格式化包含 V8 内部函数的代码 (#6496 by @rreverser)
// Input
function doSmth() {
%DebugPrint
(
foo )
}
// Prettier 1.18
SyntaxError: Unexpected token (2:13)
1 | function doSmth() {
> 2 | %DebugPrint
| ^
// Prettier 1.19
function doSmth() {
%DebugPrint(foo);
}
方法参数中的对象解构总是会折成多行 (#6646 by @ericsakmar)
// Input
const obj = {
func(id, { blog: { title } }) {
return id + title;
},
};
class A {
func(id, { blog: { title } }) {
return id + title;
}
#func(id, { blog: { title } }) {
return id + title;
}
}
// Prettier 1.18
const obj = {
func(
id,
{
blog: { title }
}
) {
return id + title;
}
};
class A {
func(
id,
{
blog: { title }
}
) {
return id + title;
}
#func(
id,
{
blog: { title }
}
) {
return id + title;
}
}
// Prettier 1.19
const obj = {
func(id, { blog: { title } }) {
return id + title;
},
};
class A {
func(id, { blog: { title } }) {
return id + title;
}
#func(id, { blog: { title } }) {
return id + title;
}
}
BigInt 字面量中的数字分隔符被错误移除 (#6796 by @thorn0)
// Input
const bigints = [200_000n, 0x0000_000An, 0b0111_1111n];
// Prettier 1.18
const bigints = [200000n, 0x0000000an, 0b01111111n];
// Prettier 1.19
const bigints = [200_000n, 0x0000_000an, 0b0111_1111n];
优化嵌套在调用中的内联 await 表达式格式化 (#6856 by @thorn0)
// Input
async function f() {
const admins = (await(db.select('*').from('admins').leftJoin('bla').where('id', 'in', [1,2,3,4]))).map(({id, name})=>({id, name}))
}
// Prettier 1.18
async function f() {
const admins = (await db
.select("*")
.from("admins")
.leftJoin("bla")
.where("id", "in", [1, 2, 3, 4])).map(({ id, name }) => ({ id, name }));
}
// Prettier 1.19
async function f() {
const admins = (
await db
.select("*")
.from("admins")
.leftJoin("bla")
.where("id", "in", [1, 2, 3, 4])
).map(({ id, name }) => ({ id, name }));
}
HTML
当行长度小于 printWidth 时不对 template 元素换行 (#6284 by @sosukesuzuki)
此前即使行长度小于 printWidth,Prettier 仍会对 template 元素强制换行。
<!-- Input -->
<template>
<template>foo</template>
</template>
<!-- Prettier 1.18 -->
<template>
<template
>foo</template
>
</template>
<!-- Prettier 1.19 -->
<template>
<template>foo</template>
</template>
格式化时 script 标签现在被视为块级元素 (#6423 by @thorn0)
此前在空白敏感模式下,它们被当作内联元素格式化。
<!-- Input -->
<script
async
src="/_next/static/development/pages/_app.js?ts=1565732195968"
></script><script></script>
<!-- Prettier 1.18 -->
<script
async
src="/_next/static/development/pages/_app.js?ts=1565732195968"
></script
><script></script>
<!-- Prettier 1.19 -->
<script
async
src="/_next/static/development/pages/_app.js?ts=1565732195968"
></script>
<script></script>
新增对 ! 等 HTML 实体的支持 (#6785 by @lydell and @ikatyang)
此前 Prettier 仅支持最常见的 HTML 实体(如 和 ")。现在 Prettier 支持 HTML 规范中的所有实体,例如 ! 和 ⋔。
<!-- Input -->
<p>Hi!</p>
<!-- Prettier 1.18
[error] stdin: SyntaxError: Unknown entity "excl" - use the ";" or "<hex>;" syntax (1:6)
[error] > 1 | <p>Hi!</p>
[error] | ^
[error] 2 |
-->
<!-- Prettier 1.19 -->
<p>Hi!</p>
新增 JSON 脚本类型支持 (#6293 by @ascorbic)
<!-- Input -->
<script type="application/json">
{ "json":true }
</script>
<script type="importmap">
{ "json":true }
{ "json":true }
</script>
</script>
<script type="systemjs-importmap">
{ "json":true }
</script>
<!-- Prettier 1.18 -->
<script type="application/json">
{ "json":true }
</script>
<script type="importmap">
{ "json":true }
{ "json":true }
</script>
</script>
<script type="systemjs-importmap">
{ "json":true }
</script>
<!-- Prettier 1.19 -->
<script type="application/json">
{ "json": true }
</script>
<script type="importmap">
{ "json": true }
</script>
<script type="systemjs-importmap">
{ "json": true }
</script>
Angular
将传递给管道的三元表达式后的右括号置于新行 (#5682 by @selvazhagan)
<!-- Input -->
{{ (isCustomDiscount ? 'DISCOUNTS__DISCOUNT_TRAINING_HEADER__CUSTOM_DISCOUNT' : 'DISCOUNTS__DISCOUNT_TRAINING_HEADER__DISCOUNT') | translate }}
<!-- Prettier 1.18 -->
{{
(isCustomDiscount
? "DISCOUNTS__DISCOUNT_TRAINING_HEADER__CUSTOM_DISCOUNT"
: "DISCOUNTS__DISCOUNT_TRAINING_HEADER__DISCOUNT") | translate
}}
<!-- Prettier 1.19 -->
{{
(isCustomDiscount
? "DISCOUNTS__DISCOUNT_TRAINING_HEADER__CUSTOM_DISCOUNT"
: "DISCOUNTS__DISCOUNT_TRAINING_HEADER__DISCOUNT"
) | translate
}}
新增 i18n 属性格式化功能 (#6695 by @voithos)
当 i18n 属性内容超出行长限制时,Prettier 会自动换行处理。
<!-- Input -->
<h1 i18n="This is a very long internationalization description text, exceeding the configured print width">
Hello!
</h1>
<!-- Prettier 1.18 -->
<h1
i18n="This is a very long internationalization description text, exceeding the configured print width"
>
Hello!
</h1>
<!-- Prettier 1.19 -->
<h1
i18n="
This is a very long internationalization description text, exceeding the
configured print width
"
>
Hello!
</h1>
Handlebars
修复空白符和换行符的处理 (#6354 by @chadian)
该修复解决了 Handlebars 和 Glimmer 模板中多种空白符和换行符的使用场景问题。
<!-- Input -->
<SomeComponent />{{name}}
Some sentence with {{dynamic}} expressions.
sometimes{{nogaps}}areimportant<Hello></Hello>
{{name}} is your name
<!-- Prettier 1.18 -->
<SomeComponent />
{{name}}
Some sentence with
{{dynamic}}
expressions.
sometimes
{{nogaps}}
areimportant
<Hello />
{{name}}
is your name
<!-- Prettier 1.19 -->
<SomeComponent />{{name}}
Some sentence with {{dynamic}} expressions.
sometimes{{nogaps}}areimportant
<Hello />
{{name}} is your name
避免在文本与 Mustache 语法之间添加多余换行 (#6186 by @gavinjoyce)
此前 Prettier 会在文本与 Mustache 语法间添加换行符,导致渲染输出中出现多余空白。
<!-- Input -->
<p>Your username is @{{name}}</p>
<p>Hi {{firstName}} {{lastName}}</p>
<!-- Prettier 1.18 -->
<p>
Your username is @
{{name}}
</p>
<p>
Hi
{{firstName}}
{{lastName}}
</p>
<!-- Prettier 1.19 -->
<p>
Your username is @{{name}}
</p>
<p>
Hi {{firstName}} {{lastName}}
</p>
优化注释格式化 (#6206 by @gavinjoyce)
<!-- Input -->
<div>
{{! Foo }}
{{#if @foo}}
Foo
{{/if}}
{{! Bar }}
{{#if @bar}}
Bar
{{/if}}
</div>
<!-- Prettier 1.18 -->
<div>
{{! Foo }}
{{#if @foo}}
Foo
{{/if}}{{! Bar }}{{#if @bar}}
Bar
{{/if}}
</div>
<!-- Prettier 1.19 -->
<div>
{{! Foo }}
{{#if @foo}}
Foo
{{/if}}
{{! Bar }}
{{#if @bar}}
Bar
{{/if}}
</div>
保留 HTML 实体 (#6234 by @gavinjoyce)
<!-- Input -->
<p>
Some escaped characters: < > &
</p>
<!-- Prettier 1.18 -->
<p>
Some escaped characters: < > &
</p>
<!-- Prettier 1.19 -->
<p>
Some escaped characters: < > &
</p>
修复 HTML 属性上的 --single-quote 选项 (#6377 by @dcyriller)
此前该标志在 HTML 属性上未生效。
<!-- Input -->
<div class="a-class-name"></div>
<!-- Prettier 1.18, with the option --single-quote -->
<div class="a-class-name"></div>
<!-- Prettier 1.19, with the option --single-quote -->
<div class='a-class-name'></div>
拆分长插值表达式 (#6249 by @jjaffeux)
<!-- Input -->
{{my-component foo="bar" bar="baz" action=(action "almostTheMaximumLengthxxxx")
}}
<!-- Prettier 1.18 -->
{{my-component foo="bar" bar="baz" action=(action "almostTheMaximumLengthxxxx")
}}
<!-- Prettier 1.19 -->
{{my-component
foo="bar"
bar="baz"
action=(action "almostTheMaximumLengthxxxx")
}}
MDX
JSX 后的文本被错误截断 (#6340 by @JounQin)
<!-- Input -->
<Hello>
test <World /> test
</Hello> 123
<!-- Prettier 1.18 -->
<Hello>
test <World /> test
</Hello>123
<!-- Prettier 1.19 -->
<Hello>
test <World /> test
</Hello> 123
应允许相邻 JSX 元素 (#6332 by @JounQin)
// Input
<Hello>
test <World /> test
</Hello>123
// Prettier 1.18
SyntaxError: Unexpected token (3:9)
1 | <Hello>
2 | test <World /> test
> 3 | </Hello>123
| ^
// Prettier 1.19
<Hello>
test <World /> test
</Hello>123
// Input
<Hello>
test <World /> test
</Hello>
<Hello>
test <World /> test
</Hello>123
// Prettier 1.18
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (4:1)
2 | test <World /> test
3 | </Hello>
> 4 | <Hello>
| ^
5 | test <World /> test
6 | </Hello>123
// Prettier 1.19
<Hello>
test <World /> test
</Hello>
<Hello>
test <World /> test
</Hello>123
Vue
格式化 style[lang="css"] (#6875 by @fisker)
此前带有 lang="css" 的 <style> 元素未被格式化,而省略该属性或设置为其他值则正常。此疏漏已修复。
<!-- Input -->
<style lang="css">
a {
color: #F00
}</style>
<!-- Output (Prettier stable) -->
<style lang="css">
a {
color: #F00
}
</style>
<!-- Output (Prettier master) -->
<style lang="css">
a {
color: #f00;
}
</style>
Less
不再小写变量名并移除变量与冒号间的空格 (#6778 by @fisker)
// Input
@FoO : bar;
// Prettier 1.18
@foo : bar;
// Prettier 1.19
@FoO: bar;
API
为 getFileInfo() 添加 resolveConfig 选项 (#6666 by @kaicataldo)
新增 resolveConfig: boolean 选项至 prettier.getFileInfo(),设置为 true 时将解析给定文件路径的配置。这使得使用者能考虑被覆盖的解析器。
CLI
处理标准输入读取错误 (#6708 by @andersk and @lydell)
若 .prettierrc 存在错误,此前 Prettier 格式化标准输入时会崩溃。此类错误现已被正确处理。
# Prettier 1.18
$ prettier --parser babel < test.js
(node:21531) UnhandledPromiseRejectionWarning: Error: Invalid printWidth value. Expected an integer, but received "nope".
at _loop (/home/you/project/node_modules/prettier/bin-prettier.js:7887:63)
at Normalizer._applyNormalization (/home/you/project/node_modules/prettier/bin-prettier.js:8000:13)
at applyNormalization (/home/you/project/node_modules/prettier/bin-prettier.js:7817:49)
at Normalizer.normalize (/home/you/project/node_modules/prettier/bin-prettier.js:7823:9)
at normalizeOptions$1 (/home/you/project/node_modules/prettier/bin-prettier.js:8760:31)
at Object.normalizeApiOptions (/home/you/project/node_modules/prettier/bin-prettier.js:8918:10)
at getOptionsForFile (/home/you/project/node_modules/prettier/bin-prettier.js:44160:69)
at /home/you/project/node_modules/prettier/bin-prettier.js:44214:22
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:21531) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:21531) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
# Prettier 1.19
$ prettier --parser babel < test.js
[error] Invalid printWidth value. Expected an integer, but received "nope".
优雅处理 --stdin-filepath 传递的不存在路径 (#6687 by @voithos and @lydell)
此前若向 --stdin-filepath 传递不存在的子目录,Prettier 会抛出错误。现在 Prettier 能优雅处理此情况。
# Prettier 1.18
$ prettier --stdin-filepath does/not/exist.js < test.js
[error] Invalid configuration file: ENOENT: no such file or directory, scandir '/home/you/project/does/not'
# Prettier 1.19
$ prettier --stdin-filepath does/not/exist.js < test.js
test;
不应为忽略文件评估配置 (#6233 by @jamesreggio)
在此变更前,CLI 会在检查忽略列表前解析文件的配置。若配置无效,CLI 会报告失败。
此变更将配置解析阶段移至确认文件未被忽略之后执行。
在错误信息中显示无效配置文件名 (#6865 by @fisker)
# Input
$ prettier filename.js --config .invalid-config
# Prettier 1.18
Invalid configuration file: ...
# Prettier 1.19
Invalid configuration file `.invalid-config`: ...
其他改进
感谢 @fisker 更新了 Prettier 的大量依赖项!
VS Code:新增对 .mongo 文件的支持 (#6848 by @aymericbouzy)
使用 VS Code 的 Azure Cosmos DB 扩展时,您可以创建 .mongo 文件来编写使用 JavaScript 语法的 MongoDB 查询。此项变更允许 VS Code 通过 Prettier 格式化这些文件。
db.users.find({ someField: { $exists: true } });
