From 6479000923f62a6e910850eb2f4c74d1ae91a363 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 25 Feb 2024 19:39:15 +0100 Subject: [PATCH] distinguish regular modules from module types --- analysis/src/ProcessCmt.ml | 17 +++++-- analysis/src/SharedTypes.ml | 2 +- tools/npm/Tools_Docgen.res | 9 ++++ tools/npm/Tools_Docgen.resi | 9 ++++ tools/src/tools.ml | 44 +++++++++++++++++-- tools/tests/src/DocExtractionRes.res | 34 +++++++++++++- .../src/expected/DocExtractionRes.res.json | 42 ++++++++++++++++-- 7 files changed, 145 insertions(+), 12 deletions(-) diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index c54e625ca..44d2cd907 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -1,5 +1,10 @@ open SharedTypes +let isModuleType (declared : Module.t Declared.t) = + match declared.modulePath with + | ExportedModule {isType} -> isType + | _ -> false + let addDeclared ~(name : string Location.loc) ~extent ~stamp ~(env : Env.t) ~item attributes addExported addStamp = let isExported = addExported name.txt stamp in @@ -150,7 +155,8 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) in [ { - Module.kind = Module declared.item; + Module.kind = + Module {type_ = declared.item; isModuleType = isModuleType declared}; name = declared.name.txt; docstring = declared.docstring; deprecated = declared.deprecated; @@ -367,7 +373,8 @@ let rec forSignatureItem ~env ~(exported : Exported.t) in [ { - Module.kind = Module declared.item; + Module.kind = + Module {type_ = declared.item; isModuleType = isModuleType declared}; name = declared.name.txt; docstring = declared.docstring; deprecated = declared.deprecated; @@ -481,7 +488,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = in [ { - Module.kind = Module declared.item; + Module.kind = + Module {type_ = declared.item; isModuleType = isModuleType declared}; name = declared.name.txt; docstring = declared.docstring; deprecated = declared.deprecated; @@ -513,7 +521,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = in [ { - Module.kind = Module modTypeItem; + Module.kind = + Module {type_ = declared.item; isModuleType = isModuleType declared}; name = declared.name.txt; docstring = declared.docstring; deprecated = declared.deprecated; diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 50ae41f8f..a3f807745 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -120,7 +120,7 @@ module Module = struct type kind = | Value of Types.type_expr | Type of Type.t * Types.rec_status - | Module of t + | Module of {type_: t; isModuleType: bool} and item = { kind: kind; diff --git a/tools/npm/Tools_Docgen.res b/tools/npm/Tools_Docgen.res index 631a54ce8..f060ab07e 100644 --- a/tools/npm/Tools_Docgen.res +++ b/tools/npm/Tools_Docgen.res @@ -59,6 +59,15 @@ type rec item = source: source, items: array, }) + | @as("moduleType") + ModuleType({ + id: string, + docstrings: array, + deprecated?: string, + name: string, + source: source, + items: array, + }) | @as("moduleAlias") ModuleAlias({ id: string, diff --git a/tools/npm/Tools_Docgen.resi b/tools/npm/Tools_Docgen.resi index c6d7595eb..c410170aa 100644 --- a/tools/npm/Tools_Docgen.resi +++ b/tools/npm/Tools_Docgen.resi @@ -58,6 +58,15 @@ type rec item = source: source, items: array, }) + | @as("moduleType") + ModuleType({ + id: string, + docstrings: array, + deprecated?: string, + name: string, + source: source, + items: array, + }) | @as("moduleAlias") ModuleAlias({ id: string, diff --git a/tools/src/tools.ml b/tools/src/tools.ml index 0db7ee50b..934175b32 100644 --- a/tools/src/tools.ml +++ b/tools/src/tools.ml @@ -44,6 +44,7 @@ type docItem = (** Additional documentation for constructors and record fields, if available. *) } | Module of docsForModule + | ModuleType of docsForModule | ModuleAlias of { id: string; docstring: string list; @@ -204,6 +205,26 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = (stringifyDocItem ~originalEnv ~indentation:(indentation + 1)) |> array) ); ] + | ModuleType m -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("id", Some (wrapInQuotes m.id)); + ("name", Some (wrapInQuotes m.name)); + ("kind", Some (wrapInQuotes "moduleType")); + ( "deprecated", + match m.deprecated with + | Some d -> Some (wrapInQuotes d) + | None -> None ); + ("docstrings", Some (stringifyDocstrings m.docstring)); + ( "source", + Some (stringifySource ~indentation:(indentation + 1) m.source) ); + ( "items", + Some + (m.items + |> List.map + (stringifyDocItem ~originalEnv ~indentation:(indentation + 1)) + |> array) ); + ] | ModuleAlias m -> stringifyObject ~startOnNewline:true ~indentation [ @@ -379,7 +400,7 @@ let extractDocs ~entryPointFile ~debug = detail = typeDetail typ ~full ~env; source; }) - | Module (Ident p) -> + | Module {type_ = Ident p; isModuleType = false} -> (* module Whatever = OtherModule *) let aliasToModule = p |> pathIdentToString in let id = @@ -409,7 +430,7 @@ let extractDocs ~entryPointFile ~debug = item.docstring @ internalDocstrings |> List.map String.trim; }) - | Module (Structure m) -> + | Module {type_ = Structure m; isModuleType = false} -> (* module Whatever = {} in res or module Whatever: {} in resi. *) let modulePath = m.name :: modulePath in let docs = extractDocsForModule ~modulePath m in @@ -423,8 +444,25 @@ let extractDocs ~entryPointFile ~debug = source; items = docs.items; }) + | Module {type_ = Structure m; isModuleType = true} -> + (* module type Whatever = {} *) + let modulePath = m.name :: modulePath in + let docs = extractDocsForModule ~modulePath m in + Some + (ModuleType + { + id = modulePath |> List.rev |> ident; + name = m.name; + docstring = item.docstring @ m.docstring; + deprecated = item.deprecated; + source; + items = docs.items; + }) | Module - (Constraint (Structure _impl, Structure interface)) -> + { + type_ = + Constraint (Structure _impl, Structure interface); + } -> (* module Whatever: { } = { }. Prefer the interface. *) Some (Module diff --git a/tools/tests/src/DocExtractionRes.res b/tools/tests/src/DocExtractionRes.res index 9ccd611c7..68c3256e6 100644 --- a/tools/tests/src/DocExtractionRes.res +++ b/tools/tests/src/DocExtractionRes.res @@ -23,7 +23,7 @@ let make = name => { let asOffline = (t: t) => {...t, online: false} /** exotic identifier */ -let \"SomeConstant\" = 12 +let \"SomeConstant" = 12 module SomeInnerModule = { /*** Another module level docstring here.*/ @@ -96,4 +96,36 @@ module ModuleWithThingsThatShouldNotBeExported: { } } +module type Example = { + /*** + this is an example module type + */ + + /** + main type of this module + */ + type t + + /** + function from t to t + */ + let f: t => t +} + +module M: Example = { + /*** + implementation of Example module type + */ + + /** + main type + */ + type t = int + + /** + identity function + */ + let f = (x: int) => x +} + // ^dex diff --git a/tools/tests/src/expected/DocExtractionRes.res.json b/tools/tests/src/expected/DocExtractionRes.res.json index 240355504..3ea8b7eb8 100644 --- a/tools/tests/src/expected/DocExtractionRes.res.json +++ b/tools/tests/src/expected/DocExtractionRes.res.json @@ -60,10 +60,10 @@ } }, { - "id": "DocExtractionRes.SomeConstant\\", + "id": "DocExtractionRes.SomeConstant", "kind": "value", - "name": "SomeConstant\\", - "signature": "let SomeConstant\\: int", + "name": "SomeConstant", + "signature": "let SomeConstant: int", "docstrings": ["exotic identifier"], "source": { "filepath": "src/DocExtractionRes.res", @@ -270,5 +270,41 @@ "col": 3 } }] + }, + { + "id": "DocExtractionRes.Example", + "name": "Example", + "kind": "moduleType", + "docstrings": [], + "source": { + "filepath": "src/DocExtractionRes.res", + "line": 99, + "col": 13 + }, + "items": [ + { + "id": "DocExtractionRes.Example.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["main type of this module"], + "source": { + "filepath": "src/DocExtractionRes.res", + "line": 107, + "col": 3 + } + }, + { + "id": "DocExtractionRes.Example.f", + "kind": "value", + "name": "f", + "signature": "let f: t => t", + "docstrings": ["function from t to t"], + "source": { + "filepath": "src/DocExtractionRes.res", + "line": 109, + "col": 3 + } + }] }] }