Currently a functor is treated exactly like a module (but ignores existent docstrings).
Example Functor to test docgen
```rescript
/***
this module provides "convenient" utilities for logging
NOTE: this is not a good example of a functor,
but just to test docgen for functors
*/
module type Input = {
/***
input module type of the functor
*/
/**
type of the input
*/
type t
/**
converts the input to a string
*/
let toString: t => string
}
module type Logger = {
/***
returned type of the functor
*/
/**
type of the input
*/
type t
/**
logs the input
*/
let log: t => unit
}
module String = {
/***
input module of the functor to hanle strings
*/
/**
type of the input
*/
type t = string
/**
converts the input to a string
*/
let toString = (x: t) => x
}
module Int = {
/***
input module of the functor to handle integers
*/
/**
type of the input
*/
type t = int
/**
converts the input to a string
*/
let toString = (x: t) => x->Int.toString
}
/**
functor that logs the input
*/
module MakeLogger = (I: Input): (Logger with type t := I.t) => {
/***
functor that logs the input
*/
/**
logs the Input
*/
let log = (x: I.t) => I.toString(x)->Console.log
}
/**
the module that contains the functions to log strings
*/
module StringLogger = MakeLogger(String)
/**
the module that contains the functions to log integers
*/
module IntLogger = MakeLogger(Int)
module Var = {
/***
another input module for the Logger functor to handle a Variant of type type
*/
/**
type of the input
*/
type t = Yes | No
/**
converts the input to a string
*/
let toString = x =>
switch x {
| Yes => "Yes"
| No => "No"
}
}
module Included = {
/***
module which includes the Var Logger!
*/
include MakeLogger(Var)
}
```
generated json
```json
{
"name": "Functor",
"docstrings": ["this module provides \"convenient\" utilities for logging \nNOTE: this is not a good example of a functor,\n but just to test docgen for functors"],
"source": {
"filepath": "test/Functor.res",
"line": 1,
"col": 1
},
"items": [
{
"id": "Functor.Input",
"name": "Input",
"kind": "moduleType",
"docstrings": [],
"source": {
"filepath": "test/Functor.res",
"line": 7,
"col": 13
},
"items": [
{
"id": "Functor.Input.t",
"kind": "type",
"name": "t",
"signature": "type t",
"docstrings": ["type of the input"],
"source": {
"filepath": "test/Functor.res",
"line": 15,
"col": 3
}
},
{
"id": "Functor.Input.toString",
"kind": "value",
"name": "toString",
"signature": "let toString: t => string",
"docstrings": ["converts the input to a string"],
"source": {
"filepath": "test/Functor.res",
"line": 16,
"col": 3
}
}]
},
{
"id": "Functor.Logger",
"name": "Logger",
"kind": "moduleType",
"docstrings": [],
"source": {
"filepath": "test/Functor.res",
"line": 22,
"col": 13
},
"items": [
{
"id": "Functor.Logger.t",
"kind": "type",
"name": "t",
"signature": "type t",
"docstrings": ["type of the input"],
"source": {
"filepath": "test/Functor.res",
"line": 30,
"col": 3
}
},
{
"id": "Functor.Logger.log",
"kind": "value",
"name": "log",
"signature": "let log: t => unit",
"docstrings": ["logs the input"],
"source": {
"filepath": "test/Functor.res",
"line": 31,
"col": 3
}
}]
},
{
"id": "Functor.String",
"name": "String",
"kind": "module",
"docstrings": ["input module of the functor to hanle strings"],
"source": {
"filepath": "test/Functor.res",
"line": 37,
"col": 8
},
"items": [
{
"id": "Functor.String.t",
"kind": "type",
"name": "t",
"signature": "type t = string",
"docstrings": ["type of the input"],
"source": {
"filepath": "test/Functor.res",
"line": 45,
"col": 3
}
},
{
"id": "Functor.String.toString",
"kind": "value",
"name": "toString",
"signature": "let toString: t => t",
"docstrings": ["converts the input to a string"],
"source": {
"filepath": "test/Functor.res",
"line": 50,
"col": 7
}
}]
},
{
"id": "Functor.Int",
"name": "Int",
"kind": "module",
"docstrings": ["input module of the functor to handle integers"],
"source": {
"filepath": "test/Functor.res",
"line": 53,
"col": 8
},
"items": [
{
"id": "Functor.Int.t",
"kind": "type",
"name": "t",
"signature": "type t = int",
"docstrings": ["type of the input"],
"source": {
"filepath": "test/Functor.res",
"line": 61,
"col": 3
}
},
{
"id": "Functor.Int.toString",
"kind": "value",
"name": "toString",
"signature": "let toString: t => string",
"docstrings": ["converts the input to a string"],
"source": {
"filepath": "test/Functor.res",
"line": 66,
"col": 7
}
}]
},
{
"id": "Functor.MakeLogger", <-- this is the functor
"name": "MakeLogger",
"kind": "module",
"docstrings": [], <-- empty docstrings
"source": {
"filepath": "test/Functor.res",
"line": 1,
"col": 1
},
"items": [
{
"id": "Functor.MakeLogger.log",
"kind": "value",
"name": "log",
"signature": "let log: I.t => unit",
"docstrings": ["logs the input"],
"source": {
"filepath": "test/Functor.res",
"line": 31,
"col": 3
}
}]
},
{
"id": "Functor.StringLogger",
"kind": "moduleAlias",
"name": "StringLogger",
"docstrings": ["the module that contains the functions to log strings"],
"source": {
"filepath": "test/Functor.res",
"line": 86,
"col": 8
},
"items": []
},
{
"id": "Functor.IntLogger",
"kind": "moduleAlias",
"name": "IntLogger",
"docstrings": ["the module that contains the functions to log integers"],
"source": {
"filepath": "test/Functor.res",
"line": 90,
"col": 8
},
"items": []
},
{
"id": "Functor.Var",
"name": "Var",
"kind": "module",
"docstrings": ["another input module for the Logger functor to handle a Variant of type type"],
"source": {
"filepath": "test/Functor.res",
"line": 92,
"col": 8
},
"items": [
{
"id": "Functor.Var.t",
"kind": "type",
"name": "t",
"signature": "type t = Yes | No",
"docstrings": ["type of the input"],
"source": {
"filepath": "test/Functor.res",
"line": 100,
"col": 3
},
"detail":
{
"kind": "variant",
"items": [
{
"name": "Yes",
"docstrings": [],
"signature": "Yes"
},
{
"name": "No",
"docstrings": [],
"signature": "No"
}]
}
},
{
"id": "Functor.Var.toString",
"kind": "value",
"name": "toString",
"signature": "let toString: t => string",
"docstrings": ["converts the input to a string"],
"source": {
"filepath": "test/Functor.res",
"line": 105,
"col": 7
}
}]
},
{
"id": "Functor.Included",
"name": "Included",
"kind": "module",
"docstrings": ["module which includes the Var Logger!"],
"source": {
"filepath": "test/Functor.res",
"line": 112,
"col": 8
},
"items": [
{
"id": "Functor.Included.log",
"kind": "value",
"name": "log",
"signature": "let log: Var.t => unit",
"docstrings": ["logs the input"],
"source": {
"filepath": "test/Functor.res",
"line": 31,
"col": 3
}
}]
}]
}
```
I guess we need to introduce a new kind called functor?
At least a "signature" field should be present (similar to items of kindvalue): "signature": "module MakeLogger = (I: Input) => (Logger with type t := I.t)". And docstrings should be taken into account.
Questions
What to show as return type for a functor with no explicit return type annotation?
How to handle (destructive) substitution (with type...:= / = e.g. Logger with type t := I.t)? Is there something to do at all?
How to make referenced module types machine readable? (should there be a json field with an array of referenced module type ids? (How) Is this related to #1010?)
Currently a functor is treated exactly like a module (but ignores existent docstrings).
Example Functor to test docgen
```rescript /*** this module provides "convenient" utilities for logging NOTE: this is not a good example of a functor, but just to test docgen for functors */ module type Input = { /*** input module type of the functor */ /** type of the input */ type t /** converts the input to a string */ let toString: t => string } module type Logger = { /*** returned type of the functor */ /** type of the input */ type t /** logs the input */ let log: t => unit } module String = { /*** input module of the functor to hanle strings */ /** type of the input */ type t = string /** converts the input to a string */ let toString = (x: t) => x } module Int = { /*** input module of the functor to handle integers */ /** type of the input */ type t = int /** converts the input to a string */ let toString = (x: t) => x->Int.toString } /** functor that logs the input */ module MakeLogger = (I: Input): (Logger with type t := I.t) => { /*** functor that logs the input */ /** logs the Input */ let log = (x: I.t) => I.toString(x)->Console.log } /** the module that contains the functions to log strings */ module StringLogger = MakeLogger(String) /** the module that contains the functions to log integers */ module IntLogger = MakeLogger(Int) module Var = { /*** another input module for the Logger functor to handle a Variant of type type */ /** type of the input */ type t = Yes | No /** converts the input to a string */ let toString = x => switch x { | Yes => "Yes" | No => "No" } } module Included = { /*** module which includes the Var Logger! */ include MakeLogger(Var) } ```generated json
```json { "name": "Functor", "docstrings": ["this module provides \"convenient\" utilities for logging \nNOTE: this is not a good example of a functor,\n but just to test docgen for functors"], "source": { "filepath": "test/Functor.res", "line": 1, "col": 1 }, "items": [ { "id": "Functor.Input", "name": "Input", "kind": "moduleType", "docstrings": [], "source": { "filepath": "test/Functor.res", "line": 7, "col": 13 }, "items": [ { "id": "Functor.Input.t", "kind": "type", "name": "t", "signature": "type t", "docstrings": ["type of the input"], "source": { "filepath": "test/Functor.res", "line": 15, "col": 3 } }, { "id": "Functor.Input.toString", "kind": "value", "name": "toString", "signature": "let toString: t => string", "docstrings": ["converts the input to a string"], "source": { "filepath": "test/Functor.res", "line": 16, "col": 3 } }] }, { "id": "Functor.Logger", "name": "Logger", "kind": "moduleType", "docstrings": [], "source": { "filepath": "test/Functor.res", "line": 22, "col": 13 }, "items": [ { "id": "Functor.Logger.t", "kind": "type", "name": "t", "signature": "type t", "docstrings": ["type of the input"], "source": { "filepath": "test/Functor.res", "line": 30, "col": 3 } }, { "id": "Functor.Logger.log", "kind": "value", "name": "log", "signature": "let log: t => unit", "docstrings": ["logs the input"], "source": { "filepath": "test/Functor.res", "line": 31, "col": 3 } }] }, { "id": "Functor.String", "name": "String", "kind": "module", "docstrings": ["input module of the functor to hanle strings"], "source": { "filepath": "test/Functor.res", "line": 37, "col": 8 }, "items": [ { "id": "Functor.String.t", "kind": "type", "name": "t", "signature": "type t = string", "docstrings": ["type of the input"], "source": { "filepath": "test/Functor.res", "line": 45, "col": 3 } }, { "id": "Functor.String.toString", "kind": "value", "name": "toString", "signature": "let toString: t => t", "docstrings": ["converts the input to a string"], "source": { "filepath": "test/Functor.res", "line": 50, "col": 7 } }] }, { "id": "Functor.Int", "name": "Int", "kind": "module", "docstrings": ["input module of the functor to handle integers"], "source": { "filepath": "test/Functor.res", "line": 53, "col": 8 }, "items": [ { "id": "Functor.Int.t", "kind": "type", "name": "t", "signature": "type t = int", "docstrings": ["type of the input"], "source": { "filepath": "test/Functor.res", "line": 61, "col": 3 } }, { "id": "Functor.Int.toString", "kind": "value", "name": "toString", "signature": "let toString: t => string", "docstrings": ["converts the input to a string"], "source": { "filepath": "test/Functor.res", "line": 66, "col": 7 } }] }, { "id": "Functor.MakeLogger", <-- this is the functor "name": "MakeLogger", "kind": "module", "docstrings": [], <-- empty docstrings "source": { "filepath": "test/Functor.res", "line": 1, "col": 1 }, "items": [ { "id": "Functor.MakeLogger.log", "kind": "value", "name": "log", "signature": "let log: I.t => unit", "docstrings": ["logs the input"], "source": { "filepath": "test/Functor.res", "line": 31, "col": 3 } }] }, { "id": "Functor.StringLogger", "kind": "moduleAlias", "name": "StringLogger", "docstrings": ["the module that contains the functions to log strings"], "source": { "filepath": "test/Functor.res", "line": 86, "col": 8 }, "items": [] }, { "id": "Functor.IntLogger", "kind": "moduleAlias", "name": "IntLogger", "docstrings": ["the module that contains the functions to log integers"], "source": { "filepath": "test/Functor.res", "line": 90, "col": 8 }, "items": [] }, { "id": "Functor.Var", "name": "Var", "kind": "module", "docstrings": ["another input module for the Logger functor to handle a Variant of type type"], "source": { "filepath": "test/Functor.res", "line": 92, "col": 8 }, "items": [ { "id": "Functor.Var.t", "kind": "type", "name": "t", "signature": "type t = Yes | No", "docstrings": ["type of the input"], "source": { "filepath": "test/Functor.res", "line": 100, "col": 3 }, "detail": { "kind": "variant", "items": [ { "name": "Yes", "docstrings": [], "signature": "Yes" }, { "name": "No", "docstrings": [], "signature": "No" }] } }, { "id": "Functor.Var.toString", "kind": "value", "name": "toString", "signature": "let toString: t => string", "docstrings": ["converts the input to a string"], "source": { "filepath": "test/Functor.res", "line": 105, "col": 7 } }] }, { "id": "Functor.Included", "name": "Included", "kind": "module", "docstrings": ["module which includes the Var Logger!"], "source": { "filepath": "test/Functor.res", "line": 112, "col": 8 }, "items": [ { "id": "Functor.Included.log", "kind": "value", "name": "log", "signature": "let log: Var.t => unit", "docstrings": ["logs the input"], "source": { "filepath": "test/Functor.res", "line": 31, "col": 3 } }] }] } ```I guess we need to introduce a new
kind
calledfunctor
? At least a "signature" field should be present (similar to items ofkind
value
):"signature": "module MakeLogger = (I: Input) => (Logger with type t := I.t)"
. And docstrings should be taken into account.Questions
with type
...:=
/=
e.g.Logger with type t := I.t
)? Is there something to do at all?