Prettier 1.18:大量修复与 OpenCollective
本页面由 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.global 和 css.resolve。https://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 中某些表达式的括号,但当表达式是以 function 或 class 开头的复杂表达式时,这些括号是必需的。
以下是一些实际示例,其中包含一个影响 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。
