forked from fsprojects/fantomas
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFakeHelpers.fs
129 lines (107 loc) · 4.1 KB
/
FakeHelpers.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
module Fantomas.FakeHelpers
open System
open System.IO
open FSharp.Compiler.SourceCodeServices
open Fantomas
open Fantomas.FormatConfig
// Share an F# checker instance across formatting calls
let sharedChecker = lazy(FSharpChecker.Create())
exception CodeFormatException of (string * Option<Exception>) array with
override x.ToString() =
let errors =
x.Data0
|> Array.choose (fun z ->
match z with
| file, Some ex -> Some(file, ex)
| _ -> None)
|> Array.map (fun z ->
let file, ex = z
file + ":\r\n" + ex.Message + "\r\n\r\n")
let files =
x.Data0
|> Array.map (fun z ->
match z with
| file, Some _ -> file + " !"
| file, None -> file)
String.Join(String.Empty, errors)
+ "The following files aren't formatted properly:"
+ "\r\n- " + String.Join("\r\n- ", files)
type FormatResult =
| Formatted of string * string
| Unchanged of string
| Error of string * Exception
let createParsingOptionsFromFile fileName =
{ FSharpParsingOptions.Default with SourceFiles = [|fileName|] }
let formatFileAsync config (file : string) =
let originalContent = File.ReadAllText file
async {
try
let! formattedContent =
CodeFormatter.FormatDocumentAsync(file, SourceOrigin.SourceString originalContent, config,
createParsingOptionsFromFile file ,sharedChecker.Value)
if originalContent <> formattedContent then
let! isValid =
CodeFormatter.IsValidFSharpCodeAsync(file, (SourceOrigin.SourceString(formattedContent)),
createParsingOptionsFromFile file, sharedChecker.Value)
if not isValid then
raise <| FormatException "Formatted content is not valid F# code"
let tempFile = Path.GetTempFileName()
use output = new StreamWriter(tempFile)
output.Write formattedContent
output.Flush()
return Formatted(file, tempFile)
else
return Unchanged file
with
| ex -> return Error(file, ex)
}
let formatFilesAsync config files =
files
|> Seq.map (formatFileAsync config)
|> Async.Parallel
let internal removeTemporaryFiles formatResult =
match formatResult with
| Formatted(_, tmp) -> File.Delete(tmp)
| _ -> ()
let formatCode config files =
async {
let! results = files |> formatFilesAsync config
try
// Check for formatting errors:
let errors =
results
|> Array.choose (fun x ->
match x with
| Error(file, ex) -> Some(file, Some(ex))
| _ -> None)
if not <| Array.isEmpty errors then
raise <| CodeFormatException errors
// Overwritte source files with formatted content
let result =
results
|> Array.choose (fun x ->
match x with
| Formatted(source, tmp) ->
File.Copy(tmp, source, true)
Some source
| _ -> None)
return result
finally
results |> Array.iter removeTemporaryFiles
}
let checkCode config files =
async {
let! results = files |> formatFilesAsync config
try
let changes =
results
|> Array.choose (fun x ->
match x with
| Formatted(file, _) -> Some(file, None)
| Error(file, ex) -> Some(file, Some(ex))
| _ -> None)
if Array.exists (function | _, Some(_) -> true | _ -> false) changes then
raise <| CodeFormatException changes
finally
results |> Array.iter removeTemporaryFiles
}