メインコンテンツへスキップ

Prettier 2.3: 代入の一貫性、短いキーの改行防止、そしてHandlebarsの正式サポート

· 1分で読める
非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

今回のリリースでは、JavaScriptプリンターの長年懸案だった問題の修正に焦点を当てています。注意点として、残念ながら新バージョンでプロジェクトを再フォーマットすると大幅な差分が発生する可能性があります。このような一括変更をgit blameから隠すためにignoreRevsFileを利用していない場合、そろそろ導入を検討する時期かもしれません。

特筆すべきマイルストーンとして、待望のEmber/Handlebarsフォーマッターが正式リリースされました。これはコアライブラリに直接組み込まれる最後のフォーマッターとなる予定です。将来的には持続可能性の観点から、言語サポートはプラグイン経由でのみ追加されるべきと考えています。

資金面でご支援いただいた皆様に深く感謝します: Salesforce, Indeed, Frontend Masters, Airbnb, Shogun Labs, Skyscanner, Konstantin Pschera、そして活動継続を支えてくださるその他多くの支援者。Prettierをご利用いただきプロジェクトを支援されたい場合は、OpenCollectiveをご覧ください。またtypescript-eslintremarkBabelなど、Prettierが依存するプロジェクトの支援もぜひご検討ください。

本リリースの変更の多くは、Fisker CheungGeorgii DolzhykovSosuke Suzukiの皆様をはじめ、多数の貢献者の尽力によるものです。

念のためご注意を:Prettierをインストールまたは更新する際は、package.json"2.3.0"のように厳密なバージョン指定を強く推奨します"^2.3.0"のような記述は避けてください。

主な変更点

JavaScript

代入式のフォーマットを一貫性を持たせる (#10222, #10643, #10672 by @thorn0; #10158 by @sosukesuzuki)

これまでPrettierは代入式の行分割処理に課題を抱えていました。例えば長い右辺が分割されないままになるケースが多々ありましたが、この問題は解消されました。

// Prettier 2.2
aParticularlyLongAndObnoxiousNameForIllustrativePurposes = anotherVeryLongNameForIllustrativePurposes;

aParticularlyLongAndObnoxiousNameForIllustrativePurposes = "a very long string for illustrative purposes"
.length;

someReallyLongThingStoredInAMapWithAReallyBigName[
pageletID
] = _someVariableThatWeAreCheckingForFalsiness
? Date.now() - _someVariableThatWeAreCheckingForFalsiness
: 0;

class x {
private readonly rawConfigFromFile$: BehaviorSubject<any> = new BehaviorSubject(
notRead
);
}

// Prettier 2.3
aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
anotherVeryLongNameForIllustrativePurposes;

aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
"a very long string for illustrative purposes".length;

someReallyLongThingStoredInAMapWithAReallyBigName[pageletID] =
_someVariableThatWeAreCheckingForFalsiness
? Date.now() - _someVariableThatWeAreCheckingForFalsiness
: 0;

class x {
private readonly rawConfigFromFile$: BehaviorSubject<any> =
new BehaviorSubject(notRead);
}

短いキーを持つオブジェクトプロパティの折り返しを防止 (#10335 by @thorn0)

オブジェクトリテラル内で短いプロパティ名の直後に改行を入れると不自然に見えることが多々あります。たとえ行長が1~2文字短くなる場合でも、その見た目の改善効果は限定的です。Prettier 2.3ではプロパティ名の長さがtabWidth + 3未満の場合(デフォルト設定なら5文字、tabWidth: 4なら7文字)、改行を回避します。このヒューリスティックは将来のバージョンで見直される可能性があります。

// Prettier 2.2
const importantLink = {
url:
"https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about",
gitHubUrl:
"https://github.com/prettier/prettier/blob/main/docs/rationale.md#what-prettier-is-concerned-about",
};

// Prettier 2.3
const importantLink = {
url: "https://prettier.io/docs/en/rationale.html#what-prettier-is-concerned-about",
gitHubUrl:
"https://github.com/prettier/prettier/blob/main/docs/rationale.md#what-prettier-is-concerned-about",
};

Ember / Handlebars

Handlebarsサポートをアルファ版から正式リリースへ移行 (#10290 by @dcyriller & @thorn0)

この取り組みは2017年に始まりました。HandlebarsのサポートはPrettierにしばらく前からありましたが、実際に準備が整っていなかったため公式リリースされていませんでした。そのステータスは「アルファ」から「実験的」、「ベータ」へと移行し、古いリリースノートを確認すると「ベータ」の後になぜか再び「アルファ」に戻っていた経緯があります...

ともあれ、ついに実現しました:PrettierがHandlebarsを使用したHTMLテンプレートを公式にフォーマットできるようになりました! 🎉

EmberのHandlebarsパーサーであるGlimmerを採用しているため、EmberチームのおかげでHTML仕様に準拠しています。

--html-whitespace-sensitivityオプションがサポートされ、デフォルト値はstrictです。これはPrettierがタグ周囲の空白の有無を常に尊重し、空白がない場所に空白を追加したり、その逆を行ったりすることを安全でないと見なすことを意味します(これらはブラウザでのレンダリングに影響する可能性があるため)。現時点ではcss値はサポートされておらず(現在はstrictとして扱われます)、将来のバージョンで対応される予定です。

この機能が「Handlebars」ではなく「Ember / Handlebars」と呼ばれるのは、GlimmerがHandlebarsの一部の構文とユースケースをサポートしていないためです。主な理由として、Handlebarsはテンプレートエンジン(プリプロセッサ)であるため処理対象の基盤構文を気にしませんが、GlimmerはHTMLとHandlebarsという2つの構文を同時に解析し、結果を単一のツリーに結合する点が異なります(Prettierはこのツリーを出力できます)。つまり、基盤構文がHTMLでない場合や、テンプレートディレクティブとタグがツリー表現不可能な形で重複している場合(例: {{#if foo}}<div>{{/if})はフォーマットできません。こうした制限があるものの、非Emberユーザーにも十分有用です。Emberで未サポートの構文については、Glimmerが本格的なHandlebarsパーサーを採用しているため、将来のPrettierバージョンでの対応が期待されます。

デフォルトでは.hbsおよび.handlebars拡張子のファイルがHandlebarsとして認識されます。他の拡張子の場合、値glimmerを指定した--parserオプションが必要です(コマンドラインで指定するか、より良い方法として[設定の上書き]を使用してください)。

実際の動作をプレイグラウンドで確認してください!

フォーマットの改善

JavaScript

カリー化されたアロー関数のフォーマットを改良 (#9992, #10543 by @sosukesuzuki & @thorn0)

// Prettier 2.2
const currying = (argument1) => (argument2) => (argument3) => (argument4) => (
argument5
) => (argument6) => foo;

// Prettier 2.3
const currying =
(argument1) =>
(argument2) =>
(argument3) =>
(argument4) =>
(argument5) =>
(argument6) =>
foo;

React Hooks呼び出しのフォーマットを改善 (#10238 by @sosukesuzuki)

// Prettier 2.2
const { firstName, lastName } = useMemo(() => parseFullName(fullName), [
fullName,
]);

// Prettier 2.3
const { firstName, lastName } = useMemo(
() => parseFullName(fullName),
[fullName]
);

複数行ヘッダーのクラスにおけるヘッダーとボディの視覚的分離を改善 (#10085 by @sosukesuzuki)

// Prettier 2.2
class loooooooooooooooooooong
extends looooooooooooooooooong
implements loooooooooooooooooooong {
property: string;
}

// Prettier 2.3
class loooooooooooooooooooong
extends looooooooooooooooooong
implements loooooooooooooooooooong
{
property: string;
}

数値のみの配列を簡潔にフォーマット (#10106, #10160 by @thorn0)

一般的にPrettierは差分表示に適さないためこの種のフォーマットを避けていますが、この特殊なケースでは利点がリスクを上回ると判断しました。

少なくとも1つの要素に同じ行に末尾の単一行コメント(// ...)がある場合、簡潔なフォーマットは適用されません。一方、別々の行に配置された単一行コメントはこのような影響を持たず、空行と同様に論理的なグループ分けに使用できます。

// Input
const lazyCatererNumbers = [1, 2, 4, 7, 11, 16, 22, 29, 37, 46,

// n > 10
56, 67, 79, 92, 106, 121, 137, 154, 172, 191, 211, 232, 254, 277, 301, 326, 352, 379, 407, 436, 466,
497, 529, 562, 596, 631, 667, 704, 742, 781,
// n > 40
821, 862, 904, 947, 991, 1036, 1082, 1129, 1177, 1226, 1276, 1327, 1379];

// Prettier 2.2
const lazyCatererNumbers = [
1,
2,
4,
7,
11,
16,
22,
29,
37,
// ... ✂ 46 lines ✂ ...
1379,
];

// Prettier 2.3
const lazyCatererNumbers = [
1, 2, 4, 7, 11, 16, 22, 29, 37, 46,

// n > 10
56, 67, 79, 92, 106, 121, 137, 154, 172, 191, 211, 232, 254, 277, 301, 326,
352, 379, 407, 436, 466, 497, 529, 562, 596, 631, 667, 704, 742, 781,
// n > 40
821, 862, 904, 947, 991, 1036, 1082, 1129, 1177, 1226, 1276, 1327, 1379,
];

メンバー式と呼び出し式の先頭におけるネストされたawait式のフォーマットを改善 (#10342 by @thorn0)

Prettierはここで役立とうとしますが、このようなコードは書かないでください。チームメイトへの配慮として中間変数を使用しましょう。

// Input
const getAccountCount = async () =>
(await
(await (
await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)
).findItem("My bookmarks")).getChildren()
).length

// Prettier 2.2
const getAccountCount = async () =>
(
await (
await (await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)).findItem(
"My bookmarks"
)
).getChildren()
).length;

// Prettier 2.3
const getAccountCount = async () =>
(
await (
await (
await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME)
).findItem("My bookmarks")
).getChildren()
).length;

関数呼び出しにおけるdo式のフォーマットを改善 (#10693 by @sosukesuzuki)

do式」はステージ1のECMAScript提案です。

// Prettier 2.2
expect(
do {
var bar = "foo";
bar;
}
).toBe("foo");

// Prettier 2.3
expect(do {
var bar = "foo";
bar;
}).toBe("foo");

条件演算子の一貫したインデント (#10187, #10266 by @sosukesuzuki)

// Prettier 2.2
const dotNotationMemberExpression = (callNode.parent?.type ===
AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent
).TSESTree.BinaryExpression;

const computedMemberExpression = (callNode.parent?.type ===
AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent)[TSESTree.BinaryExpression];

const callExpressionCallee = (callNode.parent?.type ===
AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent)(TSESTree.BinaryExpression);

const typeScriptAsExpression = (callNode.parent?.type ===
AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent) as TSESTree.BinaryExpression;

// Prettier 2.3
const dotNotationMemberExpression = (
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent
).TSESTree.BinaryExpression;

const computedMemberExpression = (
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent
)[TSESTree.BinaryExpression];

const callExpressionCallee = (
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent
)(TSESTree.BinaryExpression);

const typeScriptAsExpression = (
callNode.parent?.type === AST_NODE_TYPES.ChainExpression
? callNode.parent.parent
: callNode.parent
) as TSESTree.BinaryExpression;

HTML

class属性のプレフィックスベースの複数行フォーマット (#7865 by @thorn0)

HTMLのclass名のフォーマットでは、行長制限に達するまではクラスを1行に保持し、それ以降は同じプレフィックスを持つ連続するクラスをグループ化して各行に配置します。BootstrapやTailwind CSSなどのレイアウトフレームワークでは、要素に多数のクラスを追加するため、従来の動作(すべてのクラスを1行に保持)や各行に1クラスずつ配置する方法に比べて、可読性と保守性の面で重要です。

<!-- Prettier 2.2 -->
<div
class="SomeComponent__heading-row d-flex flex-column flex-lg-row justify-content-start justify-content-lg-between align-items-start align-items-lg-center"
></div>

<!-- Prettier 2.3 -->
<div
class="
SomeComponent__heading-row
d-flex
flex-column flex-lg-row
justify-content-start justify-content-lg-between
align-items-start align-items-lg-center
"
></div>

その他の変更

JavaScript

同一行上の複数コメントの不安定なフォーマットを修正 (#9672 by @fisker)

// Input
a;
/*1*//*2*/
/*3*/
b;

// Prettier 2.2
a; /*2*/
/*1*/ /*3*/
b;

// Prettier 2.2 (second format)
a; /*2*/ /*3*/
/*1*/ b;

// Prettier 2.3
a;
/*1*/ /*2*/
/*3*/
b;

rangeStart直前に終了するノードをフォーマットしない (#9704 by @fisker)

以前は範囲指定フォーマット時にこのようなノードが範囲の一部と見なされていましたが、現在は除外されます。この変更はJavaScriptだけでなく、範囲指定機能がサポートする他の言語にも影響します。

// Input
foo = 1.0000;bar = 1.0000;baz=1.0000;
^^^^^^^^^^^^^ Range

// Prettier 2.2
foo = 1.0;
bar = 1.0;baz=1.0000;

// Prettier 2.3
foo = 1.0000;bar = 1.0;baz=1.0000;

JSX終了タグ内のコメントを修正 (#9711 by @fisker)

// Input
<a><// comment
/a>;

// Prettier 2.2
<a></// comment
a>;

// Prettier 2.3
<a></
// comment
a
>;

言語コメント検出の不整合を修正 (#9743 by @fisker)

/* HTML */コメントは、後続のテンプレートリテラルがHTML-in-JSとして認識されるために直接前にある必要があります。以前は、このコメントが他の場所で誤って認識されることがありました。

// Input
foo /* HTML */ = `<DIV>
</DIV>`;

// Prettier 2.2 (--parser=babel)
foo /* HTML */ = `<div></div>`;

// Prettier 2.2 (--parser=meriyah)
foo /* HTML */ = `<DIV>
</DIV>`;

// Prettier 2.3 (All JavaScript parsers)
foo /* HTML */ = `<DIV>
</DIV>`;

無視されたディレクティブに余分なセミコロンが追加される問題を修正 (#9850 by @fisker)

// Input
// prettier-ignore
'use strict';

function foo() {
// prettier-ignore
"use strict";;
}

// Prettier 2.2
// prettier-ignore
'use strict';;

function foo() {
// prettier-ignore
"use strict";;
}

// Prettier 2.3
// prettier-ignore
'use strict';

function foo() {
// prettier-ignore
"use strict";
}

U+3000を含むJSXフォーマットの不安定さを修正 (#9866 by @fisker)

// Input
<p>
<span /> {this.props.data.title} <span />
//----- ^ U+3000 --------------- ^ U+3000
</p>

// Prettier 2.2
<p>
<span />
 {this.props.data.title} <span />
//----- ^ U+3000 --------------- ^ U+3000
</p>;

// Prettier 2.2 (second format)
<p>
<span /> {this.props.data.title} <span />
//----- ^ U+3000 --------------- ^ U+3000
</p>;

// Prettier 2.3
<p>
<span /> {this.props.data.title} <span />
//----- ^ U+3000 --------------- ^ U+3000
</p>;

a(b => c => function (){})のような式で発生するエラーを修正 (#10278 by @thorn0)

v2.2.0からの回帰バグです。

// Input
a(b => c => function (){})

// Prettier 2.2
TypeError: Cannot read property 'length' of undefined

// Prettier 2.3
a((b) => (c) => function () {});

インラインデコレータのフォーマットを改善 (#10296 by @fisker)

// Input
class Foo {
@decorator([]) bar() {}
@decorator(
[]
) baz() {}
}

// Prettier 2.2
class Foo {
@decorator([]) bar() {}
@decorator([])
baz() {}
}

// Prettier 2.3
class Foo {
@decorator([]) bar() {}
@decorator([]) baz() {}
}

プライベートフィールドのASI保護を修正 (#10334 by @thorn0)

// Input
class C {
#field = 'value';
["method"]() {}
}

// Prettier 2.2 (with --no-semi)
class C {
#field = "value"
["method"]() {}
}

// Prettier 2.3 (with --no-semi)
class C {
#field = "value";
["method"]() {}
}

Module Blocks提案をサポート (#10417 by @sosukesuzuki, @thorn0)

Module Blocks Stage 2提案のフォーマットをサポートします。

// Input
module { export let foo = "foo"; };

// Prettier 2.2
SyntaxError: Unexpected token, expected ";"

// Prettier 2.3
module {
export let foo = "foo";
};

パイプライン内のyieldに対する括弧の欠落を修正 (#10446 by @fisker)

// Input
function* f() {
return x |> (yield #);
}

// Prettier 2.2
function* f() {
return x |> yield #;
}

// Prettier 2.3
function* f() {
return x |> (yield #);
}

Babelのエラー回復処理をより選択的に改善 (#10495 by @fisker, #9787 by @sosukesuzuki, #10065, #10322 by @thorn0)

以前はエラー回復機能のため、Babelパーサーが過度に寛容であり、Prettierが出力できない様々なAST構造が生成されていました。Prettier 2.3では、Babelのエラー回復を無害なタイプのエラー(例えば同一名の複数const宣言)のみに限定しています。それ以外のエラーは構文エラーとして報告されます。

// Input
foo("a", , "b");

// Prettier 2.2
TypeError: Cannot read property 'type' of null

// Prettier 2.3
[error] stdin: SyntaxError: Argument expression expected. (1:10)
[error] > 1 | foo("a", , "b");
[error] | ^
// Input
const \u{20} = 1

// Prettier 2.2
const = 1;

// Prettier 2.3
[error] stdin: SyntaxError: Invalid Unicode escape (1:7)
[error] > 1 | const \u{20} = 1
[error] | ^ ^

数値のみの配列における最後の引数の密着を回避 (#10517 by @thorn0)

数値のみの配列に対する特別なケース処理を追加しました。

// Input
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [1, 1, 0.3, 1]),
]);

// Prettier 2.2
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [
1,
1,
0.3,
1,
]),
]);

// Prettier 2.3
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(
game.MaterialDiffuse,
game.Meshes["monkey_flat"],
[1, 1, 0.3, 1]
),
]);

AMD defineの検出精度を向上 (#10528 by @thorn0)

PrettierはAMD define呼び出しを特別扱いし、予期しない改行を防いでいます。今回の変更で、関数またはプログラムの最上位レベルに存在し、AMDが期待する形式で引数が渡されている場合のみdefine呼び出しをフォーマットするようになりました。

// Prettier 2.2
const someVariable = define("some string literal", anotherVariable, yetAnotherVariable);

// Prettier 2.3
const someVariable = define(
"some string literal",
anotherVariable,
yetAnotherVariable
);

prettier-ignoreコメントの重複を修正 (#10666 by @fisker)

// Input
foo = a.
// prettier-ignore
b;

// Prettier 2.2
foo =
// prettier-ignore
a.
// prettier-ignore
b;

// Prettier 2.3
foo = a.
// prettier-ignore
b;

mapDoc内での条件付きグループの処理を改善 (#10695 by @thorn0)

この修正により、特にJS内HTMLでの置換処理の不具合が解消されます。

// Input
export default function include_photoswipe(
gallery_selector = ".my-gallery"
): string {
return /* HTML */ `
<script>
window.addEventListener("load", () =>
initPhotoSwipeFromDOM("${gallery_selector}")
);
</script>`;
}

// Prettier 2.2
export default function include_photoswipe(
gallery_selector = ".my-gallery"
): string {
return /* HTML */ ` <script>
window.addEventListener("load", () =>
initPhotoSwipeFromDOM("PRETTIER_HTML_PLACEHOLDER_0_13_IN_JS")
);
</script>`;
}

// Prettier 2.3
export default function include_photoswipe(
gallery_selector = ".my-gallery"
): string {
return /* HTML */ ` <script>
window.addEventListener("load", () =>
initPhotoSwipeFromDOM("${gallery_selector}")
);
</script>`;
}

コード破損を招く引数展開を回避 (#10712 by @thorn0)

// Input
glimseGlyphsHazardNoopsTieTie(({ a, b = () => {
console.log();
}}) => averredBathersBoxroomBuggyNurl());

// Prettier 2.2
glimseGlyphsHazardNoopsTieTie(({ a, b = () => {
console.log();
} }) => averredBathersBoxroomBuggyNurl());

// Prettier 2.3
glimseGlyphsHazardNoopsTieTie(
({
a,
b = () => {
console.log();
},
}) => averredBathersBoxroomBuggyNurl()
);

for-of内のasync周囲の括弧欠落を修正 (#10781 by @fisker)

参考: https://github.com/tc39/ecma262/issues/2034

// Input
for ((async) of []);

// Prettier 2.2
for (async of []);

// Prettier 2.2 (second format)
SyntaxError: Unexpected token, expected "=>" (1:15)
> 1 | for (async of []);

// Prettier 2.3
for ((async) of []);

async do式プロポーザルをサポート (#10813 by @sosukesuzuki)

参考: https://github.com/tc39/proposal-async-do-expressions

// Input
const x = async do {
await requestAPI().json();
};

// Prettier 2.2
SyntaxError: Unexpected token, expected ";" (1:17)

// Prettier 2.3
const x = async do {
await requestAPI().json();
};

TypeScript

MethodDefinition内コメントの欠落を修正 (#9872 by @fisker)

typescriptパーサー専用の修正です(babel-tsではこの問題は発生しません)。

// Input
class Foo {
bar() /* bat */;
}

// Prettier 2.2
Error: Comment "bat" was not printed. Please report this error!

// Prettier 2.3
class Foo {
bar /* bat */();
}

メソッド型宣言パラメータにおける不要な改行を修正 (#10024 by @sosukesuzuki, #10357 by @thorn0)

// Input
type Foo = {
method(foo: "foo"): `
`
};

// Prettier 2.2
type Foo = {
method(
foo: "foo"
): `
`;
};

// Prettier 2.3
type Foo = {
method(foo: "foo"): `
`;
};

型パラメータで末尾のカンマを出力する (#10109 by @sosukesuzuki, #10353 by @thorn0)

TypeScript は 2018 年 1 月リリースの TypeScript 2.7 以降、型パラメータでの末尾のカンマをサポートしています。Prettier 2.3 では trailingComma オプションが all に設定されている場合、これらを出力します。TypeScript 2.7 以前との互換性が必要な場合は、より保守的なデフォルト値 es5 を維持してください。なお、TypeScript は依然として型引数(型パラメータのインスタンス化)での末尾のカンマをサポートしていないことに注意してください。

// Input
export class BaseSingleLevelProfileTargeting<
T extends ValidSingleLevelProfileNode,
> {
// ...
}

// Prettier 2.2
export class BaseSingleLevelProfileTargeting<
T extends ValidSingleLevelProfileNode
> {
// ...
}

// Prettier 2.3 with --trailling-comma=all
export class BaseSingleLevelProfileTargeting<
T extends ValidSingleLevelProfileNode,
> {
// ...
}

戻り値の型注釈を持つ非簡潔アロー関数の引数で密着配置を許可 (#10316 by @thorn0)

// Prettier 2.2
users.map(
(user: User): User => {
return user;
}
);

// Prettier 2.3
users.map((user: User): User => {
return user;
})

非nullアサーションの括弧を修正 (#10337 by @thorn0)

非nullアサーションを含む式で必要な括弧が出力されない場合がありました。これが修正されました。

// Input
const myFunction2 = (key: string): number =>
({
a: 42,
b: 42,
}[key]!)

// Prettier 2.2 (invalid syntax)
const myFunction2 = (key: string): number =>
{
a: 42,
b: 42,
}[key]!;

// Prettier 2.3
const myFunction2 = (key: string): number =>
({
a: 42,
b: 42,
}[key]!);

メンバー式と呼び出し式の先頭にある型アサーションをインデント (#10341 by @thorn0)

// Input
const accountCount = (findItemInSection(BOOKMARKED_PROJECTS_SECTION_NAME,
"My bookmarks") as TreeItem).getChildren().length;

// Prettier 2.2
const accountCount = (findItemInSection(
BOOKMARKED_PROJECTS_SECTION_NAME,
"My bookmarks"
) as TreeItem).getChildren().length;

// Prettier 2.3
const accountCount = (
findItemInSection(
BOOKMARKED_PROJECTS_SECTION_NAME,
"My bookmarks"
) as TreeItem
).getChildren().length;

intrinsic キーワードをサポート (#10390 by @sosukesuzuki)

// Input
type Uppercase<S extends string> = intrinsic;

// Prettier 2.2
Error: unknown type: "TSIntrinsicKeyword"

// Prettier 2.3
type Uppercase<S extends string> = intrinsic;

TypeScript 4.2 をサポート (#10418, #10466, #10546, #10589 by @sosukesuzuki)

abstract コンストラクトシグネチャ
// Input
type T = abstract new () => void;

// Prettier 2.2
SyntaxError: Unexpected token, expected ";" (1:19)

// Prettier 2.3
type T = abstract new () => void;

import require 宣言での型インポート
// Input
import type A = require("A");

// Prettier 2.2
SyntaxError: Only ECMAScript imports may use 'import type'.

// Prettier 2.3
import type A = require("A");

共用型と交差型でのコメントの位置を修正 (#10457 by @thorn0)

// Input
type Foo = "1" | "2" /* two */ | "3";

// Prettier 2.2
type Foo = "1" | "2" | /* two */ "3";

// Prettier 2.3
type Foo = "1" | "2" /* two */ | "3";

ネストした型アサーションの周囲に括弧を出力しない (#10702 by @thorn0)

// Input
foo as unknown as Bar

// Prettier 2.2
(foo as unknown) as Bar;

// Prettier 2.3
foo as unknown as Bar;

babel-ts 経由で TypeScript 4.3 をサポート (#10811 by @sosukesuzuki)

クラス要素の override 修飾子
class Foo extends  {
override method() {}
}
クラス内の静的インデックスシグネチャ ([key: KeyType]: ValueType)
class Foo {
static [key: string]: Bar;
}
型宣言での get / set
interface Foo {
set foo(value);
get foo(): string;
}

Flow

declare export * from … でセミコロンが欠落する問題を修正 (#9767 by @fisker)

// Input
declare export * from "ES6_ExportAllFrom_Source2";

// Prettier 2.2
declare export * from "ES6_ExportAllFrom_Source2"

// Prettier 2.3
declare export * from "ES6_ExportAllFrom_Source2";

babel-flow パーサー経由での関数内 this 型アノテーションをサポート (#10397 by @sosukesuzuki)

this 型アノテーションは Babel 7.13 でサポートされました。

// Input
var foo: (this: boolean) => void;

// Prettier 2.2
SyntaxError: Unexpected token, expected ")" (1:15)

// Prettier 2.3
var foo: (this: boolean) => void;

範囲指定フォーマットの問題を修正 (#10505 by @thorn0)

関数宣言内の特定の範囲をフォーマットする際に問題が発生し、SyntaxError がスローされていました。Prettier 2.3 ではこれらのケースをエラーなくフォーマットします。問題のある範囲の例を以下に示します:

declare export function graphql<Props, Variables, Component: React$ComponentType<Props>>
// ^^^^^ range 1
(query: GQLDocument, config?: Config<Props, QueryConfigOptions<Variables>>):
(Component: Component) => React$ComponentType<$Diff<React$ElementConfig<Component>, {
data: Object|void,
// ^^^^ range 2
mutate: Function|void
}>>

Flow のインデックスアクセスタイプをサポート (#10594 by @gkz)

// Input
const x: Obj['foo'] = 1;

// Prettier 2.2
// Error: unsupported node type "IndexedAccessType"

// Prettier 2.3
const x: Obj["foo"] = 1;

Flow のオプショナルインデックスアクセスタイプをサポート (#10788 by @gkz)

// Input
type T = Obj?.['foo'];

// Prettier 2.2
// Error: unsupported node type "OptionalIndexedAccessType"

// Prettier 2.3
type T = Obj?.['foo'];

JSON

--quote-props=preserve 時に JSON5 でスマートクォートを使用しない (#10323 by @thorn0)

quoteProps オプションが preserve に設定され、singleQuotesfalse(デフォルト)の場合、文字列の出力には常に二重引用符が使用されます(例: "bla\"bla")。これにより --parser json5 を「コメントと末尾カンマ付きJSON」として使用できるようになります。

// Input
{
"char": "\"",
}

// Prettier 2.2
{
"char": '"',
}

// Prettier 2.3
{
"char": "\"",
}

JSON パーサーの厳格化 (#10346, #10443, #10456, #10434 by @fisker)

Prettier は内部で JSON をパースするために JavaScript 式パーサーを使用していました。そのため jsonjson5 パーサーは非常に寛容で、あらゆる種類の JavaScript 式を許可していました。現在ではより厳格になりましたが、一部の単純な非標準構文は依然として許可されています(例: 複数のマイナス記号 ----123 を除く JSON6 がサポートされています)。

// Input
[1, 2, 1 + 2]

// Prettier 2.2
[1, 2, 1 + 2]

// Prettier 2.3
SyntaxError: BinaryExpression is not allowed in JSON. (1:8)
> 1 | [1, 2, 1 + 2]
| ^

エラーメッセージの改善 (#10433 by @fisker)

// Input
{key: "foo" + "bar"}

// Prettier 2.2 (--parser=json-stringify)
SyntaxError: BinaryExpression is not allowed in JSON. (1:7)
> 1 | {key: "foo" + "bar"}
| ^

// Prettier 2.3
SyntaxError: BinaryExpression is not allowed in JSON. (1:7)
> 1 | {key: "foo" + "bar"}
| ^^^^^^^^^^^^^

JSON の範囲指定フォーマットでの構文エラーを修正 (#10497 by @fisker)

// Input
[{ a: 1.0000}, {"b": 2.0000 }]
// ^^^^^^^^^^^ range

// Prettier 2.2
SyntaxError: Unexpected token (1:4)
> 1 | "b": 2.0000
| ^

// Prettier 2.3
[{ a: 1.0000}, { "b": 2.0 }]

CSS

カスタム CSS の -custom-url() 呼び出しにおける絶対パスの問題を修正 (#9966 by @vjeux)

CSS パーサーは url() 呼び出し内でない限り、["division", "absolute/path"] として解析し、単一の "/absolute/path" トークンとして扱いません。除算記号の後にスペースを挿入するため、不正なパスが生成されていました。修正策として、呼び出しの最初のトークンが除算である場合にスペースを出力しないようにしました。

/* Input */
-custom-url(/absolute/path)

/* Prettier 2.2 */
-custom-url(/ absolute/path)

/* Prettier 2.3 */
-custom-url(/absolute/path)

@keyframes のパラメータが Less 変数としてパースされないように除外 (#10773 by @tmazeika)

/* Input */
@keyframes :global(spin) {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

/* Prettier 2.2 */
@keyframes: global(spin){
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
};

/* Prettier 2.3 */
@keyframes :global(spin) {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

SCSS

括弧内のコメントが壊れる問題を修正 (#9710 by @fisker)

// Input
.simplification {
foo: (
calc() // not a comment anymore
);
}

// Prettier 2.2
.simplification {
foo: (calc() // not a comment anymore);
}

// Prettier 2.3
.simplification {
foo: (
calc() // not a comment anymore
);
}

キーがリストまたはマップであるマップの修正 (#10005 by @fisker)

// Input
$map: (
('my list'): 'hello world',
);

// Prettier 2.2
TypeError: Cannot read property 'length' of undefined

// Prettier 2.3
$map: (
("my list"): "hello world",
);

Ember / Handlebars

チルダコメントを保持 (#9082 by @kangax, @fisker)

{{!-- Input --}}
{{~! Comment }}
{{! Comment ~}}
{{~! Comment ~}}

{{!-- Prettier 2.2 --}}
{{! Comment }}
{{! Comment }}
{{! Comment }}

{{!-- Prettier 2.3 --}}
{{~! Comment }}
{{! Comment ~}}
{{~! Comment ~}}

空白を考慮するモードを追加 (#9885 by @dcyriller)

--html-whitespace-sensitivity strict
{{!-- Input --}}
<span>123 {{mustache}}</span>
<span>
123 {{mustache}}</span>
<span>123 {{mustache}}
</span>
<span>
123 {{mustache}}
</span>

{{!-- Prettier 2.2 --}}
<span>
123 {{mustache}}
</span>
<span>
123 {{mustache}}
</span>
<span>
123 {{mustache}}
</span>
<span>
123 {{mustache}}
</span>

{{!-- Prettier 2.3 --}}
<span>123 {{mustache}}</span>
<span>
123
{{mustache}}</span>
<span>123
{{mustache}}
</span>
<span>
123
{{mustache}}
</span>

最終的な blockParam を独自の行に出力 (#9978 by @dcyriller)

{{!-- Input --}}
<MyComponent @prop={{true}} @prop2={{true}} @prop3={{true}} @prop4={{true}} as |thing|></MyComponent>
{{#block param hashKey=hashValue hashKey=hashValue hashKey=hashValue as |blockParam|}}
Hello
{{/block}}

{{!-- Prettier 2.2 --}}
<MyComponent
@prop={{true}}
@prop2={{true}}
@prop3={{true}}
@prop4={{true}} as |thing|
/>
{{#block
param
hashKey=hashValue
hashKey=hashValue
hashKey=hashValue as |blockParam|
}}
Hello
{{/block}}

{{!-- Prettier 2.3 --}}
<MyComponent
@prop={{true}}
@prop2={{true}}
@prop3={{true}}
@prop4={{true}}
as |thing|
/>
{{#block
param
hashKey=hashValue
hashKey=hashValue
hashKey=hashValue
as |blockParam|
}}
Hello
{{/block}}

属性のフォーマットを修正 (#10145 by @thorn0)

  • 属性とテキスト内の {{ のエスケープを修正

  • 補間を含む属性での '" の選択を修正

  • class 属性に [object Object] が出力されるバグを修正

  • class 属性のシンプルなフォーマットを実装(v2.3.0 以前の Prettier が HTML でフォーマットしていたのと同様)

{{!-- Input --}}
<div class="
foo"></div>
<div bar='"{{expr}}"'></div>
<div baz="\{{ non-expression }}"></div>

{{!-- Prettier 2.2 --}}
<div class="[object Object],foo"></div>
<div bar=""{{expr}}""></div>
<div baz="{{ non-expression }}"></div>

{{!-- Prettier 2.3 --}}
<div class="foo"></div>
<div bar='"{{expr}}"'></div>
<div baz="\{{ non-expression }}"></div>

テキストコンテンツを複数行に分割 (#10179 by @dcyriller)

{{!-- Input --}}
<div>
A long enough string to trigger a line break that would prevent wrapping more and more.
</div>

{{!-- Prettier 2.2 --}}
<div>
A long enough string to trigger a line break that would prevent wrapping more and more.
</div>

{{!-- Prettier 2.3 --}}
<div>
A long enough string to trigger a line break that would prevent wrapping more
and more.
</div>

数値文字参照を保持 (#10550 by @rwjblue and @thorn0)

{{! Input }}
<span class="stampFont" style="font-family: 'stampfont'">&#xf000;</span>

{{! Prettier 2.2 }}
<span class="stampFont" style="font-family: 'stampfont'"></span>

{{! Prettier 2.3 }}
<span class="stampFont" style="font-family: 'stampfont'">&#xf000;</span>

開始波括弧とパスを改行しない (#10586 by @dcyriller)

{{!-- Input --}}
<GlimmerComponent
@errors={{or this.aVeryLongProperty (and this.aProperty (v-get bike "number" "message"))}}
data-test-beneficiary-account-number
/>
<GlimmerComponent
@progress={{aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue}}
/>

{{!-- Prettier 2.2 --}}
<GlimmerComponent
@errors={{
or
this.aVeryLongProperty
(and this.aProperty (v-get bike "number" "message"))
}}
data-test-beneficiary-account-number
/>
<GlimmerComponent
@progress={{
aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue
}}
/>

{{!-- Prettier 2.3 --}}
<GlimmerComponent
@errors={{or
this.aLongProperty
(and this.aProperty (v-get bike "number" "message"))
}}
data-test-beneficiary-account-number
/>
<GlimmerComponent
@progress={{aPropertyEngdingAfterEightiethColumnToHighlightAWeirdClosingParenIssue}}
/>

GraphQL

匿名操作でのキーワード後のスペースが欠落する問題を修正 (#10689 by @patriscus)

# Input
query ($unnamed: String) {
id
}

# Prettier 2.2
query($unnamed: String) {
id
}

# Prettier 2.3
query ($unnamed: String) {
id
}

Markdown

JavaScript のフェンスコードブロック末尾に文字列リテラルがある場合の余分な改行を修正 (#9736 by @fisker)

<!-- Input -->
Markdown

```js
"· "
```

<!-- Prettier 2.2 -->
Markdown

```js
"· ";

```

<!-- Prettier 2.3 -->
Markdown

```js
"· ";
```

空の front matter のフォーマットを修正 (#9791 by @fisker)

<!-- Input -->
---
---

# Title

a|b|c|
|:--|:-:|--:|
|d|e|f|

---

text

<!-- Prettier 2.2 -->
---
---
# Title

a|b|c|
|:--|:-:|--:|
|d|e|f|
---

text

<!-- Prettier 2.3 -->
---
---

# Title

| a | b | c |
| :-- | :-: | --: |
| d | e | f |

---

text

front matter での YAML ドキュメント終了マーカーのサポート (#9878 by @michaelbeaumont)

front matter の終わりを ... で区切る機能を追加

<!-- Input -->
---
title: Hello
slug: home
...

Markdown

<!-- Prettier 2.2 -->
---

title: Hello
slug: home
...

Markdown

<!-- Prettier 2.3 -->
---
title: Hello
slug: home
...

Markdown

YAML

アンカーの後に空行がある場合に誤って SyntaxError がスローされる問題を修正 (#10516 by @eemeli & @thorn0)

Prettierはこの有効なYAMLをパースできませんでした。基盤となるパーサーのこのバグを修正してくれたEemeli Aroに感謝します。

# Input
key1: &default

subkey1: value1

key2:
<<: *default

# Prettier 2.2
SyntaxError: Nested mappings are not allowed in compact mappings (1:7)

# Prettier 2.3
key1: &default
subkey1: value1

key2:
<<: *default

API

.prettierrcのフォーマット時にYAMLとして扱う (#8105 by @fisker)

.prettierrcファイルはJSONまたはYAMLで記述できます。以前、Prettierがこれをフォーマットする際、パーサーはjsonと推測されていたため、コンテンツがYAMLの場合にSyntaxErrorがスローされていました。今後はYAMLファイルとして扱われます。ただしJSONの場合はJSONとしてフォーマットされ(JSON風YAMLではありません)、そのままフォーマットされます。

concatの代わりに配列を使用 (#9733 by @fisker, @thorn0)

ASTプリンターのコードを簡素化するため、連結コマンドのデータ構造が{ type: 'concat', parts: Doc[] }からDoc[]に変更されました。旧形式は非推奨ですが、互換性のためドキュメントプリンターは引き続きサポートし、doc.builders.concat(および他のビルダー関数)はPrettierの次期メジャーバージョンまで旧形式を使用し続けます。

プラグイン開発者にとって、この変更はプラグインが構成済みドキュメントをイントロスペクトまたは変更する場合のみ影響します。該当する場合は、イントロスペクションコードを調整して新形式をサポートし、将来のPrettierバージョンとの互換性を確保してください。また、プラグインが別のプラグインを呼び出して埋め込み言語を出力し、返されたドキュメントをイントロスペクトする場合に問題が発生する可能性があります(ただしプラグインがそのような処理を行う理由はないと思われます)。

プラグイン内のconcat(…)呼び出しを置換するには、ESLintルールprettier-doc/no-concatによる自動修正が利用できます。

// Prettier 2.2
myDoc = group(concat(["foo", line, "bar"]));

// Prettier 2.3
myDoc = group(["foo", line, "bar"]);

lineSuffixBoundary IRコマンドの修正 (#10122 by @thorn0)

lineSuffixBoundaryコマンドの実装にバグがあり、有用性が大幅に制限されていました:プリンターアルゴリズムが改行の可能性を正しく考慮していませんでした。この修正により、プラグイン開発者にはこのコマンドを再検討し、末尾コメントの印刷を簡素化するのに役立つか確認することをお勧めします。

// Input
group([
"let foo = [",
indent([
softline,
[lineSuffixBoundary, "item1,"],
line,
[lineSuffixBoundary, "item2,", lineSuffix(" // comment")],
line,
[lineSuffixBoundary, "item3"],
]),
softline,
"];",
])

// Prettier 2.2
let foo = [item1, item2, // comment
item3];

// Prettier 2.3
let foo = [
item1,
item2, // comment
item3
];

indentIfBreak IRコマンドの追加 (#10221 by @thorn)

indentIfBreak(doc, { groupId })ifBreak(indent(doc), doc, { groupId })の最適化版です。

printコールバックの簡略化 (#10557 by @fisker)

プラグインプリンターのprintメソッドの第3引数(printコールバック)が更新されました。第1引数に文字列または文字列の配列を指定できるようになりました。

現在のノードを印刷するには、引数なしでprintを呼び出します:

 function print(path, options, print) {
const parts = [];
path.each((childPath) => {
- parts.push(print(childPath));
+ parts.push(print());
}, "children");
return parts;
}

現在のノードのプロパティを印刷するには、"property"または["property"]を使用します:

 function print(path, options, print) {
- return path.call(print, "property");
+ return print("property");
}

現在のノードのサブプロパティを印刷するには、["property1", "property2"]を使用します:

 function print(path, options, print) {
// print `node.child.child`
- return path.call(print, "child", "child");
+ return print(["child", "child"]);
}

詳細はドキュメントの例も参照してください。

CLI

マッチしないパターン時のエラー防止オプションをCLIに追加 (#10058 by @daronmcintosh)

Prettier CLIは、入力として渡されたglobパターンにマッチするファイルがない場合、エラーを表示しなくなります。

# Prettier 2.2
$ npx prettier --check "prettier/docs/*.yaml"
Checking formatting...
[error] No files matching the pattern were found: "prettier/docs/*.yaml".
All matched files use Prettier code style!

# Prettier 2.3
$ npx prettier --check --no-error-on-unmatched-pattern "prettier/docs/*.yaml"
Checking formatting...
All matched files use Prettier code style!

コメントアタッチメント問題のデバッグ用CLIフラグを追加 (#10124 by @thorn0)

新しい --debug-print-comments CLIフラグとPlayground対応機能が追加されました。

ラウンドトリップ可能な --debug-print-doc を実装 (#10169, #10177 by @thorn0)

--debug-print-doc の出力をドキュメント生成用の実際のコード(Prettierの中間表現)に近づけるための改善です。理想的にはJSファイルにコピペ後、修正なしで動作する状態を目指しています。このPRでは完全には達成されていませんが、かなり近づきました。これにより --debug-print-doc とPlaygroundの対応部分がより実用的になります。

--find-config-path が設定ファイルを見つけられない場合にエラーメッセージを出力 (#10208 by @fisker)

# Prettier 2.2
$ prettier --find-config-path /prettier.js
# Silently failed

# Prettier 2.3
$ prettier --find-config-path /prettier.js
[error] Can not find configure file for "/prettier.js"

フォーマット対象ファイルの長いファイル名表示をクリア化 (#10217 by @fisker)

# Prettier 2.2
$ prettier tests/flow-repo/config_module_system_node_resolve_dirname --check
Checking formatting...
tests\flow-repo\config_module_system_node_resolve_dirname\custom_resolve_dir\tes
tests\flow-repo\config_module_system_node_resolve_dirname\custom_resolve_dir\tes
tests\flow-repo\config_module_system_node_resolve_dirname\subdir\custom_resolve_
All matched files use Prettier code style!

# Prettier 2.3
$ prettier tests/flow-repo/config_module_system_node_resolve_dirname --check
Checking formatting...
All matched files use Prettier code style!

constructor のような特殊ワードを含むファイルパスをスキップしないように修正 (#10256 by @ashlkv)

ディレクトリ名が Object.prototype のプロパティと偶然一致する場合、Prettier CLIがそれらを無視する問題(Prettier 2.0.0で導入された古典的バグ)を修正しました。原因はオブジェクトプロパティの所有権チェック不足でした。

# Prettier 2.2
$ prettier "js/constructor/*.js" --write
[error] No matching files. Patterns: js/constructor/*.js

# Prettier 2.3
$ prettier "js/constructor/*.js" --write
js/constructor/test.js 42ms