Skip to content

Instantly share code, notes, and snippets.

@jkone27
Last active January 6, 2025 18:26
Show Gist options
  • Save jkone27/9ec341d310d82a634a3a093890d16964 to your computer and use it in GitHub Desktop.
Save jkone27/9ec341d310d82a634a3a093890d16964 to your computer and use it in GitHub Desktop.
fantomas extract namespace declaration from oak synthax F# AST
#r "nuget:Fantomas.Core"
open Fantomas.Core
open Fantomas.Core.SyntaxOak
open Fantomas.FCS.Text
open System
(** `namespace A.B.C` : https://fsprojects.github.io/fantomas-tools
Oak (1,0-1,15)
ModuleOrNamespaceNode (1,0-1,15)
ModuleOrNamespaceHeaderNode (1,0-1,15)
MultipleTextsNode (1,0-1,9)
namespace (1,0-1,9)
IdentListNode (1,10-1,15)
A (1,10-1,11)
B (1,12-1,13)
C (1,14-1,15)
*)
module FantomasWriter =
let text v = SingleTextNode(v, Range.Zero)
let toMultipleTexts lst = MultipleTextsNode(lst |> Seq.map text |> Seq.toList ,Range.Zero)
let toIdentList (lst: string seq) =
let ll =
lst
|> Seq.map (fun l ->
let content = l |> text
if l = "." then
content |> IdentifierOrDot.KnownDot
else
content |> IdentifierOrDot.Ident
)
|> Seq.toList
if ll.Length > 0 then
IdentListNode(ll, Range.Zero) |> Some
else
None
let makeModuleOrNamespaceHeaderNode (nameSpaceString: string) =
let ns = nameSpaceString.ToLower().Trim().Split([|'.'|])
if ns.Length > 0 then
ModuleOrNamespaceHeaderNode(
None,
None,
[ "namespace" ] |> toMultipleTexts,
None,
false,
ns |> toIdentList,
Range.Zero) |> Some
else
None
let makeNamespace (nameSpaceString: string) decls =
let nsOpt = makeModuleOrNamespaceHeaderNode nameSpaceString
Oak([],
[
ModuleOrNamespaceNode(nsOpt, decls, Range.Zero)
], Range.Zero)
module FantomasReader =
let extractNs (iln: IdentListNode) =
iln.Content
|> List.collect (fun iod ->
match iod with
| IdentifierOrDot.Ident(stn) -> [ stn.Text ]
| _ -> []
)
|> fun l ->
if l.Length > 0 then
String.Join('.',l) |> Some
else
None
// Define a function to extract the namespace from an Oak AST
let extractNsFromOak (oak: Oak) =
oak.ModulesOrNamespaces.Head.Header
|> Option.bind (
fun header ->
match header.LeadingKeyword.Content with
| [x] when x.Text = "namespace" ->
header.Name
|> Option.bind extractNs
| _ -> None
)
// Example usage
let oakAst = FantomasWriter.makeNamespace "hello.one.two" []
oakAst
|> FantomasReader.extractNsFromOak
|> Option.iter (printfn "NAMESPACE: %s")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment