From f83dbe10063643b8e89b20ac44dbd21d386e67e9 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Nov 2024 11:56:23 +0100 Subject: [PATCH 1/9] Use JSON.t in decodeFromJson --- runtime/RescriptTools_Docgen.res | 2 +- runtime/RescriptTools_Docgen.resi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/RescriptTools_Docgen.res b/runtime/RescriptTools_Docgen.res index c6b7d450c1..ade88ff0e0 100644 --- a/runtime/RescriptTools_Docgen.res +++ b/runtime/RescriptTools_Docgen.res @@ -89,4 +89,4 @@ type doc = { /** `decodeFromJson(json)` parse JSON generated from `restool doc` command */ -external decodeFromJson: Js.Json.t => doc = "%identity" +external decodeFromJson: JSON.t => doc = "%identity" diff --git a/runtime/RescriptTools_Docgen.resi b/runtime/RescriptTools_Docgen.resi index 271f65f993..4775d3348b 100644 --- a/runtime/RescriptTools_Docgen.resi +++ b/runtime/RescriptTools_Docgen.resi @@ -85,4 +85,4 @@ type doc = { items: array, } -let decodeFromJson: Js.Json.t => doc +let decodeFromJson: JSON.t => doc From 23a3b6717139c0f45931ef824bb9c5714e9c4a44 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Nov 2024 13:21:29 +0100 Subject: [PATCH 2/9] Add additional signature information to doc json --- runtime/RescriptTools_Docgen.res | 13 ++++ runtime/RescriptTools_Docgen.resi | 14 ++++ tools/bin/main.ml | 2 +- tools/src/tools.ml | 105 ++++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 8 deletions(-) diff --git a/runtime/RescriptTools_Docgen.res b/runtime/RescriptTools_Docgen.res index ade88ff0e0..2dc939a86d 100644 --- a/runtime/RescriptTools_Docgen.res +++ b/runtime/RescriptTools_Docgen.res @@ -17,10 +17,21 @@ type constructor = { payload?: constructorPayload, } +type rec typeInSignature = { + path: string, + genericTypeParameters: array, +} + +type signatureDetais = { + parameters: array, + returnType: typeInSignature, +} + @tag("kind") type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) + | @as("alias") Signature({details:signatureDetais}) type source = { filepath: string, @@ -38,6 +49,8 @@ type rec item = name: string, deprecated?: string, source: source, + /** Additional documentation of signature, if available. */ + detail?: detail, }) | @as("type") Type({ diff --git a/runtime/RescriptTools_Docgen.resi b/runtime/RescriptTools_Docgen.resi index 4775d3348b..116c6c4027 100644 --- a/runtime/RescriptTools_Docgen.resi +++ b/runtime/RescriptTools_Docgen.resi @@ -16,10 +16,22 @@ type constructor = { deprecated?: string, payload?: constructorPayload, } + +type rec typeInSignature = { + path: string, + genericTypeParameters: array, +} + +type signatureDetais = { + parameters: array, + returnType: typeInSignature, +} + @tag("kind") type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) + | @as("signature") Signature({details:signatureDetais}) type source = { filepath: string, @@ -37,6 +49,8 @@ type rec item = name: string, deprecated?: string, source: source, + /** Additional documentation of signature, if available. */ + detail?: detail, }) | @as("type") Type({ diff --git a/tools/bin/main.ml b/tools/bin/main.ml index 06be383b1b..bde33dc0f2 100644 --- a/tools/bin/main.ml +++ b/tools/bin/main.ml @@ -14,7 +14,7 @@ Usage: rescript-tools [command] Commands: -doc Generate documentation +doc Generate documentation reanalyze Reanalyze -v, --version Print version -h, --help Print help|} diff --git a/tools/src/tools.ml b/tools/src/tools.ml index 53aa439494..db5a052d68 100644 --- a/tools/src/tools.ml +++ b/tools/src/tools.ml @@ -18,11 +18,15 @@ type constructorDoc = { items: constructorPayload option; } +type typeDoc = {path: string; genericParameters: typeDoc list} +type valueSignature = {parameters: typeDoc list; returnType: typeDoc} + type source = {filepath: string; line: int; col: int} type docItemDetail = | Record of {fieldDocs: fieldDoc list} | Variant of {constructorDocs: constructorDoc list} + | Signature of valueSignature type docItem = | Value of { @@ -31,6 +35,7 @@ type docItem = signature: string; name: string; deprecated: string option; + detail: docItemDetail option; source: source; } | Type of { @@ -104,6 +109,19 @@ let stringifyConstructorPayload ~indentation |> array) ); ] +let rec stringifyTypeDoc ~indentation (td : typeDoc) : string = + let open Protocol in + let ps = + match td.genericParameters with + | [] -> None + | ts -> + ts |> List.map (stringifyTypeDoc ~indentation:(indentation + 1)) + |> fun ts -> Some (array ts) + in + + stringifyObject ~indentation:(indentation + 1) + [("path", Some (wrapInQuotes td.path)); ("genericTypeParameters", ps)] + let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = let open Protocol in match detail with @@ -147,6 +165,25 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = ]) |> array) ); ] + | Signature {parameters; returnType} -> + let ps = + match parameters with + | [] -> None + | ps -> + ps |> List.map (stringifyTypeDoc ~indentation:(indentation + 1)) + |> fun ps -> Some (array ps) + in + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "signature")); + ( "details", + Some + (stringifyObject ~startOnNewline:false ~indentation + [ + ("parameters", ps); + ("returnType", Some (stringifyTypeDoc ~indentation returnType)); + ]) ); + ] let stringifySource ~indentation source = let open Protocol in @@ -160,7 +197,7 @@ let stringifySource ~indentation source = let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {id; docstring; signature; name; deprecated; source} -> + | Value {id; docstring; signature; name; deprecated; source; detail} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); @@ -173,6 +210,11 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ("signature", Some (signature |> String.trim |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); ("source", Some (stringifySource ~indentation:(indentation + 1) source)); + ( "detail", + match detail with + | None -> None + | Some detail -> + Some (stringifyDetail ~indentation:(indentation + 1) detail) ); ] | Type {id; docstring; signature; name; deprecated; detail; source} -> stringifyObject ~startOnNewline:true ~indentation @@ -310,6 +352,60 @@ let typeDetail typ ~env ~full = }) | _ -> None +(* split a list into two parts all the items except the last one and the last item *) +let splitLast l = + let rec splitLast' acc = function + | [] -> failwith "splitLast: empty list" + | [x] -> (List.rev acc, x) + | x :: xs -> splitLast' (x :: acc) xs + in + splitLast' [] l + +let path_to_string path = + let buf = Buffer.create 64 in + let rec aux = function + | Path.Pident id -> Buffer.add_string buf (Ident.name id) + | Path.Pdot (p, s, _) -> + aux p; + Buffer.add_char buf '.'; + Buffer.add_string buf s + | Path.Papply (p1, p2) -> + aux p1; + Buffer.add_char buf '('; + aux p2; + Buffer.add_char buf ')' + in + aux path; + Buffer.contents buf + +let valueDetail (typ : Types.type_expr) = + let rec collectSignatureTypes (typ_desc : Types.type_desc) = + match typ_desc with + | Tlink t | Tsubst t | Tpoly (t, []) -> collectSignatureTypes t.desc + | Tconstr (Path.Pident {name = "function$"}, [t; _], _) -> + collectSignatureTypes t.desc + | Tconstr (path, ts, _) -> ( + let p = path_to_string path in + match ts with + | [] -> [{path = p; genericParameters = []}] + | ts -> + let ts = + ts + |> List.concat_map (fun (t : Types.type_expr) -> + collectSignatureTypes t.desc) + in + [{path = p; genericParameters = ts}]) + | Tarrow (_, t1, t2, _) -> + collectSignatureTypes t1.desc @ collectSignatureTypes t2.desc + | Tvar None -> [{path = "_"; genericParameters = []}] + | _ -> [] + in + match collectSignatureTypes typ.desc with + | [] -> None + | ts -> + let parameters, returnType = splitLast ts in + Some (Signature {parameters; returnType}) + let makeId modulePath ~identifier = identifier :: modulePath |> List.rev |> SharedTypes.ident @@ -385,12 +481,6 @@ let extractDocs ~entryPointFile ~debug = items = structure.items |> List.filter_map (fun (item : Module.item) -> - let item = - { - item with - name = Ext_ident.unwrap_uppercase_exotic item.name; - } - in let source = getSource ~rootPath item.loc in match item.kind with | Value typ -> @@ -404,6 +494,7 @@ let extractDocs ~entryPointFile ~debug = ^ Shared.typeToString typ; name = item.name; deprecated = item.deprecated; + detail = valueDetail typ; source; }) | Type (typ, _) -> From 8e12704424b722af090858ad5517a05a5029b260 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Nov 2024 15:34:52 +0100 Subject: [PATCH 3/9] Update tests --- tests/tools_tests/package-lock.json | 1 + .../src/expected/DocExtraction2.res.json | 24 ++++ .../src/expected/DocExtraction2.resi.json | 24 ++++ .../src/expected/DocExtractionRes.res.json | 114 +++++++++++++++++- tests/tools_tests/src/expected/ModC.res.json | 9 ++ tests/tools_tests/src/expected/ModC.resi.json | 9 ++ 6 files changed, 178 insertions(+), 3 deletions(-) diff --git a/tests/tools_tests/package-lock.json b/tests/tools_tests/package-lock.json index a8a3fb40a7..b0670b1847 100644 --- a/tests/tools_tests/package-lock.json +++ b/tests/tools_tests/package-lock.json @@ -22,6 +22,7 @@ "bsc": "cli/bsc", "bstracing": "lib/bstracing", "rescript": "cli/rescript", + "rescript-tools": "cli/rescript-tools", "rewatch": "cli/rewatch" }, "devDependencies": { diff --git a/tests/tools_tests/src/expected/DocExtraction2.res.json b/tests/tools_tests/src/expected/DocExtraction2.res.json index 224daefdc6..6b252b0548 100644 --- a/tests/tools_tests/src/expected/DocExtraction2.res.json +++ b/tests/tools_tests/src/expected/DocExtraction2.res.json @@ -30,6 +30,18 @@ "filepath": "src/DocExtraction2.resi", "line": 7, "col": 1 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "unit" + }], + "returnType": { + "path": "t" + } + } } }, { @@ -65,6 +77,18 @@ "filepath": "src/DocExtraction2.resi", "line": 15, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "unit" + }], + "returnType": { + "path": "t" + } + } } }] }] diff --git a/tests/tools_tests/src/expected/DocExtraction2.resi.json b/tests/tools_tests/src/expected/DocExtraction2.resi.json index 224daefdc6..6b252b0548 100644 --- a/tests/tools_tests/src/expected/DocExtraction2.resi.json +++ b/tests/tools_tests/src/expected/DocExtraction2.resi.json @@ -30,6 +30,18 @@ "filepath": "src/DocExtraction2.resi", "line": 7, "col": 1 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "unit" + }], + "returnType": { + "path": "t" + } + } } }, { @@ -65,6 +77,18 @@ "filepath": "src/DocExtraction2.resi", "line": 15, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "unit" + }], + "returnType": { + "path": "t" + } + } } }] }] diff --git a/tests/tools_tests/src/expected/DocExtractionRes.res.json b/tests/tools_tests/src/expected/DocExtractionRes.res.json index 93a727b3b1..ae4b46dd8a 100644 --- a/tests/tools_tests/src/expected/DocExtractionRes.res.json +++ b/tests/tools_tests/src/expected/DocExtractionRes.res.json @@ -45,6 +45,18 @@ "filepath": "src/DocExtractionRes.res", "line": 17, "col": 5 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "string" + }], + "returnType": { + "path": "t" + } + } } }, { @@ -57,18 +69,39 @@ "filepath": "src/DocExtractionRes.res", "line": 23, "col": 5 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "t" + }], + "returnType": { + "path": "t" + } + } } }, { - "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", "line": 26, "col": 5 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "int" + } + } } }, { @@ -184,6 +217,18 @@ "filepath": "src/DocExtractionRes.res", "line": 49, "col": 7 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "SomeInnerModule.status" + }], + "returnType": { + "path": "bool" + } + } } }, { @@ -268,6 +313,18 @@ "filepath": "src/DocExtractionRes.res", "line": 71, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "unit" + }], + "returnType": { + "path": "t" + } + } } }] }, @@ -304,6 +361,18 @@ "filepath": "src/DocExtractionRes.res", "line": 109, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "t" + }], + "returnType": { + "path": "t" + } + } } }] }, @@ -341,6 +410,18 @@ "filepath": "src/DocExtractionRes.res", "line": 128, "col": 7 + }, + "detail": + { + "kind": "signature", + "details": { + "parameters": [{ + "path": "int" + }], + "returnType": { + "path": "int" + } + } } }] }, @@ -365,6 +446,15 @@ "filepath": "src/DocExtractionRes.res", "line": 132, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "int" + } + } } }] }, @@ -390,6 +480,15 @@ "filepath": "src/DocExtractionRes.res", "line": 136, "col": 7 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "int" + } + } } }] }, @@ -426,6 +525,15 @@ "filepath": "src/DocExtractionRes.res", "line": 141, "col": 9 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "int" + } + } } }] }] diff --git a/tests/tools_tests/src/expected/ModC.res.json b/tests/tools_tests/src/expected/ModC.res.json index 4f68f61912..f90a09755f 100644 --- a/tests/tools_tests/src/expected/ModC.res.json +++ b/tests/tools_tests/src/expected/ModC.res.json @@ -29,6 +29,15 @@ "filepath": "src/ModC.resi", "line": 5, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "string" + } + } } }] }] diff --git a/tests/tools_tests/src/expected/ModC.resi.json b/tests/tools_tests/src/expected/ModC.resi.json index 4f68f61912..f90a09755f 100644 --- a/tests/tools_tests/src/expected/ModC.resi.json +++ b/tests/tools_tests/src/expected/ModC.resi.json @@ -29,6 +29,15 @@ "filepath": "src/ModC.resi", "line": 5, "col": 3 + }, + "detail": + { + "kind": "signature", + "details": { + "returnType": { + "path": "string" + } + } } }] }] From 1123cc8e08b2b9c895f879b283faeea07c3ff3fb Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 19 Nov 2024 15:31:06 +0100 Subject: [PATCH 4/9] Format docgen code --- runtime/RescriptTools_Docgen.res | 2 +- runtime/RescriptTools_Docgen.resi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/RescriptTools_Docgen.res b/runtime/RescriptTools_Docgen.res index 2dc939a86d..c877c2e56f 100644 --- a/runtime/RescriptTools_Docgen.res +++ b/runtime/RescriptTools_Docgen.res @@ -31,7 +31,7 @@ type signatureDetais = { type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) - | @as("alias") Signature({details:signatureDetais}) + | @as("alias") Signature({details: signatureDetais}) type source = { filepath: string, diff --git a/runtime/RescriptTools_Docgen.resi b/runtime/RescriptTools_Docgen.resi index 116c6c4027..c9d4f6ec04 100644 --- a/runtime/RescriptTools_Docgen.resi +++ b/runtime/RescriptTools_Docgen.resi @@ -31,7 +31,7 @@ type signatureDetais = { type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) - | @as("signature") Signature({details:signatureDetais}) + | @as("signature") Signature({details: signatureDetais}) type source = { filepath: string, From 6c5f523b88d81c28d36a61201b38915981497a09 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 20 Nov 2024 13:31:00 +0100 Subject: [PATCH 5/9] Revert removal of unwrap_uppercase_exotic --- tools/src/tools.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/src/tools.ml b/tools/src/tools.ml index db5a052d68..0048087e0d 100644 --- a/tools/src/tools.ml +++ b/tools/src/tools.ml @@ -481,6 +481,12 @@ let extractDocs ~entryPointFile ~debug = items = structure.items |> List.filter_map (fun (item : Module.item) -> + let item = + { + item with + name = Ext_ident.unwrap_uppercase_exotic item.name; + } + in let source = getSource ~rootPath item.loc in match item.kind with | Value typ -> From a2db7b086f3bc5ee848717410deda952996d1650 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 20 Nov 2024 13:33:41 +0100 Subject: [PATCH 6/9] Update tests --- tests/tools_tests/src/expected/DocExtractionRes.res.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tools_tests/src/expected/DocExtractionRes.res.json b/tests/tools_tests/src/expected/DocExtractionRes.res.json index ae4b46dd8a..02d688135b 100644 --- a/tests/tools_tests/src/expected/DocExtractionRes.res.json +++ b/tests/tools_tests/src/expected/DocExtractionRes.res.json @@ -84,10 +84,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", From 23caa08445d8e67426836c9b2b702b444fb521aa Mon Sep 17 00:00:00 2001 From: Florian Verdonck Date: Wed, 20 Nov 2024 13:39:28 +0100 Subject: [PATCH 7/9] Update runtime/RescriptTools_Docgen.res Co-authored-by: Christoph Knittel --- runtime/RescriptTools_Docgen.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/RescriptTools_Docgen.res b/runtime/RescriptTools_Docgen.res index c877c2e56f..8d767512e0 100644 --- a/runtime/RescriptTools_Docgen.res +++ b/runtime/RescriptTools_Docgen.res @@ -22,7 +22,7 @@ type rec typeInSignature = { genericTypeParameters: array, } -type signatureDetais = { +type signatureDetails = { parameters: array, returnType: typeInSignature, } From 09482bef75c87366a2b9362e4080cc6ad18d0875 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 20 Nov 2024 13:47:09 +0100 Subject: [PATCH 8/9] Fix typo in signature --- runtime/RescriptTools_Docgen.resi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/RescriptTools_Docgen.resi b/runtime/RescriptTools_Docgen.resi index c9d4f6ec04..a2fba2580e 100644 --- a/runtime/RescriptTools_Docgen.resi +++ b/runtime/RescriptTools_Docgen.resi @@ -22,7 +22,7 @@ type rec typeInSignature = { genericTypeParameters: array, } -type signatureDetais = { +type signatureDetails = { parameters: array, returnType: typeInSignature, } From c8f7c3f28a8edb75a382abdb5c00a12d9e7d8299 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 20 Nov 2024 13:51:58 +0100 Subject: [PATCH 9/9] Fix more typos --- runtime/RescriptTools_Docgen.res | 2 +- runtime/RescriptTools_Docgen.resi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/RescriptTools_Docgen.res b/runtime/RescriptTools_Docgen.res index 8d767512e0..c77e71bcbe 100644 --- a/runtime/RescriptTools_Docgen.res +++ b/runtime/RescriptTools_Docgen.res @@ -31,7 +31,7 @@ type signatureDetails = { type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) - | @as("alias") Signature({details: signatureDetais}) + | @as("alias") Signature({details: signatureDetails}) type source = { filepath: string, diff --git a/runtime/RescriptTools_Docgen.resi b/runtime/RescriptTools_Docgen.resi index a2fba2580e..c5d443e71d 100644 --- a/runtime/RescriptTools_Docgen.resi +++ b/runtime/RescriptTools_Docgen.resi @@ -31,7 +31,7 @@ type signatureDetails = { type detail = | @as("record") Record({items: array}) | @as("variant") Variant({items: array}) - | @as("signature") Signature({details: signatureDetais}) + | @as("signature") Signature({details: signatureDetails}) type source = { filepath: string,