rescript-vscode icon indicating copy to clipboard operation
rescript-vscode copied to clipboard

docgen does not distinguish between module and functor

Open woeps opened this issue 1 year ago • 0 comments

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?)

woeps avatar Jun 07 '24 20:06 woeps