From 3d463787c79290528b41259ca5b1e53540bde670 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 9 Oct 2023 17:10:08 +0200 Subject: [PATCH 01/21] basic doc extraction --- analysis/src/Cli.ml | 1 + analysis/src/Commands.ml | 3 + analysis/src/DocExtraction.ml | 179 ++++++++++++++++++ analysis/src/ProcessCmt.ml | 71 ++++++- analysis/src/Protocol.ml | 11 +- analysis/src/SharedTypes.ml | 2 +- analysis/tests/src/DocExtractionRes.res | 44 +++++ .../src/expected/DocExtractionRes.res.txt | 97 ++++++++++ 8 files changed, 394 insertions(+), 14 deletions(-) create mode 100644 analysis/src/DocExtraction.ml create mode 100644 analysis/tests/src/DocExtractionRes.res create mode 100644 analysis/tests/src/expected/DocExtractionRes.res.txt diff --git a/analysis/src/Cli.ml b/analysis/src/Cli.ml index 87765c755..a7529b705 100644 --- a/analysis/src/Cli.ml +++ b/analysis/src/Cli.ml @@ -120,6 +120,7 @@ let main () = ~pos:(int_of_string line_start, int_of_string line_end) ~maxLength ~debug:false | [_; "codeLens"; path] -> Commands.codeLens ~path ~debug:false + | [_; "extractDocs"; path] -> DocExtraction.extractDocs ~path ~debug:false | [_; "codeAction"; path; startLine; startCol; endLine; endCol; currentFile] -> Commands.codeAction ~path diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index c46225fa0..486f46743 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -345,6 +345,9 @@ let test ~path = let currentFile = createCurrentFile () in signatureHelp ~path ~pos:(line, col) ~currentFile ~debug:true; Sys.remove currentFile + | "dex" -> + print_endline ("Documentation extraction " ^ path); + DocExtraction.extractDocs ~path ~debug:true | "int" -> print_endline ("Create Interface " ^ path); let cmiFile = diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml new file mode 100644 index 000000000..a99dd0122 --- /dev/null +++ b/analysis/src/DocExtraction.ml @@ -0,0 +1,179 @@ +let formatCode content = + let {Res_driver.parsetree = signature; comments} = + Res_driver.parseInterfaceFromSource ~forPrinter:true + ~displayFilename:"" ~source:content + in + Res_printer.printInterface ~width:!Res_cli.ResClflags.width ~comments + signature + |> String.trim + +type docItemDetail = + | Record of {fieldDocs: (string * string list) list} + | Variant of {constructorDocs: (string * string list) list} +type docItem = + | Value of {docstring: string list; signature: string; name: string} + | Type of { + docstring: string list; + signature: string; + name: string; + detail: docItemDetail option; + } + | Module of docsForModule +and docsForModule = {docstring: string list; name: string; items: docItem list} + +let stringifyDocstrings docstrings = + let open Protocol in + docstrings + |> List.map (fun docstring -> + docstring |> String.trim |> Json.escape |> wrapInQuotes) + |> array + +let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = + let open Protocol in + match detail with + | Record {fieldDocs} -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "record")); + ( "fieldDocs", + Some + (fieldDocs + |> List.map (fun (fieldName, docstrings) -> + stringifyObject ~indentation:(indentation + 1) + [ + ("fieldName", Some (wrapInQuotes fieldName)); + ("docstrings", Some (stringifyDocstrings docstrings)); + ]) + |> array) ); + ] + | Variant {constructorDocs} -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "variant")); + ( "fieldDocs", + Some + (constructorDocs + |> List.map (fun (constructorName, docstrings) -> + stringifyObject ~startOnNewline:true + ~indentation:(indentation + 1) + [ + ("constructorName", Some (wrapInQuotes constructorName)); + ("docstrings", Some (stringifyDocstrings docstrings)); + ]) + |> array) ); + ] + +let rec stringifyDocItem ?(indentation = 0) (item : docItem) = + let open Protocol in + match item with + | Value {docstring; signature; name} -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "value")); + ("name", Some (name |> Json.escape |> wrapInQuotes)); + ( "signature", + Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); + ("docstrings", Some (stringifyDocstrings docstring)); + ] + | Type {docstring; signature; name; detail} -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "type")); + ("name", Some (name |> Json.escape |> wrapInQuotes)); + ("signature", Some (signature |> Json.escape |> wrapInQuotes)); + ("docstrings", Some (stringifyDocstrings docstring)); + ( "detail", + match detail with + | None -> None + | Some detail -> + Some (stringifyDetail ~indentation:(indentation + 1) detail) ); + ] + | Module m -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("kind", Some (wrapInQuotes "module")); + ("item", Some (stringifyDocsForModule ~indentation:(indentation + 1) m)); + ] + +and stringifyDocsForModule ?(indentation = 0) (d : docsForModule) = + let open Protocol in + stringifyObject ~startOnNewline:true ~indentation + [ + ("name", Some (wrapInQuotes d.name)); + ("docstrings", Some (stringifyDocstrings d.docstring)); + ( "items", + Some + (d.items + |> List.map (stringifyDocItem ~indentation:(indentation + 1)) + |> array) ); + ] + +let extractDocs ~path ~debug = + if debug then Printf.printf "extracting docs for %s\n" path; + match Cmt.loadFullCmtFromPath ~path with + | None -> () + | Some full -> + let file = full.file in + let structure = file.structure in + let env = SharedTypes.QueryEnv.fromFile file in + let rec extractDocs (structure : SharedTypes.Module.structure) = + { + docstring = structure.docstring |> List.map String.trim; + name = structure.name; + items = + structure.items + |> List.filter_map (fun (item : SharedTypes.Module.item) -> + match item.kind with + | Value typ -> + Some + (Value + { + docstring = item.docstring |> List.map String.trim; + signature = + "let " ^ item.name ^ ": " ^ Shared.typeToString typ + |> formatCode; + name = item.name; + }) + | Type (typ, _) -> + Some + (Type + { + docstring = item.docstring |> List.map String.trim; + signature = + typ.decl + |> Shared.declToString item.name + |> formatCode; + name = item.name; + detail = + (match + TypeUtils.extractTypeFromResolvedType ~env ~full + typ + with + | Some (Trecord {fields}) -> + Some + (Record + { + fieldDocs = + fields + |> List.map + (fun (field : SharedTypes.field) -> + (field.fname.txt, field.docstring)); + }) + | Some (Tvariant {constructors}) -> + Some + (Variant + { + constructorDocs = + constructors + |> List.map + (fun (c : SharedTypes.Constructor.t) + -> (c.cname.txt, c.docstring)); + }) + | _ -> None); + }) + | Module (Structure m) -> Some (Module (extractDocs m)) + | _ -> None); + } + in + let docs = extractDocs structure in + print_endline (stringifyDocsForModule docs) diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index c7ecd8525..c2249e7c8 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -54,7 +54,13 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) newDeclared | _ -> declared in - [{Module.kind = Module.Value declared.item; name = declared.name.txt}] + [ + { + Module.kind = Module.Value declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Sig_type ( ident, ({type_loc; type_kind; type_manifest; type_attributes} as decl), @@ -121,7 +127,13 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) (Exported.add exported Exported.Type) Stamps.addType in - [{Module.kind = Type (declared.item, recStatus); name = declared.name.txt}] + [ + { + Module.kind = Type (declared.item, recStatus); + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Sig_module (ident, {md_type; md_attributes; md_loc}, _) -> let name = Ident.name ident in let declared = @@ -132,7 +144,13 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) (Exported.add exported Exported.Module) Stamps.addModule in - [{Module.kind = Module declared.item; name = declared.name.txt}] + [ + { + Module.kind = Module declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | _ -> [] and forTypeSignature ~name ~env signature = @@ -293,6 +311,7 @@ let forTypeDeclaration ~env ~(exported : Exported.t) { Module.kind = Module.Type (declared.item, recStatus); name = declared.name.txt; + docstring = declared.docstring; } let rec forSignatureItem ~env ~(exported : Exported.t) @@ -306,7 +325,13 @@ let rec forSignatureItem ~env ~(exported : Exported.t) (Exported.add exported Exported.Value) Stamps.addValue in - [{Module.kind = Module.Value declared.item; name = declared.name.txt}] + [ + { + Module.kind = Module.Value declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Tsig_type (recFlag, decls) -> decls |> List.mapi (fun i decl -> @@ -330,7 +355,13 @@ let rec forSignatureItem ~env ~(exported : Exported.t) (Exported.add exported Exported.Module) Stamps.addModule in - [{Module.kind = Module declared.item; name = declared.name.txt}] + [ + { + Module.kind = Module declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Tsig_recmodule modDecls -> modDecls |> List.map (fun modDecl -> @@ -400,7 +431,11 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Stamps.addValue in items := - {Module.kind = Module.Value declared.item; name = declared.name.txt} + { + Module.kind = Module.Value declared.item; + name = declared.name.txt; + docstring = declared.docstring; + } :: !items | Tpat_tuple pats | Tpat_array pats | Tpat_construct (_, _, pats) -> pats |> List.iter (fun p -> handlePattern [] p) @@ -429,7 +464,13 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = (Exported.add exported Exported.Module) Stamps.addModule in - [{Module.kind = Module declared.item; name = declared.name.txt}] + [ + { + Module.kind = Module declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Tstr_recmodule modDecls -> modDecls |> List.map (fun modDecl -> @@ -453,7 +494,13 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = (Exported.add exported Exported.Module) Stamps.addModule in - [{Module.kind = Module modTypeItem; name = declared.name.txt}] + [ + { + Module.kind = Module modTypeItem; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Tstr_include {incl_mod; incl_type} -> let env = match getModulePath incl_mod.mod_desc with @@ -475,7 +522,13 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = (Exported.add exported Exported.Value) Stamps.addValue in - [{Module.kind = Value declared.item; name = declared.name.txt}] + [ + { + Module.kind = Value declared.item; + name = declared.name.txt; + docstring = declared.docstring; + }; + ] | Tstr_type (recFlag, decls) -> decls |> List.mapi (fun i decl -> diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 1f23f522e..a98007d45 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -98,16 +98,19 @@ let stringifyMarkupContent (m : markupContent) = Printf.sprintf {|{"kind": "%s", "value": "%s"}|} m.kind (Json.escape m.value) (** None values are not emitted in the output. *) -let stringifyObject properties = - {|{ +let stringifyObject ?(startOnNewline = false) ?(indentation = 1) properties = + let indentationStr = String.make (indentation * 2) ' ' in + (if startOnNewline then "\n" ^ indentationStr else "") + ^ {|{ |} ^ (properties |> List.filter_map (fun (key, value) -> match value with | None -> None - | Some v -> Some (Printf.sprintf {| "%s": %s|} key v)) + | Some v -> + Some (Printf.sprintf {|%s "%s": %s|} indentationStr key v)) |> String.concat ",\n") - ^ "\n }" + ^ "\n" ^ indentationStr ^ "}" let wrapInQuotes s = "\"" ^ Json.escape s ^ "\"" diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 7ee60c8e8..bcdedf0bc 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -122,7 +122,7 @@ module Module = struct | Type of Type.t * Types.rec_status | Module of t - and item = {kind: kind; name: string} + and item = {kind: kind; name: string; docstring: string list} and structure = { name: string; diff --git a/analysis/tests/src/DocExtractionRes.res b/analysis/tests/src/DocExtractionRes.res new file mode 100644 index 000000000..71736cadc --- /dev/null +++ b/analysis/tests/src/DocExtractionRes.res @@ -0,0 +1,44 @@ +/***Module level documentation goes here. */ + +/** This type represents stuff. */ +type t = { + /** The name of the stuff.*/ + name: string, + /** Whether stuff is online.*/ + online: bool, +} + +/** Create stuff. + +```rescript example +let stuff = make("My name") +``` +*/ +let make = name => { + name, + online: true, +} + +/** Stuff goes offline.*/ +let asOffline = (t: t) => {...t, online: false} + +module SomeInnerModule = { + /*** Another module level docstring here.*/ + type status = + | /** If this is started or not */ Started(t) | /** Stopped? */ Stopped | /** Now idle.*/ Idle + + /** These are all the valid inputs.*/ + type validInputs = [#something | #"needs-escaping" | #withPayload(int)] + + type callback = (t, ~status: status) => unit +} + +module AnotherModule = { + /*** Mighty fine module here too!*/ + + /** + Testing what this looks like.*/ + type callback = SomeInnerModule.status => unit +} + +// ^dex diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt new file mode 100644 index 000000000..f8516447e --- /dev/null +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -0,0 +1,97 @@ +Documentation extraction src/DocExtractionRes.res +extracting docs for src/DocExtractionRes.res + +{ + "name": "DocExtractionRes", + "docstrings": ["Module level documentation goes here."], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t = {name: string, online: bool}", + "docstrings": ["This type represents stuff."], + "detail": + { + "kind": "record", + "fieldDocs": [{ + "fieldName": "name", + "docstrings": ["The name of the stuff."] + }, { + "fieldName": "online", + "docstrings": ["Whether stuff is online."] + }] + } + }, + { + "kind": "value", + "name": "make", + "signature": "let make: string => t", + "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"] + }, + { + "kind": "value", + "name": "asOffline", + "signature": "let asOffline: t => t", + "docstrings": ["Stuff goes offline."] + }, + { + "kind": "module", + "item": + { + "name": "SomeInnerModule", + "docstrings": ["Another module level docstring here."], + "items": [ + { + "kind": "type", + "name": "status", + "signature": "type status = Started(t) | Stopped | Idle", + "docstrings": [], + "detail": + { + "kind": "variant", + "fieldDocs": [ + { + "constructorName": "Started", + "docstrings": ["If this is started or not"] + }, + { + "constructorName": "Stopped", + "docstrings": ["Stopped?"] + }, + { + "constructorName": "Idle", + "docstrings": ["Now idle."] + }] + } + }, + { + "kind": "type", + "name": "validInputs", + "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #withPayload(int)\\n]", + "docstrings": ["These are all the valid inputs."] + }, + { + "kind": "type", + "name": "callback", + "signature": "type callback = (t, ~status: status) => unit", + "docstrings": [] + }] + } + }, + { + "kind": "module", + "item": + { + "name": "AnotherModule", + "docstrings": ["Mighty fine module here too!"], + "items": [ + { + "kind": "type", + "name": "callback", + "signature": "type callback = SomeInnerModule.status => unit", + "docstrings": ["Testing what this looks like."] + }] + } + }] +} + From 97b145e7f956d03a2a027bc894f2ae1b5fe19e10 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sat, 11 Feb 2023 21:31:54 +0100 Subject: [PATCH 02/21] basic extraction of linkables --- analysis/src/DocExtraction.ml | 140 ++++++++++++++++-- analysis/tests/src/DocExtractionRes.res | 12 +- .../src/expected/DocExtractionRes.res.txt | 81 +++++++++- 3 files changed, 210 insertions(+), 23 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index a99dd0122..a7aa53e4d 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -1,26 +1,99 @@ -let formatCode content = - let {Res_driver.parsetree = signature; comments} = - Res_driver.parseInterfaceFromSource ~forPrinter:true - ~displayFilename:"" ~source:content - in - Res_printer.printInterface ~width:!Res_cli.ResClflags.width ~comments - signature - |> String.trim +type linkableType = { + name: string; + path: Path.t; + env: SharedTypes.QueryEnv.t; + loc: Location.t; +} type docItemDetail = | Record of {fieldDocs: (string * string list) list} | Variant of {constructorDocs: (string * string list) list} type docItem = - | Value of {docstring: string list; signature: string; name: string} + | Value of { + docstring: string list; + signature: string; + name: string; + linkables: linkableType list; + (** Relevant types to link to, found in relation to this value. *) + } | Type of { docstring: string list; signature: string; name: string; detail: docItemDetail option; + (** Additional documentation for constructors and record fields, if available. *) + linkables: linkableType list; + (** Relevant types to link to, found in relation to this type. *) } | Module of docsForModule and docsForModule = {docstring: string list; name: string; items: docItem list} +let formatCode content = + let {Res_driver.parsetree = signature; comments} = + Res_driver.parseInterfaceFromSource ~forPrinter:true + ~displayFilename:"" ~source:content + in + Res_printer.printInterface ~width:!Res_cli.ResClflags.width ~comments + signature + |> String.trim + +module Linkables = struct + (* TODO: Extend this by going into function arguments, tuples etc... *) + let labelDeclarationsTypes lds = + lds |> List.map (fun (ld : Types.label_declaration) -> ld.ld_type) + + let rec linkablesFromDecl (decl : Types.type_declaration) ~env ~full = + match decl.type_kind with + | Type_record (lds, _) -> (env, lds |> labelDeclarationsTypes) + | Type_variant cds -> + ( env, + cds + |> List.map (fun (cd : Types.constructor_declaration) -> + let fromArgs = + match cd.cd_args with + | Cstr_tuple ts -> ts + | Cstr_record lds -> lds |> labelDeclarationsTypes + in + match cd.cd_res with + | None -> fromArgs + | Some t -> t :: fromArgs) + |> List.flatten ) + | _ -> ( + match decl.type_manifest with + | None -> (env, []) + | Some typ -> linkablesFromTyp typ ~env ~full) + + and linkablesFromTyp ~env ~(full : SharedTypes.full) typ = + match typ |> Shared.digConstructor with + | Some path -> ( + match References.digConstructor ~env ~package:full.package path with + | None -> (env, [typ]) + | Some (env1, {item = {decl}}) -> linkablesFromDecl decl ~env:env1 ~full) + | None -> (env, [typ]) + + type linkableSource = + | Typ of SharedTypes.Type.t + | TypeExpr of Types.type_expr + + let findLinkables ~env ~(full : SharedTypes.full) (typ : linkableSource) = + (* Expand definitions of types mentioned in typ. + If typ itself is a record or variant, search its body *) + let envToSearch, typesToSearch = + match typ with + | Typ t -> linkablesFromDecl ~env t.decl ~full + | TypeExpr t -> linkablesFromTyp t ~env ~full + in + let fromConstructorPath ~env path = + match References.digConstructor ~env ~package:full.package path with + | None -> None + | Some (env, {name = {txt}; extentLoc}) -> + if Utils.isUncurriedInternal path then None + else Some {name = txt; env; loc = extentLoc; path} + in + let constructors = Shared.findTypeConstructors typesToSearch in + constructors |> List.filter_map (fromConstructorPath ~env:envToSearch) +end + let stringifyDocstrings docstrings = let open Protocol in docstrings @@ -28,6 +101,25 @@ let stringifyDocstrings docstrings = docstring |> String.trim |> Json.escape |> wrapInQuotes) |> array +let stringifyLinkables ?(indentation = 0) + ~(originalEnv : SharedTypes.QueryEnv.t) (linkables : linkableType list) = + let open Protocol in + linkables + |> List.map (fun l -> + stringifyObject ~indentation:(indentation + 1) + [ + ( "path", + Some + (l.path |> SharedTypes.pathIdentToString |> Json.escape + |> wrapInQuotes) ); + ("moduleName", Some (l.env.file.moduleName |> wrapInQuotes)); + ( "external", + Some + (Printf.sprintf "%b" (originalEnv.file.uri <> l.env.file.uri)) + ); + ]) + |> array + let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = let open Protocol in match detail with @@ -63,10 +155,10 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = |> array) ); ] -let rec stringifyDocItem ?(indentation = 0) (item : docItem) = +let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {docstring; signature; name} -> + | Value {docstring; signature; name; linkables} -> stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "value")); @@ -74,14 +166,22 @@ let rec stringifyDocItem ?(indentation = 0) (item : docItem) = ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); + ( "linkables", + Some + (stringifyLinkables ~originalEnv ~indentation:(indentation + 1) + linkables) ); ] - | Type {docstring; signature; name; detail} -> + | Type {docstring; signature; name; detail; linkables} -> stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "type")); ("name", Some (name |> Json.escape |> wrapInQuotes)); ("signature", Some (signature |> Json.escape |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); + ( "linkables", + Some + (stringifyLinkables ~originalEnv ~indentation:(indentation + 1) + linkables) ); ( "detail", match detail with | None -> None @@ -92,10 +192,13 @@ let rec stringifyDocItem ?(indentation = 0) (item : docItem) = stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "module")); - ("item", Some (stringifyDocsForModule ~indentation:(indentation + 1) m)); + ( "item", + Some + (stringifyDocsForModule ~originalEnv ~indentation:(indentation + 1) + m) ); ] -and stringifyDocsForModule ?(indentation = 0) (d : docsForModule) = +and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = let open Protocol in stringifyObject ~startOnNewline:true ~indentation [ @@ -104,7 +207,8 @@ and stringifyDocsForModule ?(indentation = 0) (d : docsForModule) = ( "items", Some (d.items - |> List.map (stringifyDocItem ~indentation:(indentation + 1)) + |> List.map + (stringifyDocItem ~originalEnv ~indentation:(indentation + 1)) |> array) ); ] @@ -133,11 +237,15 @@ let extractDocs ~path ~debug = "let " ^ item.name ^ ": " ^ Shared.typeToString typ |> formatCode; name = item.name; + linkables = + TypeExpr typ |> Linkables.findLinkables ~env ~full; }) | Type (typ, _) -> Some (Type { + linkables = + Typ typ |> Linkables.findLinkables ~env ~full; docstring = item.docstring |> List.map String.trim; signature = typ.decl @@ -176,4 +284,4 @@ let extractDocs ~path ~debug = } in let docs = extractDocs structure in - print_endline (stringifyDocsForModule docs) + print_endline (stringifyDocsForModule ~originalEnv:env docs) diff --git a/analysis/tests/src/DocExtractionRes.res b/analysis/tests/src/DocExtractionRes.res index 71736cadc..2eb18d0bc 100644 --- a/analysis/tests/src/DocExtractionRes.res +++ b/analysis/tests/src/DocExtractionRes.res @@ -28,7 +28,7 @@ module SomeInnerModule = { | /** If this is started or not */ Started(t) | /** Stopped? */ Stopped | /** Now idle.*/ Idle /** These are all the valid inputs.*/ - type validInputs = [#something | #"needs-escaping" | #withPayload(int)] + type validInputs = [#something | #"needs-escaping" | #withPayload(int) | #status(status)] type callback = (t, ~status: status) => unit } @@ -39,6 +39,16 @@ module AnotherModule = { /** Testing what this looks like.*/ type callback = SomeInnerModule.status => unit + + let isGoodStatus = (status: SomeInnerModule.status) => status == Stopped + + /** Trying how it looks with an inline record in a variant. */ + type someVariantWithInlineRecords = | /** This has inline records...*/ SomeStuff({offline: bool}) + + open ReactDOM + + /**Callback to get the DOM root...*/ + type domRoot = unit => Client.Root.t } // ^dex diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index f8516447e..2ea68cd26 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -10,6 +10,7 @@ extracting docs for src/DocExtractionRes.res "name": "t", "signature": "type t = {name: string, online: bool}", "docstrings": ["This type represents stuff."], + "linkables": [], "detail": { "kind": "record", @@ -26,13 +27,23 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "make", "signature": "let make: string => t", - "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"] + "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"], + "linkables": [{ + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }] }, { "kind": "value", "name": "asOffline", "signature": "let asOffline: t => t", - "docstrings": ["Stuff goes offline."] + "docstrings": ["Stuff goes offline."], + "linkables": [{ + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }] }, { "kind": "module", @@ -46,6 +57,11 @@ extracting docs for src/DocExtractionRes.res "name": "status", "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], + "linkables": [{ + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }], "detail": { "kind": "variant", @@ -67,14 +83,24 @@ extracting docs for src/DocExtractionRes.res { "kind": "type", "name": "validInputs", - "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #withPayload(int)\\n]", - "docstrings": ["These are all the valid inputs."] + "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", + "docstrings": ["These are all the valid inputs."], + "linkables": [] }, { "kind": "type", "name": "callback", "signature": "type callback = (t, ~status: status) => unit", - "docstrings": [] + "docstrings": [], + "linkables": [{ + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }, { + "path": "status", + "moduleName": "DocExtractionRes", + "external": false + }] }] } }, @@ -89,7 +115,50 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "callback", "signature": "type callback = SomeInnerModule.status => unit", - "docstrings": ["Testing what this looks like."] + "docstrings": ["Testing what this looks like."], + "linkables": [{ + "path": "SomeInnerModule.status", + "moduleName": "DocExtractionRes", + "external": false + }] + }, + { + "kind": "value", + "name": "isGoodStatus", + "signature": "let isGoodStatus: SomeInnerModule.status => bool", + "docstrings": [], + "linkables": [{ + "path": "SomeInnerModule.status", + "moduleName": "DocExtractionRes", + "external": false + }] + }, + { + "kind": "type", + "name": "someVariantWithInlineRecords", + "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", + "docstrings": ["Trying how it looks with an inline record in a variant."], + "linkables": [], + "detail": + { + "kind": "variant", + "fieldDocs": [ + { + "constructorName": "SomeStuff", + "docstrings": ["This has inline records..."] + }] + } + }, + { + "kind": "type", + "name": "domRoot", + "signature": "type domRoot = unit => ReactDOM.Client.Root.t", + "docstrings": ["Callback to get the DOM root..."], + "linkables": [{ + "path": "ReactDOM.Client.Root.t", + "moduleName": "ReactDOM", + "external": true + }] }] } }] From 3cf561d348f7fd9470df4c1df1f86546ffa99da0 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 12 Feb 2023 13:42:58 +0100 Subject: [PATCH 03/21] prefer resi file when available, and prefer module signature vs impl --- analysis/src/DocExtraction.ml | 42 +++++++++++--- analysis/tests/src/DocExtraction2.res | 12 ++++ analysis/tests/src/DocExtraction2.resi | 19 +++++++ analysis/tests/src/DocExtractionRes.res | 34 ++++++++++++ .../tests/src/expected/DocExtraction2.res.txt | 55 +++++++++++++++++++ .../src/expected/DocExtraction2.resi.txt | 54 ++++++++++++++++++ .../src/expected/DocExtractionRes.res.txt | 27 +++++++++ 7 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 analysis/tests/src/DocExtraction2.res create mode 100644 analysis/tests/src/DocExtraction2.resi create mode 100644 analysis/tests/src/expected/DocExtraction2.res.txt create mode 100644 analysis/tests/src/expected/DocExtraction2.resi.txt diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index a7aa53e4d..add4e8ed4 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -212,21 +212,42 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = |> array) ); ] +exception Invalid_file_type + let extractDocs ~path ~debug = if debug then Printf.printf "extracting docs for %s\n" path; + if + FindFiles.isImplementation path = false + && FindFiles.isInterface path = false + then raise Invalid_file_type; + let path = + if FindFiles.isImplementation path then + let pathAsResi = + (path |> Filename.dirname) ^ "/" + ^ (path |> Filename.basename |> Filename.chop_extension) + ^ ".resi" + in + if Sys.file_exists pathAsResi then ( + if debug then + Printf.printf "preferring found resi file for impl: %s\n" pathAsResi; + pathAsResi) + else path + else path + in match Cmt.loadFullCmtFromPath ~path with | None -> () | Some full -> let file = full.file in let structure = file.structure in - let env = SharedTypes.QueryEnv.fromFile file in - let rec extractDocs (structure : SharedTypes.Module.structure) = + let open SharedTypes in + let env = QueryEnv.fromFile file in + let rec extractDocs (structure : Module.structure) = { docstring = structure.docstring |> List.map String.trim; name = structure.name; items = structure.items - |> List.filter_map (fun (item : SharedTypes.Module.item) -> + |> List.filter_map (fun (item : Module.item) -> match item.kind with | Value typ -> Some @@ -263,8 +284,7 @@ let extractDocs ~path ~debug = { fieldDocs = fields - |> List.map - (fun (field : SharedTypes.field) -> + |> List.map (fun (field : field) -> (field.fname.txt, field.docstring)); }) | Some (Tvariant {constructors}) -> @@ -273,13 +293,17 @@ let extractDocs ~path ~debug = { constructorDocs = constructors - |> List.map - (fun (c : SharedTypes.Constructor.t) - -> (c.cname.txt, c.docstring)); + |> List.map (fun (c : Constructor.t) -> + (c.cname.txt, c.docstring)); }) | _ -> None); }) - | Module (Structure m) -> Some (Module (extractDocs m)) + | Module (Structure m) -> + (* module Whatever = {} in res or module Whatever: {} in resi. *) + Some (Module (extractDocs m)) + | Module (Constraint (Structure _impl, Structure interface)) -> + (* module Whatever: { } = { }. Prefer the interface. *) + Some (Module (extractDocs interface)) | _ -> None); } in diff --git a/analysis/tests/src/DocExtraction2.res b/analysis/tests/src/DocExtraction2.res new file mode 100644 index 000000000..3733153e0 --- /dev/null +++ b/analysis/tests/src/DocExtraction2.res @@ -0,0 +1,12 @@ +type t = string + +let getStr = () => "123" + +let make = getStr + +module InnerModule = { + type t = unit + let make = () => () +} + +// ^dex diff --git a/analysis/tests/src/DocExtraction2.resi b/analysis/tests/src/DocExtraction2.resi new file mode 100644 index 000000000..b653bdcab --- /dev/null +++ b/analysis/tests/src/DocExtraction2.resi @@ -0,0 +1,19 @@ +/*** Module level doc here.*/ + +/** Type t is pretty cool.*/ +type t + +/** Makerz of stuffz. */ +let make: unit => t + +module InnerModule: { + /*** This inner module is nice...*/ + + /** This type is also t. */ + type t + + /** Maker of tea.*/ + let make: unit => t +} + +// ^dex diff --git a/analysis/tests/src/DocExtractionRes.res b/analysis/tests/src/DocExtractionRes.res index 2eb18d0bc..fabb7b6b3 100644 --- a/analysis/tests/src/DocExtractionRes.res +++ b/analysis/tests/src/DocExtractionRes.res @@ -51,4 +51,38 @@ module AnotherModule = { type domRoot = unit => Client.Root.t } +module ModuleWithThingsThatShouldNotBeExported: { + /*** BROKEN: This docstring isn't picked up Doesn't seem to be parsed at all, no attributes found.*/ + + /** The type t is stuff. */ + type t + + /** The maker of stuff!*/ + let make: unit => t +} = { + /*** Mighty fine module here too!*/ + type t = string + type x = int + type f = bool + + let m1 = (x: x) => { + x + 1 + } + + let m2 = (f: f) => + if f { + true + } else { + false + } + + let make = () => { + if m2(true) && m1(1) > 2 { + "1" + } else { + "2" + } + } +} + // ^dex diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt new file mode 100644 index 000000000..4b02a17eb --- /dev/null +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -0,0 +1,55 @@ +Documentation extraction src/DocExtraction2.res +extracting docs for src/DocExtraction2.res +preferring found resi file for impl: src/DocExtraction2.resi + +{ + "name": "DocExtraction2", + "docstrings": ["Module level doc here."], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["Type t is pretty cool."], + "linkables": [] + }, + { + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Makerz of stuffz."], + "linkables": [{ + "path": "t", + "moduleName": "DocExtraction2", + "external": false + }] + }, + { + "kind": "module", + "item": + { + "name": "InnerModule", + "docstrings": [], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."], + "linkables": [] + }, + { + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Maker of tea."], + "linkables": [{ + "path": "t", + "moduleName": "DocExtraction2", + "external": false + }] + }] + } + }] +} + diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt new file mode 100644 index 000000000..d3a5fb0c3 --- /dev/null +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -0,0 +1,54 @@ +Documentation extraction src/DocExtraction2.resi +extracting docs for src/DocExtraction2.resi + +{ + "name": "DocExtraction2", + "docstrings": ["Module level doc here."], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["Type t is pretty cool."], + "linkables": [] + }, + { + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Makerz of stuffz."], + "linkables": [{ + "path": "t", + "moduleName": "DocExtraction2", + "external": false + }] + }, + { + "kind": "module", + "item": + { + "name": "InnerModule", + "docstrings": [], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."], + "linkables": [] + }, + { + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Maker of tea."], + "linkables": [{ + "path": "t", + "moduleName": "DocExtraction2", + "external": false + }] + }] + } + }] +} + diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 2ea68cd26..7a43916de 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -161,6 +161,33 @@ extracting docs for src/DocExtractionRes.res }] }] } + }, + { + "kind": "module", + "item": + { + "name": "ModuleWithThingsThatShouldNotBeExported", + "docstrings": [], + "items": [ + { + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["The type t is stuff."], + "linkables": [] + }, + { + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["The maker of stuff!"], + "linkables": [{ + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }] + }] + } }] } From e775f4c57722d1a42651ef96fbd1e062a06bd1a3 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 12 Feb 2023 16:08:55 +0100 Subject: [PATCH 04/21] temporary command for extracting docs --- client/src/commands.ts | 1 + client/src/commands/extract_docs.ts | 50 +++++++++++++++++++++++++++++ client/src/extension.ts | 4 +++ package.json | 4 +++ server/src/server.ts | 26 +++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 client/src/commands/extract_docs.ts diff --git a/client/src/commands.ts b/client/src/commands.ts index 98bcec00d..8acb2dc81 100644 --- a/client/src/commands.ts +++ b/client/src/commands.ts @@ -6,6 +6,7 @@ import { } from "./commands/code_analysis"; export { createInterface } from "./commands/create_interface"; +export { extractDocs } from "./commands/extract_docs"; export { openCompiled } from "./commands/open_compiled"; export { switchImplIntf } from "./commands/switch_impl_intf"; diff --git a/client/src/commands/extract_docs.ts b/client/src/commands/extract_docs.ts new file mode 100644 index 000000000..3d9f295a4 --- /dev/null +++ b/client/src/commands/extract_docs.ts @@ -0,0 +1,50 @@ +import * as p from "vscode-languageserver-protocol"; +import { LanguageClient, RequestType } from "vscode-languageclient/node"; +import { Position, Uri, window, workspace, WorkspaceEdit } from "vscode"; +import path = require("path"); + +export const extractDocsRequest = new RequestType< + p.TextDocumentIdentifier, + string, + void +>("textDocument/extractDocs"); + +export const extractDocs = async (client: LanguageClient) => { + if (!client) { + return window.showInformationMessage("Language server not running"); + } + + const editor = window.activeTextEditor; + + if (!editor) { + return window.showInformationMessage("No active editor"); + } + + try { + const docUri = editor.document.uri.toString(); + const res = await client.sendRequest(extractDocsRequest, { + uri: docUri, + }); + + const newFile = Uri.parse( + "untitled:" + + path.join( + workspace.workspaceFolders[0].uri.fsPath, + `${path.basename(docUri)}.json` + ) + ); + workspace.openTextDocument(newFile).then((document) => { + const edit = new WorkspaceEdit(); + edit.insert(newFile, new Position(0, 0), JSON.stringify(res, null, 2)); + return workspace.applyEdit(edit).then((success) => { + if (success) { + window.showTextDocument(document); + } else { + window.showInformationMessage("Error!"); + } + }); + }); + } catch (e) { + console.error("failed", e); + } +}; diff --git a/client/src/extension.ts b/client/src/extension.ts index 1ef2e2bca..ac901e2f5 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -203,6 +203,10 @@ export function activate(context: ExtensionContext) { customCommands.openCompiled(client); }); + commands.registerCommand("rescript-vscode.extract_docs", () => { + customCommands.extractDocs(client); + }); + commands.registerCommand( "rescript-vscode.go_to_location", async (fileUri: string, startLine: number, startCol: number) => { diff --git a/package.json b/package.json index d291fa5cc..ed13da7a2 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,10 @@ "command": "rescript-vscode.create_interface", "title": "ReScript: Create an interface file for this implementation file" }, + { + "command": "rescript-vscode.extract_docs", + "title": "ReScript: Extract documentation as JSON for file." + }, { "command": "rescript-vscode.open_compiled", "category": "ReScript", diff --git a/server/src/server.ts b/server/src/server.ts index 3e36c990a..25490208a 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -152,6 +152,12 @@ let openCompiledFileRequest = new v.RequestType< void >("textDocument/openCompiled"); +let extractDocsRequest = new v.RequestType< + p.TextDocumentIdentifier, + p.TextDocumentIdentifier, + void +>("textDocument/extractDocs"); + let getCurrentCompilerDiagnosticsForFile = ( fileUri: string ): p.Diagnostic[] => { @@ -969,6 +975,24 @@ function createInterface(msg: p.RequestMessage): p.Message { } } +function extractDocs(msg: p.RequestMessage): p.Message { + let params = msg.params as p.TextDocumentIdentifier; + let filePath = fileURLToPath(params.uri); + + let response = utils.runAnalysisCommand( + filePath, + ["extractDocs", filePath], + msg + ); + + let res: p.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + result: response.result, + }; + return res; +} + function openCompiledFile(msg: p.RequestMessage): p.Message { let params = msg.params as p.TextDocumentIdentifier; let filePath = fileURLToPath(params.uri); @@ -1234,6 +1258,8 @@ function onMessage(msg: p.Message) { send(createInterface(msg)); } else if (msg.method === openCompiledFileRequest.method) { send(openCompiledFile(msg)); + } else if (msg.method === extractDocsRequest.method) { + send(extractDocs(msg)); } else if (msg.method === p.InlayHintRequest.method) { let params = msg.params as InlayHintParams; let extName = path.extname(params.textDocument.uri); From abdd0cb6474fb570dc2647d968e79d270254ad0f Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 12 Feb 2023 16:32:38 +0100 Subject: [PATCH 05/21] add id:s and signatures for constructors/record fields --- analysis/src/DocExtraction.ml | 79 +++++++++++++++---- .../tests/src/expected/DocExtraction2.res.txt | 5 ++ .../src/expected/DocExtraction2.resi.txt | 5 ++ .../src/expected/DocExtractionRes.res.txt | 33 ++++++-- 4 files changed, 100 insertions(+), 22 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index add4e8ed4..bfdc47fc5 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -5,11 +5,20 @@ type linkableType = { loc: Location.t; } +type fieldDoc = {fieldName: string; docstrings: string list; signature: string} + +type constructorDoc = { + constructorName: string; + docstrings: string list; + signature: string; +} + type docItemDetail = - | Record of {fieldDocs: (string * string list) list} - | Variant of {constructorDocs: (string * string list) list} + | Record of {fieldDocs: fieldDoc list} + | Variant of {constructorDocs: constructorDoc list} type docItem = | Value of { + id: string; docstring: string list; signature: string; name: string; @@ -17,6 +26,7 @@ type docItem = (** Relevant types to link to, found in relation to this value. *) } | Type of { + id: string; docstring: string list; signature: string; name: string; @@ -26,7 +36,12 @@ type docItem = (** Relevant types to link to, found in relation to this type. *) } | Module of docsForModule -and docsForModule = {docstring: string list; name: string; items: docItem list} +and docsForModule = { + id: string; + docstring: string list; + name: string; + items: docItem list; +} let formatCode content = let {Res_driver.parsetree = signature; comments} = @@ -130,11 +145,13 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = ( "fieldDocs", Some (fieldDocs - |> List.map (fun (fieldName, docstrings) -> + |> List.map (fun fieldDoc -> stringifyObject ~indentation:(indentation + 1) [ - ("fieldName", Some (wrapInQuotes fieldName)); - ("docstrings", Some (stringifyDocstrings docstrings)); + ("fieldName", Some (wrapInQuotes fieldDoc.fieldName)); + ( "docstrings", + Some (stringifyDocstrings fieldDoc.docstrings) ); + ("signature", Some (wrapInQuotes fieldDoc.signature)); ]) |> array) ); ] @@ -145,12 +162,16 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = ( "fieldDocs", Some (constructorDocs - |> List.map (fun (constructorName, docstrings) -> + |> List.map (fun constructorDoc -> stringifyObject ~startOnNewline:true ~indentation:(indentation + 1) [ - ("constructorName", Some (wrapInQuotes constructorName)); - ("docstrings", Some (stringifyDocstrings docstrings)); + ( "constructorName", + Some (wrapInQuotes constructorDoc.constructorName) ); + ( "docstrings", + Some (stringifyDocstrings constructorDoc.docstrings) ); + ( "signature", + Some (wrapInQuotes constructorDoc.signature) ); ]) |> array) ); ] @@ -158,9 +179,10 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {docstring; signature; name; linkables} -> + | Value {id; docstring; signature; name; linkables} -> stringifyObject ~startOnNewline:true ~indentation [ + ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "value")); ("name", Some (name |> Json.escape |> wrapInQuotes)); ( "signature", @@ -171,9 +193,10 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = (stringifyLinkables ~originalEnv ~indentation:(indentation + 1) linkables) ); ] - | Type {docstring; signature; name; detail; linkables} -> + | Type {id; docstring; signature; name; detail; linkables} -> stringifyObject ~startOnNewline:true ~indentation [ + ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "type")); ("name", Some (name |> Json.escape |> wrapInQuotes)); ("signature", Some (signature |> Json.escape |> wrapInQuotes)); @@ -191,6 +214,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = | Module m -> stringifyObject ~startOnNewline:true ~indentation [ + ("id", Some (wrapInQuotes m.id)); ("kind", Some (wrapInQuotes "module")); ( "item", Some @@ -214,6 +238,9 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = exception Invalid_file_type +let makeId modulePath ~identifier = + identifier :: modulePath |> List.rev |> SharedTypes.ident + let extractDocs ~path ~debug = if debug then Printf.printf "extracting docs for %s\n" path; if @@ -241,8 +268,10 @@ let extractDocs ~path ~debug = let structure = file.structure in let open SharedTypes in let env = QueryEnv.fromFile file in - let rec extractDocs (structure : Module.structure) = + let rec extractDocs ?(modulePath = [env.file.moduleName]) + (structure : Module.structure) = { + id = modulePath |> ident; docstring = structure.docstring |> List.map String.trim; name = structure.name; items = @@ -253,6 +282,7 @@ let extractDocs ~path ~debug = Some (Value { + id = modulePath |> makeId ~identifier:item.name; docstring = item.docstring |> List.map String.trim; signature = "let " ^ item.name ^ ": " ^ Shared.typeToString typ @@ -265,6 +295,7 @@ let extractDocs ~path ~debug = Some (Type { + id = modulePath |> makeId ~identifier:item.name; linkables = Typ typ |> Linkables.findLinkables ~env ~full; docstring = item.docstring |> List.map String.trim; @@ -285,7 +316,12 @@ let extractDocs ~path ~debug = fieldDocs = fields |> List.map (fun (field : field) -> - (field.fname.txt, field.docstring)); + { + fieldName = field.fname.txt; + docstrings = field.docstring; + signature = + Shared.typeToString field.typ; + }); }) | Some (Tvariant {constructors}) -> Some @@ -294,16 +330,27 @@ let extractDocs ~path ~debug = constructorDocs = constructors |> List.map (fun (c : Constructor.t) -> - (c.cname.txt, c.docstring)); + { + constructorName = c.cname.txt; + docstrings = c.docstring; + signature = + CompletionBackEnd + .showConstructor c; + }); }) | _ -> None); }) | Module (Structure m) -> (* module Whatever = {} in res or module Whatever: {} in resi. *) - Some (Module (extractDocs m)) + Some + (Module (extractDocs ~modulePath:(m.name :: modulePath) m)) | Module (Constraint (Structure _impl, Structure interface)) -> (* module Whatever: { } = { }. Prefer the interface. *) - Some (Module (extractDocs interface)) + Some + (Module + (extractDocs + ~modulePath:(interface.name :: modulePath) + interface)) | _ -> None); } in diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 4b02a17eb..577094547 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -7,6 +7,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "docstrings": ["Module level doc here."], "items": [ { + "id": "DocExtraction2.t", "kind": "type", "name": "t", "signature": "type t", @@ -14,6 +15,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "linkables": [] }, { + "id": "DocExtraction2.make", "kind": "value", "name": "make", "signature": "let make: unit => t", @@ -25,6 +27,7 @@ preferring found resi file for impl: src/DocExtraction2.resi }] }, { + "id": "InnerModule.DocExtraction2", "kind": "module", "item": { @@ -32,6 +35,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "docstrings": [], "items": [ { + "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", "signature": "type t", @@ -39,6 +43,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "linkables": [] }, { + "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", "signature": "let make: unit => t", diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index d3a5fb0c3..afd475f48 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -6,6 +6,7 @@ extracting docs for src/DocExtraction2.resi "docstrings": ["Module level doc here."], "items": [ { + "id": "DocExtraction2.t", "kind": "type", "name": "t", "signature": "type t", @@ -13,6 +14,7 @@ extracting docs for src/DocExtraction2.resi "linkables": [] }, { + "id": "DocExtraction2.make", "kind": "value", "name": "make", "signature": "let make: unit => t", @@ -24,6 +26,7 @@ extracting docs for src/DocExtraction2.resi }] }, { + "id": "InnerModule.DocExtraction2", "kind": "module", "item": { @@ -31,6 +34,7 @@ extracting docs for src/DocExtraction2.resi "docstrings": [], "items": [ { + "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", "signature": "type t", @@ -38,6 +42,7 @@ extracting docs for src/DocExtraction2.resi "linkables": [] }, { + "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", "signature": "let make: unit => t", diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 7a43916de..2948db51a 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -6,6 +6,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Module level documentation goes here."], "items": [ { + "id": "DocExtractionRes.t", "kind": "type", "name": "t", "signature": "type t = {name: string, online: bool}", @@ -16,14 +17,17 @@ extracting docs for src/DocExtractionRes.res "kind": "record", "fieldDocs": [{ "fieldName": "name", - "docstrings": ["The name of the stuff."] + "docstrings": ["The name of the stuff."], + "signature": "string" }, { "fieldName": "online", - "docstrings": ["Whether stuff is online."] + "docstrings": ["Whether stuff is online."], + "signature": "bool" }] } }, { + "id": "DocExtractionRes.make", "kind": "value", "name": "make", "signature": "let make: string => t", @@ -35,6 +39,7 @@ extracting docs for src/DocExtractionRes.res }] }, { + "id": "DocExtractionRes.asOffline", "kind": "value", "name": "asOffline", "signature": "let asOffline: t => t", @@ -46,6 +51,7 @@ extracting docs for src/DocExtractionRes.res }] }, { + "id": "SomeInnerModule.DocExtractionRes", "kind": "module", "item": { @@ -53,6 +59,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Another module level docstring here."], "items": [ { + "id": "DocExtractionRes.SomeInnerModule.status", "kind": "type", "name": "status", "signature": "type status = Started(t) | Stopped | Idle", @@ -68,19 +75,23 @@ extracting docs for src/DocExtractionRes.res "fieldDocs": [ { "constructorName": "Started", - "docstrings": ["If this is started or not"] + "docstrings": ["If this is started or not"], + "signature": "Started(t)" }, { "constructorName": "Stopped", - "docstrings": ["Stopped?"] + "docstrings": ["Stopped?"], + "signature": "Stopped" }, { "constructorName": "Idle", - "docstrings": ["Now idle."] + "docstrings": ["Now idle."], + "signature": "Idle" }] } }, { + "id": "DocExtractionRes.SomeInnerModule.validInputs", "kind": "type", "name": "validInputs", "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", @@ -88,6 +99,7 @@ extracting docs for src/DocExtractionRes.res "linkables": [] }, { + "id": "DocExtractionRes.SomeInnerModule.callback", "kind": "type", "name": "callback", "signature": "type callback = (t, ~status: status) => unit", @@ -105,6 +117,7 @@ extracting docs for src/DocExtractionRes.res } }, { + "id": "AnotherModule.DocExtractionRes", "kind": "module", "item": { @@ -112,6 +125,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Mighty fine module here too!"], "items": [ { + "id": "DocExtractionRes.AnotherModule.callback", "kind": "type", "name": "callback", "signature": "type callback = SomeInnerModule.status => unit", @@ -123,6 +137,7 @@ extracting docs for src/DocExtractionRes.res }] }, { + "id": "DocExtractionRes.AnotherModule.isGoodStatus", "kind": "value", "name": "isGoodStatus", "signature": "let isGoodStatus: SomeInnerModule.status => bool", @@ -134,6 +149,7 @@ extracting docs for src/DocExtractionRes.res }] }, { + "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", "kind": "type", "name": "someVariantWithInlineRecords", "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", @@ -145,11 +161,13 @@ extracting docs for src/DocExtractionRes.res "fieldDocs": [ { "constructorName": "SomeStuff", - "docstrings": ["This has inline records..."] + "docstrings": ["This has inline records..."], + "signature": "SomeStuff" }] } }, { + "id": "DocExtractionRes.AnotherModule.domRoot", "kind": "type", "name": "domRoot", "signature": "type domRoot = unit => ReactDOM.Client.Root.t", @@ -163,6 +181,7 @@ extracting docs for src/DocExtractionRes.res } }, { + "id": "ModuleWithThingsThatShouldNotBeExported.DocExtractionRes", "kind": "module", "item": { @@ -170,6 +189,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": [], "items": [ { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", "kind": "type", "name": "t", "signature": "type t", @@ -177,6 +197,7 @@ extracting docs for src/DocExtractionRes.res "linkables": [] }, { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", "kind": "value", "name": "make", "signature": "let make: unit => t", From 6ab2b0fa5dd76398cd0e0e3034c07aa705e89560 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 12 Feb 2023 18:51:19 +0100 Subject: [PATCH 06/21] produce what id to link to in linkables --- analysis/src/DocExtraction.ml | 11 +++++++---- analysis/tests/src/expected/DocExtraction2.res.txt | 2 ++ analysis/tests/src/expected/DocExtraction2.resi.txt | 2 ++ analysis/tests/src/expected/DocExtractionRes.res.txt | 9 +++++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index bfdc47fc5..c28e7be35 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -121,17 +121,20 @@ let stringifyLinkables ?(indentation = 0) let open Protocol in linkables |> List.map (fun l -> + let isExternal = originalEnv.file.uri <> l.env.file.uri in stringifyObject ~indentation:(indentation + 1) [ + ( "linkId", + Some + ((if isExternal then "" else l.env.file.moduleName ^ ".") + ^ (l.path |> SharedTypes.pathIdentToString) + |> Json.escape |> wrapInQuotes) ); ( "path", Some (l.path |> SharedTypes.pathIdentToString |> Json.escape |> wrapInQuotes) ); ("moduleName", Some (l.env.file.moduleName |> wrapInQuotes)); - ( "external", - Some - (Printf.sprintf "%b" (originalEnv.file.uri <> l.env.file.uri)) - ); + ("external", Some (Printf.sprintf "%b" isExternal)); ]) |> array diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 577094547..85b3653cc 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -21,6 +21,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."], "linkables": [{ + "linkId": "DocExtraction2.t", "path": "t", "moduleName": "DocExtraction2", "external": false @@ -49,6 +50,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Maker of tea."], "linkables": [{ + "linkId": "DocExtraction2.t", "path": "t", "moduleName": "DocExtraction2", "external": false diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index afd475f48..838a4c5aa 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -20,6 +20,7 @@ extracting docs for src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."], "linkables": [{ + "linkId": "DocExtraction2.t", "path": "t", "moduleName": "DocExtraction2", "external": false @@ -48,6 +49,7 @@ extracting docs for src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Maker of tea."], "linkables": [{ + "linkId": "DocExtraction2.t", "path": "t", "moduleName": "DocExtraction2", "external": false diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 2948db51a..f2162ee18 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -33,6 +33,7 @@ extracting docs for src/DocExtractionRes.res "signature": "let make: string => t", "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"], "linkables": [{ + "linkId": "DocExtractionRes.t", "path": "t", "moduleName": "DocExtractionRes", "external": false @@ -45,6 +46,7 @@ extracting docs for src/DocExtractionRes.res "signature": "let asOffline: t => t", "docstrings": ["Stuff goes offline."], "linkables": [{ + "linkId": "DocExtractionRes.t", "path": "t", "moduleName": "DocExtractionRes", "external": false @@ -65,6 +67,7 @@ extracting docs for src/DocExtractionRes.res "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], "linkables": [{ + "linkId": "DocExtractionRes.t", "path": "t", "moduleName": "DocExtractionRes", "external": false @@ -105,10 +108,12 @@ extracting docs for src/DocExtractionRes.res "signature": "type callback = (t, ~status: status) => unit", "docstrings": [], "linkables": [{ + "linkId": "DocExtractionRes.t", "path": "t", "moduleName": "DocExtractionRes", "external": false }, { + "linkId": "DocExtractionRes.status", "path": "status", "moduleName": "DocExtractionRes", "external": false @@ -131,6 +136,7 @@ extracting docs for src/DocExtractionRes.res "signature": "type callback = SomeInnerModule.status => unit", "docstrings": ["Testing what this looks like."], "linkables": [{ + "linkId": "DocExtractionRes.SomeInnerModule.status", "path": "SomeInnerModule.status", "moduleName": "DocExtractionRes", "external": false @@ -143,6 +149,7 @@ extracting docs for src/DocExtractionRes.res "signature": "let isGoodStatus: SomeInnerModule.status => bool", "docstrings": [], "linkables": [{ + "linkId": "DocExtractionRes.SomeInnerModule.status", "path": "SomeInnerModule.status", "moduleName": "DocExtractionRes", "external": false @@ -173,6 +180,7 @@ extracting docs for src/DocExtractionRes.res "signature": "type domRoot = unit => ReactDOM.Client.Root.t", "docstrings": ["Callback to get the DOM root..."], "linkables": [{ + "linkId": "ReactDOM.Client.Root.t", "path": "ReactDOM.Client.Root.t", "moduleName": "ReactDOM", "external": true @@ -203,6 +211,7 @@ extracting docs for src/DocExtractionRes.res "signature": "let make: unit => t", "docstrings": ["The maker of stuff!"], "linkables": [{ + "linkId": "DocExtractionRes.t", "path": "t", "moduleName": "DocExtractionRes", "external": false From 4b52c93db8a88c98b85c4fa3e6715693567eb949 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 12 Feb 2023 22:04:34 +0100 Subject: [PATCH 07/21] linkables in constructor and record field details --- analysis/src/DocExtraction.ml | 105 +++++++++++------- .../src/expected/DocExtractionRes.res.txt | 23 +++- 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index c28e7be35..e43e31f7a 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -5,12 +5,18 @@ type linkableType = { loc: Location.t; } -type fieldDoc = {fieldName: string; docstrings: string list; signature: string} +type fieldDoc = { + fieldName: string; + docstrings: string list; + signature: string; + linkables: linkableType list; +} type constructorDoc = { constructorName: string; docstrings: string list; signature: string; + linkables: linkableType list; } type docItemDetail = @@ -83,7 +89,9 @@ module Linkables = struct | Some path -> ( match References.digConstructor ~env ~package:full.package path with | None -> (env, [typ]) - | Some (env1, {item = {decl}}) -> linkablesFromDecl decl ~env:env1 ~full) + | Some (env1, {item = {decl}}) -> + let env, types = linkablesFromDecl decl ~env:env1 ~full in + (env, typ :: types)) | None -> (env, [typ]) type linkableSource = @@ -138,7 +146,7 @@ let stringifyLinkables ?(indentation = 0) ]) |> array -let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = +let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = let open Protocol in match detail with | Record {fieldDocs} -> @@ -155,6 +163,10 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = ( "docstrings", Some (stringifyDocstrings fieldDoc.docstrings) ); ("signature", Some (wrapInQuotes fieldDoc.signature)); + ( "linkables", + Some + (stringifyLinkables ~indentation:(indentation + 1) + ~originalEnv fieldDoc.linkables) ); ]) |> array) ); ] @@ -175,6 +187,10 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = Some (stringifyDocstrings constructorDoc.docstrings) ); ( "signature", Some (wrapInQuotes constructorDoc.signature) ); + ( "linkables", + Some + (stringifyLinkables ~indentation:(indentation + 1) + ~originalEnv constructorDoc.linkables) ); ]) |> array) ); ] @@ -212,7 +228,9 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match detail with | None -> None | Some detail -> - Some (stringifyDetail ~indentation:(indentation + 1) detail) ); + Some + (stringifyDetail ~originalEnv ~indentation:(indentation + 1) + detail) ); ] | Module m -> stringifyObject ~startOnNewline:true ~indentation @@ -239,6 +257,49 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = |> array) ); ] +let typeDetail typ ~env ~full = + let open SharedTypes in + match TypeUtils.extractTypeFromResolvedType ~env ~full typ with + | Some (Trecord {fields}) -> + Some + (Record + { + fieldDocs = + fields + |> List.map (fun (field : field) -> + { + fieldName = field.fname.txt; + docstrings = field.docstring; + signature = Shared.typeToString field.typ; + linkables = + TypeExpr field.typ |> Linkables.findLinkables ~env ~full; + }); + }) + | Some (Tvariant {constructors}) -> + Some + (Variant + { + constructorDocs = + constructors + |> List.map (fun (c : Constructor.t) -> + let linkables = + (match c.args with + | Args args -> args |> List.map (fun (t, _) -> t) + | InlineRecord fields -> + fields |> List.map (fun f -> f.typ)) + |> List.map (fun t -> + TypeExpr t |> Linkables.findLinkables ~env ~full) + |> List.flatten + in + { + constructorName = c.cname.txt; + docstrings = c.docstring; + signature = CompletionBackEnd.showConstructor c; + linkables; + }); + }) + | _ -> None + exception Invalid_file_type let makeId modulePath ~identifier = @@ -307,41 +368,7 @@ let extractDocs ~path ~debug = |> Shared.declToString item.name |> formatCode; name = item.name; - detail = - (match - TypeUtils.extractTypeFromResolvedType ~env ~full - typ - with - | Some (Trecord {fields}) -> - Some - (Record - { - fieldDocs = - fields - |> List.map (fun (field : field) -> - { - fieldName = field.fname.txt; - docstrings = field.docstring; - signature = - Shared.typeToString field.typ; - }); - }) - | Some (Tvariant {constructors}) -> - Some - (Variant - { - constructorDocs = - constructors - |> List.map (fun (c : Constructor.t) -> - { - constructorName = c.cname.txt; - docstrings = c.docstring; - signature = - CompletionBackEnd - .showConstructor c; - }); - }) - | _ -> None); + detail = typeDetail typ ~full ~env; }) | Module (Structure m) -> (* module Whatever = {} in res or module Whatever: {} in resi. *) diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index f2162ee18..2a0ce46e6 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -18,11 +18,13 @@ extracting docs for src/DocExtractionRes.res "fieldDocs": [{ "fieldName": "name", "docstrings": ["The name of the stuff."], - "signature": "string" + "signature": "string", + "linkables": [] }, { "fieldName": "online", "docstrings": ["Whether stuff is online."], - "signature": "bool" + "signature": "bool", + "linkables": [] }] } }, @@ -79,17 +81,25 @@ extracting docs for src/DocExtractionRes.res { "constructorName": "Started", "docstrings": ["If this is started or not"], - "signature": "Started(t)" + "signature": "Started(t)", + "linkables": [{ + "linkId": "DocExtractionRes.t", + "path": "t", + "moduleName": "DocExtractionRes", + "external": false + }] }, { "constructorName": "Stopped", "docstrings": ["Stopped?"], - "signature": "Stopped" + "signature": "Stopped", + "linkables": [] }, { "constructorName": "Idle", "docstrings": ["Now idle."], - "signature": "Idle" + "signature": "Idle", + "linkables": [] }] } }, @@ -169,7 +179,8 @@ extracting docs for src/DocExtractionRes.res { "constructorName": "SomeStuff", "docstrings": ["This has inline records..."], - "signature": "SomeStuff" + "signature": "SomeStuff", + "linkables": [] }] } }, From 0b2cfbab9411bae9cd013ec5f24b5380b85554ca Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 13 Feb 2023 15:39:09 +0100 Subject: [PATCH 08/21] fix linkable link ids --- analysis/src/DocExtraction.ml | 23 ++++++++----- .../tests/src/expected/DocExtraction2.res.txt | 8 ++--- .../src/expected/DocExtraction2.resi.txt | 8 ++--- .../src/expected/DocExtractionRes.res.txt | 34 +++++++------------ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index e43e31f7a..8fbbbaa2c 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -1,5 +1,6 @@ type linkableType = { name: string; + modulePath: string list; path: Path.t; env: SharedTypes.QueryEnv.t; loc: Location.t; @@ -109,9 +110,17 @@ module Linkables = struct let fromConstructorPath ~env path = match References.digConstructor ~env ~package:full.package path with | None -> None - | Some (env, {name = {txt}; extentLoc}) -> + | Some (env, {name = {txt}; extentLoc; modulePath}) -> if Utils.isUncurriedInternal path then None - else Some {name = txt; env; loc = extentLoc; path} + else + Some + { + name = txt; + env; + loc = extentLoc; + modulePath = SharedTypes.ModulePath.toPath modulePath txt; + path; + } in let constructors = Shared.findTypeConstructors typesToSearch in constructors |> List.filter_map (fromConstructorPath ~env:envToSearch) @@ -130,18 +139,16 @@ let stringifyLinkables ?(indentation = 0) linkables |> List.map (fun l -> let isExternal = originalEnv.file.uri <> l.env.file.uri in + let linkId = l.env.file.moduleName :: l.modulePath in stringifyObject ~indentation:(indentation + 1) [ ( "linkId", - Some - ((if isExternal then "" else l.env.file.moduleName ^ ".") - ^ (l.path |> SharedTypes.pathIdentToString) - |> Json.escape |> wrapInQuotes) ); - ( "path", + Some (linkId |> SharedTypes.ident |> Json.escape |> wrapInQuotes) + ); + ( "name", Some (l.path |> SharedTypes.pathIdentToString |> Json.escape |> wrapInQuotes) ); - ("moduleName", Some (l.env.file.moduleName |> wrapInQuotes)); ("external", Some (Printf.sprintf "%b" isExternal)); ]) |> array diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 85b3653cc..21f6d1735 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -22,8 +22,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "docstrings": ["Makerz of stuffz."], "linkables": [{ "linkId": "DocExtraction2.t", - "path": "t", - "moduleName": "DocExtraction2", + "name": "t", "external": false }] }, @@ -50,9 +49,8 @@ preferring found resi file for impl: src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Maker of tea."], "linkables": [{ - "linkId": "DocExtraction2.t", - "path": "t", - "moduleName": "DocExtraction2", + "linkId": "DocExtraction2.InnerModule.t", + "name": "t", "external": false }] }] diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 838a4c5aa..323ccf62d 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -21,8 +21,7 @@ extracting docs for src/DocExtraction2.resi "docstrings": ["Makerz of stuffz."], "linkables": [{ "linkId": "DocExtraction2.t", - "path": "t", - "moduleName": "DocExtraction2", + "name": "t", "external": false }] }, @@ -49,9 +48,8 @@ extracting docs for src/DocExtraction2.resi "signature": "let make: unit => t", "docstrings": ["Maker of tea."], "linkables": [{ - "linkId": "DocExtraction2.t", - "path": "t", - "moduleName": "DocExtraction2", + "linkId": "DocExtraction2.InnerModule.t", + "name": "t", "external": false }] }] diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 2a0ce46e6..2aca0cc9e 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -36,8 +36,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"], "linkables": [{ "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "name": "t", "external": false }] }, @@ -49,8 +48,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Stuff goes offline."], "linkables": [{ "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "name": "t", "external": false }] }, @@ -70,8 +68,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": [], "linkables": [{ "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "name": "t", "external": false }], "detail": @@ -84,8 +81,7 @@ extracting docs for src/DocExtractionRes.res "signature": "Started(t)", "linkables": [{ "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "name": "t", "external": false }] }, @@ -119,13 +115,11 @@ extracting docs for src/DocExtractionRes.res "docstrings": [], "linkables": [{ "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "name": "t", "external": false }, { - "linkId": "DocExtractionRes.status", - "path": "status", - "moduleName": "DocExtractionRes", + "linkId": "DocExtractionRes.SomeInnerModule.status", + "name": "status", "external": false }] }] @@ -147,8 +141,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Testing what this looks like."], "linkables": [{ "linkId": "DocExtractionRes.SomeInnerModule.status", - "path": "SomeInnerModule.status", - "moduleName": "DocExtractionRes", + "name": "SomeInnerModule.status", "external": false }] }, @@ -160,8 +153,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": [], "linkables": [{ "linkId": "DocExtractionRes.SomeInnerModule.status", - "path": "SomeInnerModule.status", - "moduleName": "DocExtractionRes", + "name": "SomeInnerModule.status", "external": false }] }, @@ -192,8 +184,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Callback to get the DOM root..."], "linkables": [{ "linkId": "ReactDOM.Client.Root.t", - "path": "ReactDOM.Client.Root.t", - "moduleName": "ReactDOM", + "name": "ReactDOM.Client.Root.t", "external": true }] }] @@ -222,9 +213,8 @@ extracting docs for src/DocExtractionRes.res "signature": "let make: unit => t", "docstrings": ["The maker of stuff!"], "linkables": [{ - "linkId": "DocExtractionRes.t", - "path": "t", - "moduleName": "DocExtractionRes", + "linkId": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", + "name": "t", "external": false }] }] From 53442b360ebf35651e5a7aa3fb7fd3b09f362b69 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 14 Feb 2023 20:21:00 +0100 Subject: [PATCH 09/21] field name, and fix double escaping --- analysis/src/DocExtraction.ml | 5 ++--- analysis/tests/src/expected/DocExtractionRes.res.txt | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 8fbbbaa2c..468f24d0c 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -129,8 +129,7 @@ end let stringifyDocstrings docstrings = let open Protocol in docstrings - |> List.map (fun docstring -> - docstring |> String.trim |> Json.escape |> wrapInQuotes) + |> List.map (fun docstring -> docstring |> String.trim |> wrapInQuotes) |> array let stringifyLinkables ?(indentation = 0) @@ -181,7 +180,7 @@ let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "variant")); - ( "fieldDocs", + ( "constructorDocs", Some (constructorDocs |> List.map (fun constructorDoc -> diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 2aca0cc9e..2c6bf733b 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -33,7 +33,7 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "make", "signature": "let make: string => t", - "docstrings": ["Create stuff.\\n\\n```rescript example\\nlet stuff = make(\\\"My name\\\")\\n```"], + "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"], "linkables": [{ "linkId": "DocExtractionRes.t", "name": "t", @@ -74,7 +74,7 @@ extracting docs for src/DocExtractionRes.res "detail": { "kind": "variant", - "fieldDocs": [ + "constructorDocs": [ { "constructorName": "Started", "docstrings": ["If this is started or not"], @@ -167,7 +167,7 @@ extracting docs for src/DocExtractionRes.res "detail": { "kind": "variant", - "fieldDocs": [ + "constructorDocs": [ { "constructorName": "SomeStuff", "docstrings": ["This has inline records..."], From 96942367ad5f0e238c9c1abbb5987be0633e7429 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 14 May 2023 20:40:44 +0200 Subject: [PATCH 10/21] remove linkables concept --- analysis/src/DocExtraction.ml | 149 +----------------- .../tests/src/expected/DocExtraction2.res.txt | 20 +-- .../src/expected/DocExtraction2.resi.txt | 20 +-- .../src/expected/DocExtractionRes.res.txt | 88 ++--------- 4 files changed, 28 insertions(+), 249 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 468f24d0c..4a91c1cc4 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -1,23 +1,9 @@ -type linkableType = { - name: string; - modulePath: string list; - path: Path.t; - env: SharedTypes.QueryEnv.t; - loc: Location.t; -} - -type fieldDoc = { - fieldName: string; - docstrings: string list; - signature: string; - linkables: linkableType list; -} +type fieldDoc = {fieldName: string; docstrings: string list; signature: string} type constructorDoc = { constructorName: string; docstrings: string list; signature: string; - linkables: linkableType list; } type docItemDetail = @@ -29,8 +15,6 @@ type docItem = docstring: string list; signature: string; name: string; - linkables: linkableType list; - (** Relevant types to link to, found in relation to this value. *) } | Type of { id: string; @@ -39,8 +23,6 @@ type docItem = name: string; detail: docItemDetail option; (** Additional documentation for constructors and record fields, if available. *) - linkables: linkableType list; - (** Relevant types to link to, found in relation to this type. *) } | Module of docsForModule and docsForModule = { @@ -59,100 +41,13 @@ let formatCode content = signature |> String.trim -module Linkables = struct - (* TODO: Extend this by going into function arguments, tuples etc... *) - let labelDeclarationsTypes lds = - lds |> List.map (fun (ld : Types.label_declaration) -> ld.ld_type) - - let rec linkablesFromDecl (decl : Types.type_declaration) ~env ~full = - match decl.type_kind with - | Type_record (lds, _) -> (env, lds |> labelDeclarationsTypes) - | Type_variant cds -> - ( env, - cds - |> List.map (fun (cd : Types.constructor_declaration) -> - let fromArgs = - match cd.cd_args with - | Cstr_tuple ts -> ts - | Cstr_record lds -> lds |> labelDeclarationsTypes - in - match cd.cd_res with - | None -> fromArgs - | Some t -> t :: fromArgs) - |> List.flatten ) - | _ -> ( - match decl.type_manifest with - | None -> (env, []) - | Some typ -> linkablesFromTyp typ ~env ~full) - - and linkablesFromTyp ~env ~(full : SharedTypes.full) typ = - match typ |> Shared.digConstructor with - | Some path -> ( - match References.digConstructor ~env ~package:full.package path with - | None -> (env, [typ]) - | Some (env1, {item = {decl}}) -> - let env, types = linkablesFromDecl decl ~env:env1 ~full in - (env, typ :: types)) - | None -> (env, [typ]) - - type linkableSource = - | Typ of SharedTypes.Type.t - | TypeExpr of Types.type_expr - - let findLinkables ~env ~(full : SharedTypes.full) (typ : linkableSource) = - (* Expand definitions of types mentioned in typ. - If typ itself is a record or variant, search its body *) - let envToSearch, typesToSearch = - match typ with - | Typ t -> linkablesFromDecl ~env t.decl ~full - | TypeExpr t -> linkablesFromTyp t ~env ~full - in - let fromConstructorPath ~env path = - match References.digConstructor ~env ~package:full.package path with - | None -> None - | Some (env, {name = {txt}; extentLoc; modulePath}) -> - if Utils.isUncurriedInternal path then None - else - Some - { - name = txt; - env; - loc = extentLoc; - modulePath = SharedTypes.ModulePath.toPath modulePath txt; - path; - } - in - let constructors = Shared.findTypeConstructors typesToSearch in - constructors |> List.filter_map (fromConstructorPath ~env:envToSearch) -end - let stringifyDocstrings docstrings = let open Protocol in docstrings |> List.map (fun docstring -> docstring |> String.trim |> wrapInQuotes) |> array -let stringifyLinkables ?(indentation = 0) - ~(originalEnv : SharedTypes.QueryEnv.t) (linkables : linkableType list) = - let open Protocol in - linkables - |> List.map (fun l -> - let isExternal = originalEnv.file.uri <> l.env.file.uri in - let linkId = l.env.file.moduleName :: l.modulePath in - stringifyObject ~indentation:(indentation + 1) - [ - ( "linkId", - Some (linkId |> SharedTypes.ident |> Json.escape |> wrapInQuotes) - ); - ( "name", - Some - (l.path |> SharedTypes.pathIdentToString |> Json.escape - |> wrapInQuotes) ); - ("external", Some (Printf.sprintf "%b" isExternal)); - ]) - |> array - -let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = +let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = let open Protocol in match detail with | Record {fieldDocs} -> @@ -169,10 +64,6 @@ let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = ( "docstrings", Some (stringifyDocstrings fieldDoc.docstrings) ); ("signature", Some (wrapInQuotes fieldDoc.signature)); - ( "linkables", - Some - (stringifyLinkables ~indentation:(indentation + 1) - ~originalEnv fieldDoc.linkables) ); ]) |> array) ); ] @@ -193,10 +84,6 @@ let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = Some (stringifyDocstrings constructorDoc.docstrings) ); ( "signature", Some (wrapInQuotes constructorDoc.signature) ); - ( "linkables", - Some - (stringifyLinkables ~indentation:(indentation + 1) - ~originalEnv constructorDoc.linkables) ); ]) |> array) ); ] @@ -204,7 +91,7 @@ let stringifyDetail ?(indentation = 0) ~originalEnv (detail : docItemDetail) = let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {id; docstring; signature; name; linkables} -> + | Value {id; docstring; signature; name} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); @@ -213,12 +100,8 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); - ( "linkables", - Some - (stringifyLinkables ~originalEnv ~indentation:(indentation + 1) - linkables) ); ] - | Type {id; docstring; signature; name; detail; linkables} -> + | Type {id; docstring; signature; name; detail} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); @@ -226,17 +109,11 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ("name", Some (name |> Json.escape |> wrapInQuotes)); ("signature", Some (signature |> Json.escape |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); - ( "linkables", - Some - (stringifyLinkables ~originalEnv ~indentation:(indentation + 1) - linkables) ); ( "detail", match detail with | None -> None | Some detail -> - Some - (stringifyDetail ~originalEnv ~indentation:(indentation + 1) - detail) ); + Some (stringifyDetail ~indentation:(indentation + 1) detail) ); ] | Module m -> stringifyObject ~startOnNewline:true ~indentation @@ -277,8 +154,6 @@ let typeDetail typ ~env ~full = fieldName = field.fname.txt; docstrings = field.docstring; signature = Shared.typeToString field.typ; - linkables = - TypeExpr field.typ |> Linkables.findLinkables ~env ~full; }); }) | Some (Tvariant {constructors}) -> @@ -288,20 +163,10 @@ let typeDetail typ ~env ~full = constructorDocs = constructors |> List.map (fun (c : Constructor.t) -> - let linkables = - (match c.args with - | Args args -> args |> List.map (fun (t, _) -> t) - | InlineRecord fields -> - fields |> List.map (fun f -> f.typ)) - |> List.map (fun t -> - TypeExpr t |> Linkables.findLinkables ~env ~full) - |> List.flatten - in { constructorName = c.cname.txt; docstrings = c.docstring; signature = CompletionBackEnd.showConstructor c; - linkables; }); }) | _ -> None @@ -358,16 +223,12 @@ let extractDocs ~path ~debug = "let " ^ item.name ^ ": " ^ Shared.typeToString typ |> formatCode; name = item.name; - linkables = - TypeExpr typ |> Linkables.findLinkables ~env ~full; }) | Type (typ, _) -> Some (Type { id = modulePath |> makeId ~identifier:item.name; - linkables = - Typ typ |> Linkables.findLinkables ~env ~full; docstring = item.docstring |> List.map String.trim; signature = typ.decl diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 21f6d1735..56d770b86 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -11,20 +11,14 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "type", "name": "t", "signature": "type t", - "docstrings": ["Type t is pretty cool."], - "linkables": [] + "docstrings": ["Type t is pretty cool."] }, { "id": "DocExtraction2.make", "kind": "value", "name": "make", "signature": "let make: unit => t", - "docstrings": ["Makerz of stuffz."], - "linkables": [{ - "linkId": "DocExtraction2.t", - "name": "t", - "external": false - }] + "docstrings": ["Makerz of stuffz."] }, { "id": "InnerModule.DocExtraction2", @@ -39,20 +33,14 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "type", "name": "t", "signature": "type t", - "docstrings": ["This type is also t."], - "linkables": [] + "docstrings": ["This type is also t."] }, { "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", "signature": "let make: unit => t", - "docstrings": ["Maker of tea."], - "linkables": [{ - "linkId": "DocExtraction2.InnerModule.t", - "name": "t", - "external": false - }] + "docstrings": ["Maker of tea."] }] } }] diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 323ccf62d..cd2b5e29f 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -10,20 +10,14 @@ extracting docs for src/DocExtraction2.resi "kind": "type", "name": "t", "signature": "type t", - "docstrings": ["Type t is pretty cool."], - "linkables": [] + "docstrings": ["Type t is pretty cool."] }, { "id": "DocExtraction2.make", "kind": "value", "name": "make", "signature": "let make: unit => t", - "docstrings": ["Makerz of stuffz."], - "linkables": [{ - "linkId": "DocExtraction2.t", - "name": "t", - "external": false - }] + "docstrings": ["Makerz of stuffz."] }, { "id": "InnerModule.DocExtraction2", @@ -38,20 +32,14 @@ extracting docs for src/DocExtraction2.resi "kind": "type", "name": "t", "signature": "type t", - "docstrings": ["This type is also t."], - "linkables": [] + "docstrings": ["This type is also t."] }, { "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", "signature": "let make: unit => t", - "docstrings": ["Maker of tea."], - "linkables": [{ - "linkId": "DocExtraction2.InnerModule.t", - "name": "t", - "external": false - }] + "docstrings": ["Maker of tea."] }] } }] diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 2c6bf733b..17d38d2c7 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -11,20 +11,17 @@ extracting docs for src/DocExtractionRes.res "name": "t", "signature": "type t = {name: string, online: bool}", "docstrings": ["This type represents stuff."], - "linkables": [], "detail": { "kind": "record", "fieldDocs": [{ "fieldName": "name", "docstrings": ["The name of the stuff."], - "signature": "string", - "linkables": [] + "signature": "string" }, { "fieldName": "online", "docstrings": ["Whether stuff is online."], - "signature": "bool", - "linkables": [] + "signature": "bool" }] } }, @@ -33,24 +30,14 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "make", "signature": "let make: string => t", - "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"], - "linkables": [{ - "linkId": "DocExtractionRes.t", - "name": "t", - "external": false - }] + "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"] }, { "id": "DocExtractionRes.asOffline", "kind": "value", "name": "asOffline", "signature": "let asOffline: t => t", - "docstrings": ["Stuff goes offline."], - "linkables": [{ - "linkId": "DocExtractionRes.t", - "name": "t", - "external": false - }] + "docstrings": ["Stuff goes offline."] }, { "id": "SomeInnerModule.DocExtractionRes", @@ -66,11 +53,6 @@ extracting docs for src/DocExtractionRes.res "name": "status", "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], - "linkables": [{ - "linkId": "DocExtractionRes.t", - "name": "t", - "external": false - }], "detail": { "kind": "variant", @@ -78,24 +60,17 @@ extracting docs for src/DocExtractionRes.res { "constructorName": "Started", "docstrings": ["If this is started or not"], - "signature": "Started(t)", - "linkables": [{ - "linkId": "DocExtractionRes.t", - "name": "t", - "external": false - }] + "signature": "Started(t)" }, { "constructorName": "Stopped", "docstrings": ["Stopped?"], - "signature": "Stopped", - "linkables": [] + "signature": "Stopped" }, { "constructorName": "Idle", "docstrings": ["Now idle."], - "signature": "Idle", - "linkables": [] + "signature": "Idle" }] } }, @@ -104,24 +79,14 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "validInputs", "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", - "docstrings": ["These are all the valid inputs."], - "linkables": [] + "docstrings": ["These are all the valid inputs."] }, { "id": "DocExtractionRes.SomeInnerModule.callback", "kind": "type", "name": "callback", "signature": "type callback = (t, ~status: status) => unit", - "docstrings": [], - "linkables": [{ - "linkId": "DocExtractionRes.t", - "name": "t", - "external": false - }, { - "linkId": "DocExtractionRes.SomeInnerModule.status", - "name": "status", - "external": false - }] + "docstrings": [] }] } }, @@ -138,24 +103,14 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "callback", "signature": "type callback = SomeInnerModule.status => unit", - "docstrings": ["Testing what this looks like."], - "linkables": [{ - "linkId": "DocExtractionRes.SomeInnerModule.status", - "name": "SomeInnerModule.status", - "external": false - }] + "docstrings": ["Testing what this looks like."] }, { "id": "DocExtractionRes.AnotherModule.isGoodStatus", "kind": "value", "name": "isGoodStatus", "signature": "let isGoodStatus: SomeInnerModule.status => bool", - "docstrings": [], - "linkables": [{ - "linkId": "DocExtractionRes.SomeInnerModule.status", - "name": "SomeInnerModule.status", - "external": false - }] + "docstrings": [] }, { "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", @@ -163,7 +118,6 @@ extracting docs for src/DocExtractionRes.res "name": "someVariantWithInlineRecords", "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", "docstrings": ["Trying how it looks with an inline record in a variant."], - "linkables": [], "detail": { "kind": "variant", @@ -171,8 +125,7 @@ extracting docs for src/DocExtractionRes.res { "constructorName": "SomeStuff", "docstrings": ["This has inline records..."], - "signature": "SomeStuff", - "linkables": [] + "signature": "SomeStuff" }] } }, @@ -181,12 +134,7 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "domRoot", "signature": "type domRoot = unit => ReactDOM.Client.Root.t", - "docstrings": ["Callback to get the DOM root..."], - "linkables": [{ - "linkId": "ReactDOM.Client.Root.t", - "name": "ReactDOM.Client.Root.t", - "external": true - }] + "docstrings": ["Callback to get the DOM root..."] }] } }, @@ -203,20 +151,14 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "t", "signature": "type t", - "docstrings": ["The type t is stuff."], - "linkables": [] + "docstrings": ["The type t is stuff."] }, { "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", "kind": "value", "name": "make", "signature": "let make: unit => t", - "docstrings": ["The maker of stuff!"], - "linkables": [{ - "linkId": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", - "name": "t", - "external": false - }] + "docstrings": ["The maker of stuff!"] }] } }] From 42b64db97cf0c83cda775aeffbe37736c51f44c3 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sat, 27 May 2023 19:50:39 +0200 Subject: [PATCH 11/21] support extracting module aliases --- analysis/src/DocExtraction.ml | 40 +++++++++++++++++-- analysis/tests/src/DocExtractionRes.res | 3 ++ .../src/expected/DocExtractionRes.res.txt | 6 +++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 4a91c1cc4..202541ec5 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -6,6 +6,13 @@ type constructorDoc = { signature: string; } +type docsForModuleAlias = { + id: string; + docstring: string list; + name: string; + signature: string; +} + type docItemDetail = | Record of {fieldDocs: fieldDoc list} | Variant of {constructorDocs: constructorDoc list} @@ -25,6 +32,7 @@ type docItem = (** Additional documentation for constructors and record fields, if available. *) } | Module of docsForModule + | ModuleAlias of docsForModuleAlias and docsForModule = { id: string; docstring: string list; @@ -125,6 +133,14 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = (stringifyDocsForModule ~originalEnv ~indentation:(indentation + 1) m) ); ] + | ModuleAlias m -> + stringifyObject ~startOnNewline:true ~indentation + [ + ("id", Some (wrapInQuotes m.id)); + ("kind", Some (wrapInQuotes "moduleAlias")); + ("docstrings", Some (stringifyDocstrings m.docstring)); + ("signature", Some (m.signature |> Json.escape |> wrapInQuotes)); + ] and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = let open Protocol in @@ -203,7 +219,7 @@ let extractDocs ~path ~debug = let structure = file.structure in let open SharedTypes in let env = QueryEnv.fromFile file in - let rec extractDocs ?(modulePath = [env.file.moduleName]) + let rec extractDocsForModule ?(modulePath = [env.file.moduleName]) (structure : Module.structure) = { id = modulePath |> ident; @@ -237,19 +253,35 @@ let extractDocs ~path ~debug = name = item.name; detail = typeDetail typ ~full ~env; }) + | Module (Ident p) -> + (* module Whatever = OtherModule *) + let aliasToModule = p |> pathIdentToString in + let modulePath = aliasToModule :: modulePath in + Some + (ModuleAlias + { + id = modulePath |> List.rev |> SharedTypes.ident; + signature = + Printf.sprintf "module %s = %s" item.name + aliasToModule; + name = item.name; + docstring = item.docstring |> List.map String.trim; + }) | Module (Structure m) -> (* module Whatever = {} in res or module Whatever: {} in resi. *) Some - (Module (extractDocs ~modulePath:(m.name :: modulePath) m)) + (Module + (extractDocsForModule ~modulePath:(m.name :: modulePath) + m)) | Module (Constraint (Structure _impl, Structure interface)) -> (* module Whatever: { } = { }. Prefer the interface. *) Some (Module - (extractDocs + (extractDocsForModule ~modulePath:(interface.name :: modulePath) interface)) | _ -> None); } in - let docs = extractDocs structure in + let docs = extractDocsForModule structure in print_endline (stringifyDocsForModule ~originalEnv:env docs) diff --git a/analysis/tests/src/DocExtractionRes.res b/analysis/tests/src/DocExtractionRes.res index fabb7b6b3..0127e69c1 100644 --- a/analysis/tests/src/DocExtractionRes.res +++ b/analysis/tests/src/DocExtractionRes.res @@ -36,6 +36,9 @@ module SomeInnerModule = { module AnotherModule = { /*** Mighty fine module here too!*/ + /** This links another module. Neat. */ + module LinkedModule = SomeInnerModule + /** Testing what this looks like.*/ type callback = SomeInnerModule.status => unit diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 17d38d2c7..48e6d3617 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -98,6 +98,12 @@ extracting docs for src/DocExtractionRes.res "name": "AnotherModule", "docstrings": ["Mighty fine module here too!"], "items": [ + { + "id": "DocExtractionRes.AnotherModule.SomeInnerModule", + "kind": "moduleAlias", + "docstrings": ["This links another module. Neat."], + "signature": "module LinkedModule = SomeInnerModule" + }, { "id": "DocExtractionRes.AnotherModule.callback", "kind": "type", From 8d59cd0bef2511ee2c85f172db9efa2d52f2d44a Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 1 Jun 2023 20:37:45 -0300 Subject: [PATCH 12/21] first tests --- analysis/src/DocExtraction.ml | 71 +++++++++++++++++++++++++++++++++-- analysis/src/ProcessCmt.ml | 28 ++++++++++++-- analysis/src/SharedTypes.ml | 10 ++++- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 202541ec5..f9ea4c8aa 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -1,9 +1,16 @@ -type fieldDoc = {fieldName: string; docstrings: string list; signature: string} +type fieldDoc = { + fieldName: string; + docstrings: string list; + signature: string; + optional: bool; + deprecated: string option; +} type constructorDoc = { constructorName: string; docstrings: string list; signature: string; + deprecated: string option; } type docsForModuleAlias = { @@ -22,12 +29,16 @@ type docItem = docstring: string list; signature: string; name: string; + loc: Warnings.loc; + deprecated: string option; } | Type of { id: string; docstring: string list; signature: string; name: string; + loc: Warnings.loc; + deprecated: string option; detail: docItemDetail option; (** Additional documentation for constructors and record fields, if available. *) } @@ -36,6 +47,7 @@ type docItem = and docsForModule = { id: string; docstring: string list; + deprecated: string option; name: string; items: docItem list; } @@ -69,6 +81,15 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = stringifyObject ~indentation:(indentation + 1) [ ("fieldName", Some (wrapInQuotes fieldDoc.fieldName)); + ( "deprecated", + Some + (string_of_bool (Option.is_some fieldDoc.deprecated)) + ); + ( "deprecatedMessage", + match fieldDoc.deprecated with + | Some msg -> Some (wrapInQuotes msg) + | None -> None ); + ("optional", Some (string_of_bool fieldDoc.optional)); ( "docstrings", Some (stringifyDocstrings fieldDoc.docstrings) ); ("signature", Some (wrapInQuotes fieldDoc.signature)); @@ -88,6 +109,14 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = [ ( "constructorName", Some (wrapInQuotes constructorDoc.constructorName) ); + ( "deprecated", + Some + (string_of_bool + (Option.is_some constructorDoc.deprecated)) ); + ( "deprecatedMessage", + match constructorDoc.deprecated with + | Some msg -> Some (wrapInQuotes msg) + | None -> None ); ( "docstrings", Some (stringifyDocstrings constructorDoc.docstrings) ); ( "signature", @@ -96,25 +125,48 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = |> array) ); ] +let stringifyLoc loc ~indentation = + let open Protocol in + let line, col = Loc.start loc in + let path = loc.loc_start.pos_fname in + stringifyObject ~startOnNewline:false ~indentation:(indentation + 1) + [ + ("path", Some (wrapInQuotes path)); + ("line", Some (string_of_int (line + 1))); + ("col", Some (string_of_int (col + 1))); + ] + let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {id; docstring; signature; name} -> + | Value {id; docstring; signature; name; loc; deprecated} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "value")); ("name", Some (name |> Json.escape |> wrapInQuotes)); + ("deprecated", Some (string_of_bool (Option.is_some deprecated))); + ( "deprecatedMessage", + match deprecated with + | Some msg -> Some (wrapInQuotes msg) + | None -> None ); + ("location", Some (stringifyLoc loc ~indentation)); ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); ] - | Type {id; docstring; signature; name; detail} -> + | Type {id; docstring; signature; name; loc; deprecated; detail} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "type")); ("name", Some (name |> Json.escape |> wrapInQuotes)); + ("deprecated", Some (string_of_bool (Option.is_some deprecated))); + ( "deprecatedMessage", + match deprecated with + | Some msg -> Some (wrapInQuotes msg) + | None -> None ); + ("location", Some (stringifyLoc loc ~indentation)); ("signature", Some (signature |> Json.escape |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); ( "detail", @@ -147,6 +199,11 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = stringifyObject ~startOnNewline:true ~indentation [ ("name", Some (wrapInQuotes d.name)); + ("deprecated", Some (string_of_bool (Option.is_some d.deprecated))); + ( "deprecatedMessage", + match d.deprecated with + | Some msg -> Some (wrapInQuotes msg) + | None -> None ); ("docstrings", Some (stringifyDocstrings d.docstring)); ( "items", Some @@ -169,7 +226,9 @@ let typeDetail typ ~env ~full = { fieldName = field.fname.txt; docstrings = field.docstring; + optional = field.optional; signature = Shared.typeToString field.typ; + deprecated = field.deprecated; }); }) | Some (Tvariant {constructors}) -> @@ -183,6 +242,7 @@ let typeDetail typ ~env ~full = constructorName = c.cname.txt; docstrings = c.docstring; signature = CompletionBackEnd.showConstructor c; + deprecated = c.deprecated; }); }) | _ -> None @@ -225,6 +285,7 @@ let extractDocs ~path ~debug = id = modulePath |> ident; docstring = structure.docstring |> List.map String.trim; name = structure.name; + deprecated = structure.deprecated; items = structure.items |> List.filter_map (fun (item : Module.item) -> @@ -239,6 +300,8 @@ let extractDocs ~path ~debug = "let " ^ item.name ^ ": " ^ Shared.typeToString typ |> formatCode; name = item.name; + loc = item.loc; + deprecated = item.deprecated; }) | Type (typ, _) -> Some @@ -251,6 +314,8 @@ let extractDocs ~path ~debug = |> Shared.declToString item.name |> formatCode; name = item.name; + loc = item.loc; + deprecated = item.deprecated; detail = typeDetail typ ~full ~env; }) | Module (Ident p) -> diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index c2249e7c8..620ed45f4 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -59,6 +59,8 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; + loc; + deprecated = declared.deprecated; }; ] | Sig_type @@ -132,6 +134,8 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Type (declared.item, recStatus); name = declared.name.txt; docstring = declared.docstring; + loc = type_loc; + deprecated = declared.deprecated; }; ] | Sig_module (ident, {md_type; md_attributes; md_loc}, _) -> @@ -149,6 +153,8 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = md_loc; + deprecated = declared.deprecated; }; ] | _ -> [] @@ -160,7 +166,7 @@ and forTypeSignature ~name ~env signature = (fun item items -> forTypeSignatureItem ~env ~exported item @ items) signature [] in - {Module.name; docstring = []; exported; items} + {Module.name; docstring = []; exported; items; deprecated = None} and forTypeModule ~name ~env moduleType = match moduleType with @@ -312,6 +318,8 @@ let forTypeDeclaration ~env ~(exported : Exported.t) Module.kind = Module.Type (declared.item, recStatus); name = declared.name.txt; docstring = declared.docstring; + loc = typ_loc; + deprecated = declared.deprecated; } let rec forSignatureItem ~env ~(exported : Exported.t) @@ -330,6 +338,8 @@ let rec forSignatureItem ~env ~(exported : Exported.t) Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = name.loc; + deprecated = declared.deprecated; }; ] | Tsig_type (recFlag, decls) -> @@ -360,6 +370,8 @@ let rec forSignatureItem ~env ~(exported : Exported.t) Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = name.loc; + deprecated = declared.deprecated; }; ] | Tsig_recmodule modDecls -> @@ -395,7 +407,8 @@ let forSignature ~name ~env sigItems = | _ -> [] in let docstring = attrsToDocstring attributes in - {Module.name; docstring; exported; items} + let deprecated = ProcessAttributes.findDeprecatedAttribute attributes in + {Module.name; docstring; exported; items; deprecated} let forTreeModuleType ~name ~env {Typedtree.mty_desc} = match mty_desc with @@ -435,6 +448,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = pat.pat_loc; + deprecated = declared.deprecated; } :: !items | Tpat_tuple pats | Tpat_array pats | Tpat_construct (_, _, pats) -> @@ -469,6 +484,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = name.loc; + deprecated = declared.deprecated; }; ] | Tstr_recmodule modDecls -> @@ -499,6 +516,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module modTypeItem; name = declared.name.txt; docstring = declared.docstring; + loc = name.loc; + deprecated = declared.deprecated; }; ] | Tstr_include {incl_mod; incl_type} -> @@ -527,6 +546,8 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Value declared.item; name = declared.name.txt; docstring = declared.docstring; + loc = vd.val_loc; + deprecated = declared.deprecated; }; ] | Tstr_type (recFlag, decls) -> @@ -587,7 +608,8 @@ and forStructure ~name ~env strItems = | _ -> [] in let docstring = attrsToDocstring attributes in - {Module.name; docstring; exported; items} + let deprecated = ProcessAttributes.findDeprecatedAttribute attributes in + {Module.name; docstring; exported; items; deprecated} let fileForCmtInfos ~moduleName ~uri ({cmt_modname; cmt_annots} : Cmt_format.cmt_infos) = diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index bcdedf0bc..ca8cf59c8 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -122,13 +122,20 @@ module Module = struct | Type of Type.t * Types.rec_status | Module of t - and item = {kind: kind; name: string; docstring: string list} + and item = { + kind: kind; + name: string; + docstring: string list; + loc: Warnings.loc; + deprecated: string option; + } and structure = { name: string; docstring: string list; exported: Exported.t; items: item list; + deprecated: string option } and t = Ident of Path.t | Structure of structure | Constraint of t * t @@ -253,6 +260,7 @@ module File = struct docstring = []; exported = Exported.init (); items = []; + deprecated = None }; } end From a3affc871bf8223ddcf284d91aecfb1fb0470ae6 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 1 Jun 2023 21:05:20 -0300 Subject: [PATCH 13/21] update tests --- .../tests/src/expected/DocExtraction2.res.txt | 26 ++++++ .../src/expected/DocExtraction2.resi.txt | 26 ++++++ .../src/expected/DocExtractionRes.res.txt | 84 +++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 56d770b86..ce34582b3 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -4,12 +4,19 @@ preferring found resi file for impl: src/DocExtraction2.resi { "name": "DocExtraction2", + "deprecated": false, "docstrings": ["Module level doc here."], "items": [ { "id": "DocExtraction2.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 4, + "col": 1 + }, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -17,6 +24,12 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "DocExtraction2.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 7, + "col": 5 + }, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -26,12 +39,19 @@ preferring found resi file for impl: src/DocExtraction2.resi "item": { "name": "InnerModule", + "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 13, + "col": 3 + }, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -39,6 +59,12 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 15, + "col": 3 + }, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index cd2b5e29f..455cccd6d 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -3,12 +3,19 @@ extracting docs for src/DocExtraction2.resi { "name": "DocExtraction2", + "deprecated": false, "docstrings": ["Module level doc here."], "items": [ { "id": "DocExtraction2.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 4, + "col": 1 + }, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -16,6 +23,12 @@ extracting docs for src/DocExtraction2.resi "id": "DocExtraction2.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 7, + "col": 5 + }, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -25,12 +38,19 @@ extracting docs for src/DocExtraction2.resi "item": { "name": "InnerModule", + "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 13, + "col": 3 + }, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -38,6 +58,12 @@ extracting docs for src/DocExtraction2.resi "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", + "line": 15, + "col": 3 + }, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 48e6d3617..fdbd001ce 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -3,12 +3,19 @@ extracting docs for src/DocExtractionRes.res { "name": "DocExtractionRes", + "deprecated": false, "docstrings": ["Module level documentation goes here."], "items": [ { "id": "DocExtractionRes.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 4, + "col": 1 + }, "signature": "type t = {name: string, online: bool}", "docstrings": ["This type represents stuff."], "detail": @@ -16,10 +23,14 @@ extracting docs for src/DocExtractionRes.res "kind": "record", "fieldDocs": [{ "fieldName": "name", + "deprecated": false, + "optional": false, "docstrings": ["The name of the stuff."], "signature": "string" }, { "fieldName": "online", + "deprecated": false, + "optional": false, "docstrings": ["Whether stuff is online."], "signature": "bool" }] @@ -29,6 +40,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 17, + "col": 5 + }, "signature": "let make: string => t", "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"] }, @@ -36,6 +53,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.asOffline", "kind": "value", "name": "asOffline", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 23, + "col": 5 + }, "signature": "let asOffline: t => t", "docstrings": ["Stuff goes offline."] }, @@ -45,12 +68,19 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "SomeInnerModule", + "deprecated": false, "docstrings": ["Another module level docstring here."], "items": [ { "id": "DocExtractionRes.SomeInnerModule.status", "kind": "type", "name": "status", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 27, + "col": 3 + }, "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], "detail": @@ -59,16 +89,19 @@ extracting docs for src/DocExtractionRes.res "constructorDocs": [ { "constructorName": "Started", + "deprecated": false, "docstrings": ["If this is started or not"], "signature": "Started(t)" }, { "constructorName": "Stopped", + "deprecated": false, "docstrings": ["Stopped?"], "signature": "Stopped" }, { "constructorName": "Idle", + "deprecated": false, "docstrings": ["Now idle."], "signature": "Idle" }] @@ -78,6 +111,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.SomeInnerModule.validInputs", "kind": "type", "name": "validInputs", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 31, + "col": 3 + }, "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", "docstrings": ["These are all the valid inputs."] }, @@ -85,6 +124,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.SomeInnerModule.callback", "kind": "type", "name": "callback", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 33, + "col": 3 + }, "signature": "type callback = (t, ~status: status) => unit", "docstrings": [] }] @@ -96,6 +141,7 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "AnotherModule", + "deprecated": false, "docstrings": ["Mighty fine module here too!"], "items": [ { @@ -108,6 +154,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.callback", "kind": "type", "name": "callback", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 44, + "col": 3 + }, "signature": "type callback = SomeInnerModule.status => unit", "docstrings": ["Testing what this looks like."] }, @@ -115,6 +167,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.isGoodStatus", "kind": "value", "name": "isGoodStatus", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 46, + "col": 7 + }, "signature": "let isGoodStatus: SomeInnerModule.status => bool", "docstrings": [] }, @@ -122,6 +180,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", "kind": "type", "name": "someVariantWithInlineRecords", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 49, + "col": 3 + }, "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", "docstrings": ["Trying how it looks with an inline record in a variant."], "detail": @@ -130,6 +194,7 @@ extracting docs for src/DocExtractionRes.res "constructorDocs": [ { "constructorName": "SomeStuff", + "deprecated": false, "docstrings": ["This has inline records..."], "signature": "SomeStuff" }] @@ -139,6 +204,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.domRoot", "kind": "type", "name": "domRoot", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 54, + "col": 3 + }, "signature": "type domRoot = unit => ReactDOM.Client.Root.t", "docstrings": ["Callback to get the DOM root..."] }] @@ -150,12 +221,19 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "ModuleWithThingsThatShouldNotBeExported", + "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", "kind": "type", "name": "t", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 61, + "col": 3 + }, "signature": "type t", "docstrings": ["The type t is stuff."] }, @@ -163,6 +241,12 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", "kind": "value", "name": "make", + "deprecated": false, + "location": { + "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", + "line": 63, + "col": 3 + }, "signature": "let make: unit => t", "docstrings": ["The maker of stuff!"] }] From ec22484301a66647a20480598ba7686a93072d7e Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 1 Jun 2023 21:45:20 -0300 Subject: [PATCH 14/21] remove location field --- analysis/src/DocExtraction.ml | 4 +- .../tests/src/expected/DocExtraction2.res.txt | 20 ------- .../src/expected/DocExtraction2.resi.txt | 20 ------- .../src/expected/DocExtractionRes.res.txt | 60 ------------------- 4 files changed, 2 insertions(+), 102 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index f9ea4c8aa..a0751b48b 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -150,7 +150,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match deprecated with | Some msg -> Some (wrapInQuotes msg) | None -> None ); - ("location", Some (stringifyLoc loc ~indentation)); + (* ("location", Some (stringifyLoc loc ~indentation)); *) ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); @@ -166,7 +166,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match deprecated with | Some msg -> Some (wrapInQuotes msg) | None -> None ); - ("location", Some (stringifyLoc loc ~indentation)); + (* ("location", Some (stringifyLoc loc ~indentation)); *) ("signature", Some (signature |> Json.escape |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); ( "detail", diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index ce34582b3..274a3ad95 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -12,11 +12,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 4, - "col": 1 - }, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -25,11 +20,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 7, - "col": 5 - }, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -47,11 +37,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 13, - "col": 3 - }, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -60,11 +45,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 15, - "col": 3 - }, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 455cccd6d..ab99cc43c 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -11,11 +11,6 @@ extracting docs for src/DocExtraction2.resi "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 4, - "col": 1 - }, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -24,11 +19,6 @@ extracting docs for src/DocExtraction2.resi "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 7, - "col": 5 - }, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -46,11 +36,6 @@ extracting docs for src/DocExtraction2.resi "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 13, - "col": 3 - }, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -59,11 +44,6 @@ extracting docs for src/DocExtraction2.resi "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtraction2.resi", - "line": 15, - "col": 3 - }, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index fdbd001ce..907e79a31 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -11,11 +11,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 4, - "col": 1 - }, "signature": "type t = {name: string, online: bool}", "docstrings": ["This type represents stuff."], "detail": @@ -41,11 +36,6 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 17, - "col": 5 - }, "signature": "let make: string => t", "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"] }, @@ -54,11 +44,6 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "asOffline", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 23, - "col": 5 - }, "signature": "let asOffline: t => t", "docstrings": ["Stuff goes offline."] }, @@ -76,11 +61,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "status", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 27, - "col": 3 - }, "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], "detail": @@ -112,11 +92,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "validInputs", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 31, - "col": 3 - }, "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", "docstrings": ["These are all the valid inputs."] }, @@ -125,11 +100,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "callback", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 33, - "col": 3 - }, "signature": "type callback = (t, ~status: status) => unit", "docstrings": [] }] @@ -155,11 +125,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "callback", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 44, - "col": 3 - }, "signature": "type callback = SomeInnerModule.status => unit", "docstrings": ["Testing what this looks like."] }, @@ -168,11 +133,6 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "isGoodStatus", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 46, - "col": 7 - }, "signature": "let isGoodStatus: SomeInnerModule.status => bool", "docstrings": [] }, @@ -181,11 +141,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "someVariantWithInlineRecords", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 49, - "col": 3 - }, "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", "docstrings": ["Trying how it looks with an inline record in a variant."], "detail": @@ -205,11 +160,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "domRoot", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 54, - "col": 3 - }, "signature": "type domRoot = unit => ReactDOM.Client.Root.t", "docstrings": ["Callback to get the DOM root..."] }] @@ -229,11 +179,6 @@ extracting docs for src/DocExtractionRes.res "kind": "type", "name": "t", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 61, - "col": 3 - }, "signature": "type t", "docstrings": ["The type t is stuff."] }, @@ -242,11 +187,6 @@ extracting docs for src/DocExtractionRes.res "kind": "value", "name": "make", "deprecated": false, - "location": { - "path": "/home/pedro/Desktop/projects/rescript-vscode/analysis/tests/src/DocExtractionRes.res", - "line": 63, - "col": 3 - }, "signature": "let make: unit => t", "docstrings": ["The maker of stuff!"] }] From d8490aa569855f9fd33b34d81eeff13b3b805808 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 1 Jun 2023 21:59:35 -0300 Subject: [PATCH 15/21] only emit deprecated --- analysis/src/DocExtraction.ml | 31 ++++++------------- .../tests/src/expected/DocExtraction2.res.txt | 6 ---- .../src/expected/DocExtraction2.resi.txt | 6 ---- .../src/expected/DocExtractionRes.res.txt | 22 ------------- 4 files changed, 10 insertions(+), 55 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index a0751b48b..a91f6a8bd 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -82,12 +82,8 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = [ ("fieldName", Some (wrapInQuotes fieldDoc.fieldName)); ( "deprecated", - Some - (string_of_bool (Option.is_some fieldDoc.deprecated)) - ); - ( "deprecatedMessage", match fieldDoc.deprecated with - | Some msg -> Some (wrapInQuotes msg) + | Some d -> Some (wrapInQuotes d) | None -> None ); ("optional", Some (string_of_bool fieldDoc.optional)); ( "docstrings", @@ -110,12 +106,8 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = ( "constructorName", Some (wrapInQuotes constructorDoc.constructorName) ); ( "deprecated", - Some - (string_of_bool - (Option.is_some constructorDoc.deprecated)) ); - ( "deprecatedMessage", match constructorDoc.deprecated with - | Some msg -> Some (wrapInQuotes msg) + | Some d -> Some (wrapInQuotes d) | None -> None ); ( "docstrings", Some (stringifyDocstrings constructorDoc.docstrings) ); @@ -139,32 +131,30 @@ let stringifyLoc loc ~indentation = let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with - | Value {id; docstring; signature; name; loc; deprecated} -> + | Value {id; docstring; signature; name; deprecated} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "value")); ("name", Some (name |> Json.escape |> wrapInQuotes)); - ("deprecated", Some (string_of_bool (Option.is_some deprecated))); - ( "deprecatedMessage", + ( "deprecated", match deprecated with - | Some msg -> Some (wrapInQuotes msg) + | Some d -> Some (wrapInQuotes d) | None -> None ); (* ("location", Some (stringifyLoc loc ~indentation)); *) ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); ] - | Type {id; docstring; signature; name; loc; deprecated; detail} -> + | Type {id; docstring; signature; name; deprecated; detail} -> stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes id)); ("kind", Some (wrapInQuotes "type")); ("name", Some (name |> Json.escape |> wrapInQuotes)); - ("deprecated", Some (string_of_bool (Option.is_some deprecated))); - ( "deprecatedMessage", + ( "deprecated", match deprecated with - | Some msg -> Some (wrapInQuotes msg) + | Some d -> Some (wrapInQuotes d) | None -> None ); (* ("location", Some (stringifyLoc loc ~indentation)); *) ("signature", Some (signature |> Json.escape |> wrapInQuotes)); @@ -199,10 +189,9 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = stringifyObject ~startOnNewline:true ~indentation [ ("name", Some (wrapInQuotes d.name)); - ("deprecated", Some (string_of_bool (Option.is_some d.deprecated))); - ( "deprecatedMessage", + ( "deprecated", match d.deprecated with - | Some msg -> Some (wrapInQuotes msg) + | Some d -> Some (wrapInQuotes d) | None -> None ); ("docstrings", Some (stringifyDocstrings d.docstring)); ( "items", diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 274a3ad95..56d770b86 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -4,14 +4,12 @@ preferring found resi file for impl: src/DocExtraction2.resi { "name": "DocExtraction2", - "deprecated": false, "docstrings": ["Module level doc here."], "items": [ { "id": "DocExtraction2.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -19,7 +17,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "DocExtraction2.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -29,14 +26,12 @@ preferring found resi file for impl: src/DocExtraction2.resi "item": { "name": "InnerModule", - "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -44,7 +39,6 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index ab99cc43c..cd2b5e29f 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -3,14 +3,12 @@ extracting docs for src/DocExtraction2.resi { "name": "DocExtraction2", - "deprecated": false, "docstrings": ["Module level doc here."], "items": [ { "id": "DocExtraction2.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t", "docstrings": ["Type t is pretty cool."] }, @@ -18,7 +16,6 @@ extracting docs for src/DocExtraction2.resi "id": "DocExtraction2.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: unit => t", "docstrings": ["Makerz of stuffz."] }, @@ -28,14 +25,12 @@ extracting docs for src/DocExtraction2.resi "item": { "name": "InnerModule", - "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtraction2.InnerModule.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t", "docstrings": ["This type is also t."] }, @@ -43,7 +38,6 @@ extracting docs for src/DocExtraction2.resi "id": "DocExtraction2.InnerModule.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: unit => t", "docstrings": ["Maker of tea."] }] diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 907e79a31..62010867d 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -3,14 +3,12 @@ extracting docs for src/DocExtractionRes.res { "name": "DocExtractionRes", - "deprecated": false, "docstrings": ["Module level documentation goes here."], "items": [ { "id": "DocExtractionRes.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t = {name: string, online: bool}", "docstrings": ["This type represents stuff."], "detail": @@ -18,13 +16,11 @@ extracting docs for src/DocExtractionRes.res "kind": "record", "fieldDocs": [{ "fieldName": "name", - "deprecated": false, "optional": false, "docstrings": ["The name of the stuff."], "signature": "string" }, { "fieldName": "online", - "deprecated": false, "optional": false, "docstrings": ["Whether stuff is online."], "signature": "bool" @@ -35,7 +31,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: string => t", "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"] }, @@ -43,7 +38,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.asOffline", "kind": "value", "name": "asOffline", - "deprecated": false, "signature": "let asOffline: t => t", "docstrings": ["Stuff goes offline."] }, @@ -53,14 +47,12 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "SomeInnerModule", - "deprecated": false, "docstrings": ["Another module level docstring here."], "items": [ { "id": "DocExtractionRes.SomeInnerModule.status", "kind": "type", "name": "status", - "deprecated": false, "signature": "type status = Started(t) | Stopped | Idle", "docstrings": [], "detail": @@ -69,19 +61,16 @@ extracting docs for src/DocExtractionRes.res "constructorDocs": [ { "constructorName": "Started", - "deprecated": false, "docstrings": ["If this is started or not"], "signature": "Started(t)" }, { "constructorName": "Stopped", - "deprecated": false, "docstrings": ["Stopped?"], "signature": "Stopped" }, { "constructorName": "Idle", - "deprecated": false, "docstrings": ["Now idle."], "signature": "Idle" }] @@ -91,7 +80,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.SomeInnerModule.validInputs", "kind": "type", "name": "validInputs", - "deprecated": false, "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", "docstrings": ["These are all the valid inputs."] }, @@ -99,7 +87,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.SomeInnerModule.callback", "kind": "type", "name": "callback", - "deprecated": false, "signature": "type callback = (t, ~status: status) => unit", "docstrings": [] }] @@ -111,7 +98,6 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "AnotherModule", - "deprecated": false, "docstrings": ["Mighty fine module here too!"], "items": [ { @@ -124,7 +110,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.callback", "kind": "type", "name": "callback", - "deprecated": false, "signature": "type callback = SomeInnerModule.status => unit", "docstrings": ["Testing what this looks like."] }, @@ -132,7 +117,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.isGoodStatus", "kind": "value", "name": "isGoodStatus", - "deprecated": false, "signature": "let isGoodStatus: SomeInnerModule.status => bool", "docstrings": [] }, @@ -140,7 +124,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", "kind": "type", "name": "someVariantWithInlineRecords", - "deprecated": false, "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", "docstrings": ["Trying how it looks with an inline record in a variant."], "detail": @@ -149,7 +132,6 @@ extracting docs for src/DocExtractionRes.res "constructorDocs": [ { "constructorName": "SomeStuff", - "deprecated": false, "docstrings": ["This has inline records..."], "signature": "SomeStuff" }] @@ -159,7 +141,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.AnotherModule.domRoot", "kind": "type", "name": "domRoot", - "deprecated": false, "signature": "type domRoot = unit => ReactDOM.Client.Root.t", "docstrings": ["Callback to get the DOM root..."] }] @@ -171,14 +152,12 @@ extracting docs for src/DocExtractionRes.res "item": { "name": "ModuleWithThingsThatShouldNotBeExported", - "deprecated": false, "docstrings": [], "items": [ { "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", "kind": "type", "name": "t", - "deprecated": false, "signature": "type t", "docstrings": ["The type t is stuff."] }, @@ -186,7 +165,6 @@ extracting docs for src/DocExtractionRes.res "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", "kind": "value", "name": "make", - "deprecated": false, "signature": "let make: unit => t", "docstrings": ["The maker of stuff!"] }] From c6360961367462295de259601d463fd24a27f019 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 13 Jun 2023 19:13:03 -0300 Subject: [PATCH 16/21] remove location field --- analysis/src/DocExtraction.ml | 17 ----------------- analysis/src/ProcessCmt.ml | 10 ---------- analysis/src/SharedTypes.ml | 1 - 3 files changed, 28 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index a91f6a8bd..8ead07453 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -29,7 +29,6 @@ type docItem = docstring: string list; signature: string; name: string; - loc: Warnings.loc; deprecated: string option; } | Type of { @@ -37,7 +36,6 @@ type docItem = docstring: string list; signature: string; name: string; - loc: Warnings.loc; deprecated: string option; detail: docItemDetail option; (** Additional documentation for constructors and record fields, if available. *) @@ -117,17 +115,6 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = |> array) ); ] -let stringifyLoc loc ~indentation = - let open Protocol in - let line, col = Loc.start loc in - let path = loc.loc_start.pos_fname in - stringifyObject ~startOnNewline:false ~indentation:(indentation + 1) - [ - ("path", Some (wrapInQuotes path)); - ("line", Some (string_of_int (line + 1))); - ("col", Some (string_of_int (col + 1))); - ] - let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = let open Protocol in match item with @@ -141,7 +128,6 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match deprecated with | Some d -> Some (wrapInQuotes d) | None -> None ); - (* ("location", Some (stringifyLoc loc ~indentation)); *) ( "signature", Some (signature |> String.trim |> Json.escape |> wrapInQuotes) ); ("docstrings", Some (stringifyDocstrings docstring)); @@ -156,7 +142,6 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match deprecated with | Some d -> Some (wrapInQuotes d) | None -> None ); - (* ("location", Some (stringifyLoc loc ~indentation)); *) ("signature", Some (signature |> Json.escape |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); ( "detail", @@ -289,7 +274,6 @@ let extractDocs ~path ~debug = "let " ^ item.name ^ ": " ^ Shared.typeToString typ |> formatCode; name = item.name; - loc = item.loc; deprecated = item.deprecated; }) | Type (typ, _) -> @@ -303,7 +287,6 @@ let extractDocs ~path ~debug = |> Shared.declToString item.name |> formatCode; name = item.name; - loc = item.loc; deprecated = item.deprecated; detail = typeDetail typ ~full ~env; }) diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index 620ed45f4..6468fc83f 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -59,7 +59,6 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; - loc; deprecated = declared.deprecated; }; ] @@ -134,7 +133,6 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Type (declared.item, recStatus); name = declared.name.txt; docstring = declared.docstring; - loc = type_loc; deprecated = declared.deprecated; }; ] @@ -153,7 +151,6 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = md_loc; deprecated = declared.deprecated; }; ] @@ -318,7 +315,6 @@ let forTypeDeclaration ~env ~(exported : Exported.t) Module.kind = Module.Type (declared.item, recStatus); name = declared.name.txt; docstring = declared.docstring; - loc = typ_loc; deprecated = declared.deprecated; } @@ -338,7 +334,6 @@ let rec forSignatureItem ~env ~(exported : Exported.t) Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = name.loc; deprecated = declared.deprecated; }; ] @@ -370,7 +365,6 @@ let rec forSignatureItem ~env ~(exported : Exported.t) Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = name.loc; deprecated = declared.deprecated; }; ] @@ -448,7 +442,6 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module.Value declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = pat.pat_loc; deprecated = declared.deprecated; } :: !items @@ -484,7 +477,6 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = name.loc; deprecated = declared.deprecated; }; ] @@ -516,7 +508,6 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Module modTypeItem; name = declared.name.txt; docstring = declared.docstring; - loc = name.loc; deprecated = declared.deprecated; }; ] @@ -546,7 +537,6 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = Module.kind = Value declared.item; name = declared.name.txt; docstring = declared.docstring; - loc = vd.val_loc; deprecated = declared.deprecated; }; ] diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index ca8cf59c8..e975c6264 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -126,7 +126,6 @@ module Module = struct kind: kind; name: string; docstring: string list; - loc: Warnings.loc; deprecated: string option; } From 9aa8e0f1d0a26e806d520e0df26407aa3c645db5 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 24 Sep 2023 02:44:02 -0300 Subject: [PATCH 17/21] add module name field (#819) --- analysis/src/DocExtraction.ml | 2 ++ analysis/tests/src/expected/DocExtraction2.res.txt | 1 + analysis/tests/src/expected/DocExtraction2.resi.txt | 1 + analysis/tests/src/expected/DocExtractionRes.res.txt | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 8ead07453..9ce6d4c98 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -154,6 +154,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = stringifyObject ~startOnNewline:true ~indentation [ ("id", Some (wrapInQuotes m.id)); + ("name", Some (wrapInQuotes m.name)); ("kind", Some (wrapInQuotes "module")); ( "item", Some @@ -165,6 +166,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = [ ("id", Some (wrapInQuotes m.id)); ("kind", Some (wrapInQuotes "moduleAlias")); + ("name", Some (wrapInQuotes m.name)); ("docstrings", Some (stringifyDocstrings m.docstring)); ("signature", Some (m.signature |> Json.escape |> wrapInQuotes)); ] diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 56d770b86..47875a5cd 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -22,6 +22,7 @@ preferring found resi file for impl: src/DocExtraction2.resi }, { "id": "InnerModule.DocExtraction2", + "name": "InnerModule", "kind": "module", "item": { diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index cd2b5e29f..24e9f137d 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -21,6 +21,7 @@ extracting docs for src/DocExtraction2.resi }, { "id": "InnerModule.DocExtraction2", + "name": "InnerModule", "kind": "module", "item": { diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 62010867d..ea8c5766d 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -43,6 +43,7 @@ extracting docs for src/DocExtractionRes.res }, { "id": "SomeInnerModule.DocExtractionRes", + "name": "SomeInnerModule", "kind": "module", "item": { @@ -94,6 +95,7 @@ extracting docs for src/DocExtractionRes.res }, { "id": "AnotherModule.DocExtractionRes", + "name": "AnotherModule", "kind": "module", "item": { @@ -103,6 +105,7 @@ extracting docs for src/DocExtractionRes.res { "id": "DocExtractionRes.AnotherModule.SomeInnerModule", "kind": "moduleAlias", + "name": "LinkedModule", "docstrings": ["This links another module. Neat."], "signature": "module LinkedModule = SomeInnerModule" }, @@ -148,6 +151,7 @@ extracting docs for src/DocExtractionRes.res }, { "id": "ModuleWithThingsThatShouldNotBeExported.DocExtractionRes", + "name": "ModuleWithThingsThatShouldNotBeExported", "kind": "module", "item": { From 3d3aa8eecfeca918b6c12d354ad2e7cd13b3769a Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Wed, 27 Sep 2023 02:01:50 -0300 Subject: [PATCH 18/21] [DocGen]: Rename key `item` -> `items` (#821) * rename to items * update tests --- analysis/src/DocExtraction.ml | 2 +- analysis/tests/src/expected/DocExtraction2.res.txt | 2 +- analysis/tests/src/expected/DocExtraction2.resi.txt | 2 +- analysis/tests/src/expected/DocExtractionRes.res.txt | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 9ce6d4c98..6dc61cd19 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -156,7 +156,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ("id", Some (wrapInQuotes m.id)); ("name", Some (wrapInQuotes m.name)); ("kind", Some (wrapInQuotes "module")); - ( "item", + ( "items", Some (stringifyDocsForModule ~originalEnv ~indentation:(indentation + 1) m) ); diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 47875a5cd..afdbb4c33 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -24,7 +24,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "InnerModule.DocExtraction2", "name": "InnerModule", "kind": "module", - "item": + "items": { "name": "InnerModule", "docstrings": [], diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 24e9f137d..7b53697a0 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -23,7 +23,7 @@ extracting docs for src/DocExtraction2.resi "id": "InnerModule.DocExtraction2", "name": "InnerModule", "kind": "module", - "item": + "items": { "name": "InnerModule", "docstrings": [], diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index ea8c5766d..1f50a641d 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -45,7 +45,7 @@ extracting docs for src/DocExtractionRes.res "id": "SomeInnerModule.DocExtractionRes", "name": "SomeInnerModule", "kind": "module", - "item": + "items": { "name": "SomeInnerModule", "docstrings": ["Another module level docstring here."], @@ -97,7 +97,7 @@ extracting docs for src/DocExtractionRes.res "id": "AnotherModule.DocExtractionRes", "name": "AnotherModule", "kind": "module", - "item": + "items": { "name": "AnotherModule", "docstrings": ["Mighty fine module here too!"], @@ -153,7 +153,7 @@ extracting docs for src/DocExtractionRes.res "id": "ModuleWithThingsThatShouldNotBeExported.DocExtractionRes", "name": "ModuleWithThingsThatShouldNotBeExported", "kind": "module", - "item": + "items": { "name": "ModuleWithThingsThatShouldNotBeExported", "docstrings": [], From 58711a049061fc4c98ba676195786c3860518177 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Wed, 27 Sep 2023 11:29:24 -0300 Subject: [PATCH 19/21] docgen: convert items to array (#822) --- analysis/src/DocExtraction.ml | 6 +- .../tests/src/expected/DocExtraction2.res.txt | 33 ++- .../src/expected/DocExtraction2.resi.txt | 33 ++- .../src/expected/DocExtractionRes.res.txt | 207 ++++++++---------- 4 files changed, 128 insertions(+), 151 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 6dc61cd19..71a74e329 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -158,8 +158,10 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ("kind", Some (wrapInQuotes "module")); ( "items", Some - (stringifyDocsForModule ~originalEnv ~indentation:(indentation + 1) - m) ); + (m.items + |> List.map + (stringifyDocItem ~originalEnv ~indentation:(indentation + 1)) + |> array) ); ] | ModuleAlias m -> stringifyObject ~startOnNewline:true ~indentation diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index afdbb4c33..4f7f4dbbd 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -24,26 +24,21 @@ preferring found resi file for impl: src/DocExtraction2.resi "id": "InnerModule.DocExtraction2", "name": "InnerModule", "kind": "module", - "items": + "items": [ { - "name": "InnerModule", - "docstrings": [], - "items": [ - { - "id": "DocExtraction2.InnerModule.t", - "kind": "type", - "name": "t", - "signature": "type t", - "docstrings": ["This type is also t."] - }, - { - "id": "DocExtraction2.InnerModule.make", - "kind": "value", - "name": "make", - "signature": "let make: unit => t", - "docstrings": ["Maker of tea."] - }] - } + "id": "DocExtraction2.InnerModule.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."] + }, + { + "id": "DocExtraction2.InnerModule.make", + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Maker of tea."] + }] }] } diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 7b53697a0..923680e52 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -23,26 +23,21 @@ extracting docs for src/DocExtraction2.resi "id": "InnerModule.DocExtraction2", "name": "InnerModule", "kind": "module", - "items": + "items": [ { - "name": "InnerModule", - "docstrings": [], - "items": [ - { - "id": "DocExtraction2.InnerModule.t", - "kind": "type", - "name": "t", - "signature": "type t", - "docstrings": ["This type is also t."] - }, - { - "id": "DocExtraction2.InnerModule.make", - "kind": "value", - "name": "make", - "signature": "let make: unit => t", - "docstrings": ["Maker of tea."] - }] - } + "id": "DocExtraction2.InnerModule.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."] + }, + { + "id": "DocExtraction2.InnerModule.make", + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["Maker of tea."] + }] }] } diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 1f50a641d..4a6edea83 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -45,134 +45,119 @@ extracting docs for src/DocExtractionRes.res "id": "SomeInnerModule.DocExtractionRes", "name": "SomeInnerModule", "kind": "module", - "items": + "items": [ { - "name": "SomeInnerModule", - "docstrings": ["Another module level docstring here."], - "items": [ + "id": "DocExtractionRes.SomeInnerModule.status", + "kind": "type", + "name": "status", + "signature": "type status = Started(t) | Stopped | Idle", + "docstrings": [], + "detail": { - "id": "DocExtractionRes.SomeInnerModule.status", - "kind": "type", - "name": "status", - "signature": "type status = Started(t) | Stopped | Idle", - "docstrings": [], - "detail": + "kind": "variant", + "constructorDocs": [ { - "kind": "variant", - "constructorDocs": [ - { - "constructorName": "Started", - "docstrings": ["If this is started or not"], - "signature": "Started(t)" - }, - { - "constructorName": "Stopped", - "docstrings": ["Stopped?"], - "signature": "Stopped" - }, - { - "constructorName": "Idle", - "docstrings": ["Now idle."], - "signature": "Idle" - }] - } - }, - { - "id": "DocExtractionRes.SomeInnerModule.validInputs", - "kind": "type", - "name": "validInputs", - "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", - "docstrings": ["These are all the valid inputs."] - }, - { - "id": "DocExtractionRes.SomeInnerModule.callback", - "kind": "type", - "name": "callback", - "signature": "type callback = (t, ~status: status) => unit", - "docstrings": [] - }] - } + "constructorName": "Started", + "docstrings": ["If this is started or not"], + "signature": "Started(t)" + }, + { + "constructorName": "Stopped", + "docstrings": ["Stopped?"], + "signature": "Stopped" + }, + { + "constructorName": "Idle", + "docstrings": ["Now idle."], + "signature": "Idle" + }] + } + }, + { + "id": "DocExtractionRes.SomeInnerModule.validInputs", + "kind": "type", + "name": "validInputs", + "signature": "type validInputs = [\\n | #\\\"needs-escaping\\\"\\n | #something\\n | #status(status)\\n | #withPayload(int)\\n]", + "docstrings": ["These are all the valid inputs."] + }, + { + "id": "DocExtractionRes.SomeInnerModule.callback", + "kind": "type", + "name": "callback", + "signature": "type callback = (t, ~status: status) => unit", + "docstrings": [] + }] }, { "id": "AnotherModule.DocExtractionRes", "name": "AnotherModule", "kind": "module", - "items": + "items": [ { - "name": "AnotherModule", - "docstrings": ["Mighty fine module here too!"], - "items": [ - { - "id": "DocExtractionRes.AnotherModule.SomeInnerModule", - "kind": "moduleAlias", - "name": "LinkedModule", - "docstrings": ["This links another module. Neat."], - "signature": "module LinkedModule = SomeInnerModule" - }, - { - "id": "DocExtractionRes.AnotherModule.callback", - "kind": "type", - "name": "callback", - "signature": "type callback = SomeInnerModule.status => unit", - "docstrings": ["Testing what this looks like."] - }, - { - "id": "DocExtractionRes.AnotherModule.isGoodStatus", - "kind": "value", - "name": "isGoodStatus", - "signature": "let isGoodStatus: SomeInnerModule.status => bool", - "docstrings": [] - }, + "id": "DocExtractionRes.AnotherModule.SomeInnerModule", + "kind": "moduleAlias", + "name": "LinkedModule", + "docstrings": ["This links another module. Neat."], + "signature": "module LinkedModule = SomeInnerModule" + }, + { + "id": "DocExtractionRes.AnotherModule.callback", + "kind": "type", + "name": "callback", + "signature": "type callback = SomeInnerModule.status => unit", + "docstrings": ["Testing what this looks like."] + }, + { + "id": "DocExtractionRes.AnotherModule.isGoodStatus", + "kind": "value", + "name": "isGoodStatus", + "signature": "let isGoodStatus: SomeInnerModule.status => bool", + "docstrings": [] + }, + { + "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", + "kind": "type", + "name": "someVariantWithInlineRecords", + "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", + "docstrings": ["Trying how it looks with an inline record in a variant."], + "detail": { - "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", - "kind": "type", - "name": "someVariantWithInlineRecords", - "signature": "type someVariantWithInlineRecords = SomeStuff({offline: bool})", - "docstrings": ["Trying how it looks with an inline record in a variant."], - "detail": + "kind": "variant", + "constructorDocs": [ { - "kind": "variant", - "constructorDocs": [ - { - "constructorName": "SomeStuff", - "docstrings": ["This has inline records..."], - "signature": "SomeStuff" - }] - } - }, - { - "id": "DocExtractionRes.AnotherModule.domRoot", - "kind": "type", - "name": "domRoot", - "signature": "type domRoot = unit => ReactDOM.Client.Root.t", - "docstrings": ["Callback to get the DOM root..."] - }] - } + "constructorName": "SomeStuff", + "docstrings": ["This has inline records..."], + "signature": "SomeStuff" + }] + } + }, + { + "id": "DocExtractionRes.AnotherModule.domRoot", + "kind": "type", + "name": "domRoot", + "signature": "type domRoot = unit => ReactDOM.Client.Root.t", + "docstrings": ["Callback to get the DOM root..."] + }] }, { "id": "ModuleWithThingsThatShouldNotBeExported.DocExtractionRes", "name": "ModuleWithThingsThatShouldNotBeExported", "kind": "module", - "items": + "items": [ { - "name": "ModuleWithThingsThatShouldNotBeExported", - "docstrings": [], - "items": [ - { - "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", - "kind": "type", - "name": "t", - "signature": "type t", - "docstrings": ["The type t is stuff."] - }, - { - "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", - "kind": "value", - "name": "make", - "signature": "let make: unit => t", - "docstrings": ["The maker of stuff!"] - }] - } + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["The type t is stuff."] + }, + { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", + "kind": "value", + "name": "make", + "signature": "let make: unit => t", + "docstrings": ["The maker of stuff!"] + }] }] } From f899f947f8fc4130b891981923f01d06035511be Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Mon, 2 Oct 2023 04:21:59 -0300 Subject: [PATCH 20/21] [DocGen]: Polish (#796) * emit items from module alias * add error msg * rename fields * remove double name field * add ocaml.text attr * search for all attrs * fix id module * update tests * emit valid id path * update tests --- analysis/src/DocExtraction.ml | 65 ++++++++++++------- analysis/src/ProcessAttributes.ml | 2 +- analysis/src/ProcessCmt.ml | 8 ++- .../tests/src/expected/DocExtraction2.res.txt | 2 +- .../src/expected/DocExtraction2.resi.txt | 2 +- .../src/expected/DocExtractionRes.res.txt | 28 ++++---- 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 71a74e329..4ea095755 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -13,13 +13,6 @@ type constructorDoc = { deprecated: string option; } -type docsForModuleAlias = { - id: string; - docstring: string list; - name: string; - signature: string; -} - type docItemDetail = | Record of {fieldDocs: fieldDoc list} | Variant of {constructorDocs: constructorDoc list} @@ -41,7 +34,12 @@ type docItem = (** Additional documentation for constructors and record fields, if available. *) } | Module of docsForModule - | ModuleAlias of docsForModuleAlias + | ModuleAlias of { + id: string; + docstring: string list; + name: string; + items: docItem list; + } and docsForModule = { id: string; docstring: string list; @@ -72,13 +70,13 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "record")); - ( "fieldDocs", + ( "items", Some (fieldDocs |> List.map (fun fieldDoc -> stringifyObject ~indentation:(indentation + 1) [ - ("fieldName", Some (wrapInQuotes fieldDoc.fieldName)); + ("name", Some (wrapInQuotes fieldDoc.fieldName)); ( "deprecated", match fieldDoc.deprecated with | Some d -> Some (wrapInQuotes d) @@ -94,14 +92,14 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) = stringifyObject ~startOnNewline:true ~indentation [ ("kind", Some (wrapInQuotes "variant")); - ( "constructorDocs", + ( "items", Some (constructorDocs |> List.map (fun constructorDoc -> stringifyObject ~startOnNewline:true ~indentation:(indentation + 1) [ - ( "constructorName", + ( "name", Some (wrapInQuotes constructorDoc.constructorName) ); ( "deprecated", match constructorDoc.deprecated with @@ -170,7 +168,12 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = ("kind", Some (wrapInQuotes "moduleAlias")); ("name", Some (wrapInQuotes m.name)); ("docstrings", Some (stringifyDocstrings m.docstring)); - ("signature", Some (m.signature |> Json.escape |> wrapInQuotes)); + ( "items", + Some + (m.items + |> List.map + (stringifyDocItem ~originalEnv ~indentation:(indentation + 1)) + |> array) ); ] and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) = @@ -225,8 +228,6 @@ let typeDetail typ ~env ~full = }) | _ -> None -exception Invalid_file_type - let makeId modulePath ~identifier = identifier :: modulePath |> List.rev |> SharedTypes.ident @@ -235,7 +236,10 @@ let extractDocs ~path ~debug = if FindFiles.isImplementation path = false && FindFiles.isInterface path = false - then raise Invalid_file_type; + then ( + Printf.printf "error: failed to read %s, expected an .res or .resi file\n" + path; + exit 1); let path = if FindFiles.isImplementation path then let pathAsResi = @@ -251,7 +255,10 @@ let extractDocs ~path ~debug = else path in match Cmt.loadFullCmtFromPath ~path with - | None -> () + | None -> + Printf.printf + "error: failed to generate doc for %s, try to build the project\n" path; + exit 1 | Some full -> let file = full.file in let structure = file.structure in @@ -260,7 +267,7 @@ let extractDocs ~path ~debug = let rec extractDocsForModule ?(modulePath = [env.file.moduleName]) (structure : Module.structure) = { - id = modulePath |> ident; + id = modulePath |> List.rev |> ident; docstring = structure.docstring |> List.map String.trim; name = structure.name; deprecated = structure.deprecated; @@ -297,15 +304,27 @@ let extractDocs ~path ~debug = | Module (Ident p) -> (* module Whatever = OtherModule *) let aliasToModule = p |> pathIdentToString in - let modulePath = aliasToModule :: modulePath in + let id = + (modulePath |> List.rev |> List.hd) ^ "." ^ item.name + in + let items = + match + ProcessCmt.fileForModule ~package:full.package + aliasToModule + with + | None -> [] + | Some file -> + let docs = + extractDocsForModule ~modulePath:[id] file.structure + in + docs.items + in Some (ModuleAlias { - id = modulePath |> List.rev |> SharedTypes.ident; - signature = - Printf.sprintf "module %s = %s" item.name - aliasToModule; + id; name = item.name; + items; docstring = item.docstring |> List.map String.trim; }) | Module (Structure m) -> diff --git a/analysis/src/ProcessAttributes.ml b/analysis/src/ProcessAttributes.ml index c610d1e79..60ba88c21 100644 --- a/analysis/src/ProcessAttributes.ml +++ b/analysis/src/ProcessAttributes.ml @@ -5,7 +5,7 @@ let rec findDocAttribute attributes = let open Parsetree in match attributes with | [] -> None - | ( {Asttypes.txt = "ocaml.doc" | "ns.doc" | "res.doc"}, + | ( {Asttypes.txt = "ocaml.doc" | "ocaml.text" | "ns.doc" | "res.doc"}, PStr [ { diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index 6468fc83f..87fdba2b4 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -593,9 +593,11 @@ and forStructure ~name ~env strItems = strItems [] in let attributes = - match strItems with - | {str_desc = Tstr_attribute attribute} :: _ -> [attribute] - | _ -> [] + strItems + |> List.filter_map (fun (struc : Typedtree.structure_item) -> + match struc with + | {str_desc = Tstr_attribute attr} -> Some attr + | _ -> None) in let docstring = attrsToDocstring attributes in let deprecated = ProcessAttributes.findDeprecatedAttribute attributes in diff --git a/analysis/tests/src/expected/DocExtraction2.res.txt b/analysis/tests/src/expected/DocExtraction2.res.txt index 4f7f4dbbd..7645cfac0 100644 --- a/analysis/tests/src/expected/DocExtraction2.res.txt +++ b/analysis/tests/src/expected/DocExtraction2.res.txt @@ -21,7 +21,7 @@ preferring found resi file for impl: src/DocExtraction2.resi "docstrings": ["Makerz of stuffz."] }, { - "id": "InnerModule.DocExtraction2", + "id": "DocExtraction2.InnerModule", "name": "InnerModule", "kind": "module", "items": [ diff --git a/analysis/tests/src/expected/DocExtraction2.resi.txt b/analysis/tests/src/expected/DocExtraction2.resi.txt index 923680e52..51d938f0c 100644 --- a/analysis/tests/src/expected/DocExtraction2.resi.txt +++ b/analysis/tests/src/expected/DocExtraction2.resi.txt @@ -20,7 +20,7 @@ extracting docs for src/DocExtraction2.resi "docstrings": ["Makerz of stuffz."] }, { - "id": "InnerModule.DocExtraction2", + "id": "DocExtraction2.InnerModule", "name": "InnerModule", "kind": "module", "items": [ diff --git a/analysis/tests/src/expected/DocExtractionRes.res.txt b/analysis/tests/src/expected/DocExtractionRes.res.txt index 4a6edea83..b591bfd91 100644 --- a/analysis/tests/src/expected/DocExtractionRes.res.txt +++ b/analysis/tests/src/expected/DocExtractionRes.res.txt @@ -14,13 +14,13 @@ extracting docs for src/DocExtractionRes.res "detail": { "kind": "record", - "fieldDocs": [{ - "fieldName": "name", + "items": [{ + "name": "name", "optional": false, "docstrings": ["The name of the stuff."], "signature": "string" }, { - "fieldName": "online", + "name": "online", "optional": false, "docstrings": ["Whether stuff is online."], "signature": "bool" @@ -42,7 +42,7 @@ extracting docs for src/DocExtractionRes.res "docstrings": ["Stuff goes offline."] }, { - "id": "SomeInnerModule.DocExtractionRes", + "id": "DocExtractionRes.SomeInnerModule", "name": "SomeInnerModule", "kind": "module", "items": [ @@ -55,19 +55,19 @@ extracting docs for src/DocExtractionRes.res "detail": { "kind": "variant", - "constructorDocs": [ + "items": [ { - "constructorName": "Started", + "name": "Started", "docstrings": ["If this is started or not"], "signature": "Started(t)" }, { - "constructorName": "Stopped", + "name": "Stopped", "docstrings": ["Stopped?"], "signature": "Stopped" }, { - "constructorName": "Idle", + "name": "Idle", "docstrings": ["Now idle."], "signature": "Idle" }] @@ -89,16 +89,16 @@ extracting docs for src/DocExtractionRes.res }] }, { - "id": "AnotherModule.DocExtractionRes", + "id": "DocExtractionRes.AnotherModule", "name": "AnotherModule", "kind": "module", "items": [ { - "id": "DocExtractionRes.AnotherModule.SomeInnerModule", + "id": "DocExtractionRes.LinkedModule", "kind": "moduleAlias", "name": "LinkedModule", "docstrings": ["This links another module. Neat."], - "signature": "module LinkedModule = SomeInnerModule" + "items": [] }, { "id": "DocExtractionRes.AnotherModule.callback", @@ -123,9 +123,9 @@ extracting docs for src/DocExtractionRes.res "detail": { "kind": "variant", - "constructorDocs": [ + "items": [ { - "constructorName": "SomeStuff", + "name": "SomeStuff", "docstrings": ["This has inline records..."], "signature": "SomeStuff" }] @@ -140,7 +140,7 @@ extracting docs for src/DocExtractionRes.res }] }, { - "id": "ModuleWithThingsThatShouldNotBeExported.DocExtractionRes", + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported", "name": "ModuleWithThingsThatShouldNotBeExported", "kind": "module", "items": [ From af1a10aa771e3aa0458efc8b269eff8b4dc3b49e Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Mon, 9 Oct 2023 01:55:27 -0300 Subject: [PATCH 21/21] docgen: polish (#825) --- analysis/src/DocExtraction.ml | 4 +-- client/src/commands.ts | 1 - client/src/commands/extract_docs.ts | 50 ----------------------------- client/src/extension.ts | 3 -- package.json | 4 --- server/src/server.ts | 25 --------------- 6 files changed, 2 insertions(+), 85 deletions(-) delete mode 100644 client/src/commands/extract_docs.ts diff --git a/analysis/src/DocExtraction.ml b/analysis/src/DocExtraction.ml index 4ea095755..e1ca613bc 100644 --- a/analysis/src/DocExtraction.ml +++ b/analysis/src/DocExtraction.ml @@ -237,7 +237,7 @@ let extractDocs ~path ~debug = FindFiles.isImplementation path = false && FindFiles.isInterface path = false then ( - Printf.printf "error: failed to read %s, expected an .res or .resi file\n" + Printf.eprintf "error: failed to read %s, expected an .res or .resi file\n" path; exit 1); let path = @@ -256,7 +256,7 @@ let extractDocs ~path ~debug = in match Cmt.loadFullCmtFromPath ~path with | None -> - Printf.printf + Printf.eprintf "error: failed to generate doc for %s, try to build the project\n" path; exit 1 | Some full -> diff --git a/client/src/commands.ts b/client/src/commands.ts index 8acb2dc81..98bcec00d 100644 --- a/client/src/commands.ts +++ b/client/src/commands.ts @@ -6,7 +6,6 @@ import { } from "./commands/code_analysis"; export { createInterface } from "./commands/create_interface"; -export { extractDocs } from "./commands/extract_docs"; export { openCompiled } from "./commands/open_compiled"; export { switchImplIntf } from "./commands/switch_impl_intf"; diff --git a/client/src/commands/extract_docs.ts b/client/src/commands/extract_docs.ts deleted file mode 100644 index 3d9f295a4..000000000 --- a/client/src/commands/extract_docs.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as p from "vscode-languageserver-protocol"; -import { LanguageClient, RequestType } from "vscode-languageclient/node"; -import { Position, Uri, window, workspace, WorkspaceEdit } from "vscode"; -import path = require("path"); - -export const extractDocsRequest = new RequestType< - p.TextDocumentIdentifier, - string, - void ->("textDocument/extractDocs"); - -export const extractDocs = async (client: LanguageClient) => { - if (!client) { - return window.showInformationMessage("Language server not running"); - } - - const editor = window.activeTextEditor; - - if (!editor) { - return window.showInformationMessage("No active editor"); - } - - try { - const docUri = editor.document.uri.toString(); - const res = await client.sendRequest(extractDocsRequest, { - uri: docUri, - }); - - const newFile = Uri.parse( - "untitled:" + - path.join( - workspace.workspaceFolders[0].uri.fsPath, - `${path.basename(docUri)}.json` - ) - ); - workspace.openTextDocument(newFile).then((document) => { - const edit = new WorkspaceEdit(); - edit.insert(newFile, new Position(0, 0), JSON.stringify(res, null, 2)); - return workspace.applyEdit(edit).then((success) => { - if (success) { - window.showTextDocument(document); - } else { - window.showInformationMessage("Error!"); - } - }); - }); - } catch (e) { - console.error("failed", e); - } -}; diff --git a/client/src/extension.ts b/client/src/extension.ts index ac901e2f5..ada9f360c 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -203,9 +203,6 @@ export function activate(context: ExtensionContext) { customCommands.openCompiled(client); }); - commands.registerCommand("rescript-vscode.extract_docs", () => { - customCommands.extractDocs(client); - }); commands.registerCommand( "rescript-vscode.go_to_location", diff --git a/package.json b/package.json index ed13da7a2..d291fa5cc 100644 --- a/package.json +++ b/package.json @@ -49,10 +49,6 @@ "command": "rescript-vscode.create_interface", "title": "ReScript: Create an interface file for this implementation file" }, - { - "command": "rescript-vscode.extract_docs", - "title": "ReScript: Extract documentation as JSON for file." - }, { "command": "rescript-vscode.open_compiled", "category": "ReScript", diff --git a/server/src/server.ts b/server/src/server.ts index 25490208a..3bc5b3ec0 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -152,11 +152,6 @@ let openCompiledFileRequest = new v.RequestType< void >("textDocument/openCompiled"); -let extractDocsRequest = new v.RequestType< - p.TextDocumentIdentifier, - p.TextDocumentIdentifier, - void ->("textDocument/extractDocs"); let getCurrentCompilerDiagnosticsForFile = ( fileUri: string @@ -975,24 +970,6 @@ function createInterface(msg: p.RequestMessage): p.Message { } } -function extractDocs(msg: p.RequestMessage): p.Message { - let params = msg.params as p.TextDocumentIdentifier; - let filePath = fileURLToPath(params.uri); - - let response = utils.runAnalysisCommand( - filePath, - ["extractDocs", filePath], - msg - ); - - let res: p.ResponseMessage = { - jsonrpc: c.jsonrpcVersion, - id: msg.id, - result: response.result, - }; - return res; -} - function openCompiledFile(msg: p.RequestMessage): p.Message { let params = msg.params as p.TextDocumentIdentifier; let filePath = fileURLToPath(params.uri); @@ -1258,8 +1235,6 @@ function onMessage(msg: p.Message) { send(createInterface(msg)); } else if (msg.method === openCompiledFileRequest.method) { send(openCompiledFile(msg)); - } else if (msg.method === extractDocsRequest.method) { - send(extractDocs(msg)); } else if (msg.method === p.InlayHintRequest.method) { let params = msg.params as InlayHintParams; let extName = path.extname(params.textDocument.uri);