rescript-vscode
rescript-vscode copied to clipboard
docgen does not distinguish between module and functor
Currently a functor is treated exactly like a module (but ignores existent docstrings).
Example Functor to test docgen
/***
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
{
"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 kind value): "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?)