eslintからoxlintに移行する

oxlintが一部eslint-pluginを動かせるようになったので、移行してみました。

手元のプロジェクトいくつかを見たところ、 2-10倍くらいの速度になりました。

Oxlint | The JavaScript Oxidation Compiler rust製のjavascript/typescript Linter

eslintより高速なのが強み。

ほかにBiomeもあるけれど、こちらはpluginの互換性がない。

移行はmigrationガイドに従って行うのがはやい。

migrate

npx @oxlint/migrate --type-aware --js-plugins <flat config file path>

移行ガイドのmigrateを利用すると、完全にフラットな設定になるので、いろんなルールセットを読み込んでいると、有効になっているruleがどこ由来なのかわからなくなるので注意。

monorepoで eslint-configみたいなパッケージを作成している場合、default exportされてないとうまく動かないので、default exportを追加しておきましょう。

どこ由来のルールなのか明らかにしたい場合は、そのルールセットだけの設定ファイルを利用して上記を実行していくといいです。

修正

実行すると、移行できなかったルールが一覧で出てくる( oxlintで未実装だったり、安定してなかったり)

それらを、jsPluginとして読み込んでなんとかしていく。例えばこんな感じ

{
  "jsPlugins": [
    {
      "name": "jsx-a11y-js",
      "specifier": "eslint-plugin-jsx-a11y"
    },
    {
      "name": "react-js",
      "specifier": "eslint-plugin-react"
    }
  ],
  "rules": {
    "jsx-a11y-js/interactive-supports-focus": "error",
    "jsx-a11y-js/no-interactive-element-to-noninteractive-role": "error",
    "jsx-a11y-js/no-noninteractive-element-interactions": "error",
    "jsx-a11y-js/no-noninteractive-element-to-interactive-role": "error",
    "react-js/hook-use-state": "error",
    "react-js/jsx-no-leaked-render": "error",
    "react-js/no-unstable-nested-components": "error",
    "react-js/display-name": "error",
    "react-js/no-deprecated": "error",
    "react-js/prop-types": "error",
    "react-js/require-render-return": "error"
  }
}

oxlint側で実装されていっているものは名前が予約されているので "react-js" のように-js をつけたりして、名前が被らないように。

ファイルの中でこれらを eslint-disable-next-line したりしていると、そこも変更する必要があります。(実行してエラーを出して修正するのが楽です)

こんな感じでさらっと設定を移植したら、実行してみます。

eslint のAPIのうち、未実装のものがあったりすると、実行時エラーが出るので、エラーが出たルールについて、外せるかどうかを検討します。

外せなかったら移行をあきらめるか、 外せないルールだけeslintで実行し続けることになります。

今回の作業では幸い、外して大丈夫そうなルールしかなかったので、除外して移行しました。

hono/zod-openapiで使えないschema

最近、hono/zod-openapiでの開発(移行)を体験したのでその際、schemaを単純移行できなかった部分のメモ。

input用schemaでunionが直接使えない。

z.union([
  z.object({key1: z.string()),
  z.object({keyA:string()})
])

みたいなschemaが利用できない。

回避方法としては、transformを利用する

z.object({ key1: z.string().optional(), keyA: z.string().optional()}).transform((data)=> z.union([
  z.object({key1: z.string()),
  z.object({keyA:string()})
]).parse(data))

z.fileがそのままでは使えない。(z.fileはunknown typeとなってしまう。)

回避方法としては、typeを手動設定する

z.file().openapi({type: "string", format: "binary"})

outputはparseしてくれない

inputはschemaでparseしてくれるが、outputはschemaでparseしてくれないので、outputがschema通りであることを保証するためには、outputもちゃんとparseする必要がある。

ひさしぶりにPythonでAPIを書いたら快適だった

久しぶりにPythonでweb APIサーバを書く機会があった。

uvによるパッケージ管理は快適だったし、 FastAPI+Pydanticでしっかり型がつくうえ、OpenAPI Schemaの自動生成までできて、とても体験が良かった。

ruffとpyrightによるチェックで直すべきところも明確になる。

VSCodeでpylanceを利用して自動チェックなどもできる。

利用者が多いおかげでLLMもどんどんコードを書いてくれる。

と、とてもいい体験だった。

これはこれでありだなぁ、世の中よくなってるなぁ