跳至主内容区

Prettier 3.0:你好,ECMAScript 模块!

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

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

我们很高兴地宣布 Prettier 新版本正式发布!

我们已将全部源代码迁移至 ECMAScript 模块。这项变更显著提升了 Prettier 团队的开发体验。请放心,当将 Prettier 作为库使用时,您仍然可以按 CommonJS 方式使用它。

本次更新包含若干破坏性变更。其中一个显著变化是 Markdown 格式的调整——不再在拉丁字符与中文/日文字符之间插入空格。我们要特别感谢 Tatsunori Uchino,他在过去一年为 Prettier 做出了重大贡献,尤其是在此功能上。此外,trailingComma 的默认值已改为 "all"

本次发布的另一重要变化是对插件接口的重大重构。Prettier 现已支持使用 ECMAScript 模块编写的插件和异步解析器。如果您是插件开发者,请在更新时务必谨慎。您可以在此处查看迁移指南。一如既往,我们欢迎错误报告和反馈意见!

此版本还包含大量格式改进和错误修复。

如果您认可 Prettier 的价值并希望支持我们的工作,请考虑通过 我们的 OpenCollective 直接赞助,或赞助我们依赖的项目如 typescript-eslintremarkBabel。感谢您持续的支持!

重要更新

Markdown

改进中文、日文和韩文空白处理 (#11597 by @tats-u)

停止在中日文字符与西文字符间插入空格

此前,Prettier 会在中日文字符与西文字符(字母和数字)之间插入空格。虽然部分用户偏好此风格,但这并非标准实践,事实上与官方指南相悖。更多详情请参阅此处。我们认定强制推行特定风格不属于 Prettier 的职责范畴,因此不再插入新空格,但保留现有空格。如需强制规范间距风格,请考虑使用 textlint-jalint-md(规则 space-round-alphabetspace-round-number)。

此变更最复杂的部分在于处理中日文字符与西文字符之间的模糊换行。当 Prettier 解包文本时,需要判断此类换行应直接移除还是替换为空格。为此,Prettier 会分析上下文并推断首选风格。

<!-- Input -->
漢字
Alphabetsひらがな12345カタカナ67890

漢字 Alphabets ひらがな 12345 カタカナ 67890

<!-- Prettier 2.8 -->
漢字 Alphabets ひらがな 12345 カタカナ 67890

漢字 Alphabets ひらがな 12345 カタカナ 67890

<!-- Prettier 3.0 -->
漢字Alphabetsひらがな12345カタカナ67890

漢字 Alphabets ひらがな 12345 カタカナ 67890
遵循中日文换行规则

中文日文存在禁止特定字符出现在行首/行尾的规则。例如句号字符 . 不应出现在行首,而 不应出现在行尾。当 proseWrap 设为 always 时,Prettier 现在会在文本换行时遵循这些规则。

<!-- Input -->
HTCPCPのエラー418は、ティーポットにコーヒーを淹(い)れさせようとしたときに返されるステータスコードだ。

<!-- Prettier 2.8 with --prose-wrap always --print-width 8 -->
HTCPCP の
エラー
418 は、
ティーポ
ットにコ
ーヒーを
淹(い)
れさせよ
うとした
ときに返
されるス
テータス
コードだ


<!-- Prettier 3.0 with the same options -->
HTCPCPの
エラー
418は、
ティー
ポットに
コーヒー
を淹
(い)れ
させよう
としたと
きに返さ
れるス
テータス
コード
だ。
禁止在韩文单词内换行

韩语使用空格分隔单词,不当的分词可能改变句子含义:

  • 노래를 못해요.: 我不擅长唱歌

  • 노래를 못 해요.: 我无法唱歌(因某些原因)

此前当 proseWrap 设置为 always 时,连续的韩文字符可能被换行符拆分,当文档被编辑并重新格式化时,这些换行符可能被转换为空格。现在此问题已修复,韩语文本会像英语一样进行换行处理。

<!-- Input -->
노래를 못해요.

<!-- Prettier 2.8 with --prose-wrap always --print-width 9 -->
노래를 못
해요.

<!-- Prettier 2.8, subsequent reformat with --prose-wrap always --print-width 80 -->
노래를 못 해요.

<!-- Prettier 3.0 with --prose-wrap always --print-width 9 -->
노래를
못해요.

<!-- Prettier 3.0, subsequent reformat with --prose-wrap always --print-width 80 -->
노래를 못해요.

当 Prettier 取消文本换行时,韩文字母与英文字母/数字之间的换行符将被转换为空格。参考以下示例:

3분 기다려 주지.

若在 "3" 和 "분" 之间换行,取消换行时该位置将插入空格。

API

支持异步解析器的插件 (#12748 by @fisker, #13211 by @thorn0 and @fisker)

插件中的 parse 函数 现在可返回 Promise

为支持嵌入式语言的异步解析器,我们不得不对插件 API 进行重大变更:打印器的 embed 方法现在需匹配全新的函数签名(与先前版本不兼容)。若您是插件开发者且未定义 embed 方法则无需担心,否则请查阅文档了解详情。

此外,打印器的 preprocess 方法现在也可返回 Promise。

支持 ESM 格式的配置文件 (#13130 by @fisker)

现支持 ESM 格式的配置文件,可用文件名包括:

  • prettier.config.js (需在 package.json 中配置 {"type": "module"})

  • .prettierrc.js (同上)

  • prettier.config.mjs

  • .prettierrc.mjs

export default {
trailingComma: "es5",
tabWidth: 4,
semi: false,
singleQuote: true,
};

可共享配置包 现在也可采用纯 ESM 格式。

重大变更

JavaScript

trailingComma 默认值改为 all (#11479 by @fisker, #13143 by @sosukesuzuki)

自 2.0 版本起,我们已将 trailingComma 默认值设为 es5

Internet Explorer(最后一个禁止函数调用尾随逗号的浏览器)已于 2022 年 6 月 15 日终止支持。据此,现将 trailingComma 默认值更改为 all

如果仍然需要旧版行为,请将 Prettier 配置为 { "trailingComma": "es5" }

babel 解析器中移除 Flow 语法支持 (#14314 by @fisker, @thorn0)

由于历史原因,当 parser 选项设置为 babel 时,即使文件未包含 @flow 编译指令,Prettier 过去也会在 JS 文件中识别 Flow 语法。这种支持有限且影响性能,因此已在 Prettier 3.0 中移除。当使用 babel 解析器时,如果检测到 @flow 编译指令或文件扩展名为 .js.flow,Prettier 仍会自动切换至 Flow 语法。

Flow

移除对 Flow 注释的支持 (#13687, #13703 by @thorn0)

作为一种预处理器,Flow 注释(又称注释类型)在词法层级处理,通常无法在 AST 中表示。Flow 构建 AST 时会忽略这些特殊注释标记。例如:

/*:: if */ (x) + y;

Flow 会将其解析为 if (x) +y;,而不支持 Flow 的 JS 解析器会将其视为 x + y;

此前 Prettier 会尝试检测此类特殊语法并保留其格式。这种有限支持试图解决不可解的问题,导致实现脆弱且漏洞频发,现已被移除。当 parser 选项设为 flowbabel-flow 时,Flow 注释将被作为普通代码解析和格式化;若使用不支持 Flow 的解析器,则会视为常规注释处理。

// Input
let a /*: foo */ = b;

// Prettier 2.8
let a /*: foo */ = b;

// Prettier 3.0 with --parser flow
let a: foo = b;

// Prettier 3.0 with --parser babel
let a /*: foo */ = b;

--trailing-comma=es5 时在类型参数和元组类型中添加尾部逗号 (#14086, #14085 by @fisker)

// Input
type Foo = [
{
from: string,
to: string,
}, // <- 1
];
type Foo = Promise<
| { ok: true, bar: string, baz: SomeOtherLongType }
| { ok: false, bar: SomeOtherLongType }, // <- 2
>;

// Prettier 2.8
type Foo = [
{
from: string,
to: string,
} // <- 1
];
type Foo = Promise<
| { ok: true, bar: string, baz: SomeOtherLongType }
| { ok: false, bar: SomeOtherLongType } // <- 2
>;

// Prettier 3.0
type Foo = [
{
from: string,
to: string,
}, // <- 1
];
type Foo = Promise<
| { ok: true, bar: string, baz: SomeOtherLongType }
| { ok: false, bar: SomeOtherLongType }, // <- 2
>;

CSS

新增纯净版 css 解析器 (#7933, #9092, #9093 by @fisker)

此前当传递 --parser=css 参数时,Prettier 会尝试使用 postcss-scsspostcss-less 解析内容,这容易引发混淆且难以发现语法错误。现在 --parser=css 仅支持原生 CSS 语法。

若在 .less/.scss 文件中使用 parser="css",请更新为正确解析器,或移除 parser 选项以让 Prettier 根据文件扩展名自动检测解析器。

/* Input */
/* Less Syntax with `--parser=css` */
a {.bordered();}

/* Prettier 2.8 */
/* Less Syntax with `--parser=css` */
a {
.bordered();
}

/* Prettier 3.0 */
SyntaxError: (postcss) CssSyntaxError Unknown word (2:4)
1 | /* Less Syntax with `--parser=css` */
> 2 | a {.bordered();}
/* Input */
/* Scss Syntax with `--parser=css` */
::before {content: #{$foo}}

/* Prettier 2.8 */
/* Scss Syntax with `--parser=css` */
::before {
content: #{$foo};
}

/* Prettier 3.0 */
SyntaxError: (postcss) CssSyntaxError Unknown word (2:22)
1 | /* Scss Syntax with `--parser=css` */
> 2 | ::before {content: #{$foo}}

GraphQL

弃用"逗号分隔接口"语法支持 (#12835 by @fisker)

# Input
type Type1 implements A, B {a: a}

# Prettier 2.8
type Type1 implements A, B {
a: a
}

# Prettier 3.0
SyntaxError: Syntax Error: Unexpected Name "B". (1:26)
> 1 | type Type1 implements A, B {a: a}

API

停止支持 Node.js 10 和 12 (#11830@fisker#13118@sosukesuzuki)

最低要求的 Node.js 版本为 v14

将公共 API 改为异步 (#12574, #12788, #12790, #13265@fisker)

  • prettier.format() 现在返回 Promise<string>

  • prettier.formatWithCursor() 现在返回 Promise<{formatted: string, cursorOffset: number}>

  • prettier.formatAST() 现在返回 Promise<string>

  • prettier.check() 现在返回 Promise<boolean>

  • prettier.getSupportInfo() 现在返回 Promise

  • prettier.clearConfigCache() 现在返回 Promise<void>

  • prettier.resolveConfig.sync 已被移除

  • prettier.resolveConfigFile.sync 已被移除

  • prettier.getFileInfo.sync 已被移除

如果你仍需要同步 API,可以尝试 @prettier/sync

Npm 包文件结构调整 (#12740@fisker, #13530@fisker, #14570@fisker)

文件结构变更如下:

  • bin-prettier.js -> bin/prettier.cjs

  • esm/standalone.mjs -> standalone.mjs

  • esm/parser-angular.mjs -> plugins/angular.mjs

  • parser-angular.js -> plugins/angular.js

  • esm/parser-babel.mjs -> plugins/babel.mjs

  • parser-babel.js -> plugins/babel.js

  • esm/parser-espree.mjs -> plugins/acorn-and-espree.mjs

  • parser-espree.js -> plugins/acorn.js
    全局对象重命名为 prettierPlugins.espree -> prettierPlugins.acorn

  • esm/parser-flow.mjs -> plugins/flow.mjs

  • parser-flow.js -> plugins/flow.js

  • esm/parser-glimmer.mjs -> plugins/glimmer.mjs

  • parser-glimmer.js -> plugins/glimmer.js

  • esm/parser-graphql.mjs -> plugins/graphql.mjs

  • parser-graphql.js -> plugins/graphql.js

  • esm/parser-html.mjs -> plugins/html.mjs

  • parser-html.js -> plugins/html.js

  • esm/parser-markdown.mjs -> plugins/markdown.mjs

  • parser-markdown.js -> plugins/markdown.js

  • esm/parser-meriyah.mjs -> plugins/meriyah.mjs

  • parser-meriyah.js -> plugins/meriyah.js

  • esm/parser-postcss.mjs -> plugins/postcss.mjs

  • parser-postcss.js -> plugins/postcss.js

  • esm/parser-typescript.mjs -> plugins/typescript.mjs

  • parser-typescript.js -> plugins/typescript.js

  • esm/parser-yaml.mjs -> plugins/yaml.mjs

  • parser-yaml.js -> plugins/yaml.js

完整列表请查看 https://unpkg.com/browse/prettier@3.0.0/。

新增了一个插件:

  • plugins/estree.mjs (ESM 版本)

  • plugins/estree.js (UMD 版本)

如果使用独立版本,在打印 JavaScript、TypeScript、Flow 或 JSON 时应加载此插件。

import { format } from "prettier/standalone";
- import prettierPluginBabel from "prettier/parser-babel";
+ import * as prettierPluginBabel from "prettier/plugins/babel";
+ import * as prettierPluginEstree from "prettier/plugins/estree";

console.log(
- format(code, {
+ await format(code, {
parser: "babel",
- plugins: [prettierPluginBabel],
+ plugins: [prettierPluginBabel, prettierPluginEstree],
})
);
- node ./node_modules/prettier/bin-prettier.js . --write
+ node ./node_modules/prettier/bin/prettier.cjs . --write

支持 ESM 格式的插件 (#13201 by @fisker)

从 v3.0.0 开始,我们通过 import() 而非 require() 加载插件,因此插件现在可以是 ESM 模块。

如果通过目录路径或无扩展名的文件路径使用 --plugin,可能无法加载插件。

- prettier . --plugin=path/to/my-plugin-directory
+ prettier . --plugin=path/to/my-plugin-directory/index.js
- prettier . --plugin=path/to/my-plugin-file
+ prettier . --plugin=path/to/my-plugin-file.js

更新 prettier.doc (#13203, #14456 by @fisker)

prettier.doc.builders.concat 已在 v2.3.0 中弃用,现已被移除。

以下 API 从未被记录,它们仅限内部使用,现已被移除:

  • prettier.doc.utils.getDocParts

  • prettier.doc.utils.propagateBreaks

  • prettier.doc.utils.cleanDoc

  • prettier.doc.utils.getDocType

  • prettier.doc.debug.printDocToDebug

textToDoc 修剪尾部硬换行 (#13220 by @fisker)

以前,在所有核心语言中,当嵌入式代码打印为 Doc 后,我们会调用 prettier.doc.utils.stripTrailingHardline() 来移除尾部的硬换行。

我们认为让 textToDoc 返回不带尾部硬换行的文档,可使插件更易于实现 embed 打印。

移除对自定义解析器 API 的支持 (#13250 by @fisker and @thorn0)

插件功能出现之前,Prettier 曾提供过类似但功能有限的"自定义解析器"特性。该特性在 v3.0.0 中已被移除,因为它的功能仅是插件 API 的子集。如果您曾使用过此功能,请查阅迁移指南

移除传递给 parsers.parse 的第二个参数 parsers (#13268 by @fisker)

插件 print 函数签名从

function parse(text: string, parsers: object, options: object): AST;

改为

function parse(text: string, options: object): Promise<AST> | AST;

移除了第二个参数 parsers。若解析过程中仍需使用其他解析器,您可以选择:

  1. 自行导入插件(推荐方式)

    import * as prettierPluginBabel from "prettier/plugins/babel";

    const myCustomPlugin = {
    parsers: {
    "my-custom-parser": {
    async parse(text) {
    const ast = await prettierPluginBabel.parsers.babel.parse(text);
    ast.program.body[0].expression.callee.name = "_";
    return ast;
    },
    astFormat: "estree",
    },
    },
    };
  2. 通过 options 参数获取解析器

    function getParserFromOptions(options, parserName) {
    const parserOrParserInitFunction = options.plugins.find(
    (plugin) => plugin.parsers && Object.hasOwn(plugin.parsers, parserName),
    )?.parsers[parserName];
    return typeof parserOrParserInitFunction === "function"
    ? parserOrParserInitFunction()
    : parserOrParserInitFunction;
    }

    const myCustomPlugin = {
    parsers: {
    "my-custom-parser": {
    async parse(text, options) {
    const babelParser = await getParserFromOptions(options, "babel");
    const ast = await babelParser.parse(text);
    ast.program.body[0].expression.callee.name = "_";
    return ast;
    },
    astFormat: "estree",
    },
    },
    };

插件 print 函数不再接收 undefinednull 值 (#13397 by @fisker)

若您的插件曾通过 print 处理这些值,请改为在父节点中进行检查。

function print(path, print) {
- const value = path.getValue();
- if (!value?.type) {
- return String(value);
- }

- return path.map(print, "values");

+ return path.map(({node}) => (node?.type ? print() : String(node)), "values");
}

支持在文档中使用任意真值作为 label (#13532 by @thorn0)

label 文档构建器已变更,详见文档说明

getFileInfo() 默认解析配置 (#14108 by @fisker)

options.resolveConfig 现在默认为 true,参见文档说明

移除插件自动搜索功能 (#14759 by @fisker)

该功能在使用 pnpm 时表现不佳且会导致性能下降。

Prettier 3.0 中已移除 CLI 的 --plugin-search-dir--no-plugin-search 参数以及 API 的 pluginSearchDirs 选项。

请改用 --plugin 参数和 plugins 选项,详见文档说明

CLI

默认忽略 .gitignore 文件 (#14731 by @fisker)

Prettier 现在默认忽略被 .gitignore 排除的文件。 如需恢复旧行为(仅忽略 .prettierignore 中的文件),请使用:

prettier . --write --ignore-path=.prettierignore

其他变更

JavaScript

支持 "装饰器函数" 模式 (#10714 by @thorn0)

这种模式中,开发者通常愿意牺牲箭头函数签名的可读性来减少函数体的缩进。Prettier 现在能识别此模式,即使签名过长也会保持箭头函数紧凑格式。

// Prettier 2.8
const Counter = decorator("my-counter")(
(props: { initialCount?: number; label?: string }) => {
// ...
}
);

// Prettier 3.0
const Counter = decorator("my-counter")((props: {
initialCount?: number;
label?: string;
}) => {
// ...
});

修复含表情符号文件的游标定位 (#13340 by @fisker)

$ cat test.js
const { formatWithCursor } = await import("prettier");
const code = "'😀😀😀😀'";
await formatWithCursor(code, {parser: "babel", cursorOffset: 9})

# Prettier 2.8
$ node test.js
{ formatted: '"😀😀😀😀";\n', cursorOffset: 5, comments: [] }

# Prettier 3.0
$ node test.js
{ formatted: '"😀😀😀😀";\n', cursorOffset: 9, comments: [] }

修复首调用参数展开的边缘情况 (#13341 by @thorn0)

// Input
export default whatever(function (a: {
aaaaaaaaa: string;
bbbbbbbbb: string;
ccccccccc: string;
}) {
return null;
}, "xyz");

call(
function() {
return 1;
},
$var ?? $var ?? $var ?? $var ?? $var ?? $var ?? $var ?? $var ?? $var ?? 'test'
);

// Prettier 2.8
export default whatever(function (a: {
aaaaaaaaa: string;
bbbbbbbbb: string;
ccccccccc: string;
}) {
return null;
},
"xyz");

call(function () {
return 1;
}, $var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
"test");

// Prettier 3.0
export default whatever(function (a: {
aaaaaaaaa: string,
bbbbbbbbb: string,
ccccccccc: string,
}) {
return null;
}, "xyz");

call(
function () {
return 1;
},
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
$var ??
"test",
);

修复调用参数和二元表达式中箭头函数链的缩进 (#13391 by @thorn0)

当前格式化规则的核心目标是清晰展示函数调用的参数数量。 但当链式调用中首个签名跨行显示时,其缩进存在缺陷。

// Prettier 2.8
askTrovenaBeenaDependsRowans(
glimseGlyphsHazardNoopsTieTie,
(
averredBathersBoxroomBuggyNurl,
anodyneCondosMalateOverateRetinol = "default"
) =>
(annularCooeedSplicesWalksWayWay) =>
(kochabCooieGameOnOboleUnweave) =>
abugidicRomanocastorProvider,
weaponizedStellatedOctahedron
);

// Prettier 3.0
askTrovenaBeenaDependsRowans(
glimseGlyphsHazardNoopsTieTie,
(
averredBathersBoxroomBuggyNurl,
anodyneCondosMalateOverateRetinol = "default",
) =>
(annularCooeedSplicesWalksWayWay) =>
(kochabCooieGameOnOboleUnweave) =>
abugidicRomanocastorProvider,
weaponizedStellatedOctahedron,
);

当参数为无类型的标识符时,不拆解紧凑函数表达式的签名 (#13410 by @thorn0)

// Prettier 2.8
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
props,
ref
) {
return <ThemeUILink ref={ref} variant="default" {...props} />;
});

// Prettier 3.0
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
function Link(props, ref) {
return <ThemeUILink ref={ref} variant="default" {...props} />;
},
);

修复交错注释的处理 (#13438 by @thorn0)

// Input
function x() {
} // first
; // second

// Prettier 2.8
function x() {} // first // second

// Prettier 3.0
function x() {} // first
// second

支持嵌套 JSDoc 注释 (#13445 by @thorn0)

此类注释常用于重载函数文档(参见 https://github.com/jsdoc/jsdoc/issues/1017).

// Input
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}

// Prettier 2.8
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*/ /**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}

// Prettier 3.0
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}

修复含嵌入式语言的模板字符串稳定性 (#13532 by @thorn0)

若包含嵌入式语法的模板字符串是函数的唯一参数,或是箭头函数体且首尾含空白符,则不会换行显示。

// Input
foo(/* HTML */ ` <!-- bar1 --> bar <!-- bar2 --> `);

// Prettier 2.8 (first output)
foo(
/* HTML */ `
<!-- bar1 -->
bar
<!-- bar2 -->
`
);

// Prettier 2.8 (second output)
foo(/* HTML */ `
<!-- bar1 -->
bar
<!-- bar2 -->
`);

// Prettier 3.0 (first output)
foo(/* HTML */ `
<!-- bar1 -->
bar
<!-- bar2 -->
`);

修复模板字符串内表达式的缩进 (#13621 by @fisker)

// Input
`
1. Go to ${chalk.green.underline(FOO_LINK)}
2. Click "${chalk.green(
"Run workflow"
)}" button, type "${chalk.yellow.underline(
version
)}", hit the "${chalk.bgGreen("Run workflow")}" button.
`

// Prettier 2.8
`
1. Go to ${chalk.green.underline(FOO_LINK)}
2. Click "${chalk.green(
"Run workflow"
)}" button, type "${chalk.yellow.underline(
version
)}", hit the "${chalk.bgGreen("Run workflow")}" button.
`;

// Prettier 3.0
`
1. Go to ${chalk.green.underline(FOO_LINK)}
2. Click "${chalk.green(
"Run workflow",
)}" button, type "${chalk.yellow.underline(
version,
)}", hit the "${chalk.bgGreen("Run workflow")}" button.
`;

新增 "显式资源管理" 提案支持 (#13752 by @fisker, #14862 by @sosukesuzuki)

Stage 2 提案 "显式资源管理" 现通过 Babel 7.20.07.22.0 获得支持。

另外,在使用 Prettier 处理此提议的语法特性前,请牢记我们的关于非标准化语法的政策

// Examples
{
using obj = g(); // block-scoped declaration
const r = obj.next();
} // calls finally blocks in `g`

{
await using obj = g(); // block-scoped declaration
const r = obj.next();
} // calls finally blocks in `g`

新增对"导入反射"(Import Reflection)提案的支持 (#13771 by @fisker)

通过 Babel 7.20.0 现已支持处于 Stage 2 阶段的提案"导入反射"。另外,在使用 Prettier 处理此提议的语法特性前,请牢记我们的关于非标准化语法的政策

// Examples
import module x from "<specifier>";

修复数组/元组与对象/记录之间的不一致性 (#14065 by @fisker)

// Input
foo.a().b().c([n, o])
foo.a().b().c(#[n, o])
foo.a().b().c({n, o})
foo.a().b().c(#{n, o})

// Prettier 2.8
foo.a().b().c([n, o]);
foo
.a()
.b()
.c(#[n, o]);
foo.a().b().c({ n, o });
foo
.a()
.b()
.c(#{ n, o });

// Prettier 3.0
foo.a().b().c([n, o]);
foo.a().b().c(#[n, o]);
foo.a().b().c({ n, o });
foo.a().b().c(#{ n, o });

修复 JSX 文本内的光标追踪问题 (#14163 by @fisker)

// Prettier 2.8
formatWithCursor(
["<>a", " <div>hi</div>", "</>"].join("\n"),
{ cursorOffset: 3, parser: "babel" }
).cursorOffset;
// -> 2

// Prettier 3.0
(await formatWithCursor(
["<>a", " <div>hi</div>", "</>"].join("\n"),
{ cursorOffset: 3, parser: "babel" }
)).cursorOffset;
// -> 6

避免对嵌套的 await 表达式进行不必要的缩进 (#14192 by @thorn0)

这是对 v2.3 中这一变更 的优化。有时无需强制对嵌套的 await 表达式进行缩进。

// Prettier 2.8
await Promise.all(
(
await readdir("src")
).map((path) => {
import(`./${path}`);
})
);

// Prettier 3.0
await Promise.all(
(await readdir("src")).map((path) => {
import(`./${path}`);
}),
);

支持正则表达式修饰符提案 (#14391 by @fisker)

详见 ECMAScript 的正则表达式模式修饰符提案

修复 prettier-ignore 节点周围缺失的括号和分号 (#14406 by @fisker)

// Input
async function request(url) {
return (
// prettier-ignore
await fetch(url)
).json()
}

// Prettier 2.8
async function request(url) {
return (
// prettier-ignore
await fetch(url).json()
);
}

// Prettier 3.0
async function request(url) {
return (
// prettier-ignore
(await fetch(url)).json()
);
}
// Input
foo();
// prettier-ignore
[bar, baz].forEach(console.log)

// Prettier 2.8 (--no-semi)
foo()
// prettier-ignore
[bar, baz].forEach(console.log)

// Prettier 3.0
foo()
// prettier-ignore
;[bar, baz].forEach(console.log)

移除类表达式周围不必要的括号 (#14409 by @fisker)

// Input
call(
@dec class {}
);

// Prettier 2.8
call(
(
@dec
class {}
)
);

// Prettier 3.0
call(
@dec
class {},
);

ExpressionStatement 的头部而非整个语句添加括号 (#14599 by @fisker)

// Input
const isArray = (object) => ({}).toString.call(foo) === "[object Array]";

// Prettier 2.8
const isArray = (object) => ({}.toString.call(foo) === "[object Array]");

// Prettier 3.0
const isArray = (object) => ({}).toString.call(foo) === "[object Array]";

提高柯里化与非柯里化箭头函数之间的一致性 (#14633 by @seiyab, @fisker)

// Input
Y(() => a ? b : c);
Y(() => () => a ? b : c);

// Prettier 2.8
Y(() => (a ? b : c));
Y(() => () => a ? b : c);

// Prettier 3.0
Y(() => (a ? b : c));
Y(() => () => (a ? b : c));

修复数组元素间的空行检查 (#14736 by @solarized-fox)

// Input
[
(a = b),

c // comment
]

// Prettier 2.8
[
(a = b),
c, // comment
];

// Prettier 3.0
[
(a = b),

c, // comment
];

支持所有参数类型的函数参数尾部注释 (#14835 by @pieterv)

支持 RestElementArrayPatternObjectPattern 参数节点类型的函数参数尾部注释。

// Input
function Foo(
...bar
// Trailing comment
) {}

// Prettier 2.8
function Foo(...bar) // Trailing comment
{}

// Prettier 3.0
function Foo(
...bar
// Trailing comment
) {}

支持导入属性 (#14861, #14863 by @sosukesuzuki)

支持 Import Attributes 提案。

import json from "./foo.json" with { type: "json" };
import("./foo.json", { with: { type: "json" } });

TypeScript

修复带 readonly 的映射类型中前导注释的格式问题 (#13427 by @thorn0, @sosukesuzuki)

// Input
type Type = {
// comment
readonly [key in Foo];
};

// Prettier 2.8
type Type = {
readonly // comment
[key in Foo];
};

// Prettier 3.0
type Type = {
// comment
readonly [key in Foo];
};

统一元组类型和数组的悬挂注释格式 (#13608 by @sosukesuzuki)

// Input
type Foo = [
// comment
];
const bar = [
// comment
];

// Prettier 2.8
type Foo = [// comment];
const bar = [
// comment
];

// Prettier 3.0
type Foo = [
// comment
];
const bar = [
// comment
];

修复含注释时联合类型应打印为多行格式的问题 (#13860 by @PerfectPan)

// Input
type FooBar =
| Number // this documents the first option
| void // this documents the second option
;

// Prettier 2.8
type FooBar = Number | void; // this documents the first option // this documents the second option

// Prettier 3.0
type FooBar =
| Number // this documents the first option
| void; // this documents the second option

改进类型注解周围的注释打印与光标追踪 (#14171 by @fisker)

// Input
let foo /* comment */ : number;

// Prettier 2.8
let foo: /* comment */ number;

// Prettier 3.0
<Same as input>
// Prettier 2.8
prettier.formatWithCursor("let foo: number", {
cursorOffset: 7,
parser: "babel",
}).cursorOffset;

// -> 9

// Prettier 3.0
(
await prettier.formatWithCursor("let foo: number", {
cursorOffset: 7,
parser: "babel",
})
).cursorOffset;

// -> 7

在 TypeScript 参数属性处换行 (#14402 by @seiyab)

// Input
class MyClass {
constructor(
protected x: number,
private y: string
) {}
}

// Prettier 2.8
class MyClass {
constructor(protected x: number, private y: string) {}
}

// Prettier 3.0
class MyClass {
constructor(
protected x: number,
private y: string,
) {}
}

修复单类型联合类型的格式化问题 (#14654 by @fisker and @auvred)

// Input
type T =
| (
| {
value: number
}
| {
value: string
}
)

// Prettier 2.8
type T =
|
| {
value: number;
}
| {
value: string;
};

// Prettier 3.0
type T =
| {
value: number;
}
| {
value: string;
};

改进映射类型中的换行检测 (#14659 by @fisker)

// Input
type A1 = { [A in B]:
T}
type A2 = {
[A in B]:T}

// Prettier 2.8
type A1 = {
[A in B]: T;
};
type A2 = {
[A in B]: T;
};

// Prettier 3.0
type A1 = { [A in B]: T };
type A2 = {
[A in B]: T;
};

类型参数中 extends 后换行 (#14672, #14858 by @sosukesuzuki)

// Input
export type OuterType2<
LongerLongerLongerLongerInnerType extends LongerLongerLongerLongerLongerLongerLongerLongerOtherType
> = { a: 1 };

// Prettier 2.8
export type OuterType2<
LongerLongerLongerLongerInnerType extends LongerLongerLongerLongerLongerLongerLongerLongerOtherType
> = { a: 1 };

// Prettier 3.0
export type OuterType2<
LongerLongerLongerLongerInnerType extends
LongerLongerLongerLongerLongerLongerLongerLongerOtherType,
> = { a: 1 };

修复类型参数中缺失的必要逗号 (#14688 by @fisker, @sosukesuzuki)

此前仅在 .tsx 文件扩展名时打印尾部逗号,现已确认 .mts.cts 文件解析时同样需要。

// Input
export const unsafeCoerce = <T,>(u: unknown): T => u as T

// Prettier 2.8
export const unsafeCoerce = <T>(u: unknown): T => u as T;

// Prettier 3.0
export const unsafeCoerce = <T,>(u: unknown): T => u as T;

保留 TSInstantiationExpression 后接属性访问时的括号 (#14701 by @morsko1)

// Input
(Array<string>).a;
(Array<string>)?.a;
(Array<string>)[a];
(Array<string>)?.[a];

// Prettier 2.8
Array<string>.a;
Array<string>?.a;
Array<string>[a];
Array<string>?.[a];

// Prettier 3.0
(Array<string>).a;
(Array<string>)?.a;
(Array<string>)[a];
(Array<string>)?.[a];

修复调用签名行使用 // prettier-ignore 导致双分号的问题 (#14830 by @ot07)

// Input
type Foo = {
(): void; // prettier-ignore
second: string;
};

// Prettier 2.8
type Foo = {
(): void;; // prettier-ignore
second: string;
};

// Prettier 3.0
type Foo = {
(): void; // prettier-ignore
second: string;
};

Flow

declare function 签名中的对象类型现在会在返回类型前换行 (#13396 by @thorn0)

该行为已与 TypeScript 的格式化方式统一。

// Input
declare function bla (props: { a: boolean, b: string, c: number }): Promise<Array<foo>>

// Prettier 2.8
declare function bla(props: { a: boolean, b: string, c: number }): Promise<
Array<foo>
>;

// Prettier 3.0
declare function bla(props: {
a: boolean;
b: string;
c: number;
}): Promise<Array<foo>>;

支持条件类型与 infer 类型 (#14573 by @SamChou19815)

// Input
type TestReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;

// Prettier 2.8
// Does not parse

// Prettier 3.0
type TestReturnType<T extends (...args: any[]) => any> = T extends (
...args: any[]
) => infer R
? R
: any;

支持映射类型和 keyof (#14619 by @jbrown215)

// Input
type Mapped = { [key in keyof O]: number };

// Prettier 2.8
// Does not parse

// Prettier 3.0
type Mapped = { [key in keyof O]: number };

支持类型守卫 (#14767 by @panagosg7)

// Input
function isString (x: mixed): x is string { return typeof x === "string"; }

// Prettier 2.8
// Does not parse

// Prettier 3.0
function isString(x: mixed): x is string {
return typeof x === 'string';
}

CSS

改进自定义属性格式 (#9209 by @fisker)

得益于 PostCSS 8.0,我们现在能够正确处理自定义属性的边界情况。

/* Input */
:root {
--empty: ;
--JSON: [1, "2", {"three": {"a":1}}, [4]];
--javascript: function(rule) { console.log(rule) };
}

@supports (--element(".minwidth", { "minWidth": 300 })) {
[--self] {
background: greenyellow;
}
}

/* Prettier 2.8 */
SyntaxError: (postcss) CssSyntaxError Missed semicolon (3:20)
1 | :root {
2 | --empty: ;
> 3 | --JSON: [1, "2", {"three": {"a":1}}, [4]];
| ^
4 | --javascript: function(rule) { console.log(rule) };
5 | }
6 |

/* Prettier 3.0 */
:root {
--empty: ;
--JSON: [1, "2", {"three": {"a": 1}}, [4]];
--javascript: function(rule) {console.log(rule)};
}

@supports (--element(".minwidth", {"minWidth": 300})) {
[--self] {
background: greenyellow;
}
}

var 函数保留尾部逗号 (#13402 by @sosukesuzuki)

/* Input */
.foo {
--bar: var(--baz,);
}

/* Prettier 2.8 */
.foo {
--bar: var(--baz);
}

/* Prettier 3.0 */
.foo {
--bar: var(--baz,);
}

修复含逗号的 CSS 声明中的换行问题 (#14208 by @mvorisek)

// Input
.myclass {
box-shadow:
inset 0 0 10px #555,
0 0 20px black;
}

// Prettier 2.8
.myclass {
box-shadow: inset 0 0 10px #555, 0 0 20px black;
}

// Prettier 3.0
.myclass {
box-shadow:
inset 0 0 10px #555,
0 0 20px black;
}

修复 URL 包含逗号的情况 (#14476 by @seiyab)

/* Input */
@font-face {
src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
}

/* Prettier 2.8 */
@font-face {
src: url(RobotoFlex-VariableFont_GRADXTRAYOPQYTASYTDEYTFIYTLCYTUCopszslntwdthwght.ttf);
}

/* Prettier 3.0 */
@font-face {
src: url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);
}

SCSS

修复含转义符 \ 的字符串值格式问题 (#13487 by @sosukesuzuki)

/* Input */
$description: "Lorem ipsum dolor sit \"amet\", consectetur adipiscing elit, " +
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

/* Prettier 2.8 */
$description: 'Lorem ipsum dolor sit "amet", consectetur adipiscing elit, '+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

/* Prettier 3.0 */
$description: 'Lorem ipsum dolor sit "amet", consectetur adipiscing elit, ' +
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

Less

修复插值解析错误 (#11343 by @fisker)

// Input
@{selector}-title{ @{prop}-size: @{color} }

// Prettier 2.8
SyntaxError: CssSyntaxError: Unknown word (1:20)
> 1 | @{selector}-title{ @{prop}-size: @{color} }

// Prettier 3.0
@{selector}-title {
@{prop}-size: @{color};
}

保持内联 JavaScript 代码原样 (#14109 by @fisker)

// Input
.calcPxMixin() {
@functions: ~`(function() {
const designWidth = 3840
const actualWidth = 5760
this.calcPx = function(_) {
return _ * actualWidth / designWidth + 'px'
}
})()`;
}

// Prettier 2.8
.calcPxMixin() {
@functions: ~`(
function() {const designWidth = 3840 const actualWidth = 5760 this.calcPx =
function(_) {return _ * actualWidth / designWidth + "px"}}
)
() `;
}

// Prettier 3.0
<Same as input>

HTML

使用小写打印 HTML5 doctype (#7391 by @fisker)

<!-- Input -->
<!DocType html>
<html><head></head><body></body></html>

<!-- Prettier 2.8 -->
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>

<!-- Prettier 3.0 -->
<!doctype html>
<html>
<head></head>
<body></body>
</html>

更新 angular-html-parser (#13578 by @thorn0)

Prettier 的 Angular HTML 解析器分支已与上游同步。

格式化 SVG 内的 <script> 标签 (#14400 by @fisker)

<!-- Input -->
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<script>
document.addEventListener(
'DOMContentLoaded', () => {
const element = document.getElementById('foo')
if (element) {
element.fillStyle = 'currentColor'
}
});
</script>
</svg>

<!-- Prettier 2.8 -->
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<script>
document.addEventListener( 'DOMContentLoaded', () => { const element =
document.getElementById('foo') if (element) { element.fillStyle =
'currentColor' } });
</script>
</svg>

<!-- Prettier 3.0 -->
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<script>
document.addEventListener("DOMContentLoaded", () => {
const element = document.getElementById("foo");
if (element) {
element.fillStyle = "currentColor";
}
});
</script>
</svg>

识别 <search> 元素 (#14615 by @fisker)

HTML 规范新增了 <search> 元素

<!-- Input -->
<SEARCH title="Website">
...
</SEARCH>

<!-- Prettier 2.8 -->
<SEARCH title="Website"> ... </SEARCH>

<!-- Prettier 3.0 -->
<search title="Website">...</search>

Vue

格式化 Vue SFC 根块时忽略 htmlWhitespaceSensitivity 设置 (#14401 by @fisker)

<!-- Input -->
<docs lang=unknown></docs><docs lang=unknown></docs><!-- display: inline --><docs lang=unknown></docs><docs lang=unknown style="display: inline"></docs>

<!-- Prettier 2.8 (--html-whitespace-sensitivity=strict) -->
<docs lang="unknown"></docs>><docs lang="unknown"></docs
><!-- display: inline --><docs lang="unknown"></docs
>><docs lang="unknown" style="display: inline"></docs>

<!-- Prettier 3.0 -->
<docs lang="unknown"></docs>
<docs lang="unknown"></docs>
<!-- display: inline -->
<docs lang="unknown"></docs>
<docs lang="unknown" style="display: inline"></docs>

格式化属性绑定中的 TypeScript 表达式 (#14506 by @seiyab)

<!-- Input -->
<script lang="ts"></script>
<template>
<comp :foo=" (a:string)=>1"/>
</template>

<!-- Prettier 2.8 -->
<script lang="ts"></script>
<template>
<comp :foo=" (a:string)=>1" />
</template>

<!-- Prettier 3.0 -->
<script lang="ts"></script>
<template>
<comp :foo="(a: string) => 1" />
</template>

修复 Vue 过滤器检测逻辑 (#14542 by @fisker)

<!-- Input -->
<template>
<div>
{{
fn(
bitwise | or | operator | a_long_long_long_long_long_long_long_long_long_long_variable
)
| filter1
| filter2
| filter3
| filter4
}}
</div>
</template>

<!-- Prettier 2.8 -->
<template>
<div>
{{
fn(
bitwise
| or
| operator
| a_long_long_long_long_long_long_long_long_long_long_variable
)
| filter1
| filter2
| filter3
| filter4
}}
</div>
</template>

<!-- Prettier 3.0 -->
<template>
<div>
{{
fn(
bitwise |
or |
operator |
a_long_long_long_long_long_long_long_long_long_long_variable,
)
| filter1
| filter2
| filter3
| filter4
}}
</div>
</template>

避免不必要的首部分号 (#14557 by @fisker)

<!-- Input -->
<template>
<div @click="[foo, bar].forEach(fn => void fn())"></div>
</template>

<!-- Prettier 2.8 (With `--no-semi` option) -->
<template>
<div @click=";[foo, bar].forEach((fn) => void fn())"></div>
</template>

<!-- Prettier 3.0 -->
<template>
<div @click="[foo, bar].forEach((fn) => void fn())"></div>
</template>

当任意 script 标签含有 lang="ts" 时格式化 TS 表达式 (#14587 by @seiyab)

<!-- Input -->
<script></script>
<script setup lang="ts"></script>
<template>
{{ (x as number).toFixed(2) }}
</template>

<!-- Prettier 2.8 -->
<script></script>
<script setup lang="ts"></script>
<template>
{{ (x as number).toFixed(2) }}
</template>

<!-- Prettier 3.0 -->
<script></script>
<script setup lang="ts"></script>
<template>
{{ (x as number).toFixed(2) }}
</template>

Angular

@angular/compiler 更新至 v14 (#13609 by @fisker)

<!-- Input -->
<div [input]="{a, b : 2 }"></div>

<!-- Prettier 2.8 -->
Error: Cannot find front char /:/ from index 0 in "{a, b : 2 }"

<!-- Prettier 3.0 -->
<div [input]="{ a, b: 2 }"></div>
<!-- Input -->
<a [href]="http://google.com">Click me</a>

<!-- Prettier 2.8 -->
<a [href]="http: //google.com">Click me</a>

<!-- Prettier 3.0 -->
<a [href]="http://google.com">Click me</a>

修复空值合并运算符的括号问题 (#14216 by @thron0)

<!-- Input -->
<img [src]="(x && y) ?? z" />

<!-- Prettier 2.8 -->
<img [src]="x && y ?? z" />

<!-- Prettier 3.0 -->
<img [src]="(x && y) ?? z" />

支持计算式可选链 (#14658 by @fisker)

<!-- Input -->
<img [src]=" a?.[0]" />

<!-- Prettier 2.8 -->
<img [src]=" a?.[0]" />

<!-- Prettier 3.0 -->
<img [src]="a?.[0]" />

移除管道名称后的空格 (#14961 by @waterplea)

我们在 Prettier 2.8 中引入了新的管道格式,但该方案未被社区采纳。

因此我们根据社区反馈引入了新的格式方案。

详细讨论请参阅 https://github.com/prettier/prettier/issues/13887。

<!-- Input -->
<my-component
[value]="value | transform: arg1 : arg2 | format: arg3 : arg4"
></my-component>

<!-- Prettier 2.8 -->
<my-component
[value]="value | transform : arg1 : arg2 | format : arg3 : arg4"
></my-component>

<!-- Prettier 3.0 -->
<my-component
[value]="value | transform: arg1 : arg2 | format: arg3 : arg4"
></my-component>

Markdown

保留行内代码中的多个空格 (#13590 by @kachkaev@thorn0)

此前行内代码中的多个空白字符会被压缩为单个空格。为遵循 CommonMark 规范,此行为已取消。

<!-- Input -->
` foo bar baz `

<!-- Prettier 2.8 -->
` foo bar baz `

<!-- Prettier 3.0 -->
` foo bar baz `

API

添加 .d.ts 类型声明文件 (#14212 by @sosukesuzuki, @fisker)

新增使用 TypeScript 调用 Prettier JavaScript API 所需的类型声明文件,用户不再需要单独安装 @types/prettier

更新 prettier.util 工具函数 (#14317, #14320 by @fisker)

  • 新增 prettier.util.getNextNonSpaceNonCommentCharacter

  • 变更 prettier.util.getNextNonSpaceNonCommentCharacter 函数签名

    function getNextNonSpaceNonCommentCharacterIndex<N>(
    text: string,
    node: N,
    locEnd: (node: N) => number,
    ): number | false;

    变更为

    function getNextNonSpaceNonCommentCharacterIndex(
    text: string,
    startIndex: number,
    ): number | false;
  • 变更 prettier.util.isPreviousLineEmpty 函数签名

    function isPreviousLineEmpty<N>(
    text: string,
    node: N,
    locStart: (node: N) => number,
    ): boolean;

    变更为

    function isPreviousLineEmpty(text: string, startIndex: number): boolean;
  • 更改了 prettier.util.isNextLineEmpty

    函数签名从

    function isNextLineEmpty<N>(
    text: string,
    node: N,
    locEnd: (node: N) => number,
    ): boolean;

    变更为

    function isNextLineEmpty(text: string, startIndex: number): boolean;
  • 弃用 prettier.util.isNextLineEmptyAfterIndex

    请改用 prettier.util.isNextLineEmpty

详见文档说明

修复插件加载缓存问题 (#14576 by @fisker)

插件实例存在错误的缓存机制,具体细节请参阅此问题报告

停止使用 babel 解析器格式化未知代码 (#14718 by @fisker)

await prettier.format("foo")

// Prettier 2.8
No parser and no filepath given, using 'babel' the parser now but this will throw an error in the future. Please specify a parser or a filepath so one can be inferred.
'foo;\n'

// Prettier 3.0
UndefinedParserError: No parser and no file path given, couldn't infer a parser.

CLI

优化失败提示信息使其更明确 (#11369 by @webark)

将"忘记运行 Prettier了?"提示更新为"请运行 Prettier 并添加 --write 参数进行修复"。

这保留了原提示的核心意图,但减少了歧义风险。新提示采用更正式的表述方式,避免了过于口语化的表达。

--loglevel 参数更名为 --log-level (#13204 by @sosukesuzuki)

# Prettier 2.8
prettier test.js --loglevel=debug

# Prettier 3.0
prettier test.js --log-level=debug

支持多个 --ignore-path 参数 (#14332 by @fisker)

现在可同时传递多个 --ignore-path 参数。

prettier . --ignore-path=.prettier-ignore --ignore-path=.eslintignore

在 Windows 系统显示 POSIX 风格路径 (#14333 by @fisker)

与 ESLint 和 Stylelint 等工具保持统一标准。

// Prettier 2.8
Checking formatting...
[warn] src\utilities\create-get-visitor-keys.js
[warn] src\utilities\unexpected-node-error.js
[warn] Code style issues found in 2 files. Forgot to run Prettier?

// Prettier 3.0
Checking formatting...
[warn] src/utilities/create-get-visitor-keys.js
[warn] src/utilities/unexpected-node-error.js
[warn] Code style issues found in 2 files. Forgot to run Prettier?

禁止通过符号链接展开 glob 模式 (#14627 by @andersk)

Prettier 在展开命令行参数时将不再追踪符号链接。这有效避免了多种场景下的问题,包括: 指向源码树外的符号链接、指向忽略文件的符号链接以及符号链接循环引用等。

错误文件路径后添加换行符 (#14788 by @sosukesuzuki)

此前仅 --write 选项会在错误信息前输出换行符,现在所有选项(包括无参数调用)均会执行此操作。

# Input
prettier ./test.js

# Prettier 2.8
test.js[error] test.js: SyntaxError: Unexpected token: ')' (1:6)
[error] > 1 | 1 (+-) hoge
[error] | ^

# Prettier 3.0
test.js
[error] test.js: SyntaxError: Unexpected token: ')' (1:6)
[error] > 1 | 1 (+-) hoge
[error] |

打印忽略文件代码前清除文件名 (#14794 by @fisker)

# Input
echo test.js > .prettierignore
echo code > test.js
prettier ./test.js

# Prettier 2.8
test.jscode

# Prettier 3.0
code