-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
Library.fs
91 lines (74 loc) · 3.66 KB
/
Library.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
namespace Ionide.ProjInfo
open System
open System.IO
open Ionide.ProjInfo.Types
open FSharp.Compiler.CodeAnalysis
module FCS =
let private loadFromDotnetDll (p: ProjectOptions) =
/// because only a successful compilation will be written to a DLL, we can rely on
/// the file metadata for things like write times
let projectFile = FileInfo p.TargetPath
let getStamp () = projectFile.LastWriteTimeUtc
let getStream (ctok: System.Threading.CancellationToken) =
try
projectFile.OpenRead() :> Stream
|> Some
with _ ->
None
let delayedReader = DelayedILModuleReader(p.TargetPath, getStream)
FSharpReferencedProject.PEReference(getStamp, delayedReader)
let private makeFCSOptions mapProjectToReference (project: ProjectOptions) = {
ProjectId = None
ProjectFileName = project.ProjectFileName
SourceFiles = List.toArray project.SourceFiles
OtherOptions = List.toArray project.OtherOptions
ReferencedProjects =
project.ReferencedProjects
|> List.toArray
|> Array.choose mapProjectToReference
IsIncompleteTypeCheckEnvironment = false
UseScriptResolutionRules = false
LoadTime = project.LoadTime
UnresolvedReferences = None // it's always None
OriginalLoadReferences = [] // it's always empty list
Stamp = None
}
let rec private makeProjectReference isKnownProject makeFSharpProjectReference (p: ProjectReference) : FSharpReferencedProject option =
let knownProject = isKnownProject p
let isDotnetProject (knownProject: ProjectOptions option) =
match knownProject with
| Some p ->
(p.ProjectFileName.EndsWith(".csproj")
|| p.ProjectFileName.EndsWith(".vbproj"))
&& File.Exists p.ResolvedTargetPath
| None -> false
if p.ProjectFileName.EndsWith ".fsproj" then
knownProject
|> Option.map (fun (p: ProjectOptions) ->
let theseOptions = makeFSharpProjectReference p
FSharpReferencedProject.FSharpReference(p.ResolvedTargetPath, theseOptions)
)
elif isDotnetProject knownProject then
knownProject
|> Option.map loadFromDotnetDll
else
None
let mapManyOptions (allKnownProjects: ProjectOptions seq) : FSharpProjectOptions seq =
seq {
let dict = System.Collections.Concurrent.ConcurrentDictionary<ProjectOptions, FSharpProjectOptions>()
let isKnownProject (p: ProjectReference) =
allKnownProjects
|> Seq.tryFind (fun kp -> kp.ProjectFileName = p.ProjectFileName)
let rec makeFSharpProjectReference (p: ProjectOptions) =
let factory = makeProjectReference isKnownProject makeFSharpProjectReference
dict.GetOrAdd(p, (fun p -> makeFCSOptions factory p))
for project in allKnownProjects do
let thisProject =
dict.GetOrAdd(project, (fun p -> makeFCSOptions (makeProjectReference isKnownProject makeFSharpProjectReference) p))
yield thisProject
}
let rec mapToFSharpProjectOptions (projectOptions: ProjectOptions) (allKnownProjects: ProjectOptions seq) : FSharpProjectOptions =
let isKnownProject (d: ProjectReference) =
allKnownProjects
|> Seq.tryFind (fun n -> n.ProjectFileName = d.ProjectFileName)
makeFCSOptions (makeProjectReference isKnownProject (fun p -> mapToFSharpProjectOptions p allKnownProjects)) projectOptions