2025-04-13

F# で command-line predictor を書いてる Part 6

FSharp.Analyzer.SDK

krymtkts/SnippetPredictorv0.3.0 をリリースした。

v0.3.0 の新しい機能は、に触れていた snippet の検索の case-sensitivity を指定する option の追加だ。

ただこれは PSReadLine の挙動的には HistorySearchCaseSensitive で制御可能なので、設定ファイルに持たせた方がいいかも。

今度こそ一通りの機能が揃ったか。 あと使い出して感じてるのが、よく使う snippet の表示順位を上げられたらいいなというところだが、この場合 snippet を選んだ履歴を記録する必要があるからなんともなという感じ。 .snippet-predictor.json とは別に二重で記録するわけになるからなんともな。これは本当に必要か検討を要する。

あと、 SnippetPredictor は長らく linter の類を CI に組み込んでなかったのだけど、追加したのでそれを記録しておく。


SnippetPredictor は pocof での経験から FSharpLint をうまく使えてないのもあって、 linter の類を CI に組み込んでなかった。 しかし最近 Fsharp.Analyzers.SDK で解析できるのを知ったので、これを導入してコード解析する。 知ったきっかけは Fantomas で使われてるのを見つけたから。 スキャン結果の SARIF report を生成して GitHub の Code Scanning にアップロードしてた。

fantomas/.github/workflows/main.yml at 938160e6c9660af5bda33e4d20c7b522b8359789 · fsprojects/fantomas

数ヶ月 FSharpLint が使えなくなって無防備になってるわたしにとっては、こりゃ良さそうだと考えた。

導入の手順は Installation | FSharp.Analyzers.SDKIonide.Analyzers | ionide-analyzers を参考にした。

はじめに tool を導入する。

dotnet tool install fsharp-analyzers

次に解析対象の project に Ionide.Analyzers を追加する。 初めてなので、単純化のため G-Research.FSharp.Analyzers の導入はしてない。 最新 version がわからなかったので、 dotnet add ~ で追加してから IncludeAssets を編集した。

dotnet add ./src/SnippetPredictor package Ionide.Analyzers
    <!-- Analyzer configurations. -->
<PackageReference Include="Ionide.Analyzers" Version="0.14.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

Paket を使ってない場合、実行するには analyzer の path を --analyzers-path に指定する必要がある。 FSharp.Analyzers.SDK にはその path を知る方法が書いてない(熟練の .NET ユーザにならよく知られたものかも知れないが)。 Ionide.Analyzers の方はその点わかりやすく、具体的に NuGet で install された analyzer の配置先を取得するための手順が記載されている。 これを使って以下のようにコマンドを構築でき、実行できるようになった。

$analyzerPath = dotnet build ./src/SnippetPredictor  --getProperty:PkgIonide_Analyzers
dotnet fsharp-analyzers --project ./src/SnippetPredictor/SnippetPredictor.fsproj --analyzers-path $analyzerPath
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(163,4): Hint IONIDE-012 : Consider adding [<Struct>] to Discriminated Union
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(314,28): Hint IONIDE-010 : Seq.filter |> Seq.map can be combined into Seq.choose
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(89,16): Info IONIDE-002 : Prefer postfix syntax for arrays.
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(144,15): Warning IONIDE-005 : Test for empty strings should use the String.Length property or the String.IsNullOrEmpty method.
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(319,18): Warning IONIDE-005 : Test for empty strings should use the String.Length property or the String.IsNullOrEmpty method.
# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Library.fs(65,20): Info IONIDE-002 : Prefer postfix syntax for arrays.

コマンドのオプションは文書に載ってなかったので、 --help で確認した。 SARIF report を出力するには --report に file path を指定するだけで良い。

とりあえずコード解析はうまくできるのがわかったので SnippetPredictor の CI に組み込んだ。 #45

CI 的には warn は error にして task をこかせたいところだが、今のところ --treat_as_error で個別の識別子を指定するしかないっぽい。どうしたもんかな。 他にも、今は test の project を解析対象にしてないのもあるし、 Directory.Build.props で全体に反映するのがいいかな。 Fantomas では tool の fsharp-analyzers は使ってなくて MSBuild でやってるのだけど、同じ方法を採用するかはちょっと検討。

もうちょっと使ってみて、いい感じの設定ができたら pocof にも反映させよう。