Hello ReScript community,
I want to perform code generation on simple types by developing a custom attribute. My goal is to generate the corresponding builder pattern for a given type by adding this attribute. I believe there’s a strong use case for this in scenarios like forms, where filling out a type one property at a time is cumbersome, even with make functions.
// src/User.res
@builder
type user = {
name: string,
age: int,
}
// Generated output would look like:
// src/generated/UserBuilder.res
type t = {
name: option<string>,
age: option<int>,
}
let empty = () => {
name: None,
age: None,
}
let withName = (builder: t, name: string) => {
...builder,
name: Some(name),
}
let withAge = (builder: t, age: int) => {
...builder,
age: Some(age),
}
// Build with validation
let build = (builder: t): result<User.user, string> => {
switch (builder.name, builder.age) {
| (Some(name), Some(age)) =>
Ok({
name,
age,
})
| (None, _) => Error("User name is missing")
| (_, None) => Error("User age is missing")
}
}
// Usage example:
let user = UserBuilder.empty()
->UserBuilder.withName("John")
->UserBuilder.withAge(30)
->UserBuilder.build()
Based on this post’s response, I understand that working with PPXs is cautioned against because the AST evolves internally and could cause breakage.
The other option I’m aware of is dumping the AST via npx bsc -dparsetree MyFile.res and working with the generated dump file.
I’ve also considered a pure ReScript/regex solution, but that does not seem idiomatic to me.
What is the best approach for creating an attribute such as the @builder attribute that I hope to develop? Should I use PPX, work with the ReScript AST directly, or is there another recommended approach?