Skip to content

Instantly share code, notes, and snippets.

@mjblacker
Created October 18, 2024 06:02
Show Gist options
  • Save mjblacker/e663676e99d6013dbfffc06e7455e9ea to your computer and use it in GitHub Desktop.
Save mjblacker/e663676e99d6013dbfffc06e7455e9ea to your computer and use it in GitHub Desktop.
FSharp Iconify generator
#load "FSharp.Keywords.fs"
open System
open System.IO
open System.Text.Json
open System.Text.RegularExpressions
// string helpers from Glutinum
let pascalize (input : string) =
Regex.Replace(
input,
"(?:^|_|-| +)(.)",
fun m -> m.Groups[1].Value.ToUpper()
)
let capitalize (input : string) =
if input.Length > 0 then
(string input[0]).ToLower() + input.Substring(1)
else
input
let camelize (input : string) =
let word = pascalize input
if word.Length > 0 then
(string word[0]).ToLower() + word.Substring(1)
else
word
let sanitizeKeyword (input : string) =
if Set.contains input FSharp.Keywords.keywords then
input + "_"
else
input
let sanitizeIfStartWithNumber (value : string) =
if Regex.IsMatch(value, "^\d") then
"_" + value
else
value
// Generate F# code
let generateCode (iconSet: string) =
try
let iconSet = iconSet.ToLower()
// Read the JSON file
let jsonFile = $"node_modules/@iconify-json/{iconSet}/icons.json"
let jsonText = File.ReadAllText(jsonFile)
let jsonDocument = JsonDocument.Parse(jsonText)
// Extract icon names
let iconNames =
jsonDocument.RootElement.GetProperty("icons").EnumerateObject()
|> Seq.map (fun prop -> prop.Name)
|> Seq.toList
// PascalCase the module name
let moduleName = iconSet |> pascalize
// setup the new file to generate
let sb = System.Text.StringBuilder()
sb.AppendLine($"module Feliz.Iconify") |> ignore
sb.AppendLine("") |> ignore
sb.AppendLine($" [<RequireQualifiedAccess>]") |> ignore
sb.AppendLine($" module {moduleName} = ") |> ignore
for icon in iconNames do
let cleanIconName = icon |> camelize |> sanitizeIfStartWithNumber |> sanitizeKeyword
sb.AppendLine($" let [<Literal>] {cleanIconName} = \"{iconSet}--{icon}\"") |> ignore
sb.ToString() |> Ok
with
| _ -> Error "Failed, ensure the iconSet has been installed using NPM/Yarn first"
// get the arg for the name of the package
let args =
match fsi.CommandLineArgs |> Array.toList with
| _::tail when tail.IsEmpty = false -> tail |> List.head |> Ok
| _ -> Error "Please provide an installed icon set name as the argument"
match args with
| Ok iconSet ->
// Generate and write the F# code to a file
match generateCode iconSet with
| Ok generatedCode ->
let fileName = iconSet |> pascalize |> (+) <| "Icons.fs"
File.WriteAllText(fileName, generatedCode)
printfn $"F# code generated successfully in {fileName}"
| Error msg ->
printfn $"{msg}"
| Error msg ->
printfn $"{msg}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment