My latest shot at this is by using the rescript-tools doc
command. (from @rescript/tools
)
In a simple script I get the json ast from a file, traverse the nodes a bit and generate some simple code.
open Tools_Docgen
@scope(("import", "meta")) @val external importMetaDir: string = "dir"
let currentDir = Path.resolve([importMetaDir])
let domainFile = Path.join([currentDir, "..", "functions", "src", "Domain.res"])
let json = await (sh`bun rescript-tools doc ${domainFile}`)->ShellPromise.json
let doc = decodeFromJson(json)
let domainFirebase = doc.items->Array.find(item => {
switch item {
| Module({id: "Domain.Firebase"}) => true
| _ => false
}
})
let records = switch domainFirebase {
| Some(Module({items})) =>
items->ArrayX.choose(item => {
switch item {
| Type({name, detail: Record({items: fields})}) => {
let fieldNames = fields->Array.map(f => f.name)
Some(name, fieldNames)
}
| _ => None
}
})
| _ => []
}
let keysFile = Path.join([Path.dirname(domainFile), "Keys.res"])
let uppercase = (value: string) => {
let capital = value->String.substring(~start=0, ~end=1)->String.toUpperCase
let rest = String.substringToEnd(~start=1, value)
`${capital}${rest}`
}
let contents =
records
->Array.map(((name, properties)) => {
let keys = properties->Array.map(p => `let ${p} = "${p}"`)->Array.join("\n")
`module ${uppercase(name)} = {
${keys}
}`
})
->Array.join("\n\n")
->Bun.Write.Input.fromString
let _ = await Bun.Write.write(
~destination=Bun.Write.Destination.fromPath(keysFile),
~input=contents,
)
let _ = await sh`bun rescript format ${keysFile}`
Console.log("Keys.res was generated")