From 0caefea8bbb187586387a9e544c89de83f62a468 Mon Sep 17 00:00:00 2001
From: Martin521 <29605222+Martin521@users.noreply.github.com>
Date: Tue, 3 Jun 2025 16:18:53 +0000
Subject: [PATCH 1/3] adaptations for sdk 9.0 and 10.0
---
Directory.Build.props | 2 +-
Directory.Packages.props | 2 +-
build.fsx | 4 +
global.json | 2 +-
src/Fantomas.Benchmarks/packages.lock.json | 10 +-
src/Fantomas.Client.Tests/packages.lock.json | 8 +-
src/Fantomas.Client/packages.lock.json | 6 +-
.../ASTTransformerTests.fs | 4 +-
.../AutoPropertiesTests.fs | 2 +-
src/Fantomas.Core.Tests/CommentTests.fs | 5 +
src/Fantomas.Core.Tests/HashDirectiveTests.fs | 3 +-
src/Fantomas.Core.Tests/SynLongIdentTests.fs | 4 +-
src/Fantomas.Core.Tests/packages.lock.json | 10 +-
src/Fantomas.Core/ASTTransformer.fs | 47 +++---
src/Fantomas.Core/Trivia.fs | 43 +++---
src/Fantomas.Core/packages.lock.json | 8 +-
src/Fantomas.FCS/Fantomas.FCS.fsproj | 16 +-
src/Fantomas.FCS/Parse.fs | 137 +++++-------------
src/Fantomas.FCS/packages.lock.json | 6 +-
src/Fantomas.Tests/packages.lock.json | 14 +-
src/Fantomas/packages.lock.json | 12 +-
21 files changed, 154 insertions(+), 191 deletions(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 26e34508ab..1d03c11ff1 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -45,7 +45,7 @@ Some common use cases include:
- e668b90e3c087e5fba8a855e502af60bf35be45e
+ 20ff6a94300b5f2f5498d3d8ad1a44abaabc5c22
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 084fea47dc..878be9ff50 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,7 +4,7 @@
true
-
+
diff --git a/build.fsx b/build.fsx
index 63c8458d3a..6c4a2f0e08 100644
--- a/build.fsx
+++ b/build.fsx
@@ -301,6 +301,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/global.json b/global.json
index 6f6aff9de6..d3dbe09378 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.400",
+ "version": "9.0.300",
"rollForward": "latestPatch"
}
}
\ No newline at end of file
diff --git a/src/Fantomas.Benchmarks/packages.lock.json b/src/Fantomas.Benchmarks/packages.lock.json
index cc618a9806..664a872c78 100644
--- a/src/Fantomas.Benchmarks/packages.lock.json
+++ b/src/Fantomas.Benchmarks/packages.lock.json
@@ -28,9 +28,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",
@@ -272,14 +272,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, )",
+ "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.Client.Tests/packages.lock.json b/src/Fantomas.Client.Tests/packages.lock.json
index 6bbec117ff..54e3169b0b 100644
--- a/src/Fantomas.Client.Tests/packages.lock.json
+++ b/src/Fantomas.Client.Tests/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",
@@ -137,7 +137,7 @@
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
diff --git a/src/Fantomas.Client/packages.lock.json b/src/Fantomas.Client/packages.lock.json
index 65f0ab5696..c1c97d0b32 100644
--- a/src/Fantomas.Client/packages.lock.json
+++ b/src/Fantomas.Client/packages.lock.json
@@ -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",
diff --git a/src/Fantomas.Core.Tests/ASTTransformerTests.fs b/src/Fantomas.Core.Tests/ASTTransformerTests.fs
index 498f9c86c5..41a5b7c9e0 100644
--- a/src/Fantomas.Core.Tests/ASTTransformerTests.fs
+++ b/src/Fantomas.Core.Tests/ASTTransformerTests.fs
@@ -40,7 +40,6 @@ let ``avoid stack-overflow in long array/list, 2485`` () =
true,
QualifiedNameOfFile(Ident("", Range.Zero)),
[],
- [],
[ SynModuleOrNamespace(
[],
false,
@@ -53,8 +52,7 @@ let ``avoid stack-overflow in long array/list, 2485`` () =
{ 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..8600920912 100644
--- a/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
+++ b/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
@@ -74,7 +74,7 @@ type X =
member internal Y: int with public get, private set
"""
-[]
+[]
let ``abstract member with public get, private set`` () =
formatSignatureString
"""
diff --git a/src/Fantomas.Core.Tests/CommentTests.fs b/src/Fantomas.Core.Tests/CommentTests.fs
index e3285e3e3c..228d01bb09 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 directivesXXX`` () =
+ 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/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/SynLongIdentTests.fs b/src/Fantomas.Core.Tests/SynLongIdentTests.fs
index eed7c2d0e5..c10079c6c1 100644
--- a/src/Fantomas.Core.Tests/SynLongIdentTests.fs
+++ b/src/Fantomas.Core.Tests/SynLongIdentTests.fs
@@ -352,7 +352,6 @@ let ``backticks can be added from AST only scenarios`` () =
true,
QualifiedNameOfFile testIdent,
[],
- [],
[ SynModuleOrNamespace(
[ testIdent ],
false,
@@ -377,8 +376,7 @@ let ``backticks can be added from AST only scenarios`` () =
{ LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.None }
) ],
(true, false),
- { ConditionalDirectives = []
- CodeComments = [] },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
diff --git a/src/Fantomas.Core.Tests/packages.lock.json b/src/Fantomas.Core.Tests/packages.lock.json
index 50a2903a96..87f141e46c 100644
--- a/src/Fantomas.Core.Tests/packages.lock.json
+++ b/src/Fantomas.Core.Tests/packages.lock.json
@@ -19,9 +19,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",
@@ -138,14 +138,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, )",
+ "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.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs
index 58450725c3..292d3b7984 100644
--- a/src/Fantomas.Core/ASTTransformer.fs
+++ b/src/Fantomas.Core/ASTTransformer.fs
@@ -966,22 +966,22 @@ 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)) ->
+ | SynExpr.YieldOrReturn((true, _), e, StartRange 5 (yieldKeyword, _range), _) ->
ExprSingleNode(stn "yield" yieldKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturn((false, _), e, StartRange 6 (returnKeyword, _range)) ->
+ | SynExpr.YieldOrReturn((false, _), e, StartRange 6 (returnKeyword, _range), _) ->
ExprSingleNode(stn "return" returnKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturnFrom((true, _), e, StartRange 6 (yieldBangKeyword, _range)) ->
+ | SynExpr.YieldOrReturnFrom((true, _), e, StartRange 6 (yieldBangKeyword, _range), _) ->
ExprSingleNode(stn "yield!" yieldBangKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
- | SynExpr.YieldOrReturnFrom((false, _), e, StartRange 7 (returnBangKeyword, _range)) ->
+ | SynExpr.YieldOrReturnFrom((false, _), e, StartRange 7 (returnBangKeyword, _range), _) ->
ExprSingleNode(stn "return!" returnBangKeyword, 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)) ->
+ | SynExpr.DoBang(e, StartRange 3 (doBangKeyword, _range), _) ->
ExprSingleNode(stn "do!" doBangKeyword, true, true, mkExpr creationAide e, exprRange)
|> Expr.Single
| SynExpr.Fixed(e, StartRange 5 (fixedKeyword, _range)) ->
@@ -1029,9 +1029,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)
)
@@ -1144,7 +1142,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,
@@ -2809,7 +2807,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
let memberDefinitionRange = md.Range
match md with
- | SynMemberDefn.ImplicitInherit(t, e, _, StartRange 7 (mInherit, _)) ->
+ | SynMemberDefn.ImplicitInherit(t, e, _, StartRange 7 (mInherit, _), _) ->
mkInheritConstructor creationAide t e mInherit memberDefinitionRange
|> MemberDefn.ImplicitInherit
@@ -2870,9 +2868,12 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
)
|> 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.Inherit(baseTypeOpt, _, StartRange 7 (mInherit, _), _) ->
+ match baseTypeOpt with
+ | Some baseType ->
+ MemberDefnInheritNode(stn "inherit" mInherit, 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 ]) ->
@@ -3598,25 +3599,27 @@ 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 ->
@@ -3668,7 +3671,7 @@ let mkFullTreeRange ast =
| 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 =
@@ -3688,7 +3691,7 @@ let mkFullTreeRange ast =
| 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/Trivia.fs b/src/Fantomas.Core/Trivia.fs
index 2c963cb350..4d243ee753 100644
--- a/src/Fantomas.Core/Trivia.fs
+++ b/src/Fantomas.Core/Trivia.fs
@@ -136,15 +136,21 @@ type ConditionalDirectiveTrivia with
| ConditionalDirectiveTrivia.Else m
| ConditionalDirectiveTrivia.EndIf m -> m
-let internal collectTriviaFromDirectives
+type WarnDirectiveTrivia with
+
+ member x.Range =
+ match x with
+ | WarnDirectiveTrivia.Nowarn m
+ | WarnDirectiveTrivia.Warnon m -> m
+
+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))
@@ -315,27 +321,24 @@ 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 directiveRanges =
+ (parsedTrivia.ConditionalDirectives |> List.map _.Range)
+ @ (parsedTrivia.WarnDirectives |> List.map _.Range)
- let directives = collectTriviaFromDirectives sourceText directives fullTreeRange
+ 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 423ac63843..b816c9716a 100644
--- a/src/Fantomas.Core/packages.lock.json
+++ b/src/Fantomas.Core/packages.lock.json
@@ -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",
@@ -127,7 +127,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..26de30e34b 100644
--- a/src/Fantomas.FCS/Fantomas.FCS.fsproj
+++ b/src/Fantomas.FCS/Fantomas.FCS.fsproj
@@ -220,11 +220,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 +273,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 9482e407e7..5aaf2aa316 100644
--- a/src/Fantomas.FCS/packages.lock.json
+++ b/src/Fantomas.FCS/packages.lock.json
@@ -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=="
},
"FsLexYacc": {
"type": "Direct",
diff --git a/src/Fantomas.Tests/packages.lock.json b/src/Fantomas.Tests/packages.lock.json
index 7c8f686ebd..c69c2a15ac 100644
--- a/src/Fantomas.Tests/packages.lock.json
+++ b/src/Fantomas.Tests/packages.lock.json
@@ -19,9 +19,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",
@@ -213,7 +213,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, )",
@@ -230,7 +230,7 @@
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
@@ -238,14 +238,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, )",
+ "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/packages.lock.json b/src/Fantomas/packages.lock.json
index a69893af5b..86e7420ce4 100644
--- a/src/Fantomas/packages.lock.json
+++ b/src/Fantomas/packages.lock.json
@@ -38,9 +38,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",
@@ -278,7 +278,7 @@
"fantomas.client": {
"type": "Project",
"dependencies": {
- "FSharp.Core": "[8.0.100, )",
+ "FSharp.Core": "[9.0.300, )",
"SemanticVersioning": "[2.0.2, )",
"StreamJsonRpc": "[2.20.20, )"
}
@@ -286,14 +286,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, )",
+ "FSharp.Core": "[9.0.300, )",
"System.Collections.Immutable": "[8.0.0, )",
"System.Diagnostics.DiagnosticSource": "[8.0.1, )",
"System.Memory": "[4.6.0, )",
From 421673728687c7c113b29fb17cb3d9e3ae872697 Mon Sep 17 00:00:00 2001
From: Martin521 <29605222+Martin521@users.noreply.github.com>
Date: Wed, 4 Jun 2025 11:57:33 +0000
Subject: [PATCH 2/3] review follow-up
---
src/Fantomas.Core.Tests/CommentTests.fs | 2 +-
src/Fantomas.Core/ASTTransformer.fs | 32 ++++++++++++++-----------
2 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/src/Fantomas.Core.Tests/CommentTests.fs b/src/Fantomas.Core.Tests/CommentTests.fs
index 228d01bb09..55e064344f 100644
--- a/src/Fantomas.Core.Tests/CommentTests.fs
+++ b/src/Fantomas.Core.Tests/CommentTests.fs
@@ -6,7 +6,7 @@ open Fantomas.Core.Tests.TestHelpers
open Fantomas.Core
[]
-let ``should keep sticky-to-the-left comments after #if directivesXXX`` () =
+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"
diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs
index 292d3b7984..8916c767d8 100644
--- a/src/Fantomas.Core/ASTTransformer.fs
+++ b/src/Fantomas.Core/ASTTransformer.fs
@@ -966,23 +966,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)
@@ -2807,8 +2807,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"`
@@ -2868,10 +2868,14 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
)
|> MemberDefn.ExplicitCtor
| SynMemberDefn.Member(memberDefn, _) -> mkBinding creationAide memberDefn |> MemberDefn.Member
- | SynMemberDefn.Inherit(baseTypeOpt, _, StartRange 7 (mInherit, _), _) ->
+ | SynMemberDefn.Inherit(baseTypeOpt, _, _isInline, trivia) ->
match baseTypeOpt with
| Some baseType ->
- MemberDefnInheritNode(stn "inherit" mInherit, mkType creationAide baseType, memberDefinitionRange)
+ 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
From 10b59bb1f47d0dd7a07bb02326e27aac76aca928 Mon Sep 17 00:00:00 2001
From: Martin521 <29605222+Martin521@users.noreply.github.com>
Date: Wed, 4 Jun 2025 15:39:48 +0000
Subject: [PATCH 3/3] update dockerfile also to sdk 9
---
.devcontainer/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index bda0692f15..63fd6d08db 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:9.0.300
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive