diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index bda0692f15..6e3cd0f5b4 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:8.0.400
+FROM mcr.microsoft.com/dotnet/sdk:10.0.100
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
diff --git a/Directory.Build.props b/Directory.Build.props
index e39f292f81..1db3744778 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -45,7 +45,7 @@ Some common use cases include:
- e668b90e3c087e5fba8a855e502af60bf35be45e
+ 43932b4c7984d6562e91e5f1484868cd4f5befcf
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c3a3050a0a..0f4d93870d 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,7 +4,7 @@
true
-
+
diff --git a/build.fsx b/build.fsx
index 382cae6feb..158f30082a 100644
--- a/build.fsx
+++ b/build.fsx
@@ -233,6 +233,8 @@ pipeline "Init" {
"src/Compiler/Utilities/NullnessShims.fs"
"src/Compiler/Utilities/Activity.fsi"
"src/Compiler/Utilities/Activity.fs"
+ "src/Compiler/Utilities/Caches.fsi"
+ "src/Compiler/Utilities/Caches.fs"
"src/Compiler/Utilities/sformat.fsi"
"src/Compiler/Utilities/sformat.fs"
"src/Compiler/Utilities/sr.fsi"
@@ -301,6 +303,10 @@ pipeline "Init" {
"src/Compiler/SyntaxTree/SyntaxTree.fs"
"src/Compiler/SyntaxTree/SyntaxTreeOps.fsi"
"src/Compiler/SyntaxTree/SyntaxTreeOps.fs"
+ "src/Compiler/SyntaxTree/WarnScopes.fsi"
+ "src/Compiler/SyntaxTree/WarnScopes.fs"
+ "src/Compiler/SyntaxTree/LexerStore.fsi"
+ "src/Compiler/SyntaxTree/LexerStore.fs"
"src/Compiler/SyntaxTree/ParseHelpers.fsi"
"src/Compiler/SyntaxTree/ParseHelpers.fs"
"src/Compiler/SyntaxTree/LexHelpers.fsi"
diff --git a/docs/docs/contributors/Transforming.md b/docs/docs/contributors/Transforming.md
index 0b96378684..b4ecfddde0 100644
--- a/docs/docs/contributors/Transforming.md
+++ b/docs/docs/contributors/Transforming.md
@@ -74,6 +74,15 @@ let a =
Depending on the defines `[]` or `["DEBUG"]`, the AST will be different.
The tree will also be created based on a single code path.
+You can use your locally installed F# compiler to parse a file and view the AST via:
+
+```shell
+# Tip: figure out the location of your installed sdk
+whereis dotnet
+# Invoke the parser
+dotnet '/Users/nojaf/Library/Application Support/dnvm/dn/sdk/10.0.100/FSharp/fsc.dll' --parseonly --ast foo.fs
+```
+
### Transform untyped AST to Oak
The untyped syntax tree from the F# compiler is used as an intermediate representation of source code in the process of transforming a text file to binary.
diff --git a/global.json b/global.json
index 6f6aff9de6..971b5004e2 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.400",
+ "version": "10.0.100",
"rollForward": "latestPatch"
}
}
\ No newline at end of file
diff --git a/scripts/ast.fsx b/scripts/ast.fsx
new file mode 100644
index 0000000000..01bb5e890f
--- /dev/null
+++ b/scripts/ast.fsx
@@ -0,0 +1,19 @@
+#r "../artifacts/bin/Fantomas.FCS/debug/Fantomas.FCS.dll"
+
+open System.IO
+
+match Array.tryHead fsi.CommandLineArgs with
+| Some scriptPath ->
+ let scriptFile = FileInfo(scriptPath)
+ let sourceFile = FileInfo(Path.Combine(__SOURCE_DIRECTORY__, __SOURCE_FILE__))
+
+ if scriptFile.FullName = sourceFile.FullName then
+ let sample = File.ReadAllText(fsi.CommandLineArgs.[fsi.CommandLineArgs.Length - 1])
+ let isSignature = sample.EndsWith(".fsi")
+
+ let ast =
+ Fantomas.FCS.Parse.parseFile isSignature (Fantomas.FCS.Text.SourceText.ofString sample) []
+ |> fst
+
+ ast |> printfn "%A"
+| _ -> printfn "Usage: dotnet fsi ast.fsx "
diff --git a/scripts/oak.fsx b/scripts/oak.fsx
new file mode 100644
index 0000000000..d7a608c6dc
--- /dev/null
+++ b/scripts/oak.fsx
@@ -0,0 +1,35 @@
+#r "../artifacts/bin/Fantomas.FCS/debug/Fantomas.FCS.dll"
+#r "../artifacts/bin/Fantomas.Core/debug/Fantomas.Core.dll"
+
+open System.Threading.Tasks
+open Fantomas.Core
+
+let parseOak (input: string) (isSignature: bool) : Task =
+ task {
+ try
+ let! oaks = CodeFormatter.ParseOakAsync(isSignature, input)
+
+ match Array.tryHead oaks with
+ | None -> return "No Oak found in input"
+ | Some(oak, _) -> return (string oak)
+
+ with ex ->
+ return $"Error while parsing to Oak: %A{ex}"
+ }
+
+open System.IO
+
+match Array.tryHead fsi.CommandLineArgs with
+| Some scriptPath ->
+ let scriptFile = FileInfo(scriptPath)
+ let sourceFile = FileInfo(Path.Combine(__SOURCE_DIRECTORY__, __SOURCE_FILE__))
+
+ if scriptFile.FullName = sourceFile.FullName then
+ let sample = File.ReadAllText(fsi.CommandLineArgs.[fsi.CommandLineArgs.Length - 1])
+ let isSignature = sample.EndsWith(".fsi")
+
+ parseOak sample isSignature
+ |> Async.AwaitTask
+ |> Async.RunSynchronously
+ |> printfn "%s"
+| _ -> printfn "Usage: dotnet fsi oak.fsx "
diff --git a/src/Fantomas.Benchmarks/Fantomas.Benchmarks.fsproj b/src/Fantomas.Benchmarks/Fantomas.Benchmarks.fsproj
index 5152fe51d8..88a3ddcbda 100644
--- a/src/Fantomas.Benchmarks/Fantomas.Benchmarks.fsproj
+++ b/src/Fantomas.Benchmarks/Fantomas.Benchmarks.fsproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net10.0
false
diff --git a/src/Fantomas.Benchmarks/packages.lock.json b/src/Fantomas.Benchmarks/packages.lock.json
index bad220a5b4..488ed3ebf2 100644
--- a/src/Fantomas.Benchmarks/packages.lock.json
+++ b/src/Fantomas.Benchmarks/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net8.0": {
+ "net10.0": {
"BenchmarkDotNet": {
"type": "Direct",
"requested": "[0.14.0, )",
@@ -22,9 +22,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"G-Research.FSharp.Analyzers": {
"type": "Direct",
@@ -73,13 +73,7 @@
"resolved": "4.1.0",
"contentHash": "bNzTyxP3iD5FPFHfVDl15Y6/wSoI7e3MeV0lOaj9igbIKTjgrmuw6LoVJ06jUNFA7+KaDC/OIsStWl/FQJz6sQ==",
"dependencies": {
- "Microsoft.CodeAnalysis.Analyzers": "3.3.3",
- "System.Collections.Immutable": "5.0.0",
- "System.Memory": "4.5.4",
- "System.Reflection.Metadata": "5.0.0",
- "System.Runtime.CompilerServices.Unsafe": "5.0.0",
- "System.Text.Encoding.CodePages": "4.5.1",
- "System.Threading.Tasks.Extensions": "4.5.4"
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.3"
}
},
"Microsoft.CodeAnalysis.CSharp": {
@@ -104,19 +98,13 @@
"resolved": "2.2.332302",
"contentHash": "Hp84ivxSKIMTBzYSATxmUsm3YSXHWivcwiRRbsydGmqujMUK8BAueLN0ssAVEOkOBmh0vjUBhrq7YcroT7VCug==",
"dependencies": {
- "Microsoft.Diagnostics.NETCore.Client": "0.2.251802",
- "System.Collections.Immutable": "5.0.0",
- "System.Runtime.CompilerServices.Unsafe": "5.0.0"
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.251802"
}
},
"Microsoft.Diagnostics.Tracing.TraceEvent": {
"type": "Transitive",
"resolved": "3.1.8",
- "contentHash": "kl3UMrZKSeSEYZ8rt/GjLUQToREjgQABqfg6PzQBmSlYHTZOKE9ePEOS2xptROQ9SVvngg3QGX51TIT11iZ0wA==",
- "dependencies": {
- "Microsoft.Win32.Registry": "4.4.0",
- "System.Runtime.CompilerServices.Unsafe": "5.0.0"
- }
+ "contentHash": "kl3UMrZKSeSEYZ8rt/GjLUQToREjgQABqfg6PzQBmSlYHTZOKE9ePEOS2xptROQ9SVvngg3QGX51TIT11iZ0wA=="
},
"Microsoft.DotNet.PlatformAbstractions": {
"type": "Transitive",
@@ -180,31 +168,13 @@
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.1.1",
- "contentHash": "scJ1GZNIxMmjpENh0UZ8XCQ6vzr/LzeF9WvEA51Ix2OQGAs9WPgPu8ABVUdvpKPLuor/t05gm6menJK3PwqOXg==",
- "dependencies": {
- "System.Memory": "4.5.1",
- "System.Runtime.CompilerServices.Unsafe": "4.5.1"
- }
+ "contentHash": "scJ1GZNIxMmjpENh0UZ8XCQ6vzr/LzeF9WvEA51Ix2OQGAs9WPgPu8ABVUdvpKPLuor/t05gm6menJK3PwqOXg=="
},
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ=="
},
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.3",
- "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
- },
- "Microsoft.Win32.Registry": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
"Perfolizer": {
"type": "Transitive",
"resolved": "0.3.17",
@@ -221,91 +191,20 @@
"contentHash": "MF1CHaRcC+MLFdnDthv4/bKWBZnlnSpkGqa87pKukQefgEdwtb9zFW6zs0GjPp73qtpYYg4q6PEKbzJbxCpKfw==",
"dependencies": {
"Microsoft.NETCore.Platforms": "5.0.0",
- "Microsoft.Win32.Registry": "5.0.0",
"System.CodeDom": "5.0.0"
}
},
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ=="
- },
- "System.Runtime.CompilerServices.Unsafe": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA=="
- },
- "System.Security.AccessControl": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Security.Principal.Windows": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
- },
- "System.Text.Encoding.CodePages": {
- "type": "Transitive",
- "resolved": "4.5.1",
- "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "2.1.2",
- "System.Runtime.CompilerServices.Unsafe": "4.5.2"
- }
- },
- "System.Threading.Tasks.Extensions": {
- "type": "Transitive",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg=="
- },
"fantomas.core": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"Fantomas.FCS": "[1.0.0, )"
}
},
"fantomas.fcs": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
- "System.Collections.Immutable": "[8.0.0, )",
- "System.Diagnostics.DiagnosticSource": "[8.0.1, )",
- "System.Memory": "[4.6.0, )",
- "System.Runtime": "[4.3.1, )"
- }
- },
- "System.Collections.Immutable": {
- "type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "CentralTransitive",
- "requested": "[8.0.1, )",
- "resolved": "8.0.1",
- "contentHash": "vaoWjvkG1aenR2XdjaVivlCV9fADfgyhW5bZtXT23qaEea0lWiUljdQuze4E31vKM7ZWJaSUsbYIKE3rnzfZUg=="
- },
- "System.Memory": {
- "type": "CentralTransitive",
- "requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "OEkbBQoklHngJ8UD8ez2AERSk2g+/qpAaSWWCBFbpH727HxDq5ydVkuncBaKcKfwRqXGWx64dS6G1SUScMsitg=="
- },
- "System.Runtime": {
- "type": "CentralTransitive",
- "requested": "[4.3.1, )",
- "resolved": "4.3.1",
- "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.1",
- "Microsoft.NETCore.Targets": "1.1.3"
+ "FSharp.Core": "[9.0.300, )"
}
}
}
diff --git a/src/Fantomas.Client.Tests/Fantomas.Client.Tests.fsproj b/src/Fantomas.Client.Tests/Fantomas.Client.Tests.fsproj
index 3fe6e272c0..b1ea8b9214 100644
--- a/src/Fantomas.Client.Tests/Fantomas.Client.Tests.fsproj
+++ b/src/Fantomas.Client.Tests/Fantomas.Client.Tests.fsproj
@@ -2,7 +2,7 @@
FS0988
- net8.0
+ net10.0
false
false
Major
diff --git a/src/Fantomas.Client.Tests/packages.lock.json b/src/Fantomas.Client.Tests/packages.lock.json
index 962b7621bb..158cd732e4 100644
--- a/src/Fantomas.Client.Tests/packages.lock.json
+++ b/src/Fantomas.Client.Tests/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net8.0": {
+ "net10.0": {
"CliWrap": {
"type": "Direct",
"requested": "[3.6.7, )",
@@ -10,9 +10,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"G-Research.FSharp.Analyzers": {
"type": "Direct",
@@ -75,10 +75,7 @@
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.12.0",
- "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==",
- "dependencies": {
- "System.Reflection.Metadata": "1.6.0"
- }
+ "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ=="
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
@@ -114,24 +111,13 @@
"contentHash": "r4G7uHHfoo8LCilPOdtf2C+Q5ymHOAXtciT4ZtB2xRlAvv4gPkWBYNAijFblStv3+uidp81j5DP11jMZl4BfJw==",
"dependencies": {
"Microsoft.VisualStudio.Threading": "17.10.48",
- "Microsoft.VisualStudio.Validation": "17.8.8",
- "System.IO.Pipelines": "8.0.0"
+ "Microsoft.VisualStudio.Validation": "17.8.8"
}
},
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
- },
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "1.6.0",
- "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
- },
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
@@ -159,8 +145,7 @@
"Microsoft.VisualStudio.Threading.Analyzers": "17.10.48",
"Microsoft.VisualStudio.Validation": "17.8.8",
"Nerdbank.Streams": "2.11.74",
- "Newtonsoft.Json": "13.0.1",
- "System.IO.Pipelines": "8.0.0"
+ "Newtonsoft.Json": "13.0.1"
}
}
}
diff --git a/src/Fantomas.Client/packages.lock.json b/src/Fantomas.Client/packages.lock.json
index c389b5e46d..01c36cdedc 100644
--- a/src/Fantomas.Client/packages.lock.json
+++ b/src/Fantomas.Client/packages.lock.json
@@ -16,9 +16,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"G-Research.FSharp.Analyzers": {
"type": "Direct",
diff --git a/src/Fantomas.Core.Tests/ASTTransformerTests.fs b/src/Fantomas.Core.Tests/ASTTransformerTests.fs
index 498f9c86c5..2cb7409581 100644
--- a/src/Fantomas.Core.Tests/ASTTransformerTests.fs
+++ b/src/Fantomas.Core.Tests/ASTTransformerTests.fs
@@ -11,8 +11,8 @@ open Fantomas.Core
let ``avoid stack-overflow in long array/list, 2485`` () =
let mkStringExpr () =
SynExpr.Const(
- SynConst.String((System.Guid.NewGuid().ToString("N"), SynStringKind.Regular, Range.Zero)),
- Range.Zero
+ SynConst.String((System.Guid.NewGuid().ToString("N"), SynStringKind.Regular, Range.range0)),
+ Range.range0
)
let longArrayExpr: SynExpr =
@@ -27,34 +27,32 @@ let ``avoid stack-overflow in long array/list, 2485`` () =
true,
mkStringExpr (),
childExpr,
- Range.Zero,
+ Range.range0,
SynExprSequentialTrivia.Zero
))
- SynExpr.ArrayOrListComputed(true, mkArray 0 (mkStringExpr ()), Range.Zero)
+ SynExpr.ArrayOrListComputed(true, mkArray 0 (mkStringExpr ()), Range.range0)
let ast =
ParsedInput.ImplFile(
ParsedImplFileInput(
"filename.fsx",
true,
- QualifiedNameOfFile(Ident("", Range.Zero)),
- [],
+ QualifiedNameOfFile(Ident("", Range.range0)),
[],
[ SynModuleOrNamespace(
[],
false,
SynModuleOrNamespaceKind.AnonModule,
- [ SynModuleDecl.Expr(longArrayExpr, Range.Zero) ],
+ [ SynModuleDecl.Expr(longArrayExpr, Range.range0) ],
PreXmlDoc.Empty,
[],
None,
- Range.Zero,
+ Range.range0,
{ LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.None }
) ],
(false, false),
- { ConditionalDirectives = []
- CodeComments = [] },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
diff --git a/src/Fantomas.Core.Tests/AutoPropertiesTests.fs b/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
index ab6a962df9..b58e43de7a 100644
--- a/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
+++ b/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
@@ -73,23 +73,3 @@ type X =
new: unit -> X
member internal Y: int with public get, private set
"""
-
-[]
-let ``abstract member with public get, private set`` () =
- formatSignatureString
- """
-namespace Meh
-
-type X =
- abstract Y: int with public get, private set
-"""
- config
- |> prepend newline
- |> should
- equal
- """
-namespace Meh
-
-type X =
- abstract Y: int with public get, private set
-"""
diff --git a/src/Fantomas.Core.Tests/CodeFormatterTests.fs b/src/Fantomas.Core.Tests/CodeFormatterTests.fs
index f44801cc39..89e0f862cf 100644
--- a/src/Fantomas.Core.Tests/CodeFormatterTests.fs
+++ b/src/Fantomas.Core.Tests/CodeFormatterTests.fs
@@ -4,7 +4,6 @@ open Fantomas.Core.SyntaxOak
open NUnit.Framework
open Fantomas.FCS.Text
open Fantomas.Core
-open Fantomas.Core.SyntaxOak
open Fantomas.Core.Tests.TestHelpers
[]
diff --git a/src/Fantomas.Core.Tests/CodePrinterHelperFunctionsTests.fs b/src/Fantomas.Core.Tests/CodePrinterHelperFunctionsTests.fs
index 82d131e21a..df920d6c59 100644
--- a/src/Fantomas.Core.Tests/CodePrinterHelperFunctionsTests.fs
+++ b/src/Fantomas.Core.Tests/CodePrinterHelperFunctionsTests.fs
@@ -209,7 +209,7 @@ let a =
// Let's create a dummy Oak
// In practise, a FCS Syntax tree will be transformed to an Oak
- let zeroRange = Fantomas.FCS.Text.Range.Zero
+ let zeroRange = Fantomas.FCS.Text.Range.range0
let stn text = SingleTextNode(text, zeroRange)
let tree =
@@ -231,6 +231,7 @@ let a =
None,
stn "=",
Expr.Ident(stn "b"),
+ None,
zeroRange
)
) ],
@@ -321,7 +322,7 @@ let b = 2
"""
// Imagine that we always want to print a new line between let bindings.
- let zeroRange = Fantomas.FCS.Text.Range.Zero
+ let zeroRange = Fantomas.FCS.Text.Range.range0
let stn text = SingleTextNode(text, zeroRange)
let mkBinding name body =
@@ -338,6 +339,7 @@ let b = 2
None,
stn "=",
Expr.Ident(stn body),
+ None,
zeroRange
)
diff --git a/src/Fantomas.Core.Tests/CommentTests.fs b/src/Fantomas.Core.Tests/CommentTests.fs
index e3285e3e3c..55e064344f 100644
--- a/src/Fantomas.Core.Tests/CommentTests.fs
+++ b/src/Fantomas.Core.Tests/CommentTests.fs
@@ -5,6 +5,11 @@ open FsUnit
open Fantomas.Core.Tests.TestHelpers
open Fantomas.Core
+[]
+let ``should keep sticky-to-the-left comments after #if directives`` () =
+ formatSourceString "#if DEBUG // debug only\n#endif\n" config
+ |> should equal "#if DEBUG // debug only\n#endif\n"
+
[]
let ``should keep sticky-to-the-left comments after nowarn directives`` () =
formatSourceString """#nowarn "51" // address-of operator can occur in the code""" config
diff --git a/src/Fantomas.Core.Tests/ComputationExpressionTests.fs b/src/Fantomas.Core.Tests/ComputationExpressionTests.fs
index 1b7912be90..44e744d353 100644
--- a/src/Fantomas.Core.Tests/ComputationExpressionTests.fs
+++ b/src/Fantomas.Core.Tests/ComputationExpressionTests.fs
@@ -1642,7 +1642,9 @@ let private removeSubscription (log : ILogger) (req : HttpRequest) =
return sendText "Subscription removed"
}
"""
- { config with SpaceBeforeColon = true }
+ { config with
+ SpaceBeforeColon = true
+ MaxValueBindingWidth = 120 }
|> prepend newline
|> should
equal
@@ -2467,3 +2469,89 @@ A() {}
"""
A() { }
"""
+
+[]
+let ``typed let bang expression`` () =
+ formatSourceString
+ """
+async {
+ let! { Name = name }: Person = asyncPerson()
+ return name
+}
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+async {
+ let! { Name = name }: Person = asyncPerson ()
+ return name
+}
+"""
+
+[]
+let ``unwrap union case in computation expression`` () =
+ formatSourceString
+ """
+async {
+ let! Union value = asyncOption()
+ ()
+}
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+async {
+ let! Union value = asyncOption ()
+ ()
+}
+"""
+
+[]
+let ``typed and bang expression`` () =
+ formatSourceString
+ """
+async {
+ let! x: int = doX()
+ and! y: int = doY()
+ return x + y
+}
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+async {
+ let! x: int = doX ()
+ and! y: int = doY ()
+ return x + y
+}
+"""
+
+// In older versions of F# the parser would allow an in keyword after and!
+// However, according to the F# language specification, it is not allowed.
+[]
+let ``and! cannot have an in keyword`` () =
+ formatSourceString
+ """
+comp {
+ let! a = b
+ and! c = d in
+ ()
+}
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+comp {
+ let! a = b
+ and! c = d
+ ()
+}
+"""
diff --git a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
index 6f606dc0ce..433285415b 100644
--- a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
+++ b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
@@ -1,7 +1,7 @@
FS0988
- net8.0
+ net10.0
FS0025
false
Major
diff --git a/src/Fantomas.Core.Tests/FormattingSelectionOnlyTests.fs b/src/Fantomas.Core.Tests/FormattingSelectionOnlyTests.fs
index 6099d0d19a..ee304873d2 100644
--- a/src/Fantomas.Core.Tests/FormattingSelectionOnlyTests.fs
+++ b/src/Fantomas.Core.Tests/FormattingSelectionOnlyTests.fs
@@ -303,3 +303,17 @@ and a b c = 2
"""
config
|> should equal "and a b c = 2"
+
+[]
+let ``format and! binding inside computation expression nojaf`` () =
+ formatSelectionOnly
+ false
+ (mkSelection (3, 4) (3, 19))
+ """
+comp {
+ let! a = b in
+ ()
+}
+"""
+ config
+ |> should equal "let! a = b in"
diff --git a/src/Fantomas.Core.Tests/HashDirectiveTests.fs b/src/Fantomas.Core.Tests/HashDirectiveTests.fs
index 233b10aee6..0edfeb5d08 100644
--- a/src/Fantomas.Core.Tests/HashDirectiveTests.fs
+++ b/src/Fantomas.Core.Tests/HashDirectiveTests.fs
@@ -248,6 +248,7 @@ let ``#help without string`` () =
#help List.map
"""
+// As of F# 10.0, warn directives are treated as trivia like #if, so argruments are not formatted
[]
let ``#nowarn with integer`` () =
formatSourceString
@@ -259,5 +260,5 @@ let ``#nowarn with integer`` () =
|> should
equal
"""
-#nowarn 1182
+#nowarn 1182
"""
diff --git a/src/Fantomas.Core.Tests/LetBindingTests.fs b/src/Fantomas.Core.Tests/LetBindingTests.fs
index 62207419d6..4a4a4e86fc 100644
--- a/src/Fantomas.Core.Tests/LetBindingTests.fs
+++ b/src/Fantomas.Core.Tests/LetBindingTests.fs
@@ -1626,6 +1626,20 @@ stepLog.LogInformation (
)
"""
+[]
+let ``short let binding with in keyword should not add newline`` () =
+ formatSourceString
+ """
+let _ = BlahBlah foo in a
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+let _ = BlahBlah foo in a
+"""
+
[]
let ``in keyword in let binding should stay in one line, 1610`` () =
formatSourceString
diff --git a/src/Fantomas.Core.Tests/QuotationTests.fs b/src/Fantomas.Core.Tests/QuotationTests.fs
index 39f40f8a02..7e6d84f67a 100644
--- a/src/Fantomas.Core.Tests/QuotationTests.fs
+++ b/src/Fantomas.Core.Tests/QuotationTests.fs
@@ -170,3 +170,19 @@ test
Pop = null } }
@>
"""
+
+[]
+let ``quotation in anonymous record`` () =
+ formatSourceString
+ """
+{| A= <@ 1 + 1 @>|}
+{| A = <@@ 1 + 1 @@>|}
+"""
+ { config with IndentSize = 2 }
+ |> prepend newline
+ |> should
+ equal
+ """
+{| A = <@ 1 + 1 @> |}
+{| A = <@@ 1 + 1 @@> |}
+"""
diff --git a/src/Fantomas.Core.Tests/SynLongIdentTests.fs b/src/Fantomas.Core.Tests/SynLongIdentTests.fs
index eed7c2d0e5..ef99c6e95a 100644
--- a/src/Fantomas.Core.Tests/SynLongIdentTests.fs
+++ b/src/Fantomas.Core.Tests/SynLongIdentTests.fs
@@ -344,7 +344,7 @@ let path =
[]
let ``backticks can be added from AST only scenarios`` () =
let tree =
- let testIdent = Ident("Test", Range.Zero)
+ let testIdent = Ident("Test", Range.range0)
ParsedInput.ImplFile(
ParsedImplFileInput(
@@ -352,7 +352,6 @@ let ``backticks can be added from AST only scenarios`` () =
true,
QualifiedNameOfFile testIdent,
[],
- [],
[ SynModuleOrNamespace(
[ testIdent ],
false,
@@ -361,24 +360,23 @@ let ``backticks can be added from AST only scenarios`` () =
SynExpr.LongIdent(
false,
SynLongIdent(
- [ Ident("new", Range.Zero) ],
+ [ Ident("new", Range.range0) ],
[],
[ Some(IdentTrivia.OriginalNotation "``new``") ]
),
None,
- Range.Zero
+ Range.range0
),
- Range.Zero
+ Range.range0
) ],
PreXmlDoc.Empty,
[],
None,
- Range.Zero,
+ Range.range0,
{ LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.None }
) ],
(true, false),
- { ConditionalDirectives = []
- CodeComments = [] },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
diff --git a/src/Fantomas.Core.Tests/TestHelpers.fs b/src/Fantomas.Core.Tests/TestHelpers.fs
index 616b5e2d8e..76c88a3d35 100644
--- a/src/Fantomas.Core.Tests/TestHelpers.fs
+++ b/src/Fantomas.Core.Tests/TestHelpers.fs
@@ -31,7 +31,7 @@ let formatFSharpString isFsiFile (s: string) config =
if formattedCode <> secondFormattedCode then
failwith $"The formatted result was not idempotent.\n%s{formattedCode}\n%s{secondFormattedCode}"
- printfn "formatted code:\n%s\n" formattedCode
+ // printfn "formatted code:\n%s\n" formattedCode
return formattedCode
}
diff --git a/src/Fantomas.Core.Tests/packages.lock.json b/src/Fantomas.Core.Tests/packages.lock.json
index 9d84872dfc..47e54d5b51 100644
--- a/src/Fantomas.Core.Tests/packages.lock.json
+++ b/src/Fantomas.Core.Tests/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net8.0": {
+ "net10.0": {
"FsCheck": {
"type": "Direct",
"requested": "[2.16.5, )",
@@ -13,9 +13,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"FsUnit": {
"type": "Direct",
@@ -75,23 +75,10 @@
"resolved": "17.12.0",
"contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA=="
},
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "1.1.1",
- "contentHash": "TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ=="
- },
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.3",
- "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
- },
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.12.0",
- "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==",
- "dependencies": {
- "System.Reflection.Metadata": "1.6.0"
- }
+ "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ=="
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
@@ -102,11 +89,6 @@
"Newtonsoft.Json": "13.0.1"
}
},
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "1.6.0",
- "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
- },
"TestableIO.System.IO.Abstractions": {
"type": "Transitive",
"resolved": "21.1.3",
@@ -132,18 +114,14 @@
"fantomas.core": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"Fantomas.FCS": "[1.0.0, )"
}
},
"fantomas.fcs": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
- "System.Collections.Immutable": "[8.0.0, )",
- "System.Diagnostics.DiagnosticSource": "[8.0.1, )",
- "System.Memory": "[4.6.0, )",
- "System.Runtime": "[4.3.1, )"
+ "FSharp.Core": "[9.0.300, )"
}
},
"Newtonsoft.Json": {
@@ -151,34 +129,6 @@
"requested": "[13.0.3, )",
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
- },
- "System.Collections.Immutable": {
- "type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "CentralTransitive",
- "requested": "[8.0.1, )",
- "resolved": "8.0.1",
- "contentHash": "vaoWjvkG1aenR2XdjaVivlCV9fADfgyhW5bZtXT23qaEea0lWiUljdQuze4E31vKM7ZWJaSUsbYIKE3rnzfZUg=="
- },
- "System.Memory": {
- "type": "CentralTransitive",
- "requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "OEkbBQoklHngJ8UD8ez2AERSk2g+/qpAaSWWCBFbpH727HxDq5ydVkuncBaKcKfwRqXGWx64dS6G1SUScMsitg=="
- },
- "System.Runtime": {
- "type": "CentralTransitive",
- "requested": "[4.3.1, )",
- "resolved": "4.3.1",
- "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.1",
- "Microsoft.NETCore.Targets": "1.1.3"
- }
}
}
}
diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs
index f7e48dad8d..4d3c8718a1 100644
--- a/src/Fantomas.Core/ASTTransformer.fs
+++ b/src/Fantomas.Core/ASTTransformer.fs
@@ -298,10 +298,14 @@ let mkTuple (creationAide: CreationAide) (exprs: SynExpr list) (commas: range li
/// Recursive and use properties have to be determined at this point
let rec (|LetOrUses|_|) =
function
- | SynExpr.LetOrUse(_, _, xs, LetOrUses(ys, e), _, trivia) ->
+ | SynExpr.LetOrUse { Bindings = xs
+ Body = LetOrUses(ys, e)
+ Trivia = trivia } ->
let xs' = List.mapWithLast (fun b -> b, None) (fun b -> b, trivia.InKeyword) xs
Some(xs' @ ys, e)
- | SynExpr.LetOrUse(_, _, xs, e, _, trivia) ->
+ | SynExpr.LetOrUse { Bindings = xs
+ Body = e
+ Trivia = trivia } ->
let xs' = List.mapWithLast (fun b -> b, None) (fun b -> b, trivia.InKeyword) xs
Some(xs', e)
| _ -> None
@@ -316,54 +320,11 @@ let rec collectComputationExpressionStatements
let bindings =
bindings
|> List.map (fun (b, inNode) ->
- let b: BindingNode = mkBinding creationAide b
-
- let inNode, m =
- match inNode with
- | None -> None, b.Range
- | Some mIn -> Some(stn "in" mIn), unionRanges b.Range mIn
-
- ExprLetOrUseNode(b, inNode, m)
- |> ComputationExpressionStatement.LetOrUseStatement)
+ mkBinding creationAide b (Option.map (stn "in") inNode)
+ |> ComputationExpressionStatement.BindingStatement)
collectComputationExpressionStatements creationAide body (fun bodyStatements ->
[ yield! bindings; yield! bodyStatements ] |> finalContinuation)
- | SynExpr.LetOrUseBang(_,
- isUse,
- _,
- pat,
- expr,
- andBangs,
- body,
- StartRange 4 (mLeading, _m),
- { EqualsRange = Some mEq }) ->
- let letOrUseBang =
- ExprLetOrUseBangNode(
- stn (if isUse then "use!" else "let!") mLeading,
- mkPat creationAide pat,
- stn "=" mEq,
- mkExpr creationAide expr,
- unionRanges mLeading expr.Range
- )
- |> ComputationExpressionStatement.LetOrUseBangStatement
-
- let andBangs =
- andBangs
- |> List.map
- (fun
- (SynExprAndBang(_,
- _,
- _,
- ap,
- ae,
- m,
- { AndBangKeyword = mAnd
- EqualsRange = mEq })) ->
- ExprAndBang(stn "and!" mAnd, mkPat creationAide ap, stn "=" mEq, mkExpr creationAide ae, m)
- |> ComputationExpressionStatement.AndBangStatement)
-
- collectComputationExpressionStatements creationAide body (fun bodyStatements ->
- [ letOrUseBang; yield! andBangs; yield! bodyStatements ] |> finalContinuation)
| SynExpr.Sequential(expr1 = e1; expr2 = e2; trivia = trivia) ->
let continuations
: ((ComputationExpressionStatement list -> ComputationExpressionStatement list)
@@ -966,23 +927,23 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
| SynExpr.AddressOf(false, e, _, StartRange 2 (ampersandToken, _range)) ->
ExprSingleNode(stn "&&" ampersandToken, false, false, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturn((true, _), e, StartRange 5 (yieldKeyword, _range)) ->
- ExprSingleNode(stn "yield" yieldKeyword, true, true, mkExpr creationAide e, exprRange)
+ | SynExpr.YieldOrReturn((true, _), e, _range, trivia) ->
+ ExprSingleNode(stn "yield" trivia.YieldOrReturnKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturn((false, _), e, StartRange 6 (returnKeyword, _range)) ->
- ExprSingleNode(stn "return" returnKeyword, true, true, mkExpr creationAide e, exprRange)
+ | SynExpr.YieldOrReturn((false, _), e, _range, trivia) ->
+ ExprSingleNode(stn "return" trivia.YieldOrReturnKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturnFrom((true, _), e, StartRange 6 (yieldBangKeyword, _range)) ->
- ExprSingleNode(stn "yield!" yieldBangKeyword, true, true, mkExpr creationAide e, exprRange)
+ | SynExpr.YieldOrReturnFrom((true, _), e, _range, trivia) ->
+ ExprSingleNode(stn "yield!" trivia.YieldOrReturnFromKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturnFrom((false, _), e, StartRange 7 (returnBangKeyword, _range)) ->
- ExprSingleNode(stn "return!" returnBangKeyword, true, true, mkExpr creationAide e, exprRange)
+ | SynExpr.YieldOrReturnFrom((false, _), e, _range, trivia) ->
+ ExprSingleNode(stn "return!" trivia.YieldOrReturnFromKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
| SynExpr.Do(e, StartRange 2 (doKeyword, _range)) ->
ExprSingleNode(stn "do" doKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.DoBang(e, StartRange 3 (doBangKeyword, _range)) ->
- ExprSingleNode(stn "do!" doBangKeyword, true, true, mkExpr creationAide e, exprRange)
+ | SynExpr.DoBang(e, _range, trivia) ->
+ ExprSingleNode(stn "do!" trivia.DoBangKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
| SynExpr.Fixed(e, StartRange 5 (fixedKeyword, _range)) ->
ExprSingleNode(stn "fixed" fixedKeyword, true, false, mkExpr creationAide e, exprRange)
@@ -1029,9 +990,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
let fieldNodes =
recordFields
|> List.choose (function
- | SynExprRecordField((fieldName, _), Some mEq, Some expr, _) ->
- let m = unionRanges fieldName.Range expr.Range
-
+ | SynExprRecordField((fieldName, _), Some mEq, Some expr, m, _) ->
Some(
RecordFieldNode(mkSynLongIdent creationAide fieldName, stn "=" mEq, mkExpr creationAide expr, m)
)
@@ -1102,7 +1061,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
stn "interface" mInterface,
mkType creationAide t,
Option.map (stn "with") mWith,
- List.map (mkBinding creationAide) bs,
+ List.map (fun b -> mkBinding creationAide b None) bs,
List.map (mkMemberDefn creationAide) members,
m
))
@@ -1113,7 +1072,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
mkType creationAide t,
Option.map (fun (e, _) -> mkExpr creationAide e) eio,
Option.map (stn "with") withKeyword,
- List.map (mkBinding creationAide) bd,
+ List.map (fun b -> mkBinding creationAide b None) bd,
List.map (mkMemberDefn creationAide) members,
interfaceNodes,
stn "}" mClose,
@@ -1144,7 +1103,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
_,
pat,
e1,
- SynExpr.YieldOrReturn((true, _), e2, _),
+ SynExpr.YieldOrReturn((true, _), e2, _, _),
StartRange 3 (mFor, _)) ->
ExprForEachNode(
stn "for" mFor,
@@ -1183,7 +1142,6 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
|> Expr.Computation
| SynExpr.LetOrUse _
- | SynExpr.LetOrUseBang _
| SynExpr.Sequential _ ->
ExprCompExprBodyNode(collectComputationExpressionStatements creationAide e id, exprRange)
|> Expr.CompExprBody
@@ -1278,7 +1236,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
ExprNamedComputationNode(
mkExpr creationAide expr,
stn "{" mOpen,
- Expr.Ident(stn "" Range.Zero),
+ Expr.Ident(stn "" Range.range0),
stn "}" mClose,
m
)
@@ -1758,14 +1716,14 @@ let mkPat (creationAide: CreationAide) (p: SynPat) =
let pairs =
nps
- |> List.choose (fun (ident, eq, pat) ->
+ |> List.choose (fun (NamePatPairField(fieldName = fieldName; equalsRange = eq; pat = pat)) ->
eq
|> Option.map (fun eq ->
- NamePatPair(
- mkIdent ident,
+ NamePatPairNode(
+ mkSynLongIdent creationAide fieldName,
stn "=" eq,
mkPat creationAide pat,
- unionRanges ident.idRange pat.Range
+ unionRanges fieldName.Range pat.Range
)))
PatNamePatPairsNode(
@@ -1804,16 +1762,10 @@ let mkPat (creationAide: CreationAide) (p: SynPat) =
| SynPat.Record(fields, StartEndRange 1 (o, _, c)) ->
let fields =
fields
- |> List.map (fun ((lid, ident), eq, pat) ->
- let prefix = if lid.IsEmpty then None else Some(mkLongIdent lid)
-
- let range =
- match prefix with
- | None -> unionRanges ident.idRange pat.Range
- | Some prefix -> unionRanges prefix.Range pat.Range
-
- let eqNode = stn "=" (Option.defaultValue Range.Zero eq)
- PatRecordField(prefix, mkIdent ident, eqNode, mkPat creationAide pat, range))
+ |> List.map (fun (NamePatPairField(fieldName = fieldName; equalsRange = eq; pat = pat) as np) ->
+ let range = np.Range // TODO: might be wrong unionRanges prefix.Range pat.Range
+ let eqNode = stn "=" (Option.defaultValue Range.range0 eq)
+ NamePatPairNode(mkSynLongIdent creationAide fieldName, eqNode, mkPat creationAide pat, range))
PatRecordNode(stn "{" o, fields, stn "}" c, patternRange) |> Pattern.Record
| SynPat.Const(c, r) -> mkConstant creationAide c r |> Pattern.Const
@@ -1842,6 +1794,7 @@ let (|OperatorWithStar|_|) (si: SynIdent) =
let mkBinding
(creationAide: CreationAide)
(SynBinding(_, _, _, isMutable, attributes, xmlDoc, _, pat, returnInfo, expr, _, _, trivia))
+ (inKeyword: SingleTextNode option)
=
let mkFunctionName (sli: SynLongIdent) : IdentListNode =
match sli.IdentsWithTrivia with
@@ -1898,7 +1851,11 @@ let mkBinding
| SynLeadingKeyword.Member _, SynPat.LongIdent(extraId = Some _) -> pat.Range
| _ -> trivia.LeadingKeyword.Range
- unionRanges start e.Range
+ let range = unionRanges start e.Range
+
+ match inKeyword with
+ | None -> range
+ | Some inKeyword -> unionRanges range inKeyword.Range
BindingNode(
mkXmlDoc xmlDoc,
@@ -1913,6 +1870,7 @@ let mkBinding
returnTypeNode,
equals,
(mkExpr creationAide e),
+ inKeyword,
range
)
@@ -2058,10 +2016,11 @@ let mkModuleDecl (creationAide: CreationAide) (decl: SynModuleDecl) =
declRange
)
|> ModuleDecl.Exception
- | SynModuleDecl.Let(_, [ SynBinding(trivia = { LeadingKeyword = SynLeadingKeyword.Extern _ }) as binding ], _) ->
+ | SynModuleDecl.Let(bindings = [ SynBinding(trivia = { LeadingKeyword = SynLeadingKeyword.Extern _ }) as binding ]) ->
mkExternBinding creationAide binding |> ModuleDecl.ExternBinding
- | SynModuleDecl.Let(bindings = [ singleBinding ]) ->
- mkBinding creationAide singleBinding |> ModuleDecl.TopLevelBinding
+ | SynModuleDecl.Let(bindings = [ singleBinding ]; trivia = trivia) ->
+ mkBinding creationAide singleBinding (Option.map (stn "in") trivia.InKeyword)
+ |> ModuleDecl.TopLevelBinding
| SynModuleDecl.ModuleAbbrev(ident, lid, StartRange 6 (mModule, _)) ->
ModuleAbbrevNode(stn "module" mModule, mkIdent ident, mkLongIdent lid, declRange)
|> ModuleDecl.ModuleAbbrev
@@ -2401,9 +2360,12 @@ let mkSynLeadingKeyword (lk: SynLeadingKeyword) =
match lk with
| SynLeadingKeyword.Let letRange -> mtn [ "let", letRange ]
+ | SynLeadingKeyword.LetBang letBangRange -> mtn [ "let!", letBangRange ]
| SynLeadingKeyword.LetRec(letRange, recRange) -> mtn [ "let", letRange; "rec", recRange ]
| SynLeadingKeyword.And andRange -> mtn [ "and", andRange ]
+ | SynLeadingKeyword.AndBang andBangRange -> mtn [ "and!", andBangRange ]
| SynLeadingKeyword.Use useRange -> mtn [ "use", useRange ]
+ | SynLeadingKeyword.UseBang useBangRange -> mtn [ "use!", useBangRange ]
| SynLeadingKeyword.UseRec(useRange, recRange) -> mtn [ "use", useRange; "rec", recRange ]
| SynLeadingKeyword.Extern externRange -> mtn [ "extern", externRange ]
| SynLeadingKeyword.Member memberRange -> mtn [ "member", memberRange ]
@@ -2809,8 +2771,8 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
let memberDefinitionRange = md.Range
match md with
- | SynMemberDefn.ImplicitInherit(t, e, _, StartRange 7 (mInherit, _)) ->
- mkInheritConstructor creationAide t e mInherit memberDefinitionRange
+ | SynMemberDefn.ImplicitInherit(t, e, _, _, trivia) ->
+ mkInheritConstructor creationAide t e trivia.InheritKeyword memberDefinitionRange
|> MemberDefn.ImplicitInherit
// Transforms: `member this.Y with get() = "meh"` into `member this.Y = "meh"`
@@ -2843,6 +2805,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
mkBinding
creationAide
(SynBinding(None, kind, isInline, isMutable, ats, px, valData, pat, ri, e, bindingRange, dp, trivia))
+ None
|> MemberDefn.Member
| SynMemberDefn.Member(
memberDefn = SynBinding(
@@ -2869,10 +2832,17 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
memberDefinitionRange
)
|> MemberDefn.ExplicitCtor
- | SynMemberDefn.Member(memberDefn, _) -> mkBinding creationAide memberDefn |> MemberDefn.Member
- | SynMemberDefn.Inherit(baseType, _, StartRange 7 (mInherit, _)) ->
- MemberDefnInheritNode(stn "inherit" mInherit, mkType creationAide baseType, memberDefinitionRange)
- |> MemberDefn.Inherit
+ | SynMemberDefn.Member(memberDefn, _) -> mkBinding creationAide memberDefn None |> MemberDefn.Member
+ | SynMemberDefn.Inherit(baseTypeOpt, _, _isInline, trivia) ->
+ match baseTypeOpt with
+ | Some baseType ->
+ MemberDefnInheritNode(
+ stn "inherit" trivia.InheritKeyword,
+ mkType creationAide baseType,
+ memberDefinitionRange
+ )
+ |> MemberDefn.Inherit
+ | None -> failwith "successful parse shouldn't have any unfinished inherit"
| SynMemberDefn.ValField(f, _) -> mkSynField creationAide f |> MemberDefn.ValField
| SynMemberDefn.LetBindings(
bindings = [ SynBinding(trivia = { LeadingKeyword = SynLeadingKeyword.Extern _ }) as binding ]) ->
@@ -2892,8 +2862,15 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
memberDefinitionRange
)
|> MemberDefn.DoExpr
- | SynMemberDefn.LetBindings(bindings = bindings) ->
- BindingListNode(List.map (mkBinding creationAide) bindings, memberDefinitionRange)
+ | SynMemberDefn.LetBindings(bindings = bindings; trivia = trivia) ->
+ BindingListNode(
+ List.mapi
+ (fun i b ->
+ let inKeyword = if i <> 0 then None else trivia.InKeyword
+ mkBinding creationAide b (Option.map (stn "in") inKeyword))
+ bindings,
+ memberDefinitionRange
+ )
|> MemberDefn.LetBinding
| SynMemberDefn.Interface(t, mWith, mdsOpt, _) ->
let interfaceNode =
@@ -3189,9 +3166,15 @@ let rec mkModuleDecls
let node = ModuleDeclAttributesNode(attributes, expr, range)
mkModuleDecls creationAide rest (fun nodes -> ModuleDecl.Attributes node :: nodes |> finalContinuation)
- | SynModuleDecl.Let(bindings = bindings) :: rest when List.moreThanOne bindings ->
+ | SynModuleDecl.Let(bindings = bindings; trivia = { InKeyword = inKeyword }) :: rest when List.moreThanOne bindings ->
let bindingNodes =
- List.map (fun b -> mkBinding creationAide b |> ModuleDecl.TopLevelBinding) bindings
+ List.mapi
+ (fun i b ->
+ let inKeyword = if i <> 0 then None else inKeyword
+
+ mkBinding creationAide b (Option.map (stn "in") inKeyword)
+ |> ModuleDecl.TopLevelBinding)
+ bindings
mkModuleDecls creationAide rest (fun nodes -> [ yield! bindingNodes; yield! nodes ] |> finalContinuation)
@@ -3217,7 +3200,7 @@ let mkModuleOrNamespace
| SynModuleOrNamespaceLeadingKeyword.Namespace mNamespace ->
match kind with
| SynModuleOrNamespaceKind.GlobalNamespace ->
- Some(MultipleTextsNode([ stn "namespace" mNamespace; stn "global" Range.Zero ], mNamespace))
+ Some(MultipleTextsNode([ stn "namespace" mNamespace; stn "global" Range.range0 ], mNamespace))
| _ -> Some(MultipleTextsNode([ stn "namespace" mNamespace ], mNamespace))
| SynModuleOrNamespaceLeadingKeyword.None -> None
@@ -3542,7 +3525,7 @@ let mkModuleOrNamespaceSig
| SynModuleOrNamespaceLeadingKeyword.Namespace mNamespace ->
match kind with
| SynModuleOrNamespaceKind.GlobalNamespace ->
- Some(MultipleTextsNode([ stn "namespace" mNamespace; stn "global" Range.Zero ], mNamespace))
+ Some(MultipleTextsNode([ stn "namespace" mNamespace; stn "global" range0 ], mNamespace))
| _ -> Some(MultipleTextsNode([ stn "namespace" mNamespace ], mNamespace))
| SynModuleOrNamespaceLeadingKeyword.None -> None
@@ -3598,25 +3581,28 @@ let mkSigFile
let mds = List.map (mkModuleOrNamespaceSig creationAide) contents
Oak(phds, mds, m)
-let includeTrivia
- (baseRange: range)
- (comments: CommentTrivia list)
- (conditionDirectives: ConditionalDirectiveTrivia list)
- : range =
+let includeTrivia (baseRange: range) (trivia: ParsedInputTrivia) : range =
let ranges =
[ yield!
List.map
(function
| CommentTrivia.LineComment m
| CommentTrivia.BlockComment m -> m)
- comments
+ trivia.CodeComments
yield!
List.map
(function
| ConditionalDirectiveTrivia.If(range = range)
| ConditionalDirectiveTrivia.Else(range = range)
| ConditionalDirectiveTrivia.EndIf(range = range) -> range)
- conditionDirectives ]
+ trivia.ConditionalDirectives
+
+ yield!
+ List.map
+ (function
+ | WarnDirectiveTrivia.Nowarn(range)
+ | WarnDirectiveTrivia.Warnon(range) -> range)
+ trivia.WarnDirectives ]
(baseRange, ranges)
||> List.fold (fun acc triviaRange ->
@@ -3631,7 +3617,7 @@ let mkSynModuleOrNamespaceFullRange (mn: SynModuleOrNamespace) =
match mn with
| SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.AnonModule; decls = decls) ->
match List.tryHead decls, List.tryLast decls with
- | None, None -> Range.Zero
+ | None, None -> RangeHelpers.absoluteZeroRange
| Some d, None
| None, Some d -> d.Range
| Some s, Some e -> unionRanges s.Range e.Range
@@ -3641,7 +3627,7 @@ let mkSynModuleOrNamespaceSigFullRange (mn: SynModuleOrNamespaceSig) =
match mn with
| SynModuleOrNamespaceSig(kind = SynModuleOrNamespaceKind.AnonModule; decls = decls) ->
match List.tryHead decls, List.tryLast decls with
- | None, None -> Range.Zero
+ | None, None -> RangeHelpers.absoluteZeroRange
| Some d, None
| None, Some d -> d.Range
| Some s, Some e -> unionRanges s.Range e.Range
@@ -3657,18 +3643,18 @@ let mkFullTreeRange ast =
| [] ->
match modules with
| m :: _ -> mkSynModuleOrNamespaceFullRange m
- | _ -> Range.Zero
+ | _ -> RangeHelpers.absoluteZeroRange
let endPos =
match List.tryLast modules with
| None ->
match List.tryLast directives with
- | None -> Range.Zero
+ | None -> RangeHelpers.absoluteZeroRange
| Some(ParsedHashDirective(range = r)) -> r
| Some lastModule -> mkSynModuleOrNamespaceFullRange lastModule
let astRange = unionRanges startPos endPos
- includeTrivia astRange trivia.CodeComments trivia.ConditionalDirectives
+ includeTrivia astRange trivia
| ParsedInput.SigFile(ParsedSigFileInput(hashDirectives = directives; contents = modules; trivia = trivia)) ->
let startPos =
@@ -3677,18 +3663,18 @@ let mkFullTreeRange ast =
| [] ->
match modules with
| m :: _ -> mkSynModuleOrNamespaceSigFullRange m
- | _ -> Range.Zero
+ | _ -> RangeHelpers.absoluteZeroRange
let endPos =
match List.tryLast modules with
| None ->
match List.tryLast directives with
- | None -> Range.Zero
+ | None -> RangeHelpers.absoluteZeroRange
| Some(ParsedHashDirective(range = r)) -> r
| Some lastModule -> mkSynModuleOrNamespaceSigFullRange lastModule
let astRange = unionRanges startPos endPos
- includeTrivia astRange trivia.CodeComments trivia.ConditionalDirectives
+ includeTrivia astRange trivia
let mkOak (sourceText: ISourceText option) (ast: ParsedInput) =
let creationAide = { SourceText = sourceText }
diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs
index 71b9ee65a5..4a34c869fb 100644
--- a/src/Fantomas.Core/CodePrinter.fs
+++ b/src/Fantomas.Core/CodePrinter.fs
@@ -644,51 +644,17 @@ let genExpr (e: Expr) =
let genStatements =
node.Statements
|> List.map (function
- | ComputationExpressionStatement.LetOrUseStatement node ->
- let expr =
- genBinding node.Binding
- +> optSingle (fun inNode -> sepSpace +> genSingleTextNode inNode) node.In
- |> genNode node
-
- ColMultilineItem(expr, sepNlnUnlessContentBefore node)
- | ComputationExpressionStatement.LetOrUseBangStatement node ->
- let expr =
- genSingleTextNode node.LeadingKeyword
- +> sepSpace
- +> genPat node.Pattern
- +> sepSpace
- +> genSingleTextNode node.Equals
- +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup genExpr node.Expression
- |> genNode node
-
- ColMultilineItem(expr, sepNlnUnlessContentBefore node)
- | ComputationExpressionStatement.AndBangStatement node ->
- let expr =
- genSingleTextNode node.LeadingKeyword
- +> sepSpace
- +> genPat node.Pattern
- +> sepSpace
- +> genSingleTextNode node.Equals
- +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup genExpr node.Expression
- |> genNode node
-
- ColMultilineItem(expr, sepNlnUnlessContentBefore node)
+ | ComputationExpressionStatement.BindingStatement bindingNode ->
+ ColMultilineItem(genBinding bindingNode, sepNlnUnlessContentBefore bindingNode)
| ComputationExpressionStatement.OtherStatement e ->
ColMultilineItem(genExpr e, sepNlnUnlessContentBefore (Expr.Node e)))
|> colWithNlnWhenItemIsMultilineUsingConfig
|> genNode node
match node.Statements with
- | [ ComputationExpressionStatement.LetOrUseStatement letOrUseNode
- ComputationExpressionStatement.OtherStatement inExpr ] when letOrUseNode.In.IsSome ->
- let short =
- (genBinding letOrUseNode.Binding
- +> optSingle (fun inNode -> sepSpace +> genSingleTextNode inNode +> sepSpace) letOrUseNode.In
- |> genNode letOrUseNode)
- +> sepSpace
- +> genExpr inExpr
- |> genNode node
-
+ | [ ComputationExpressionStatement.BindingStatement bindingNode
+ ComputationExpressionStatement.OtherStatement otherNode ] when bindingNode.In.IsSome ->
+ let short = genBinding bindingNode +> sepSpace +> genExpr otherNode
expressionFitsOnRestOfLine short genStatements
| _ -> genStatements
| Expr.JoinIn node ->
@@ -1049,9 +1015,9 @@ let genExpr (e: Expr) =
let parenExpr =
mkExprParenNode
node.OpeningParen
- (Expr.Null(SingleTextNode("", Fantomas.FCS.Text.Range.Zero)))
+ (Expr.Null(SingleTextNode("", Fantomas.FCS.Text.Range.range0)))
node.ClosingParen
- Fantomas.FCS.Text.Range.Zero
+ Fantomas.FCS.Text.Range.range0
sepSpaceBeforeParenInFuncInvocation node.FunctionName parenExpr
| _ -> sepSpace
@@ -1892,16 +1858,16 @@ let genTupleExpr (node: ExprTupleNode) =
| IsLambdaOrIfThenElse e ->
let parenNode =
mkExprParenNode
- (SingleTextNode("(", Fantomas.FCS.Text.Range.Zero))
+ (SingleTextNode("(", Fantomas.FCS.Text.Range.range0))
e
- (SingleTextNode(")", Fantomas.FCS.Text.Range.Zero))
- Fantomas.FCS.Text.Range.Zero
+ (SingleTextNode(")", Fantomas.FCS.Text.Range.range0))
+ Fantomas.FCS.Text.Range.range0
ExprInfixAppNode(
exprInfixAppNode.LeftHandSide,
exprInfixAppNode.Operator,
parenNode,
- Fantomas.FCS.Text.range.Zero
+ Fantomas.FCS.Text.Range.range0
)
|> Expr.InfixApp
| _ -> expr
@@ -2236,38 +2202,48 @@ let genMultilineInfixExpr (node: ExprInfixAppNode) =
let genExprInMultilineInfixExpr (e: Expr) =
match e with
| Expr.CompExprBody node ->
- let areLetOrUseStatementsEndingWithOtherStatement =
+ // See https://github.com/fsprojects/fantomas/issues/1461
+ // If there are bindings, it is safer to include the `in` keyword artificially.
+
+ let hasBindings =
node.Statements
- |> List.mapWithLast
- (function
- | ComputationExpressionStatement.LetOrUseStatement _ -> true
+ |> List.exists (function
+ | ComputationExpressionStatement.BindingStatement _ -> true
| _ -> false)
- (function
- | ComputationExpressionStatement.OtherStatement _ -> true
- | _ -> false)
- |> List.reduce (&&)
- if not areLetOrUseStatementsEndingWithOtherStatement then
+ if not hasBindings then
genExpr e
else
- colWithNlnWhenMappedNodeIsMultiline
- true
- ComputationExpressionStatement.Node
- (fun ces ->
- match ces with
- | ComputationExpressionStatement.LetOrUseStatement letOrUseNode ->
- let genIn =
- match letOrUseNode.In with
- | None -> !-"in"
- | Some inNode -> genSingleTextNode inNode
-
- genBinding letOrUseNode.Binding +> sepSpace +> genIn +> sepSpace
- |> genNode letOrUseNode
- | ComputationExpressionStatement.OtherStatement otherNode -> genExpr otherNode
- | _ -> failwith "unexpected ComputationExpressionStatement")
+ let statements =
node.Statements
- |> atCurrentColumn
- |> genNode node
+ |> List.map (fun statement ->
+ match statement with
+ | ComputationExpressionStatement.OtherStatement _ -> statement
+ | ComputationExpressionStatement.BindingStatement bindingNode ->
+ let inKeyword = Some(SingleTextNode("in", bindingNode.Range.EndRange))
+
+ let updatedBindingNode =
+ BindingNode(
+ bindingNode.XmlDoc,
+ bindingNode.Attributes,
+ bindingNode.LeadingKeyword,
+ bindingNode.IsMutable,
+ bindingNode.Inline,
+ bindingNode.Accessibility,
+ bindingNode.FunctionName,
+ bindingNode.GenericTypeParameters,
+ bindingNode.Parameters,
+ bindingNode.ReturnType,
+ bindingNode.Equals,
+ bindingNode.Expr,
+ inKeyword,
+ bindingNode.Range
+ )
+
+ ComputationExpressionStatement.BindingStatement updatedBindingNode)
+
+ let compExprBodyNode = ExprCompExprBodyNode(statements, node.Range)
+ atCurrentColumn (genExpr (Expr.CompExprBody compExprBodyNode))
| Expr.Paren parenNode ->
match parenNode.Expr with
| Expr.Match _ as mex ->
@@ -2626,6 +2602,14 @@ let genTuplePat (node: PatTupleNode) =
atCurrentColumn (expressionFitsOnRestOfLine short (atCurrentColumn (genTuplePatLong node)))
|> genNode node
+let genNamePatPair (node: NamePatPairNode) =
+ genIdentListNode node.FieldName
+ +> sepSpace
+ +> genSingleTextNode node.Equals
+ +> sepSpace
+ +> genPat node.Pattern
+ |> genNode node
+
let genPat (p: Pattern) =
match p with
| Pattern.OptionalVal n -> genSingleTextNode n
@@ -2654,18 +2638,11 @@ let genPat (p: Pattern) =
| Pattern.As node
| Pattern.ListCons node -> genPatLeftMiddleRight node
| Pattern.NamePatPairs node ->
- let genPatWithIdent (node: NamePatPair) =
- genSingleTextNode node.Ident
- +> sepSpace
- +> genSingleTextNode node.Equals
- +> sepSpace
- +> genPat node.Pattern
- |> genNode node
let pats =
expressionFitsOnRestOfLine
- (atCurrentColumn (col sepSemi node.Pairs genPatWithIdent))
- (atCurrentColumn (col sepNln node.Pairs genPatWithIdent))
+ (atCurrentColumn (col sepSemi node.Pairs genNamePatPair))
+ (atCurrentColumn (col sepNln node.Pairs genNamePatPair))
genIdentListNode node.Identifier
+> optSingle genTyparDecls node.TyparDecls
@@ -2732,14 +2709,14 @@ let genPat (p: Pattern) =
let smallRecordExpr =
genSingleTextNode node.OpeningNode
+> addSpaceIfSpaceAroundDelimiter
- +> col sepSemi node.Fields genPatRecordFieldName
+ +> col sepSemi node.Fields genNamePatPair
+> addSpaceIfSpaceAroundDelimiter
+> genSingleTextNode node.ClosingNode
let multilineRecordExpr =
genSingleTextNode node.OpeningNode
+> addSpaceIfSpaceAroundDelimiter
- +> atCurrentColumn (col sepNln node.Fields genPatRecordFieldName)
+ +> atCurrentColumn (col sepNln node.Fields genNamePatPair)
+> addSpaceIfSpaceAroundDelimiter
+> genSingleTextNode node.ClosingNode
@@ -2747,7 +2724,7 @@ let genPat (p: Pattern) =
genSingleTextNode node.OpeningNode
+> indent
+> sepNln
- +> atCurrentColumn (col sepNln node.Fields genPatRecordFieldName)
+ +> atCurrentColumn (col sepNln node.Fields genNamePatPair)
+> unindent
+> sepNln
+> genSingleTextNode node.ClosingNode
@@ -2790,23 +2767,6 @@ let genPatInClause (pat: Pattern) =
genPatMultiline pat
-let genPatRecordFieldName (node: PatRecordField) =
- match node.Prefix with
- | None ->
- genSingleTextNode node.FieldName
- +> sepSpace
- +> genSingleTextNode node.Equals
- +> sepSpace
- +> genPat node.Pattern
- | Some prefix ->
- genIdentListNode prefix
- +> sepDot
- +> genSingleTextNode node.FieldName
- +> sepSpace
- +> genSingleTextNode node.Equals
- +> sepSpace
- +> genPat node.Pattern
-
let genReturnTypeBinding (node: BindingReturnInfoNode option) =
match node with
| None -> sepNone
@@ -2831,7 +2791,7 @@ let genBinding (b: BindingNode) (ctx: Context) : Context =
let isRecursiveLetOrUseFunction =
match b.LeadingKeyword.Content with
- | [ singleText ] -> singleText.Text = "and"
+ | [ singleText ] -> singleText.Text = "and" || singleText.Text = "and!"
| _ -> false
let binding =
@@ -3099,7 +3059,7 @@ let genBinding (b: BindingNode) (ctx: Context) : Context =
let long = prefix +> indentSepNlnUnindentUnlessStroustrup genExpr b.Expr
isShortExpression ctx.Config.MaxValueBindingWidth short long ctx)
- genNode b binding ctx
+ genNode b (binding +> optSingle (fun inNode -> sepSpace +> genSingleTextNode inNode) b.In) ctx
let genBindings withUseConfig (bs: BindingNode list) : Context -> Context =
colWithNlnWhenNodeIsMultiline withUseConfig genBinding bs
diff --git a/src/Fantomas.Core/RangeHelpers.fs b/src/Fantomas.Core/RangeHelpers.fs
index 16f3863cd6..bacfae40bc 100644
--- a/src/Fantomas.Core/RangeHelpers.fs
+++ b/src/Fantomas.Core/RangeHelpers.fs
@@ -27,6 +27,9 @@ module RangeHelpers =
startRange, endRange
+ let absoluteZeroRange =
+ Range.mkRange Range.range0.FileName (Position.mkPos 0 0) (Position.mkPos 0 0)
+
module RangePatterns =
let (|StartEndRange|) (size: int) (range: range) =
let o, c = RangeHelpers.mkStartEndRange size range
diff --git a/src/Fantomas.Core/RangeHelpers.fsi b/src/Fantomas.Core/RangeHelpers.fsi
index 36033b7534..7e156375e7 100644
--- a/src/Fantomas.Core/RangeHelpers.fsi
+++ b/src/Fantomas.Core/RangeHelpers.fsi
@@ -8,6 +8,9 @@ module RangeHelpers =
val rangeContainsRange: a: Range -> b: Range -> bool
val rangeEq: (range -> range -> bool)
val isAdjacentTo: r1: Range -> r2: Range -> bool
+ /// Range.range0 starts at line 1, column 0
+ /// This range starts at line 0, column 0
+ val absoluteZeroRange: Range
module RangePatterns =
val (|StartEndRange|): size: int -> range: range -> range * range * range
diff --git a/src/Fantomas.Core/Selection.fs b/src/Fantomas.Core/Selection.fs
index 66d4ad3400..e266b2746d 100644
--- a/src/Fantomas.Core/Selection.fs
+++ b/src/Fantomas.Core/Selection.fs
@@ -95,7 +95,7 @@ let mkExtractableOakFromModule (md: ModuleDecl) (t: System.Type) =
TreeForSelection.RequiresExtraction(Oak([], [ ModuleOrNamespaceNode(None, [ md ], m) ], m), t)
let dummyUnit: Expr =
- UnitNode(SingleTextNode("(", Range.Zero), SingleTextNode(")", Range.Zero), Range.Zero)
+ UnitNode(SingleTextNode("(", Range.range0), SingleTextNode(")", Range.range0), Range.range0)
|> Constant.Unit
|> Expr.Constant
@@ -192,6 +192,7 @@ let mkTreeWithSingleNode (node: Node) : TreeForSelection =
| :? ExprCompExprBodyNode as node ->
let expr = Expr.CompExprBody node
mkOakFromModuleDecl (ModuleDecl.DeclExpr expr)
+ // TODO: we don't have ComputationExpressionStatement it seems
| :? ExprJoinInNode as node ->
let expr = Expr.JoinIn node
mkOakFromModuleDecl (ModuleDecl.DeclExpr expr)
@@ -309,6 +310,7 @@ let mkTreeWithSingleNode (node: Node) : TreeForSelection =
| :? ExceptionDefnNode as node -> mkOakFromModuleDecl (ModuleDecl.Exception node)
| :? ExternBindingNode as node -> mkOakFromModuleDecl (ModuleDecl.ExternBinding node)
| :? BindingNode as node -> mkOakFromModuleDecl (ModuleDecl.TopLevelBinding node)
+ // ComputationExpressionStatement.OtherStatement isn't needed as Expr is covered.
| :? ModuleAbbrevNode as node -> mkOakFromModuleDecl (ModuleDecl.ModuleAbbrev node)
| :? NestedModuleNode as node -> mkOakFromModuleDecl (ModuleDecl.NestedModule node)
// TypeDefn
@@ -346,16 +348,6 @@ let mkTreeWithSingleNode (node: Node) : TreeForSelection =
#endif
TreeForSelection.Unsupported
-#if DEBUG
-let printTriviaNode (node: Node) : unit =
- let rec visit (level: int) (node: Node) =
- let name = node.GetType().Name
- printfn "%s%s: %A" ("".PadRight(level * 2)) name node.Range
- Array.iter (visit (level + 1)) node.Children
-
- visit 0 node
-#endif
-
// Find the first node that matches the type
let rec findRangeOf (t: System.Type) (root: Node) : range option =
if root.GetType() = t then
@@ -380,9 +372,8 @@ let formatSelection
let rootNode = ASTTransformer.mkOak (Some sourceText) baseUntypedTree
-#if DEBUG
- printTriviaNode rootNode
-#endif
+ // Uncomment if needed to debug the root node
+ // printfn "rootNode:\n%A" rootNode
let selection = correctSelection rootNode.Range.FileIndex sourceText selection
diff --git a/src/Fantomas.Core/SyntaxOak.fs b/src/Fantomas.Core/SyntaxOak.fs
index c15dc6f0da..bd58b1cf02 100644
--- a/src/Fantomas.Core/SyntaxOak.fs
+++ b/src/Fantomas.Core/SyntaxOak.fs
@@ -1,6 +1,7 @@
module rec Fantomas.Core.SyntaxOak
open System.Collections.Generic
+open System.Text
open Fantomas.FCS.Text
type TriviaContent =
@@ -15,6 +16,18 @@ type TriviaNode(content: TriviaContent, range: range) =
member val Content = content
member val Range = range
+ override x.ToString() =
+ let rangeStr = $"range: %A{x.Range}"
+
+ match x.Content with
+ | CommentOnSingleLine s -> $"CommentOnSingleLine(%s{rangeStr}, \"%s{s}\")"
+ | LineCommentAfterSourceCode s -> $"LineCommentAfterSourceCode(%s{rangeStr}, \"%s{s}\")"
+ | BlockComment(s, before, after) ->
+ $"BlockComment(%s{rangeStr}, \"%s{s}\", newlineBefore: %b{before}, newlineAfter: %b{after})"
+ | Newline -> $"Newline(%s{rangeStr})"
+ | Directive s -> $"Directive(%s{rangeStr}, \"%s{s}\")"
+ | Cursor -> $"Cursor(%s{rangeStr})"
+
[]
type Node =
abstract ContentBefore: TriviaNode seq
@@ -63,6 +76,48 @@ type NodeBase(range: range) =
member _.AddCursor cursor = potentialCursor <- Some cursor
member _.TryGetCursor = potentialCursor
+ member private x.AppendToStringWithIndent(sb: StringBuilder, depth: int) =
+ let indent = String.replicate depth " "
+ let contentIndent = String.replicate (depth + 1) " "
+
+ sb.Append(indent).Append(x.GetType().Name).Append("(").Append(x.Range) |> ignore
+
+ let hasContentBefore = not (Seq.isEmpty x.ContentBefore)
+ let hasChildren = not (Array.isEmpty x.Children)
+ let hasContentAfter = not (Seq.isEmpty x.ContentAfter)
+ let hasContent = hasContentBefore || hasChildren || hasContentAfter
+
+ if hasContent then
+ sb.AppendLine() |> ignore
+
+ if hasContentBefore then
+ for tn in x.ContentBefore do
+ sb.Append(contentIndent).Append(tn.ToString()).AppendLine() |> ignore
+
+ if hasChildren then
+ for n in x.Children do
+ match n with
+ | :? SingleTextNode as stn -> sb.Append(contentIndent).Append(stn.ToString()).AppendLine() |> ignore
+ | :? NodeBase as nb ->
+ nb.AppendToStringWithIndent(sb, depth + 1)
+ sb.AppendLine() |> ignore
+ | _ -> sb.Append(contentIndent).Append(n.ToString()).AppendLine() |> ignore
+
+ if hasContentAfter then
+ for tn in x.ContentAfter do
+ sb.Append(contentIndent).Append(tn.ToString()).AppendLine() |> ignore
+
+ sb.Append(indent).Append(")") |> ignore
+ else
+ sb.Append(")") |> ignore
+
+ member private x.ToStringWithIndent(depth: int) =
+ let sb = StringBuilder()
+ x.AppendToStringWithIndent(sb, depth)
+ sb.ToString()
+
+ override x.ToString() = x.ToStringWithIndent(0)
+
interface Node with
member x.ContentBefore = x.ContentBefore
member x.HasContentBefore = x.HasContentBefore
@@ -91,7 +146,7 @@ let nodeRange (n: Node) = n.Range
let combineRanges (ranges: range seq) =
if Seq.isEmpty ranges then
- Range.Zero
+ Range.range0
else
Seq.reduce Range.unionRanges ranges
@@ -111,7 +166,7 @@ type IdentListNode(content: IdentifierOrDot list, range) =
inherit NodeBase(range)
member val IsEmpty = content.IsEmpty
member val Content = content
- static member Empty = IdentListNode(List.empty, Range.Zero)
+ static member Empty = IdentListNode(List.empty, Range.range0)
override x.Children =
x.Content
@@ -126,6 +181,9 @@ type SingleTextNode(idText: string, range: range) =
member val Text = idText
override val Children = Array.empty
+ override x.ToString() =
+ $"SingleTextNode(%A{x.Range}, \"%s{x.Text}\")"
+
type MultipleTextsNode(content: SingleTextNode list, range) =
inherit NodeBase(range)
override val Children: Node array = [| yield! nodes content |]
@@ -477,10 +535,10 @@ type PatNamedNode(accessibility: SingleTextNode option, name: SingleTextNode, ra
member val Name = name
member val Accessibility = accessibility
-type NamePatPair(ident: SingleTextNode, equals: SingleTextNode, pat: Pattern, range) =
+type NamePatPairNode(fieldName: IdentListNode, equals: SingleTextNode, pat: Pattern, range) =
inherit NodeBase(range)
- override val Children: Node array = [| yield ident; yield equals; yield Pattern.Node pat |]
- member val Ident = ident
+ override val Children: Node array = [| yield fieldName; yield equals; yield Pattern.Node pat |]
+ member val FieldName = fieldName
member val Equals = equals
member val Pattern = pat
@@ -489,7 +547,7 @@ type PatNamePatPairsNode
identifier: IdentListNode,
typarDecls: TyparDecls option,
openingParen: SingleTextNode,
- pairs: NamePatPair list,
+ pairs: NamePatPairNode list,
closingParen: SingleTextNode,
range
) =
@@ -564,18 +622,7 @@ type PatArrayOrListNode(openToken: SingleTextNode, pats: Pattern list, closeToke
member val Patterns = pats
member val CloseToken = closeToken
-type PatRecordField
- (prefix: IdentListNode option, fieldName: SingleTextNode, equals: SingleTextNode, pat: Pattern, range) =
- inherit NodeBase(range)
-
- override val Children: Node array = [| yield! noa prefix; yield fieldName; yield equals; yield Pattern.Node pat |]
-
- member val Prefix = prefix
- member val FieldName = fieldName
- member val Equals = equals
- member val Pattern = pat
-
-type PatRecordNode(openingNode: SingleTextNode, fields: PatRecordField list, closingNode: SingleTextNode, range) =
+type PatRecordNode(openingNode: SingleTextNode, fields: NamePatPairNode list, closingNode: SingleTextNode, range) =
inherit NodeBase(range)
override val Children: Node array = [| yield openingNode; yield! nodes fields; yield closingNode |]
@@ -996,52 +1043,14 @@ type ExprComputationNode(openingBrace: SingleTextNode, bodyExpr: Expr, closingBr
member val Body = bodyExpr
member val ClosingBrace = closingBrace
-type ExprLetOrUseNode(binding: BindingNode, inKeyword: SingleTextNode option, range) =
- inherit NodeBase(range)
- override val Children: Node array = [| yield binding; yield! noa inKeyword |]
- member val Binding = binding
- member val In = inKeyword
-
-type ExprLetOrUseBangNode(leadingKeyword: SingleTextNode, pat: Pattern, equals: SingleTextNode, expr: Expr, range) =
- inherit NodeBase(range)
-
- override val Children: Node array =
- [| yield leadingKeyword
- yield Pattern.Node pat
- yield equals
- yield Expr.Node expr |]
-
- member val LeadingKeyword = leadingKeyword
- member val Pattern = pat
- member val Equals = equals
- member val Expression = expr
-
-type ExprAndBang(leadingKeyword: SingleTextNode, pat: Pattern, equals: SingleTextNode, expr: Expr, range) =
- inherit NodeBase(range)
-
- override val Children: Node array =
- [| yield leadingKeyword
- yield Pattern.Node pat
- yield equals
- yield Expr.Node expr |]
-
- member val LeadingKeyword = leadingKeyword
- member val Pattern = pat
- member val Equals = equals
- member val Expression = expr
-
[]
type ComputationExpressionStatement =
- | LetOrUseStatement of ExprLetOrUseNode
- | LetOrUseBangStatement of ExprLetOrUseBangNode
- | AndBangStatement of ExprAndBang
+ | BindingStatement of BindingNode
| OtherStatement of Expr
static member Node(ces: ComputationExpressionStatement) : Node =
match ces with
- | LetOrUseStatement n -> n
- | LetOrUseBangStatement n -> n
- | AndBangStatement n -> n
+ | BindingStatement n -> n
| OtherStatement o -> Expr.Node o
type ExprCompExprBodyNode(statements: ComputationExpressionStatement list, range) =
@@ -2036,6 +2045,7 @@ type BindingNode
returnType: BindingReturnInfoNode option,
equals: SingleTextNode,
expr: Expr,
+ inKeyword: SingleTextNode option,
range
) =
inherit NodeBase(range)
@@ -2051,6 +2061,7 @@ type BindingNode
member val ReturnType = returnType
member val Equals = equals
member val Expr = expr
+ member val In = inKeyword
override val Children: Node array =
[| yield! noa xmlDoc
@@ -2066,7 +2077,8 @@ type BindingNode
yield! nodes (List.map Pattern.Node parameters)
yield! noa returnType
yield equals
- yield Expr.Node expr |]
+ yield Expr.Node expr
+ yield! noa inKeyword |]
type BindingListNode(bindings: BindingNode list, range) =
inherit NodeBase(range)
diff --git a/src/Fantomas.Core/Trivia.fs b/src/Fantomas.Core/Trivia.fs
index 8ea4141fed..7063833e58 100644
--- a/src/Fantomas.Core/Trivia.fs
+++ b/src/Fantomas.Core/Trivia.fs
@@ -136,15 +136,14 @@ type ConditionalDirectiveTrivia with
| ConditionalDirectiveTrivia.Else m
| ConditionalDirectiveTrivia.EndIf m -> m
-let internal collectTriviaFromDirectives
+let internal collectTriviaFromDirectiveRanges
(source: ISourceText)
- (directives: ConditionalDirectiveTrivia list)
+ (directiveRanges: range list)
(codeRange: range)
: TriviaNode list =
- directives
- |> List.filter (fun cdt -> RangeHelpers.rangeContainsRange codeRange cdt.Range)
- |> List.map (fun cdt ->
- let m = cdt.Range
+ directiveRanges
+ |> List.filter (RangeHelpers.rangeContainsRange codeRange)
+ |> List.map (fun m ->
let text = (source.GetSubTextFromRange m).TrimEnd()
let content = Directive text
TriviaNode(content, m))
@@ -180,9 +179,6 @@ let rec visitLastChildNode (node: Node) : Node =
| :? ExprSameInfixAppsNode
| :? ExprInfixAppNode
| :? ExprLambdaNode
- | :? ExprLetOrUseNode
- | :? ExprLetOrUseBangNode
- | :? ExprAndBang
| :? BindingNode
| :? TypeDefnEnumNode
| :? TypeDefnUnionNode
@@ -312,27 +308,27 @@ let addToTree (tree: Oak) (trivia: TriviaNode seq) =
let enrichTree (config: FormatConfig) (sourceText: ISourceText) (ast: ParsedInput) (tree: Oak) : Oak =
let fullTreeRange = tree.Range
- let directives, codeComments =
+ let parsedTrivia =
match ast with
- | ParsedInput.ImplFile(ParsedImplFileInput(
- trivia = { ConditionalDirectives = directives
- CodeComments = codeComments })) -> directives, codeComments
- | ParsedInput.SigFile(ParsedSigFileInput(
- trivia = { ConditionalDirectives = directives
- CodeComments = codeComments })) -> directives, codeComments
+ | ParsedInput.ImplFile(ParsedImplFileInput(trivia = t))
+ | ParsedInput.SigFile(ParsedSigFileInput(trivia = t)) -> t
let trivia =
let newlines =
- collectTriviaFromBlankLines config sourceText tree codeComments fullTreeRange
+ collectTriviaFromBlankLines config sourceText tree parsedTrivia.CodeComments fullTreeRange
let comments =
- match ast with
- | ParsedInput.ImplFile(ParsedImplFileInput(trivia = trivia)) ->
- collectTriviaFromCodeComments sourceText trivia.CodeComments fullTreeRange
- | ParsedInput.SigFile(ParsedSigFileInput(trivia = trivia)) ->
- collectTriviaFromCodeComments sourceText trivia.CodeComments fullTreeRange
+ collectTriviaFromCodeComments sourceText parsedTrivia.CodeComments fullTreeRange
- let directives = collectTriviaFromDirectives sourceText directives fullTreeRange
+ let directiveRanges =
+ (parsedTrivia.ConditionalDirectives |> List.map _.Range)
+ @ (parsedTrivia.WarnDirectives
+ |> List.map (function
+ | WarnDirectiveTrivia.Nowarn(m)
+ | WarnDirectiveTrivia.Warnon(m) -> m))
+
+ let directives =
+ collectTriviaFromDirectiveRanges sourceText directiveRanges fullTreeRange
[| yield! comments; yield! newlines; yield! directives |]
|> Array.sortBy (fun n -> n.Range.Start.Line, n.Range.Start.Column)
diff --git a/src/Fantomas.Core/packages.lock.json b/src/Fantomas.Core/packages.lock.json
index 2d733dafbc..76ad1fb086 100644
--- a/src/Fantomas.Core/packages.lock.json
+++ b/src/Fantomas.Core/packages.lock.json
@@ -16,9 +16,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"G-Research.FSharp.Analyzers": {
"type": "Direct",
@@ -121,7 +121,7 @@
"fantomas.fcs": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"System.Collections.Immutable": "[8.0.0, )",
"System.Diagnostics.DiagnosticSource": "[8.0.1, )",
"System.Memory": "[4.6.0, )",
diff --git a/src/Fantomas.FCS/Fantomas.FCS.fsproj b/src/Fantomas.FCS/Fantomas.FCS.fsproj
index dc2b8f3d4a..dbc05bc235 100644
--- a/src/Fantomas.FCS/Fantomas.FCS.fsproj
+++ b/src/Fantomas.FCS/Fantomas.FCS.fsproj
@@ -33,6 +33,12 @@
Utilities\Activity.fs
+
+ Utilities\Caches.fsi
+
+
+ Utilities\Caches.fs
+
Utilities\sformat.fsi
@@ -220,11 +226,11 @@
SyntaxTree\pplex.fsl
- --module Fantomas.FCS.PPParser --open Fantomas.FCS --open Fantomas.FCS.Syntax --open Fantomas.FCS.ParseHelpers --internal --lexlib Internal.Utilities.Text.Lexing --parslib Internal.Utilities.Text.Parsing --buffer-type-argument char
+ --module Fantomas.FCS.PPParser --open Fantomas.FCS --open Fantomas.FCS.Syntax --open Fantomas.FCS.ParseHelpers --open Fantomas.FCS.LexerStore --internal --lexlib Internal.Utilities.Text.Lexing --parslib Internal.Utilities.Text.Parsing --buffer-type-argument char
SyntaxTree\pppars.fsy
- --module Fantomas.FCS.Lexer --open Fantomas.FCS.Lexhelp --open Internal.Utilities.Text.Lexing --open Fantomas.FCS.Parser --open Fantomas.FCS.Text --open Fantomas.FCS.ParseHelpers --internal --unicode --lexlib Internal.Utilities.Text.Lexing
+ --module Fantomas.FCS.Lexer --open Fantomas.FCS.Lexhelp --open Internal.Utilities.Text.Lexing --open Fantomas.FCS.Parser --open Fantomas.FCS.Text --open Fantomas.FCS.ParseHelpers --open Fantomas.FCS.LexerStore --internal --unicode --lexlib Internal.Utilities.Text.Lexing
SyntaxTree\lex.fsl
@@ -273,6 +279,18 @@
SyntaxTree\SyntaxTreeOps.fs
+
+ SyntaxTree\WarnScopes.fsi
+
+
+ SyntaxTree\WarnScopes.fs
+
+
+ SyntaxTree\LexerStore.fsi
+
+
+ SyntaxTree\LexerStore.fs
+
SyntaxTree\ParseHelpers.fsi
diff --git a/src/Fantomas.FCS/Parse.fs b/src/Fantomas.FCS/Parse.fs
index e95dcea013..f12385f1ae 100644
--- a/src/Fantomas.FCS/Parse.fs
+++ b/src/Fantomas.FCS/Parse.fs
@@ -11,6 +11,7 @@ open Fantomas.FCS
open Fantomas.FCS.AbstractIL.IL
open Fantomas.FCS.DiagnosticsLogger
open Fantomas.FCS.Features
+open Fantomas.FCS.LexerStore
open Fantomas.FCS.Lexhelp
open Fantomas.FCS.Text
open Fantomas.FCS.Text.Position
@@ -153,27 +154,16 @@ let QualFileNameOfImpls filename specs =
| [ SynModuleOrNamespace(kind = kind; range = m) ] when not kind.IsModule -> QualFileNameOfFilename m filename
| _ -> QualFileNameOfFilename (mkRange filename pos0 pos0) filename
-let GetScopedPragmasForInput input =
- match input with
- | ParsedInput.SigFile(ParsedSigFileInput(scopedPragmas = pragmas)) -> pragmas
- | ParsedInput.ImplFile(ParsedImplFileInput(scopedPragmas = pragmas)) -> pragmas
+let collectCodeComments (lexbuf: UnicodeLexing.Lexbuf) =
+ let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions lexbuf
-let collectCodeComments (lexbuf: UnicodeLexing.Lexbuf) (tripleSlashComments: range list) =
- [ yield! LexbufCommentStore.GetComments(lexbuf)
- yield! (List.map CommentTrivia.LineComment tripleSlashComments) ]
+ [ yield! CommentStore.GetComments(lexbuf)
+ yield! List.map CommentTrivia.LineComment tripleSlashComments ]
|> List.sortBy (function
| CommentTrivia.LineComment r
| CommentTrivia.BlockComment r -> r.StartLine, r.StartColumn)
-let PostParseModuleImpls
- (
- defaultNamespace,
- filename,
- isLastCompiland,
- ParsedImplFile(hashDirectives, impls),
- lexbuf: UnicodeLexing.Lexbuf,
- tripleSlashComments: range list
- ) =
+let PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, ParsedImplFile(hashDirectives, impls), lexbuf) =
match
impls
|> List.rev
@@ -191,23 +181,13 @@ let PostParseModuleImpls
let qualName = QualFileNameOfImpls filename impls
let isScript = IsScript filename
- let scopedPragmas = []
- let conditionalDirectives = LexbufIfdefStore.GetTrivia(lexbuf)
- let codeComments = collectCodeComments lexbuf tripleSlashComments
+ let trivia =
+ { ConditionalDirectives = IfdefStore.GetTrivia(lexbuf)
+ WarnDirectives = WarnScopes.getDirectiveTrivia (lexbuf)
+ CodeComments = collectCodeComments lexbuf }
ParsedInput.ImplFile(
- ParsedImplFileInput(
- filename,
- isScript,
- qualName,
- scopedPragmas,
- hashDirectives,
- impls,
- isLastCompiland,
- { ConditionalDirectives = conditionalDirectives
- CodeComments = codeComments },
- Set.empty
- )
+ ParsedImplFileInput(filename, isScript, qualName, hashDirectives, impls, isLastCompiland, trivia, Set.empty)
)
let PostParseModuleSpec (_i, defaultNamespace, _isLastCompiland, filename, intf) =
@@ -273,14 +253,8 @@ let PostParseModuleSpec (_i, defaultNamespace, _isLastCompiland, filename, intf)
SynModuleOrNamespaceSig(lid, isRecursive, kind, decls, xmlDoc, attributes, None, range, trivia)
let PostParseModuleSpecs
- (
- defaultNamespace,
- filename,
- isLastCompiland,
- ParsedSigFile(hashDirectives, specs),
- lexbuf: UnicodeLexing.Lexbuf,
- tripleSlashComments: range list
- ) =
+ (defaultNamespace, filename, isLastCompiland, ParsedSigFile(hashDirectives, specs), lexbuf: UnicodeLexing.Lexbuf)
+ =
match
specs
|> List.rev
@@ -296,23 +270,13 @@ let PostParseModuleSpecs
|> List.mapi (fun i x -> PostParseModuleSpec(i, defaultNamespace, isLastCompiland, filename, x))
let qualName = QualFileNameOfSpecs filename specs
- let scopedPragmas = []
-
- let conditionalDirectives = LexbufIfdefStore.GetTrivia(lexbuf)
- let codeComments = collectCodeComments lexbuf tripleSlashComments
-
- ParsedInput.SigFile(
- ParsedSigFileInput(
- filename,
- qualName,
- scopedPragmas,
- hashDirectives,
- specs,
- { ConditionalDirectives = conditionalDirectives
- CodeComments = codeComments },
- Set.empty
- )
- )
+
+ let trivia =
+ { ConditionalDirectives = IfdefStore.GetTrivia(lexbuf)
+ WarnDirectives = WarnScopes.getDirectiveTrivia (lexbuf)
+ CodeComments = collectCodeComments lexbuf }
+
+ ParsedInput.SigFile(ParsedSigFileInput(filename, qualName, hashDirectives, specs, trivia, Set.empty))
let ParseInput
(
@@ -337,38 +301,24 @@ let ParseInput
use _ = UseDiagnosticsLogger delayLogger
use _ = UseBuildPhase BuildPhase.Parse
- let mutable scopedPragmas = []
-
try
- let input =
- if mlCompatSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
- if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
- errorR (Error(FSComp.SR.buildInvalidSourceFileExtensionML filename, rangeStartup))
- else
- mlCompatWarning (FSComp.SR.buildCompilingExtensionIsForML ()) rangeStartup
-
- // Call the appropriate parser - for signature files or implementation files
- if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
- let impl = Parser.implementationFile lexer lexbuf
-
- let tripleSlashComments =
- LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf)
-
- PostParseModuleImpls(defaultNamespace, filename, isLastCompiland, impl, lexbuf, tripleSlashComments)
- elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
- let intfs = Parser.signatureFile lexer lexbuf
-
- let tripleSlashComments =
- LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf)
-
- PostParseModuleSpecs(defaultNamespace, filename, isLastCompiland, intfs, lexbuf, tripleSlashComments)
- else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
- error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated filename, rangeStartup))
+ if mlCompatSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
+ if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
+ errorR (Error(FSComp.SR.buildInvalidSourceFileExtensionML filename, rangeStartup))
else
- error (Error(FSComp.SR.buildInvalidSourceFileExtension filename, rangeStartup))
-
- scopedPragmas <- GetScopedPragmasForInput input
- input
+ mlCompatWarning (FSComp.SR.buildCompilingExtensionIsForML ()) rangeStartup
+
+ // Call the appropriate parser - for signature files or implementation files
+ if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
+ let impl = Parser.implementationFile lexer lexbuf
+ PostParseModuleImpls(defaultNamespace, filename, isLastCompiland, impl, lexbuf)
+ elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
+ let intfs = Parser.signatureFile lexer lexbuf
+ PostParseModuleSpecs(defaultNamespace, filename, isLastCompiland, intfs, lexbuf)
+ else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
+ error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated filename, rangeStartup))
+ else
+ error (Error(FSComp.SR.buildInvalidSourceFileExtension filename, rangeStartup))
finally
// OK, now commit the errors, since the ScopedPragmas will (hopefully) have been scraped
let filteringErrorLogger = errorLogger // TODO: does this matter? //GetErrorLoggerFilteringByScopedPragmas(false, scopedPragmas, diagnosticOptions, errorLogger)
@@ -379,16 +329,7 @@ let EmptyParsedInput (filename, isLastCompiland) =
if FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then
ParsedInput.SigFile(
- ParsedSigFileInput(
- filename,
- QualFileNameOfImpls filename [],
- [],
- [],
- [],
- { ConditionalDirectives = []
- CodeComments = [] },
- Set.empty
- )
+ ParsedSigFileInput(filename, QualFileNameOfImpls filename [], [], [], ParsedInputTrivia.Empty, Set.empty)
)
else
ParsedInput.ImplFile(
@@ -398,10 +339,8 @@ let EmptyParsedInput (filename, isLastCompiland) =
QualFileNameOfImpls filename [],
[],
[],
- [],
isLastCompiland,
- { ConditionalDirectives = []
- CodeComments = [] },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
diff --git a/src/Fantomas.FCS/packages.lock.json b/src/Fantomas.FCS/packages.lock.json
index 2e46fd10c8..cb7006a63b 100644
--- a/src/Fantomas.FCS/packages.lock.json
+++ b/src/Fantomas.FCS/packages.lock.json
@@ -16,9 +16,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"FsLexYacc": {
"type": "Direct",
diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj
index 8243c389c8..502ee6f1a0 100644
--- a/src/Fantomas.Tests/Fantomas.Tests.fsproj
+++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj
@@ -1,7 +1,7 @@
- net8.0
+ net10.0
false
false
FS0988
diff --git a/src/Fantomas.Tests/packages.lock.json b/src/Fantomas.Tests/packages.lock.json
index 1786c3260a..f168991f53 100644
--- a/src/Fantomas.Tests/packages.lock.json
+++ b/src/Fantomas.Tests/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net8.0": {
+ "net10.0": {
"FsCheck": {
"type": "Direct",
"requested": "[2.16.5, )",
@@ -13,9 +13,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"FsUnit": {
"type": "Direct",
@@ -102,23 +102,10 @@
"resolved": "17.6.3",
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA=="
},
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "1.1.1",
- "contentHash": "TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ=="
- },
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.3",
- "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
- },
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.12.0",
- "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==",
- "dependencies": {
- "System.Reflection.Metadata": "1.6.0"
- }
+ "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ=="
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
@@ -154,8 +141,7 @@
"contentHash": "r4G7uHHfoo8LCilPOdtf2C+Q5ymHOAXtciT4ZtB2xRlAvv4gPkWBYNAijFblStv3+uidp81j5DP11jMZl4BfJw==",
"dependencies": {
"Microsoft.VisualStudio.Threading": "17.10.48",
- "Microsoft.VisualStudio.Validation": "17.8.8",
- "System.IO.Pipelines": "8.0.0"
+ "Microsoft.VisualStudio.Validation": "17.8.8"
}
},
"System.Configuration.ConfigurationManager": {
@@ -166,16 +152,6 @@
"System.Security.Cryptography.ProtectedData": "4.4.0"
}
},
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
- },
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "1.6.0",
- "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
- },
"System.Security.Cryptography.ProtectedData": {
"type": "Transitive",
"resolved": "4.4.0",
@@ -207,7 +183,7 @@
"type": "Project",
"dependencies": {
"Argu": "[6.2.4, )",
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"Fantomas.Client": "[1.0.0, )",
"Fantomas.Core": "[1.0.0, )",
"Ignore": "[0.2.1, )",
@@ -224,7 +200,7 @@
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
@@ -232,18 +208,14 @@
"fantomas.core": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"Fantomas.FCS": "[1.0.0, )"
}
},
"fantomas.fcs": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
- "System.Collections.Immutable": "[8.0.0, )",
- "System.Diagnostics.DiagnosticSource": "[8.0.1, )",
- "System.Memory": "[4.6.0, )",
- "System.Runtime": "[4.3.1, )"
+ "FSharp.Core": "[9.0.300, )"
}
},
"Argu": {
@@ -321,22 +293,9 @@
"Microsoft.VisualStudio.Threading.Analyzers": "17.10.48",
"Microsoft.VisualStudio.Validation": "17.8.8",
"Nerdbank.Streams": "2.11.74",
- "Newtonsoft.Json": "13.0.1",
- "System.IO.Pipelines": "8.0.0"
+ "Newtonsoft.Json": "13.0.1"
}
},
- "System.Collections.Immutable": {
- "type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "CentralTransitive",
- "requested": "[8.0.1, )",
- "resolved": "8.0.1",
- "contentHash": "vaoWjvkG1aenR2XdjaVivlCV9fADfgyhW5bZtXT23qaEea0lWiUljdQuze4E31vKM7ZWJaSUsbYIKE3rnzfZUg=="
- },
"System.IO.Abstractions": {
"type": "CentralTransitive",
"requested": "[21.1.3, )",
@@ -347,22 +306,6 @@
"TestableIO.System.IO.Abstractions.Wrappers": "21.1.3"
}
},
- "System.Memory": {
- "type": "CentralTransitive",
- "requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "OEkbBQoklHngJ8UD8ez2AERSk2g+/qpAaSWWCBFbpH727HxDq5ydVkuncBaKcKfwRqXGWx64dS6G1SUScMsitg=="
- },
- "System.Runtime": {
- "type": "CentralTransitive",
- "requested": "[4.3.1, )",
- "resolved": "4.3.1",
- "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.1",
- "Microsoft.NETCore.Targets": "1.1.3"
- }
- },
"Thoth.Json.Net": {
"type": "CentralTransitive",
"requested": "[12.0.0, )",
diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj
index 08a87ac2bd..cb1f9b3788 100644
--- a/src/Fantomas/Fantomas.fsproj
+++ b/src/Fantomas/Fantomas.fsproj
@@ -1,7 +1,7 @@
Exe
- net8.0
+ net10.0
en
diff --git a/src/Fantomas/packages.lock.json b/src/Fantomas/packages.lock.json
index 3ccde9971a..581ee2db52 100644
--- a/src/Fantomas/packages.lock.json
+++ b/src/Fantomas/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net8.0": {
+ "net10.0": {
"Argu": {
"type": "Direct",
"requested": "[6.2.4, )",
@@ -32,9 +32,9 @@
},
"FSharp.Core": {
"type": "Direct",
- "requested": "[8.0.100, )",
- "resolved": "8.0.100",
- "contentHash": "ZOVZ/o+jI3ormTZOa28Wh0tSRoyle1f7lKFcUN61sPiXI7eDZu8eSveFybgTeyIEyW0ujjp31cp7GOglDgsNEg=="
+ "requested": "[9.0.300, )",
+ "resolved": "9.0.300",
+ "contentHash": "TVt2J7RCE1KCS2IaONF+p8/KIZ1eHNbW+7qmKF6hGoD4tXl+o07ja1mPtFjMqRa5uHMFaTrGTPn/m945WnDLiQ=="
},
"G-Research.FSharp.Analyzers": {
"type": "Direct",
@@ -101,8 +101,7 @@
"Microsoft.VisualStudio.Threading.Analyzers": "17.10.48",
"Microsoft.VisualStudio.Validation": "17.8.8",
"Nerdbank.Streams": "2.11.74",
- "Newtonsoft.Json": "13.0.1",
- "System.IO.Pipelines": "8.0.0"
+ "Newtonsoft.Json": "13.0.1"
}
},
"System.IO.Abstractions": {
@@ -158,16 +157,6 @@
"resolved": "17.6.3",
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA=="
},
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "1.1.1",
- "contentHash": "TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ=="
- },
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.3",
- "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
- },
"Microsoft.SourceLink.AzureRepos.Git": {
"type": "Transitive",
"resolved": "1.1.1",
@@ -234,8 +223,7 @@
"contentHash": "r4G7uHHfoo8LCilPOdtf2C+Q5ymHOAXtciT4ZtB2xRlAvv4gPkWBYNAijFblStv3+uidp81j5DP11jMZl4BfJw==",
"dependencies": {
"Microsoft.VisualStudio.Threading": "17.10.48",
- "Microsoft.VisualStudio.Validation": "17.8.8",
- "System.IO.Pipelines": "8.0.0"
+ "Microsoft.VisualStudio.Validation": "17.8.8"
}
},
"System.Configuration.ConfigurationManager": {
@@ -246,11 +234,6 @@
"System.Security.Cryptography.ProtectedData": "4.4.0"
}
},
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
- },
"System.Security.Cryptography.ProtectedData": {
"type": "Transitive",
"resolved": "4.4.0",
@@ -272,7 +255,7 @@
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
@@ -280,18 +263,14 @@
"fantomas.core": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"Fantomas.FCS": "[1.0.0, )"
}
},
"fantomas.fcs": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
- "System.Collections.Immutable": "[8.0.0, )",
- "System.Diagnostics.DiagnosticSource": "[8.0.1, )",
- "System.Memory": "[4.6.0, )",
- "System.Runtime": "[4.3.1, )"
+ "FSharp.Core": "[9.0.300, )"
}
},
"Newtonsoft.Json": {
@@ -305,34 +284,6 @@
"requested": "[2.0.2, )",
"resolved": "2.0.2",
"contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA=="
- },
- "System.Collections.Immutable": {
- "type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "CentralTransitive",
- "requested": "[8.0.1, )",
- "resolved": "8.0.1",
- "contentHash": "vaoWjvkG1aenR2XdjaVivlCV9fADfgyhW5bZtXT23qaEea0lWiUljdQuze4E31vKM7ZWJaSUsbYIKE3rnzfZUg=="
- },
- "System.Memory": {
- "type": "CentralTransitive",
- "requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "OEkbBQoklHngJ8UD8ez2AERSk2g+/qpAaSWWCBFbpH727HxDq5ydVkuncBaKcKfwRqXGWx64dS6G1SUScMsitg=="
- },
- "System.Runtime": {
- "type": "CentralTransitive",
- "requested": "[4.3.1, )",
- "resolved": "4.3.1",
- "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.1",
- "Microsoft.NETCore.Targets": "1.1.3"
- }
}
}
}