Program
のインスタンス化の仕方とか CompilerHost
をどう作ればいいかとか、そういうのが全くdocsに記載されてないので、困った。
色々試した結果、とりあえず以下が最小構成。
import { type Namespace, compile, NodeHost } from "@typespec/compiler";
// tspファイルをコンパイル
const program = await compile(NodeHost, "./your-file.tsp")
// エラーがあればdiagnosticsに入ってくる
// これをチェックしないで、後続の `namespace.models` を参照しようとすると実行時エラーになる
const { diagnostics } = program;
if (diagnostics.length > 0) {
throw new Error("Compilation failed");
}
// Databaseというnamespace配下の定義をすべて取り出す
const [untypedNamespace] = program.resolveTypeReference("Database");
if (!untypedNamespace) {
throw new Error("Namespace not found");
}
// こうやって型つける以外にやり方が分からなかった
const namespace = untypedNamespace as Namespace;
// namespace.modelsにmodelの定義が全て入っている
for (const [name, modelDef] of namespace.models) {
// ...ここでイイ感じにmodelDefを参照してフィールド定義とか取り出す...
}
TypeSpecは compile
関数の第一引数で CompilerHost
というインターフェイスでコンパイラーの実行環境を与えることができる。
NodeHost
というのがデフォルトのコンパイラー実装だが、細かくカスタマイズしたければ createCLICompilerHost
という関数を使ってロガーやトレーサーなどをカスタマイズした実行環境を作れるらしい。