sosukesuzuki.dev

June, 01 2020

5 月の OSS 活動

5 月のオープンソース活動です。意外とちゃんとやってた。

Prettier

Vue や HTML の改善をやっていたような気がします。あと Babel 7.10 や TypeScript 3.9 の対応も若干。ここに載せた以外にも細かな改善もしました。

Vue の SFC のパース改善

https://github.com/prettier/prettier/pull/8153

Prettier は HTML をパースするためにangular-html-parserという Angular の HTML パーサーのフォークを使っているんですが、Vue の SFC のような HTML ではないけど HTML っぽいものにもそれを使用しています。

今までは Vue の SFC をそのまんま HTML としてパースしていました。なのでカスタムブロック内や pug 等の HTML 以外の言語を使った template 内に HTML タグとして認識されちゃう文字のパターンを入れるとシンタックスエラーになっていました。(Playground Link)

<!-- これをPrettierでフォーマットしようとするとシンタックスエラーになる -->
<custom-block>
const foo =    "</";
</custom-block>

これを解消するためにいくつか方法を考えました。vue-eslint-parserを使うか?とか、Vue 公式の SFC コンパイラのパーサーを使うか?とか。しかし、前者はカスタムブロックのサポートを公式にはしていないようで今回のニーズを満たすパース結果が得られず、後者はルートのコメント情報がパース結果に残らずフォーマッターに使うには不十分でした。

なので angular-html-parser を修正してもらって、最終的に少々トリッキーな方法で解決しました。気が向いたらそのお話もどこかに書くかもしれません。

Stage-1 プロポーザル private filed in in の対応

https://github.com/prettier/prettier/pull/8431

Babel 7.10 で対応された Stage-1 のプロポーザルの対応です。次のようなコードはいままでシンタックスエラーだったんですが、フォーマットできるようになります。Prettier 側の対応はパーサーのバージョンアップとオプションの指定だけだったので楽でした。

#prop in obj;

TypeScript 3.9 で入った Non Null Assertion と Optional Chaining の解釈の変更の対応

https://github.com/prettier/prettier/pull/8450

リリースノートを見て TypeScript 3.9 は新しい構文ないから Prettier の対応ないじゃん!って思ってたらありましたね。

Babel 7.10 も同様の修正が入っているので、babel-tsパーサーにも対応しています。

TypeScript 3.8 までは

x?.y!.z;

(x === null || x === void 0 ? void 0 : x.y).z;

という JavaScript にコンパイルされていたんですが、TypeScript 3.9 からは

x === null || x === void 0 ? void 0 : x.y.z;

にコンパイルされるようになりました。なので以前までの挙動を再現したい場合にカッコを補ってあげなくてはいけないんですが、Prettier はそのカッコをはずすようにフォーマットをしていたので、維持するようにしました。

// Input
(a?.b)!.c;

// Prettier stable
a?.b!.c;

// Prettier master
(a?.b)!.c;

eslint-plugin-vue

no-arrow-functions-in-watch ルールの追加

https://github.com/vuejs/eslint-plugin-vue/pull/1155

ドキュメントに書いてあるんですが、Vue のwatchにアロー関数を使うのはアンチパターンです。thisで束縛される値が変わってしまって、Vue インスタンスを指さなくなります。

なので、watchにアロー関数を使っているときに警告を出すルールを追加しました。

詳しくは eslint-plugin-vue のドキュメントの https://eslint.vuejs.org/rules/no-arrow-functions-in-watch.html を見ていただけると。

typescript-eslint

method-signature-styleルールの自動修正のバグの修正

https://github.com/typescript-eslint/typescript-eslint/pull/1966

TypeScript では interface の関数プロパティを二通りの方法で書くことができます。

// メソッドのショートハンド
interface T1 {
  func(arg: string): number;
}

// 通常の関数プロパティ
interface T2 {
  func: (arg: string) => number;
}

method-signagure-styleルールはこれをどちらかに強制できます。

ただ、メソッドのオーバーロードがあったときにメソッドのショートハンドから通常の関数プロパティに強制すると、ルールの自動フォーマットの結果がエラーになってしまうバグがありました。

例えば、次のコードを通常の関数プロパティに強制することを考えます。

interface T {
  method(): void;
  method(arg: string): void;
  method(arg: number): string;
}

今までの実装だと、このようにフォーマットされていました。

interface T {
  method: () => void;
  method: (arg: string) => void;
  method: (arg: number) => string;
}

実際試してみるとわかりますが(Playground link)、これはDuplicate identifier 'method'.でコンパイラに怒られてしまいます。なので、これを intersection types としてフォーマットすることでエラーを回避します。

interface T {
  method: (() => void) & ((arg: string) => void) & ((arg: number) => string);
}

これはセーフになります(Playground link)。