Ppxlib deriver that produces modified types

Hi! I’m trying to create a ppxlib deriver that should emit original types with some modifications and conversion functions. In general those modifications/conversions can be thought of some validation, that can change the type of validated value. For example we might want to have an int option field foo in the original record type t to be required - deriver should emit some t_validated where field foo is of type int without an option and there should be some functions validated_of_t (returning result) and t_of_validated that convert the values back and forth.

The task itself is pretty straightfoward, but I’m a bit stuck on how to generate a new type out of ppxlib deriver plugin. Hooks that I pass to Ppxlib.Deriving.add (~str_type_decl and ~sig_type_decl) get called for each type for a group of recursive types, and when I emit a modified type group in one of those hooks - it gets emitted twice. So far I was unable to find proper place that will get called once for each group of recursive types and will appreciate some advice here.

To add some context, I’m feeding this code as an input to my deriver plugin:

type node =
  | List of alist
  | Val of string
[@@deriving my_validate ~name:"Node"]

and alist = { nodes : node list }
[@@deriving my_validate ~name:"AList"]

And I’m getting str_type_decl called twice with different ~name parameters, but each time I get both node and alist type definitions passed as ast (rec_flag * type_declaration list). I’m looking for some way to distinguish these calls of str_type_decl - which one gets called for which set of arguments within that group of recursive types.

What about something like this?

type node =
  | List of alist
  | Val of string
[@@validation_name "Node"]

and alist = { nodes : node list } 
[@@validation_name "AList"]
[@@deriving my_validate ]

Thanks @Kakadu, this trick seems to work. Ppxlib deriver is taking a group of recursive types if one of those types has corresponding attribute annotation, and per-type metadata encoded via separate attributes does not trigger extra invocations of the deriver and can be read by my code from the ast in a sane way.