sosukesuzuki.dev

January, 05 2020

Prettier がファイルパスからパーサを推測するときの情報源

Prettier の.cjs対応をしようとおもって、すでに対応されているmjsとかで grep してもヒットしないからどこに情報持ってるんだろうって思って調べたメモをちょっとちゃんと書いたものです。

前提

1: Prettier はファイル名からパーサーを推測する

Prettier を CLI から使うとき、parserオプションを使ってパーサーを指定できます。

# パーサーオプションを指定してみる
$ prettier foo.js parser=babel

ただし、ファイル名からパーサーを推測できるときは、parserオプションを省略できます。「foo.jsは拡張子が.jsだから、JavaScript としてパースすればいいよね」といった具合に、Prettier がパーサーを推測してくれます。

# これもオッケー
$ prettier foo.js

もっとも多いユースケースであるソースコードのフォーマットにおいては、パーサーを明示的に指定せずに使っている人が大半だと思います。

2: JavaScript としてパースしてほしいいろんなファイル

.js ファイルはもちろんですが.jsx.es6 など、JavaScript としてパースしたいファイルが他にもいくつかあります。

.cjsも JavaScript としてパースしたいファイル拡張子の1つなのですが、現時点で Prettier は対応していませんでした。(.mjsは対応しています。)

$ prettier test.mjs
console.log("Hello, ECMAScript Modules!");

$ prettier test.cjs
test.cjs[error] No parser could be inferred for file: test.cjs

(補足) 一応 .cjs について大雑把に解説しておきます。Node.js は CommonJS と ECMAScript Modules という2つのモジュールシステムをサポートしていて、あるファイルがそのどちらのモジュールシステムを使って書かれているのかを Node.js になんらかの方法で伝える必要があります。その方法の1つがファイル拡張子であり、.cjsの場合は CommonJS、.mjsの場合は ECMAScript Modules となります。詳しく知りたい人は https://nodejs.org/api/esm.html を読んでください。

Prettier Plugins

https://prettier.io/docs/en/plugins.html

Prettier にはプラグインという機能があり、コアで対応できていない言語でも外部のプラグインとして対応できます。

例えば、GitHub の Prettier オーガナイゼーション下には https://github.com/prettier/plugin-phphttps://github.com/prettier/plugin-ruby といったプラグインが存在しており、コミュニティによって管理されています。

Prettier のプラグインは次の5つを named export することで実装できます。(optionsdefaultOptionsは必須ではなかった気がする)

  • languages
  • parsers
  • printers
  • options
  • defaultOptions

このlanguagesというのは、当然ですが決められた形をしたオブジェクトの配列で、そのオブジェクトにはextensionsというプロパティを含めることができます。そしてextensionsに渡す配列で、言語と拡張子の対応付け行っています。

実は、JavaScript や HTML などのコアでサポートしている言語も、内部的にはプラグインとして実装されています。(これらは Prettier のソースコード内ではinternalPluginsと呼ばれています。) https://github.com/prettier/prettier/blob/master/src/common/internal-plugins.js

なので、前述のlanguagesはコアでサポートしている言語にも存在し、extensionsも存在します。

linguist-languages

internalPluginsの実装を読むと、extensionslinguist-languagesというライブラリからひっぱってきていることがわかります。どうりでどれだけ grep してもヒットしないわけです。ソースコードに含まれていないのですから。 https://github.com/prettier/prettier/blob/master/src/language-js/index.js#L9

これは Prettier のメンテナの一人であるika 氏が、github/linguistlanguages.yamlを JSON に自動でフォーマットしたものみたいです。

本家 linguist の.cjs追加は、https://github.com/github/linguist/pull/4703 で行われており、それに追従したlinguist-languagesが v7.7 としてリリースされていました。(Prettier が依存しているのは 7.6)

つまり、依存しているlinguist-langagesのバージョンを 7.6=>7.7 にしたら直ったよっていう話でした。