GraphQLの静的解析をCLIで作りやすくしてくれるgqlgo/gqlanalysisというライブラリがある。

go/analysisを使ったことがあればそれと殆ど同じ使い方ができるため非常に便利だが、CLIに引数を渡すときにハマったのでその備忘録。

この記事で言及している gqlgo/gqlanalysis のバージョンはv0.3.5

作成したCLIに引数を渡したい場合、go/analysisではAnalyzer.FlagsにGo標準のFlagと同じように設定をすることでunitchecker.Mainが勝手にflagをparseしてくれいていた。

var (
	configPath string
)

func init() {
	Analyzer.Flags.StringVar(&configPath, "config", "", "config file path")
}

しかし、gqlanalysisだと以下の部分のように引数がflagパッケージ直接に設定されている。

https://github.com/gqlgo/gqlanalysis/blob/v0.3.5/multichecker/checker.go#L16-L19

そのため、 gqlanalysisで作成したCLIでは暗黙的に、 -schema="schema/**/*.graphql" -query="query/**/*.graphql" のような引数を受け取れるようになっている。

また、AnalyzerのFlagsに設定をしたとしても、上記の設定が選考するため、Usage等でschemaとqueryをセットでCLIの引数として表示できない。

もし独自引数を設定したい場合は以下のようにflagパッケージに直接渡してschemaとqueryと同じ扱いにする必要がある。

func main() {
	var (
		flagTypes      string
		flagDirectives string
	)

	flag.StringVar(&flagDirectives, "directives", "", "required: comma-separated list of directives")
	flag.StringVar(&flagTypes, "types", "", "comma-separated list of list types")

	if flag.Parse(); flagDirectives == "" {
		flag.Usage()
		return
	}

	types := parseTypes(flagTypes)
	directives := parseDirectives(flagDirectives)
	multichecker.Main(arraydirective.NewAnalyzer(types, directives))
}

また、上記のようにflagパッケージに直接指定したとしても、schemaだけではなくqueryもセットで渡さないと正しく解析をしてくれない。

schemaが必要な理由はわかるが、queryが必要な理由はちょっと不思議。

これらの挙動はちょっと不思議なため、どこかで誰かが(もしくは自分が)PRを出して直すかもしれない。