Skip to content

Commit 4d57d2d

Browse files
authored
Update F# Analyzers page. (#24)
1 parent a1535d3 commit 4d57d2d

File tree

1 file changed

+3
-91
lines changed

1 file changed

+3
-91
lines changed

content/Libraries/fsanalyzers.md

Lines changed: 3 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,11 @@ menu_order: 2
55

66
# FSharp.Analyzers.SDK
77

8-
**GitHub link:** [https://github.com/ionide/FSharp.Analyzers.SDK](https://github.com/ionide/FSharp.Analyzers.SDK)
8+
**GitHub link:** [https://github.com/ionide/FSharp.Analyzers.SDK](https://github.com/ionide/FSharp.Analyzers.SDK)
99
**License:** [MIT](https://github.com/ionide/FSharp.Analyzers.SDK/blob/master/LICENSE.md)
1010

1111
`FSharp.Analyzers.SDK` is a library used for building custom analyzers for FSAC / F# editors. F# analyzers are live, real-time, project-based plugins that enables diagnosis of source code and surfacing of custom errors, warnings and code fixes into the editor. They're heavily influenced and inspired by [Roslyn Analyzers](https://docs.microsoft.com/en-us/visualstudio/code-quality/roslyn-analyzers-overview?view=vs-2019).
1212

13-
Read more about F# Analyzers here - [https://medium.com/lambda-factory/introducing-f-analyzers-772487889429](https://medium.com/lambda-factory/introducing-f-analyzers-772487889429)
13+
Read more about F# Analyzers here - [https://medium.com/lambda-factory/introducing-f-analyzers-772487889429](https://medium.com/lambda-factory/introducing-f-analyzers-772487889429) (<small>Note that the API has changed since this article.</small>)
1414

15-
## Writing Analyzers
16-
17-
Analyzers that are consumed by this SDK and from Ionide are simply .NET core class libraries. These class libraries expose a *value* of type `Analyzer` which is effectively a function that has input of type `Context` and returns a list of `Message` records:
18-
19-
```fsharp
20-
module BadCodeAnalyzer
21-
22-
open FSharp.Analyzers.SDK
23-
24-
[<Analyzer>]
25-
let badCodeAnalyzer : Analyzer =
26-
fun (context: Context) =
27-
// inspect context to determine the error/warning messages
28-
[ ]
29-
```
30-
31-
Notice how we expose the function `BadCodeAnalyzer.badCodeAnalyzer` with an attribute `[<Analyzer>]` that allows the SDK to detect the function. The input `Context` is a record that contains information about a single F# file such as the typed AST, the AST, the file content, the file name and more. The SDK runs this function against all files of a project during editing. The output messages that come out of the function are eventually used by Ionide to highlight the inspected code as a warning or error depending on the `Severity` level of each message.
32-
33-
### Analyzer Requirements
34-
35-
Analyzers are .NET Core class libraries and they are distributed as such. However, since the SDK relies on dynamically loading the analyzers during runtime, there are some requirements to get them to work properly:
36-
- The analyzer class library has to target the `net6.0` framework
37-
- The analyzer has to reference the latest `FSharp.Analyzers.SDK` (at least the version used by FsAutoComplete which is subsequently used by Ionide)
38-
39-
### Packaging and Distribution
40-
41-
Since analyzers are just .NET core libraries, you can distribute them to the nuget registry just like you would with a normal .NET package. Simply run `dotnet pack --configuration Release` against the analyzer project to get a nuget package and publish it with
42-
43-
```
44-
dotnet nuget push {NugetPackageFullPath} -s nuget.org -k {NugetApiKey}
45-
```
46-
47-
However, the story is different and slightly more complicated when your analyzer package has third-party dependencies also coming from nuget. Since the SDK dynamically loads the package assemblies (`.dll` files), the assemblies of the dependencies has be located *next* to the main assembly of the analyzer. Using `dotnet pack` will **not** include these dependencies into the output Nuget package. More specifically, the `./lib/net6.0` directory of the nuget package must have all the required assemblies, also those from third-party packages. In order to package the analyzer properly with all the assemblies, you need to take the output you get from running:
48-
49-
```
50-
dotnet publish --configuration Release --framework net6.0
51-
```
52-
53-
against the analyzer project and put every file from that output into the `./lib/net6.0` directory of the nuget package. This requires some manual work by unzipping the nuget package first (because it is just an archive), modifying the directories then zipping the package again. It can be done using a FAKE build target to automate the work:
54-
55-
```fsharp
56-
// make ZipFile available
57-
#r "System.IO.Compression.FileSystem.dll"
58-
59-
let releaseNotes = ReleaseNotes.load "RELEASE_NOTES.md"
60-
61-
Target.create "PackAnalyzer" (fun _ ->
62-
let analyzerProject = "src" </> "BadCodeAnalyzer"
63-
let args =
64-
[
65-
"pack"
66-
"--configuration Release"
67-
sprintf "/p:PackageVersion=%s" releaseNotes.NugetVersion
68-
sprintf "/p:PackageReleaseNotes=\"%s\"" (String.concat "\n" releaseNotes.Notes)
69-
sprintf "--output %s" (__SOURCE_DIRECTORY__ </> "dist")
70-
]
71-
72-
// create initial nuget package
73-
let exitCode = Shell.Exec("dotnet", String.concat " " args, analyzerProject)
74-
if exitCode <> 0 then
75-
failwith "dotnet pack failed"
76-
else
77-
match Shell.Exec("dotnet", "publish --configuration Release --framework net6.0", analyzerProject) with
78-
| 0 ->
79-
let nupkg =
80-
System.IO.Directory.GetFiles(__SOURCE_DIRECTORY__ </> "dist")
81-
|> Seq.head
82-
|> IO.Path.GetFullPath
83-
84-
let nugetParent = DirectoryInfo(nupkg).Parent.FullName
85-
let nugetFileName = IO.Path.GetFileNameWithoutExtension(nupkg)
86-
87-
let publishPath = analyzerProject </> "bin" </> "Release" </> "net6.0" </> "publish"
88-
// Unzip the nuget
89-
ZipFile.ExtractToDirectory(nupkg, nugetParent </> nugetFileName)
90-
// delete the initial nuget package
91-
File.Delete nupkg
92-
// remove stuff from ./lib/net6.0
93-
Shell.deleteDir (nugetParent </> nugetFileName </> "lib" </> "net6.0")
94-
// move the output of publish folder into the ./lib/net6.0 directory
95-
Shell.copyDir (nugetParent </> nugetFileName </> "lib" </> "net6.0") publishPath (fun _ -> true)
96-
// re-create the nuget package
97-
ZipFile.CreateFromDirectory(nugetParent </> nugetFileName, nupkg)
98-
// delete intermediate directory
99-
Shell.deleteDir(nugetParent </> nugetFileName)
100-
| _ ->
101-
failwith "dotnet publish failed"
102-
)
103-
```
15+
Check out the [FSharp.Analyzers.SDK documentation](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started.html).

0 commit comments

Comments
 (0)