跳至主内容区

Prettier 1.18:大量修复与 OpenCollective

· 1 分钟阅读
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

本次发布虽然没有引入闪亮的新功能,但包含大量针对 JavaScript(特别是 JSX 和模板字面量)、TypeScript 和 Markdown 的修复。

借此机会提醒大家:Prettier 现已接受捐赠!如果您喜欢 Prettier 并希望支持我们的工作,请访问我们的 OpenCollective

重要更新

JavaScript

停止对简单模板字面量的换行处理 (#5979 by @jwbay)

这是 Prettier 中收到大量变更请求的功能之一:对模板字面量中的简单表达式进行换行。此前,如果整个字面量超出打印宽度,Prettier 会将表达式拆分成多行。现在,当表达式简单时,我们将阻止这种换行行为。

这是对之前行为的改进,但该领域仍有待完善。

// Input
console.log(chalk.white(`Covered Lines below threshold: ${coverageSettings.lines}%. Actual: ${coverageSummary.total.lines.pct}%`))

// Output (Prettier stable)
console.log(
chalk.white(
`Covered Lines below threshold: ${coverageSettings.lines}%. Actual: ${
coverageSummary.total.lines.pct
}%`
)
);

// Output (Prettier master)
console.log(
chalk.white(
`Covered Lines below threshold: ${coverageSettings.lines}%. Actual: ${coverageSummary.total.lines.pct}%`
)
);

停止将空 JSX 元素转换为自闭合元素 (#6127 by @duailibe)

Prettier 一直将空 JSX 元素(<div></div>)转换为自闭合元素(<div />),因为二者在功能上是等价的。

我们收到反馈:开发过程中,开发者希望先输入开闭标签占位,稍后再添加子元素,但 Prettier 会将其转换为自闭合元素,迫使开发者手动改回。此版本已改变这一行为。

// Input
function Foo() {
return <div></div>;
}

// Output (Prettier stable)
function Foo() {
return <div />;
}

// Output (Prettier master)
function Foo() {
return <div></div>;
}

其他变更

JavaScript

修复 Closure Compiler 的类型转换 (#5947 by @jridgewell)

如果内部表达式中的类型转换后紧跟着右括号,该类型转换会将所有内容错误地包裹至该右括号。

// Input
test(/** @type {!Array} */(arrOrString).length);
test(/** @type {!Array} */((arrOrString)).length + 1);
// Output (Prettier stable)
test(/** @type {!Array} */ (arrOrString.length));
test(/** @type {!Array} */ (arrOrString.length + 1));
// Output (Prettier master)
test(/** @type {!Array} */ (arrOrString).length);
test(/** @type {!Array} */ (arrOrString).length + 1);

修复不带空格的 Closure 类型转换 (#6116 by @jridgewell)

此前,Closure 类型转换必须在 @type 和开头 { 之间添加空格,否则外层括号会被移除。而 Closure 本身并不要求此空格。

// Input
const v = /** @type{string} */(value);

// Output (Prettier stable)
const v = /** @type{string} */ value;

// Output (prettier master)
const v = /** @type{string} */ (value);

修复使用 --quote-props=consistent 时对数字或计算表达式键名添加引号的问题 (#6119#6138 by @duailibe)

此前,如果对象中存在至少一个包含"复杂"表达式(如成员表达式)或数字字面量的计算键,Prettier 会为对象的键或类的属性和方法添加不必要的引号。

// Input
const obj = {
foo: "",
[foo.bar]: "",
};

const other = {
foo: "",
1: ""
};

// Output (Prettier stable)
const obj = {
"foo": "",
[foo.bar]: "",
};

const other = {
"foo": "",
1: ""
};

// Output (Prettier master)
const obj = {
foo: "",
[foo.bar]: "",
};

const other = {
foo: "",
1: ""
};

为含逻辑表达式的 JSX 展开元素添加括号 (#6130 by @duailibe)

此前 Prettier 不会在 JSX 展开元素中添加括号(因其非必需),但为保持与对象/数组中展开运算符的一致性,现在 JSX 中也会添加括号。

// Input
<Component {...(props || {})} />;

// Output (Prettier stable)
<Component {...props || {}} />;

// Output (Prettier master)
<Component {...(props || {})} />;

正确处理空箭头函数表达式中的注释 (#6086 by @evilebottnawi)

// Input
const fn = (/*event, data*/) => doSomething(anything);

// Output (Prettier stable)
const fn = () => /*event, data*/ doSomething(anything);

// Output (Prettier master)
const fn = (/*event, data*/) => doSomething(anything);

不再优化对象属性中的序列表达式间距 (#6088 by @evilebottnawi)

// Input
const a = {
someKey:
(longLongLongLongLongLongLongLongLongLongLongLongLongLongName, shortName)
};

// Output (Prettier stable)
const a = {
someKey: (longLongLongLongLongLongLongLongLongLongLongLongLongLongName,
shortName)
};

// Output (Prettier master)
const a = {
someKey:
(longLongLongLongLongLongLongLongLongLongLongLongLongLongName, shortName)
};

新增对 styled-jsx 外部样式的支持 (#6089 by @hongrich)

新增对 styled-jsx/css 中两种外部样式标签的支持:css.globalcss.resolvehttps://github.com/zeit/styled-jsx/#external-css-and-styles-outside-of-the-component

css 模板标签此前已获支持。

// Input
const styles = css.resolve`
.box {background:black;
}`;

// Output (Prettier stable)
const styles = css.resolve`
.box {background:black;
}`;

// Output (prettier master)
const styles = css.resolve`
.box {
background: black;
}
`;

保留 export default 声明中函数和类周围的括号 (#6133 by @duailibe)

此前 Prettier 会移除 export default 中某些表达式的括号,但当表达式是以 functionclass 开头的复杂表达式时,这些括号是必需的。

以下是一些实际示例,其中包含一个影响 TypeScript 的案例。

// Input
export default (function log() {}).toString();
export default (function log() {} as typeof console.log);

// Output (Prettier stable)
export default function log() {}.toString();
export default function log() {} as typeof console.log; // syntax error

// Output (Prettier master)
export default (function log() {}).toString();
export default (function log() {} as typeof console.log);

修复调用和 new 边缘场景中的括号问题 (#6148 by @bakkot)

在混合使用 new 和函数调用时精确添加必要括号非常复杂。本次变更修复了两处遗漏必要括号的问题和一处冗余括号问题。

// Input
new (x()``.y)();
new (x()!.y)();
new e[f().x].y()

// Output (Prettier stable)
new x()``.y();
new x()!.y();
new e[(f()).x].y();

// Output (Prettier master)
new (x())``.y();
new (x())!.y();
new e[f().x].y();

修复嵌套嵌入场景(JS 中的 HTML 中的 JS) (#6038 by @thorn0)

此前,若通过模板字面量嵌入的 HTML(通过 <script>)中包含模板字面量,内层 JS 代码不会被格式化。

// Input
const html = /* HTML */ `<script>var a=\`\`</script>`;

// Output (Prettier stable)
// SyntaxError: Expecting Unicode escape sequence \uXXXX (1:8)

// Output (Prettier master)
const html = /* HTML */ `
<script>
var a = \`\`;
</script>
`;

保留传递给 new 表达式的 bind 表达式必要括号 (#6152 by @sosukesuzuki)

此前,当 bind 表达式作为参数传递给 new 表达式时,Prettier 会移除其必要括号。

// Input
new (a::b)();

// Output (Prettier stable)
new a::b();

// Output (Prettier master)
new (a::b)();

避免在成员表达式属性中的 bind 表达式添加冗余括号 (#6159 by @duailibe)

// Input
f[a::b];

// Output (Prettier stable)
f[(a::b)];

// Output (Prettier master);
f[a::b];

TypeScript

保留 TSX 类型参数中的尾部逗号 (#6115 by @sosukesuzuki)

此前单类型参数的箭头函数尾部逗号会被清除。格式化结果在 TS 中有效但在 TSX 中无效,该问题已在 1.19 版本修复。

// Input
type G<T> = any;
const myFunc = <T,>(arg1: G<T>) => false;

// Output (Prettier stable)
type G<T> = any;
const myFunc = <T>(arg1: G<T>) => false;

// Output (prettier master)
type G<T> = any;
const myFunc = <T,>(arg1: G<T>) => false;

当末位参数是带简单返回类型的箭头函数时不拆分调用表达式 (#6106 by @brainkim)

修复了边缘场景:当调用表达式包含带简单返回类型的箭头函数时被错误拆分的问题。

app.get("/", (req, res): void => {
res.send("Hello World!");
});

// Output (Prettier stable)
app.get(
"/",
(req, res): void => {
res.send("Hello World!");
},
);

// Output (Prettier master)
app.get("/", (req, res): void => {
res.send("Hello World!");
});

存在多余括号时保留必要括号对 (#6131 by @sosukesuzuki)

此前在 TypeScript 中,Prettier 在尝试移除冗余括号时会错误删除必要括号。

// Input
type G = ((keyof T))[];

// Output (Prettier stable)
type G = keyof T[];

// Output (prettier master)
type G = (keyof T)[];

保留非空断言的必要括号 (#6136 by @sosukesuzuki, #6140 by @thorn0, #6148 by @bakkot)

此前若断言表达式结果被作为构造函数调用,Prettier 会移除非空断言的必要括号。

// Input
const b = new (c()!)();

// Output (Prettier stable)
const b = new c()!();

// Output (Prettier master)
const b = new (c())!();

保留映射类型内部的换行符 (#6146 by @sosukesuzuki)

此前 Prettier 会移除映射类型内部的换行符。为保持与对象字面量处理逻辑一致,现在会保留源码中存在的换行符。

// Input
type A<T> = {
readonly [P in keyof T]: T[P];
};

// Output (Prettier stable)
type A<T> = { readonly [P in keyof T]: T[P] };

// Output (Prettier master)
type A<T> = {
readonly [P in keyof T]: T[P];
};

在元组类型中添加尾部逗号(配合 --trailing-comma=all) (#6172 by @sosukesuzuki)

TypeScript 从 3.3 版本开始支持元组类型尾部逗号。

// Input
export type Foo = [
number,
number, // comment
];

// Output (Prettier stable)
export type Foo = [
number,
number // comment
];

// Output (Prettier master);
export type Foo = [
number,
number, // comment
];

Markdown

正确计算行内代码的反引号数量 (#6110 by @belochub)

根据 CommonMark 规范,必须选择由 n 个反引号组成的字符串作为分隔符,且行内代码中不能包含恰好 n 个反引号的字符串。

本次变更优化了反引号数量计算逻辑:不再简单采用"当行内代码块包含单反引号时用双反引号,其余情况用单反引号"的策略,而是动态计算能正确作为分隔符的最小长度反引号字符串。

<!-- Input -->
``` 3 ``22`` `1` ```

`` 2 ```123``` `1` ``

<!-- Output (Prettier stable) -->
` 3 ``22`` `1` `

` 2 ```123``` `1` `

<!-- Output (Prettier master) -->
``` 3 ``22`` `1` ```

`` 2 ```123``` `1` ``

Handlebars

虽然 Handlebars 支持仍处于测试阶段,但 @GavinJoyce 正在持续修复问题以期推出稳定版本!

避免在组件后添加多余空白符 (#6178 by @GavinJoyce)

此前 Prettier 会在 /> 前添加空格并在其后换行,即使位于行首。现在这些多余空格和换行已被移除。

// Input
<div>
<UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/>
</div>

// Output (Prettier stable)
<div>
<UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/>

</div>

// Output (Prettier master)
<div>
<UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/>
</div>

API

Prettier 现已恢复在 Atom 中的运行支持(由 @duailibe#6129 中修复)

Atom 的安全机制禁止执行包含 eval 的代码。由于 Prettier 某个依赖使用 eval 防止打包工具包含调试代码,我们已确保该 eval 不会出现在 npm 发布的正式代码中,从而使 Prettier 重新兼容 Atom。