📖

esquery 便利ラッパー

2021/07/05に公開

ESTree を CSS のセレクター風の記法で走査する esquery というライブラリがある。

https://github.com/estools/esquery

直接使ったことがある人は少ないかもしれないが、ESLint ルールを書くときに使ことがあるので esquery の構文を使ったことがある人は多いのではないだろうか。

esquery は便利だが、長いクエリを文字列で渡したりするのが微妙。テンプレートリテラルでいい感じにしたい。ということで outdent と組み合わせる小さなラッパーを書いた。

import esquery from "esquery";
import outdent from "outdent";
import type { Node } from "@types/estree";

function query<T extends Node>(
  ast: Node,
  query: string,
  cb: (node: T) => void
) {
  const nodes = esquery(ast, outdent({ newline: "" }).string(query)) as T[];
  for (const node of nodes) {
    cb(node);
  }
}

こんな風に使う。

import { parse } from "acorn";
import type { Node, CallExpression } from "@types/estree";

const ast = (parse(code, { ecmaVersion: 2020 })) as Node;
query<CallExpression>(
  ast,
  // hello(...)
  `
    CallExpression
    [callee.type="Identifier"]
    [callee.name="hello"]
  `,
  (callExpression) => {
    console.log(callExpression.arguments);
  }
);

便利なときがある。

自分のユースケースではコールバックの方がいいかんじだったのでそうしたが、普通にノードを返すようにしてもいいと思う。

追記:

でもよく考えたらこれだと > を使うのが難しい。

Discussion