泥沼のDSLを「Prettierの流儀」で支配する:独自言語フォーマッタ開発の深淵
多くのエンジニアにとって、Prettierは「設定ファイルを置けば勝手にコードを整えてくれる魔法の箱」だ。しかし、我々アーキテクトにとって、それは「ソースコードをAST(抽象構文木)という名の純粋な構造データに変換し、再び文字列へシリアライズする強力なパイプライン」に他ならない。
社内で独自開発したDSL(ドメイン固有言語)や、非標準のテンプレート言語を扱う際、多くのチームは泥臭い正規表現ベースのスクリプトで妥協する。だが、それは技術的負債の温床だ。今回は、Prettierの内部アーキテクチャを掌握し、独自言語をネイティブのフォーマッタとして昇華させるための「禁断の技術」を伝授する。
—
1. Prettierの心臓部:ASTとPrinterの設計思想
Prettierの動作原理は、単なるテキスト置換ではない。以下の3段階の変換プロセスを理解する必要がある。
1. Parser: ソースコードを解析し、独自のAST(JSON構造)を生成する。
2. Printer: ASTを走査し、Prettierのドキュメント生成用中間言語(`Doc`)に変換する。
3. Printer (final): `Doc`を評価し、ハードリミット(`printWidth`)に基づいた改行とインデントを最適化した文字列を生成する。
独自言語をサポートするには、この`Parser`と`Printer`の両方を実装する必要がある。
実装の戦略:既存Parserの活用
ゼロからParserを書くのは地獄だ。もしその言語がC言語やJSに似ているなら、`acorn`や`babel`のパーサーを拡張するか、`chevrotain`のような高速なパーサーライブラリを活用し、PrettierのAST仕様(ESTree準拠を推奨)にマッピングせよ。
—
2. 独自フォーマッタの核:`Printer`インターフェースの実装
Prettierプラグインの肝は、`embed`関数の実装にある。これは特定のノードを別の言語として再帰的にフォーマットする機能だ。
// printer.js: ASTノードをPrettierのDocに変換するロジック
const { concat, group, indent, softline } = require(“prettier”).doc.builders;
function print(path, options, print) {
const node = path.getValue();
switch (node.type) {
case “CustomCommand”:
// ASTノードを再帰的にDocに変換する
return group(concat([
“CMD “,
node.name,
indent(concat([softline, path.call(print, “args”)])),
]));
default:
throw new Error(`Unknown node type: ${node.type}`);
}
}
ここがアーキテクトの腕の見せ所だ:
メモリ消費を抑えるため、ASTの走査には`path.map`を利用し、不要なオブジェクト生成を避けること。巨大なテンプレートファイルを扱う場合、V8エンジンのガベージコレクションがボトルネックになる。`node`オブジェクトに循環参照を含めないよう設計するのが鉄則だ。
—
3. CI/CDパイプラインへの統合:完全自動化の設計
自作フォーマッタが完成したら、CI環境での実行パフォーマンスが次の課題となる。単に`prettier –write`を叩くのではない。
コンテナ内での最適化ハック
Docker環境でPrettierを走らせる際、毎回`node_modules`をインストールするのは非効率の極みだ。以下のようなマルチステージビルドとキャッシュ戦略を導入せよ。
CI実行ステージ
FROM node:18-alpine AS runner
Prettier本体と自作プラグインをグローバルインストールしてパスを通す
RUN npm install -g prettier /path/to/my-custom-plugin
実行時間を短縮するため、チェック対象のファイル群をキャッシュから比較
変更されたファイルのみを対象にするスクリプトをCIに組み込む
COPY –from=builder /app/src /app/src
CMD [“sh”, “-c”, “prettier –check $(git diff –name-only origin/main)”]
—
4. なぜ「手作業」を排除すべきなのか
開発者が「フォーマットの揺れ」を気にする時間は、思考のコンテキストスイッチを発生させる。1件につき数秒のロスだが、1年で数千時間の生産性が失われる。
独自言語をPrettier配下に置くことは、単に「見た目を揃える」ことではない。「コードの構造定義をASTという単一の真実(Single Source of Truth)に変換し、それをプログラムが解釈可能な状態に置く」という、大規模開発における極めて高度なメタプログラミングの第一歩なのだ。
究極のデバッグ法:ASTビジュアライザ
独自のパーサーが正しいASTを生成しているか確認するために、`prettier-plugin-debug-print`のようなツールを自作せよ。パース結果をJSONでダンプし、`ajv`等でスキーマ検証をCIに組み込むことで、フォーマッタの破壊的変更を即座に検知できる。
—
最後に:現場のエンジニアへ
「そんな手間をかける価値があるのか?」という問いに対し、私はこう答える。
「自動化されていない規約は、存在しないのと同じだ。」
Prettierの拡張は、単なるフォーマット作業の自動化を超え、チームのコードベースに「言語としての厳格さ」を強制する。これこそが、数年後も陳腐化しない強固な開発基盤を築くための、真のアーキテクトの仕事である。
さあ、今すぐ自作パーサーの設計図を書き始めろ。そのDSLの混沌を、整然たるASTの秩序へと変える準備はできているはずだ。