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

Prettier 3.4: 多数のバグ修正

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

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

このリリースには数多くのバグ修正とその他の改善が含まれています。

Prettierを評価いただき、私たちの活動を支援したい場合は、OpenCollectiveを通じた直接のスポンサーシップや、typescript-eslintremarkBabelなど当プロジェクトが依存するプロジェクトのスポンサーをご検討ください。皆様の継続的なご支援に感謝申し上げます。

その他の変更

JavaScript

配列を含むテンプレートリテラルの出力を修正 (#13315 by @fisker, @syi0808)

// Input
const string = `${[[1, 2], [3, 4]]}`

// Prettier 3.3
const string = `${[
[2],
[4],
]}`;

// Prettier 3.4
const string = `${[
[1, 2],
[3, 4],
]}`;

タグ付きテンプレートリテラルで不足していた括弧を追加 (#16500 by @syi0808)

// Input
(String?.raw)``;
(getTag?.())``;

// Prettier 3.3
String?.raw``;
getTag?.()``;

// Prettier 3.4
(String?.raw)``;
(getTag?.())``;

文字列リテラル内の不要な \ を削除しないように変更 (#16563 by @sosukesuzuki, #16763 by @fisker)

以前のPrettierは、文字列リテラルから不要なエスケープ文字(\)を削除していました。しかし、この動作はテンプレートリテラルには適用されておらず、issue #16542で報告された通り一貫性がありませんでした。

このissueは、同様の動作をテンプレートリテラルにも拡張する機能リクエストです。

内部での議論を経て、Prettierチームは不要なエスケープ文字の削除(文字列リテラルとテンプレートリテラルのいずれにおいても)はフォーマッタではなくリンターの責務であると結論付けました。

この変更により、Prettierがサポートする全言語において、文字列リテラルから不要なエスケープ文字を削除する機能が無効化されます。以前の動作を維持したい場合は、no-useless-escapeなどのESLintルールの使用をお勧めします。

エスケープされた引用符(例:"\"\'")は、異なる引用符に変更する際にエスケープが解除される可能性があります。この動作は公式ドキュメントの設計思想ページで説明されています。

// Input
const str = "\a";

// Prettier 3.3
const str = "a";

// Prettier 3.4
const str = "\a";

単項式内の論理式に対するコメント書式を改善 (#16593 by @sosukesuzuki)

// Input
!(
cond1 || // foo
cond2 || // bar
cond3 // baz
);

// Prettier 3.3
!(
(
cond1 || // foo
cond2 || // bar
cond3
) // baz
);

// Prettier 3.4
!(
cond1 || // foo
cond2 || // bar
cond3 // baz
);

実験的構文のサポートを削除 (#16643, #16705 by @fisker)

TypeScript

タグ付きテンプレートリテラルで不足していた括弧を追加 (#16500 by @syi0808)

// Input
(String?.raw!)``;
(String?.raw)!``;

// Prettier 3.3
String?.raw!``;
String?.raw!``;

// Prettier 3.4
(String?.raw)!``;
(String?.raw)!``;

デコレータと修飾付きパラメータプロパティ間のコメントを保持 (#16574 by @sosukesuzuki)

現在のPrettierは、readonlyprivatepublicなどで修飾されたパラメータプロパティとデコレータの間にある行コメントを意図せず移動させます。この出力は無効なTypeScriptコードとなります。

この変更により元の書式が保持されるようになります。

// Input
class Foo {
constructor(
@decorator
// comment
readonly foo,
) {}
}

// Prettier 3.3
class Foo {
constructor(
@decorator
readonly // comment
foo,
) {}
}

// Prettier 3.4
class Foo {
constructor(
@decorator
// comment
readonly foo,
) {}
}

修飾子とデコレートされたプロパティ名の間のコメントを保持 (#16578 by @sosukesuzuki)

修飾子とデコレートされたプロパティ名の間にあるブロックコメントがデコレータの後続コメントとして扱われるバグがありました。この動作は予期せぬものであっただけでなく、冪等性も欠如していました。

この変更により、修飾子とプロパティ名の間にあるブロックコメントの位置が保持されるようになります。

// Input
class Foo {
@decorator
readonly /* comment */ propertyName;
}

// Prettier 3.3
class Foo {
@decorator /* comment */
readonly propertyName;
}

// Prettier 3.3 (second output)
class Foo {
@decorator /* comment */ readonly propertyName;
}

// Prettier 3.4
class Foo {
@decorator
readonly /* comment */ propertyName;
}

代入時の型パラメータ付きアロー関数で余分な改行を出力しない (#16586 by @sosukesuzuki)

型パラメータを持つチェーンされたアロー関数を変数に代入する際、その上にラインコメントがある場合に余分な行が挿入されるバグがありました。

この変更により、余分な行が挿入されなくなります。

// Input
const foo1 =
// comment
<T,>() => () => 1;

// Prettier 3.3
const foo1 =
// comment

<T,>() =>
() =>
1;

// Prettier 3.4
const foo1 =
// comment
<T,>() =>
() =>
1;

"トップレベルawaitステートメント"をサポート (#16729 by @fisker)

// Input
(await (await fetch()).json()).foo

// Prettier 3.3
await(await fetch()).json().foo;

// Prettier 3.4
(await (await fetch()).json()).foo;

行幅内に収まる場合でもクラス継承が改行される問題を修正 (#16730 by @fisker)

// Input
export class JiraCreatePixFraudDetectionGateway
implements Pick<IssuePixFraudDetectionGateway, "createPixFraudDetectionIssue">
{
constructor(private readonly logger: Logger) {
this.logger = logger.child({
context: JiraCreatePixFraudDetectionGateway.name,
});
}
}

// Prettier 3.3
export class JiraCreatePixFraudDetectionGateway
implements
Pick<IssuePixFraudDetectionGateway, "createPixFraudDetectionIssue">
{
constructor(private readonly logger: Logger) {
this.logger = logger.child({
context: JiraCreatePixFraudDetectionGateway.name,
});
}
}

// Prettier 3.4
export class JiraCreatePixFraudDetectionGateway
implements Pick<IssuePixFraudDetectionGateway, "createPixFraudDetectionIssue">
{
constructor(private readonly logger: Logger) {
this.logger = logger.child({
context: JiraCreatePixFraudDetectionGateway.name,
});
}
}

クラスプロパティでアクセシビリティ修飾子の前にdeclareを出力 (#16731 by @fisker)

// Input
class A {
declare private readonly name: string;
}

// Prettier 3.3
class A {
private declare readonly name: string;
}

// Prettier 3.4
class A {
declare private readonly name: string;
}

CSS

CSSでのオーバーラン(行溢れ)の特定タイプを解決 (#16570 by @seiyab)

/* Input */
@media (prefers-reduced-data: no-preference) {
@font-face {
unicode-range: U+0000-00FF, U+0131,
U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
}

/* Prettier 3.3 */
@media (prefers-reduced-data: no-preference) {
@font-face {
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
U+2215, U+FEFF, U+FFFD;
}
}

/* Prettier 3.4 */
@media (prefers-reduced-data: no-preference) {
@font-face {
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
}

疑似クラス関数内の余分なインデントを削除 (#16572 by @sosukesuzuki)

この変更は、:where():is():notなどの疑似クラス関数の引数リストに改行が含まれる場合に余分なインデントが追加されるバグを修正します。

/* Input */
:where(input:not([type="button"], [type="reset"], [type="submit"]), textarea, select) {
/* CSS here */
}

/* Prettier 3.3 */
:where(
input:not([type="button"], [type="reset"], [type="submit"]),
textarea,
select
) {
/* CSS here */
}

/* Prettier 3.4 */
:where(
input:not([type="button"], [type="reset"], [type="submit"]),
textarea,
select
) {
/* CSS here */
}

不完全なCSS値コメントのフォーマットを修正 (#16583 by @sosukesuzuki, @fisker)

CSSの値コメントをフォーマットする際、末尾の/が失われて無効なコメントになる可能性がありました。

この変更により、値コメントが切り詰められないようになります。

/* Input */
h1 {
--OFF: /* OFF */;
}

/* Prettier 3.3 */
h1 {
--OFF: /* OFF *;
}

/* Prettier 3.4 */
h1 {
--OFF: /* OFF */;
}

SCSS

SCSSファイルのフォーマット時に発生するエラーを修正 (#16607 by @fisker)

// Input
@if true {
$newKey: ($key: ( $theme-name: $value ))
}

// Prettier 3.3
Error

// Prettier 3.4
@if true {
$newKey: (
$key:
(
$theme-name: $value,
),
);
}

SCSSにおけるコメント後の誤った末尾カンマ位置を修正 (#16617 by @Ma-hawaj, @fisker)

/* Input */
$z-indexes: (
header: 1035,
overlay: 1202 // TODO: change to 1050 after bootstrap modals will be removed
);

/* Prettier 3.3 */
$z-indexes: (
header: 1035,
overlay: 1202 // TODO: change to 1050 after bootstrap modals will be removed,
);

/* Prettier 3.4 */
$z-indexes: (
header: 1035,
overlay: 1202, // TODO: change to 1050 after bootstrap modals will be removed
);

HTML

非HTMLファイルのdoctypeを変更せず保持 (#16765 by @fisker)

Prettier v3ではHTML5 doctypeを小文字で出力するように変更されました。この変更はHTMLファイルでは安全ですが、ユーザーがhtmlパーサーをXHTMLファイルなど他のファイルのフォーマットに使用する場合、doctypeを小文字化するとXHTMLドキュメントが破損する可能性があります。

Prettier 3.4以降では、HTML5 doctype (<!doctype html>)の小文字化はファイル拡張子が.htmlまたは.htmの場合のみ適用され、それ以外のファイルでは元のケースが保持されます。

<!-- Input -->
<!-- foo.xhtml -->
<!DOCTYPE html>

<!-- Prettier 3.3 -->
<!doctype html>

<!-- Prettier 3.4 -->
<!DOCTYPE html>

Vue

Vueイベントバインディングにおける非ASCII文字を含む場合の余分なセミコロン挿入を修正 (#16733 by @fisker)

<!-- Input -->
<template>
<button @click="点击事件">点击!</button>
<button @click="onClick">Click!</button>
</template>

<!-- Prettier 3.3 -->
<template>
<button @click="点击事件;">点击!</button>
<button @click="onClick">Click!</button>
</template>

<!-- Prettier 3.4 -->
<template>
<button @click="点击事件">点击!</button>
<button @click="onClick">Click!</button>
</template>

Angular

Angular 19のサポートを追加 (#16862 by @fisker)

Angular 19ではテンプレート式内でのtypeofキーワードのサポートが追加されました。

<!-- Input -->
<div>{{ typeof
x ===
'object' ? 'Y' : 'N'}}</div>

<!-- Prettier 3.3 -->
<div>
{{ typeof
x ===
'object' ? 'Y' : 'N'}}
</div>

// Prettier 3.4
<div>{{ typeof x === "object" ? "Y" : "N" }}</div>

Markdown

Markdownの順序なしリストで行プレフィックス後に余分なスペースが挿入される問題を修正 (#15526 by @TomasLudvik)

<!-- Input -->
- first line
- second line indented
- third line
- fourth line
- fifth line

<!-- Prettier 3.3 -->
- first line
- second line indented
- third line
- fourth line
- fifth line

<!-- Prettier 3.4 -->
- first line
- second line indented
- third line
- fourth line
- fifth line

linkReferenceを含む文の誤った改行を修正 (#16546 by @seiyab)

<!-- Input (--prose-wrap=always) -->
This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To run them, install VHS from main (the theme and screenshot commands are not yet released).

<!-- Prettier 3.3 -->
This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To run
them, install VHS from main (the theme and screenshot commands are not yet released).

<!-- Prettier 3.4 -->
This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To
run them, install VHS from main (the theme and screenshot commands are not yet
released).

行末と次行頭の非ASCII空白文字を保持するように変更 (#16619 by @tats-u)

Prettierはこれまで行末と次行頭の非ASCII空白文字を削除していましたが、この動作はCommonMark仕様と整合性がありませんでした。

https://spec.commonmark.org/0.31.2/#soft-line-breaks

行末と次行頭のスペースは削除されます:

https://spec.commonmark.org/0.31.2/#unicode-whitespace-character

Unicode空白文字とは、Unicode Zs汎用カテゴリに属する文字、またはタブ(U+0009)、改行(U+000A)、改ページ(U+000C)、キャリッジリターン(U+000D)を指します。

Unicode空白とは、1つ以上のUnicode空白文字の連続です。

スペースはU+0020です。

CommonMark仕様では非ASCIIスペースについて言及しておらず、これらを削除するとMarkdown文書の内容が変更されてしまいます。

<!-- Input -->
 EM Space (U+2003) EM Space

 全角スペース (U+3000) 全形空白

<!-- Prettier 3.3 -->
EM Space (U+2003) EM Space

全角スペース (U+3000) 全形空白

<!-- Prettier 3.4 -->
 EM Space (U+2003) EM Space

 全角スペース (U+3000) 全形空白

日本語・中国語文字と他言語の間での改行を禁止 (#16691 by @tats-u)

Markdown文書は主にHTMLやJavaScriptベースフレームワークのコンポーネントに変換されます。つまり、Markdownの段落は最終的にCSSルールに従ってブラウザで処理されます。これは多くのMarkdownコンバータが入力Markdownの段落内の改行を保持し、HTML自体がブラウザにHTML内のテキストの改行をどのように処理するかを指定していないためです。

CSSルール(CSS Text Module Level 3以降)によれば、ブラウザは日本語・中国語文字間の改行をスペースに置換せずに削除するべきですが、このルールはWebKitベースまたはWebkit派生ブラウザ(Chrome、Safariなど)で長らく無視されてきました。

例えば、次のHTML段落:

<p>
日本語
汉语
漢語
<p>

は以下のMarkdownから生成されます:

日本語
汉语
漢語

CSSルールに従えば以下のようにレンダリングされるべきであり、実際にFirefoxではこのようにレンダリングされます:

日本語汉语漢語

しかしChromeとSafariでは以下のようにレンダリングされます:

日本語 汉语 漢語

このため、Prettierが中国語/日本語文字間で改行するのを防ぐ必要があります。私たちは、中国語/日本語文字で始まる/終わる行を連結するMarkdownコンバーター用プラグイン(例: remark-join-cjk-lines)の使用をユーザーに強制するPrettierの動作を止めることにしました。

また、CSS Text Module Level 3の具体的なルールをコメントアウトして一時停止するコミット以前は、中国語/日本語と他言語間の改行はスペースと同等とされていました(CSSワーキンググループのエディター草案に関する問題を修正)。Firefoxはこのルールを遵守しています。したがって、すべてのブラウザは次の段落を:

<!-- prettier-ignore -->
```html
<p>日本語 English 汉语 한국어 漢語</p>

<p></p>

以下のようにレンダリングします:

日本語 English 汉语 한국어 漢語

しかしPrettierは長らくMarkdown内の中国語/日本語文字間で改行を行い、3.0.0以降では中国語/日本語とラテン文字間でも場合によって改行してきました。例えば次のMarkdown段落:

日本語English汉语
English
漢語

はPrettier 3.xで--prose-wrappreserve以外に設定されている場合、以下のようにフォーマットされます:

日本語English汉语English漢語

しかし上記Markdownから生成される次のHTML:

<p>
日本語English汉语
English
漢語
</p>

はすべてのブラウザで以下のようにレンダリングされます:

日本語English汉语 English 漢語

このため、PrettierがMarkdown内の中国語/日本語文字周辺でも改行するのを防ぐ必要があります。将来のバージョンではPrettierの動作をこのルールに準拠させる予定です。その後、中国語/日本語と他言語間の改行は特定のルール下で再び許可されます。

数少ない例外の一つが中国語/日本語と韓国語文字間のスペース・改行です。次のMarkdown段落は現行Prettierバージョンでも同等です:

현재 韓國의 大統領은 尹錫悅이다.
현재
韓國의
大統領은
尹錫悅이다.

後者を--prose-wrap=alwaysと十分な--print-width値、または--prose-wrap=neverでフォーマットすると前者が得られ、前者を極端に短い--print-width値で--prose-wrap=always設定すると後者が得られます。したがって、このようなスペース・改行は修正不要です。

別の例外は中国語/日本語文字とMarkdownの意味記号(*`[]など)の間です。例えば次のMarkdown段落は現行Prettierでも同等です:

**Yarn** のCLI経由でフォーマットするには `yarn prettier -w ` を実行してください。
**Yarn**
のCLI経由でフォーマットするには
`yarn prettier -w .`
を実行してください。
<!-- Input (--prose-wrap=always --print-width=20) -->
日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어

日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어

<!-- Prettier 3.3 -->
日本語 汉语 漢語
English 한국어 日本
語 汉语 漢語 English
한국어 日本語 汉语
漢語 English 한국어
日本語 汉语 漢語
English 한국어

日本語汉语漢語
English한국어日本語
汉语漢語
English한국어日本語
汉语漢語
English한국어日本語
汉语漢語
English한국어

<!-- Prettier 3.4 -->
日本語 汉语 漢語 English
한국어
日本語 汉语 漢語 English
한국어
日本語 汉语 漢語 English
한국어
日本語 汉语 漢語 English
한국어

日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어

regexp-utilにuフラグ互換の正規表現生成を指示 (#16816 by @tats-u)

BMP外のCJK文字および表意文字異体字シーケンス(IVS;漢字専用異体字セレクター)はJavaScript文字列で2文字消費しますが、これまでCJKとして扱われてきませんでした。これはPrettierがregexp-utilパッケージに適切な"u"フラグを渡していなかったためです。

次の例では、「𠮷」(U+20BB7)はBMP外、「葛󠄀」はBMP内漢字「葛」(U+845B)とIVS U+E0100の組み合わせです。後者はIVSなし文字(葛)とは異なる表示形態のため、Adobe Japan-1対応フォント(例: Yu Gothic UIやSource Han Sans)が必要です。

<!-- Input (--prose-wrap=never) -->
a 字 a 字 a 字
𠮷
𠮷
葛󠄀
葛󠄀


<!-- Prettier 3.3 -->
a 字 a 字 a 字 𠮷 𠮷 葛󠄀 葛󠄀 終

<!-- Prettier 3.4 -->
a 字 a 字 a 字𠮷𠮷葛󠄀葛󠄀終

YAML

YAMLの非単一行アイテム内のコメントで#の前にスペースが不足していた問題を修正 (#16489 by @fyc09)

# Input
123: # hello
# comment

# Prettier 3.3
123:# hello
# comment

# Prettier 3.4
123: # hello
# comment

API

prettier.doc.printDocToStringでのドキュメント変更を停止 (#13315 by @fisker)

パフォーマンス上の理由から、prettier.doc.printDocToStringは印刷中にfillコマンドの.partsを変更していました。出力の正確性を保証するため、純粋関数に変換されました。

getPreferredQuoteを公開 (#16567 by @sosukesuzuki)

この変更により内部関数getPreferredQuoteがパブリックAPIの一部となりました。

JavaScriptなどの言語では、文字列リテラルにシングルクォートとダブルクォートの両方を使用できます。Prettierは文字列内のクォート数とsingleQuoteオプション値に基づいて囲むクォートを決定します。詳細は設計思想ページをご覧ください。

getPreferredQuote関数は文字列リテラルを囲む適切なクォートを決定し、次のインターフェースを持ちます:

type Quote = '"' | "'";
function getPreferredQuote(
text: string,
preferredQuoteOrPreferSingleQuote: Quote | boolean,
): Quote;

使用例をいくつか示します:

import * as prettier from "prettier";

const SINGLE_QUOTE = `'`;
const DOUBLE_QUOTE = `"`;

console.log(prettier.util.getPreferredQuote(`Hello World Test`, SINGLE_QUOTE)); // '
console.log(prettier.util.getPreferredQuote(`Hello World Test`, DOUBLE_QUOTE)); // "
console.log(prettier.util.getPreferredQuote(`'Hello' "World" 'Test'`, SINGLE_QUOTE)); // "
console.log(prettier.util.getPreferredQuote(`"Hello" 'World' "Test"`, DOUBLE_QUOTE)); // '
console.log(prettier.util.getPreferredQuote(`"Hello" "World" "Test"`, SINGLE_QUOTE)); // '
console.log(prettier.util.getPreferredQuote(`'Hello' 'World' 'Test'`, DOUBLE_QUOTE)); // "

この関数の公開はプラグイン開発者に有益です。関数は比較的短いため、詳細は実装をご覧ください。

Node.js 23でのESM形式共有設定ファイルの読み込みを修正 (#16857 by @sosukesuzuki)

Prettier 3.3ではNode.js 23でESM形式の共有設定ファイルを読み込むと次の警告が発生し、オプション読み込みが妨げられていました:

[warn] Ignored unknown option { __esModule: true }.
[warn] Ignored unknown option { default: { trailingComma: "es5", tabWidth: 4, singleQuote: true } }.

この問題はNode.js 23の新機能require(ESM)が原因でした。Prettier 3.4ではこの問題が解決され、オプションが正しく読み込まれます。

詳細は https://github.com/prettier/prettier/issues/16812 をご覧ください。

CLI

Jujutsuディレクトリ内のファイルを無視 (#16684 by @marcusirgens)

Jujutsu VCSはGitが.gitを使用するのと同様に.jjディレクトリを使用します。

この変更によりPrettierが暗黙的に無視するディレクトリリストに.jjが追加されました。

その他の変更

cursorOffset機能が極端に遅くなる問題を修正 (#15709 by @ExplodingCabbage)

以前はPrettierのcursorOffset機能が特定の状況(ユーザーのカーソルがASTのリーフノード内に含まれず、それを含む非リーフノードが非常に大きくPrettierで大幅に再フォーマットされる場合)で著しく遅くなることがありました。この結果、内部でcursorOffsetを使用するエディター統合経由でPrettierを使うと、ファイルフォーマット時にエディターが不可解にハングすることがありました。

私たちが把握しているこの現象のすべての例は修正済みのはずですが、今後さらに問題のある事例が見つかった場合は、バグレポートを歓迎します。