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

Prettier 1.6: 設定ファイルとJSXの改善

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

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

このリリースでは、Prettierの設定ファイルサポートとJSX出力の大幅な機能強化が行われました。

特に、休暇やチーム異動により私がPrettierに割ける時間が減る中、リポジトリのメンテナンスを担当し今回のリリースの多くの変更を実装してくれた@azzに感謝します :)

主な変更点

設定機能

ワークスペース設定にcosmiconfigを実装 (#2434) by @azz

Prettierの最初のリリースからずっと、ユーザーは.prettierrcファイルを求めてきました。私たちはオプション数を最小限に抑え、新規プロジェクトで必須となる.dotfileがまた一つ増えることを避けようとしてきました。

しかし実際には、すべての統合環境と同期できる設定方法が必要でした。これを提供しなかったことで問題を各環境に押し付け、互換性のない様々な解決方法が生まれてしまいました。そのため現在では、Prettier自体がこの問題を処理します。

// .prettierrc
{
"trailingComma": "es5",
"singleQuote": true
}

設定ファイルサポートの詳細については、READMEをご覧ください。

.prettierignoreファイルのサポート (#2412) by @evilebottnawi

使用する設定を指定するのに加え、どのファイルを変換対象から除外するかを指定する.prettierignoreファイルを作成できるようになりました。

## .prettierignore
dist/
package.json

JSX

JSXフォーマットの改善 (#2398) by @suchipi

Prettier導入の最後の大きな障壁はJSXの出力方法でした。報告されたすべての課題を検討し、以下の変更を実施しました:

  • JSXを返すアロー関数式でJSXが改行される場合、括弧を追加するようになりました
// Before
const Component = props =>
<div>
Hello {props.name}!
</div>;

// After
const Component = props => (
<div>
Hello {props.name}!
</div>
);
  • JSX内(またはJSXを含む)条件式は、括弧を使用した別の形式でフォーマットされます
// Before
<div>
{props.isVisible
? <BaseForm
url="/auth/google"
method="GET"
/>
: <Placeholder />}
</div>;

// After
<div>
{props.isVisible ? (
<BaseForm
url="/auth/google"
method="GET"
/>
) : (
<Placeholder />
)}
</div>
  • 論理式(|| または &&)内のJSXは、JSXが改行される際に常に括弧で囲まれます
// Before
<div>
{props.isVisible &&
<BaseForm
url="/auth/google"
method="GET"
/>}
</div>;

// After
<div>
{props.isVisible && (
<BaseForm
url="/auth/google"
method="GET"
/>
)}
</div>

これによりコミュニティの大多数がJSXを記述する方法に沿い、より多くの場所でPrettierが使用できるようになるでしょう ;)

JSX内の単一式のインライン化 (#2442) by @karl

当初JSXでは、元のソースに含まれる多くの改行を保持していました。これによりコードベースへの変更を最小限に抑えられましたが、同じ意味を持つコードが2通りの方法で記述できるため、一貫性のあるプリティプリンティングの価値が損なわれていました。

各リリースごとにこの挙動を厳格化し、コード片の出力方法を決定してきました。最新の決定では、JSXオブジェクト内に単一の子要素がある場合、常にインライン化するようになりました。

// Before
return (
<div>
{this.props.test}
</div>
);
return <div>{this.props.test}</div>;

// After
return <div>{this.props.test}</div>;
return <div>{this.props.test}</div>;

JSX先頭の空白後に改行を確保 (#2348) by @karl

JSXの先頭にある空白は現在、独立した行に配置されます。タグの前に空白があると、他の部分と異なる「インデント」のように見えて不自然だったためです。

// Before
<span className="d1">
{' '}<a
href="https://github.schibsted.io/finn/troika"
className="link"
/>
</span>

// After
<span className="d1">
{' '}
<a
href="https://github.schibsted.io/finn/troika"
className="link"
/>
</span>

その他の変更

JSON

JSON に babylon.parseExpression を使用する (#2476) by @josephfrazier

以前は厳格なJSONパーサーを使用しており、コメントや末尾のカンマがあるとエラーが発生していました。これは不便でした。なぜなら実際には多くのJSONファイルがJavaScriptやjson5など、より寛容なパーサーで処理されているためです。今回、この制限を緩和しJavaScriptパーサーを使ってJSONを解析・出力するようにしました。これにより既存のコメントが維持されるようになります。

注意点として、これは純粋に追加的な変更です。元のファイルがJSON仕様に準拠している場合、引き続き有効なJSONが出力されます。

// Before
Syntax error

// After
{ /* some comment */ "a": 1 }

JavaScript

3つ以上の連鎖呼び出しを複数行で出力する (#2673) by @azz

これは長いメンバーチェーンの出力方法に関する長年の課題でした。Prettierは最終コールバック以外を1行に詰め込もうとし、可読性を低下させていました。今回の解決策は、メソッドチェーン内の関数呼び出しが3つ以上ある場合、常に複数行に分割するというものです。

// Before
Promise.resolve(0).catch(function(err) {}).then(function(res) {
//
});

// After
Promise.resolve(0)
.catch(function(err) {})
.then(function(res) {
//
});

制御用括弧を追加強化 (#2423) by @azz

括弧はASTの一部ではないため、Prettierはユーザーが追加した括弧をすべて無視して一から再作成します。ユーザー報告を精査した結果、比較演算子が連鎖していたり%*/と混在する場合など、混乱を招くエッジケースがいくつか判明しました。

変更しない点として、基本的な算術演算子(+-*/)の組み合わせ周囲の余分な括弧は引き続き削除されます。

// Before
x !== y === z;
x * y % z;

// After
(x !== y) === z;
(x * y) % z;

JSX内でのprettier-ignoreを実装 (#2487) by @azz

JSXの特定部分をフォーマット対象外にできると便利です。JSX式内にコメントを追加することで、次の要素のフォーマットを無視できるようになりました。

// Before
<Component>
{/*prettier-ignore*/}
<span ugly format="" />
</Component>

// Before
<Component>
{/*prettier-ignore*/}
<span ugly format='' />
</Component>

prettier-ignoreコメントが無視されないように修正 (#2664)

エッジケース対応のため、内部的に汎用的なコメント出力を回避し呼び出し元で出力する仕組みがありました。しかしprettier-ignore使用時にコメントが完全に出力されない問題が判明し、この度修正されました。

// Before
push(
<td> :)
</td>,
);

// After
push(
// prettier-ignore
<td> :)
</td>,
);

do-while条件式のインデントを修正 (#2359) by @jsnajdr

while条件が複数行の場合のdo-whileの不具合報告まで6ヶ月かかった事実は、この構文が実践でほとんど使われていないという私の予感を裏付けています。

// Before
do {} while (
someVeryLongFunc(
someVeryLongArgA,
someVeryLongArgB,
someVeryLongArgC
)
);

// After
do {} while (
someVeryLongFunc(
someVeryLongArgA,
someVeryLongArgB,
someVeryLongArgC
)
);

シーケンス式の改行処理を改善 (#2388) by @bakkot

JavaScriptのもうひとつの使用頻度の低い機能であるシーケンス式について、複数行になる際の出力が不十分でしたが、この度修正されました :)

// Before
(a = b ? c : "lllllllllllllllllllllll"), (a = b
? c
: "lllllllllllllllllllllll"), (a = b ? c : "lllllllllllllllllllllll"), (a = b
? c
: "lllllllllllllllllllllll"), (a = b ? c : "lllllllllllllllllllllll");

// After
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll')

コメント末尾の空白文字を削除 (#2494) by @azz

Prettierでは末尾の空白をすべて削除する方針を採用しています。従来ユーザー生成コンテンツであるコメントには手を付けませんでしたが、コメントに空白が残るべき理由はありませんでした :)

// Before
// There is some space here ->______________

// After
// There is some space here ->

クラスデコレータ内のインターリーブコメントを修正 (#2660, #2661)

クラス宣言内のコメント処理は非常に単純で、すべてのコメントを先頭に移動していました。現在はより正確になり、デコレーター間やextends周辺に散在するコメントの位置を尊重します。

// Before
// A
// B
// C
@Foo()
@Bar()
class Bar {}

// After
// A
@Foo()
// B
@Bar()
// C
class Bar {}

bind式のフォーマット改善 (#2493) by @azz

bind式はTC39で議論中ですが、Prettierで整形できるようにしました。以前は単純にチェーンするだけでしたが、現在は.演算子を使ったメソッドチェーンと同じロジックを適用しています。また、不正なコードを出力するエッジケースも修正しました。

// Before
observable::filter(data => data.someTest)::throttle(() =>
interval(10)::take(1)::takeUntil(observable::filter(data => someOtherTest))
)::map(someFunction);

// After
observable
::filter(data => data.someTest)
::throttle(() =>
interval(10)::take(1)::takeUntil(observable::filter(data => someOtherTest))
)
::map(someFunction);

オプショナルcatchバインディングの出力サポート追加 (#2570) by @existentialism

catch(e)の引数をオプショナルにする提案がTC39で議論されています。ユーザーが使用する場合に備え、Prettierでのサポートを確実にしました。

// Before
Syntax error

// After
try {} catch {}

オプショナルチェーン構文の出力サポート追加 (#2572) by @azz

TC39で議論中の別の新提案であるオプショナルチェーン構文を追加しました。これは現在ステージ1提案のため、構文は変更される可能性があります。

obj?.prop       // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call

Closure Compilerの型キャスト構文を正しく処理 (#2484) by @yangsu

コメントの処理は特に位置に意味がある場合に困難です。Closure Compilerの型キャストとして使用されるコメントを特別扱いし、同じセマンティクスを維持するようにしました。

// Before
let assignment /** @type {string} */ = getValue();

// After
let assignment = /** @type {string} */ (getValue());

メンバーチェーン内の最初の計算プロパティ参照をインライン化 (#2670) by @azz

計算プロパティ参照が次の行にあるのは不自然に見えるため、インライン化する特別なケースを追加しました。

// Before
data
[key]('foo')
.then(() => console.log('bar'))
.catch(() => console.log('baz'));

// After
data[key]('foo')
.then(() => console.log('bar'))
.catch(() => console.log('baz'));

Flow

不透明型とexport starのサポート (#2543, #2542) by @existentialism

Flowチームが新構文で導入した2つの重要な機能をPrettierでサポートしました。個人的には不透明型を非常に長く待ち望んでいました!

// Before
Syntax error

// After
opaque type ID = string;
export type * from "module";

型オブジェクトとインターフェースのキーから不要な引用符を除去 (#2643) by @jackyho112

JavaScriptオブジェクトではPrettierの初期からこの処理を行っていましたが、FlowやTypeScriptの型には適用し忘れていました。

// Before
type A = {
"string": "A";
}

// After
type A = {
string: "A";
}

単項関数型でもTypeParameterを出力 (#2406) by @danwang

失礼、この特殊なケースでジェネリック型を省略していました。

// Before
type myFunction = A => B;

// After
type myFunction = <T>(A) => B;

ArrayTypeAnnotation内のFunctionTypeAnnotationを括弧で囲む (#2561) by @azz

括弧...いつか全ての問題を解決できるでしょう :)

// Before
const actionArray: () => void[] = [];

// After
const actionArray: (() => void)[] = [];

TypeScript

TypeScript 2.5 RC のサポート (#2672) by @azz

TypeScript 2.5 RCが最近発表され、TypeScriptでも新たな「オプショナルなcatchバインド」構文が利用可能になりました。🎉

グローバル宣言へのnamespaceキーワード追加を停止 (#2329) by @azz

// Before
namespace global {
export namespace JSX { }
}

// After
global {
export namespace JSX {}
}

<this.Component /> の修正 (#2472) by @backus

JavaScriptの型指定がなく自由度の高い性質を活かし、未定義値を文字列に連結することで興味深いコードが生成されていましたが、このケースは修正されました :)

// Before
<undefined.Author />

// After
<this.Author />

型アサーションの簡略化を許可 (#2439) by @azz

JavaScriptやFlow向けに追加した特別なケース処理が、TypeScriptの構文でも確実に機能するよう対応しました。特にas演算子でラップされたオブジェクトは簡略化された形式で出力されるようになります。

// Before
const state = JSON.stringify(
{
next: window.location.href,
nonce,
} as State
);

// After
const state = JSON.stringify({
next: window.location.href,
nonce,
} as State);

二項演算内の型アサーションから不要な括弧を削除 (#2419) by @azz

多くのケースでは正確性のために括弧を追加しますが、このケースでは不要な括弧が付加されていたため削除し、よりクリーンなコードを実現しました :)

// Before
(<x>a) || {};

// After
<x>a || {};

代入式左辺値としての型アサーションに括弧を追加 (#2525) by @azz

また別の括弧不足ケースを修正。最近ではこの種の問題は非常に稀で、極めて特殊なエッジケースに限られてきています。

// Before
foo.bar as Baz = [bar];

// After
(foo.bar as Baz) = [bar];

TSInterfaceDeclarationでのdeclareキーワード出力 (#2574) by @existentialism

declareキーワードはinterfaceに対して実質的な効果を持ちませんが、宣言ファイル内で他の要素にはdeclareが付いているのにインターフェースだけ欠けているのは不自然でした。元のソースにdeclareが存在した場合は、それを再出力するようになりました。

// Before
interface Dictionary<T> {
[index: string]: T
}

// After
declare interface Dictionary<T> {
[index: string]: T
}

CSS

CSS内の引用符を正規化 (#2624) by @lydell

CSS初版では文字列引用符をそのまま維持していましたが、PrettierのsingleQuoteオプションを尊重するよう変更しました。課題は、エスケープ処理やUnicode文字、絵文字、charsetのような二重引用符必須の特殊ルールなど、あらゆるケースで正しいコードを出力することでした。

// Before
div {
content: "abc";
}

// After
div {
content: 'abc';
}

CSS内の数値表現を正規化 (#2627) by @lydell

JavaScript向けに開発したロジックを再利用し、CSSの出力品質を向上させました。

// Before
foo {
border: 1px solid rgba(0., 0.0, .0, .3);
}

// After
foo {
border: 1px solid rgba(0, 0, 0, 0.3);
}

セレクタ内の非引用CSS属性値に引用符を追加 (#2644) by @lydell

属性値周りの引用符ルールは常に記憶しづらいため、常に引用符を付ける方式に統一しました。

// Before
a[id=test] {}

// After
a[id="test"] {}

cssキーワードのサポート追加 (#2337) by @zanza00

// Before
const header = css`.top-bar {background: black;margin: 0;position: fixed;}`

// After
const header = css`
.top-bar {
background: black;
margin: 0;
position: fixed;
}
`;

styled-components の既存コンポーネントサポート (#2552, #2619) by @azz

styled-components には、テンプレートリテラルを CSS としてタグ付けするための多様なバリエーションが存在します。Prettier 内部でこれらの方法をすべてエンコードするのは理想的ではありませんが、対応を始めた以上、本格的に実装することにしました。

styled(ExistingComponent)`
css: property;
`;

styled.button.attr({})`
border: rebeccapurple;
`;

子孫結合子の空白トリミング (#2411) by @azz

使用している CSS パーサーは完全なセマンティックツリーを提供しないため、多くの場合入力内容をそのまま返します。正しさを維持しつつこれを整理するのは私たちの責任です。今回、セレクター間のスペースをそのまま出力していましたが、常に単一スペースに置き換えるのが正しいと判断しました。

// Before
.hello

.how-you-doin {
height: 42;
}

// After
.hello .how-you-doin {
height: 42;
}

パース前の BOM 除去 (#2373) by @azz

以前の経験で BOM 対応に悪夢のような思いをしましたが、2017年現在ではほとんどのツールが認識するため大きな問題ではなくなりました。CSS パーサー関連のエッジケースを修正してくれた @azz に感謝します。

// Before
[BOM]/* Block comment *
html {
content: "#{1}";
}
// After
[BOM]/* Block comment */
html {
content: "#{1}";
}

GraphQL

GraphQL の範囲指定フォーマット対応 (#2319) by @josephfrazier

GraphQL ファイルで範囲指定フォーマット機能を使用すると例外が発生していましたが、今回の修正で選択部分のみを再フォーマットできるようになりました。

.gql 拡張子の GraphQL パーサー対応追加 (#2357) by @rrdelaney

Facebook では .graphql 拡張子を使用していますが、.gql も一般的であることが判明しました。使用パーサーを決定するヒューリスティックに追加するコストは小さいため対応しました。

CLI

無視パターンでの複数パターン対応 (#2356) by @evilebottnawi

既に複数の glob パターン指定は可能でしたが、この変更により特定ファイルを無視する glob パターンを追加できるようになりました。深くネストされたフォルダを無視する際に特に有用です。

prettier --write '{**/*,*}.{js,jsx,json}' '!vendor/**'

--list-different の --stdin 対応 (#2393) by @josephfrazier

これは Prettier がコードを異なる方法で出力するか確認する便利な方法です。必要な概念は既に揃っており、正しく連携させるだけで実現できました。

$ echo 'call ( ) ;' | prettier --list-different
(stdin)
$ echo $?
1