Skip to content

Commit

Permalink
Support inline record fields in doc extraction (#889)
Browse files Browse the repository at this point in the history
* support inline record fields in doc extraction

* changelog

* fix missing docstrings in module

* rename constructor payload field and prepare for potentially adding more detail for other constructor payload types as well

* rename
  • Loading branch information
zth authored Jan 11, 2024
1 parent d39e28c commit ddf14cf
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 212 deletions.
13 changes: 12 additions & 1 deletion analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@ open SharedTypes
let showConstructor {Constructor.cname = {txt}; args; res} =
txt
^ (match args with
| Args [] | InlineRecord _ -> ""
| Args [] -> ""
| InlineRecord fields ->
"({"
^ (fields
|> List.map (fun (field : field) ->
Printf.sprintf "%s%s: %s" field.fname.txt
(if field.optional then "?" else "")
(Shared.typeToString
(if field.optional then Utils.unwrapIfOption field.typ
else field.typ)))
|> String.concat ", ")
^ "})"
| Args args ->
"("
^ (args
Expand Down
94 changes: 63 additions & 31 deletions analysis/src/DocExtraction.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ type fieldDoc = {
deprecated: string option;
}

type constructorPayload = InlineRecord of {fieldDocs: fieldDoc list}

type constructorDoc = {
constructorName: string;
docstrings: string list;
signature: string;
deprecated: string option;
items: constructorPayload option;
}

type docItemDetail =
Expand Down Expand Up @@ -54,6 +57,35 @@ let stringifyDocstrings docstrings =
|> List.map (fun docstring -> docstring |> String.trim |> wrapInQuotes)
|> array

let stringifyFieldDoc ~indentation (fieldDoc : fieldDoc) =
let open Protocol in
stringifyObject ~indentation:(indentation + 1)
[
("name", Some (wrapInQuotes fieldDoc.fieldName));
( "deprecated",
match fieldDoc.deprecated with
| Some d -> Some (wrapInQuotes d)
| None -> None );
("optional", Some (string_of_bool fieldDoc.optional));
("docstrings", Some (stringifyDocstrings fieldDoc.docstrings));
("signature", Some (wrapInQuotes fieldDoc.signature));
]

let stringifyConstructorPayload ~indentation
(constructorPayload : constructorPayload) =
let open Protocol in
match constructorPayload with
| InlineRecord {fieldDocs} ->
stringifyObject ~indentation:(indentation + 1)
[
("kind", Some (wrapInQuotes "inlineRecord"));
( "fields",
Some
(fieldDocs
|> List.map (stringifyFieldDoc ~indentation:(indentation + 1))
|> array) );
]

let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
let open Protocol in
match detail with
Expand All @@ -62,22 +94,8 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
[
("kind", Some (wrapInQuotes "record"));
( "items",
Some
(fieldDocs
|> List.map (fun fieldDoc ->
stringifyObject ~indentation:(indentation + 1)
[
("name", Some (wrapInQuotes fieldDoc.fieldName));
( "deprecated",
match fieldDoc.deprecated with
| Some d -> Some (wrapInQuotes d)
| None -> None );
("optional", Some (string_of_bool fieldDoc.optional));
( "docstrings",
Some (stringifyDocstrings fieldDoc.docstrings) );
("signature", Some (wrapInQuotes fieldDoc.signature));
])
|> array) );
Some (fieldDocs |> List.map (stringifyFieldDoc ~indentation) |> array)
);
]
| Variant {constructorDocs} ->
stringifyObject ~startOnNewline:true ~indentation
Expand All @@ -100,6 +118,14 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
Some (stringifyDocstrings constructorDoc.docstrings) );
( "signature",
Some (wrapInQuotes constructorDoc.signature) );
( "payload",
match constructorDoc.items with
| None -> None
| Some constructorPayload ->
Some
(stringifyConstructorPayload
~indentation:(indentation + 1)
constructorPayload) );
])
|> array) );
]
Expand Down Expand Up @@ -145,6 +171,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) =
("id", Some (wrapInQuotes m.id));
("name", Some (wrapInQuotes m.name));
("kind", Some (wrapInQuotes "module"));
("docstrings", Some (stringifyDocstrings m.docstring));
( "items",
Some
(m.items
Expand Down Expand Up @@ -185,24 +212,20 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) =
|> array) );
]

let fieldToFieldDoc (field : SharedTypes.field) : fieldDoc =
{
fieldName = field.fname.txt;
docstrings = field.docstring;
optional = field.optional;
signature = Shared.typeToString field.typ;
deprecated = field.deprecated;
}

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;
optional = field.optional;
signature = Shared.typeToString field.typ;
deprecated = field.deprecated;
});
})
Some (Record {fieldDocs = fields |> List.map fieldToFieldDoc})
| Some (Tvariant {constructors}) ->
Some
(Variant
Expand All @@ -215,6 +238,13 @@ let typeDetail typ ~env ~full =
docstrings = c.docstring;
signature = CompletionBackEnd.showConstructor c;
deprecated = c.deprecated;
items =
(match c.args with
| InlineRecord fields ->
Some
(InlineRecord
{fieldDocs = fields |> List.map fieldToFieldDoc})
| _ -> None);
});
})
| _ -> None
Expand Down Expand Up @@ -312,7 +342,9 @@ let extractDocs ~path ~debug =
id;
name = item.name;
items;
docstring = item.docstring @ internalDocstrings |> List.map String.trim;
docstring =
item.docstring @ internalDocstrings
|> List.map String.trim;
})
| Module (Structure m) ->
(* module Whatever = {} in res or module Whatever: {} in resi. *)
Expand Down
7 changes: 6 additions & 1 deletion analysis/tests/src/DocExtractionRes.res
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ module AnotherModule = {
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})
type someVariantWithInlineRecords =
| /** This has inline records...*/
SomeStuff({
offline: bool,
/** Is the user online? */ online?: bool,
})
open ReactDOM
Expand Down
1 change: 1 addition & 0 deletions analysis/tests/src/expected/DocExtraction2.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ preferring found resi file for impl: src/DocExtraction2.resi
"id": "DocExtraction2.InnerModule",
"name": "InnerModule",
"kind": "module",
"docstrings": [],
"items": [
{
"id": "DocExtraction2.InnerModule.t",
Expand Down
1 change: 1 addition & 0 deletions analysis/tests/src/expected/DocExtraction2.resi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extracting docs for src/DocExtraction2.resi
"id": "DocExtraction2.InnerModule",
"name": "InnerModule",
"kind": "module",
"docstrings": [],
"items": [
{
"id": "DocExtraction2.InnerModule.t",
Expand Down
21 changes: 19 additions & 2 deletions analysis/tests/src/expected/DocExtractionRes.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extracting docs for src/DocExtractionRes.res
"id": "DocExtractionRes.SomeInnerModule",
"name": "SomeInnerModule",
"kind": "module",
"docstrings": ["Another module level docstring here."],
"items": [
{
"id": "DocExtractionRes.SomeInnerModule.status",
Expand Down Expand Up @@ -99,6 +100,7 @@ extracting docs for src/DocExtractionRes.res
"id": "DocExtractionRes.AnotherModule",
"name": "AnotherModule",
"kind": "module",
"docstrings": ["Mighty fine module here too!"],
"items": [
{
"id": "DocExtractionRes.LinkedModule",
Expand All @@ -125,7 +127,7 @@ extracting docs for src/DocExtractionRes.res
"id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords",
"kind": "type",
"name": "someVariantWithInlineRecords",
"signature": "type someVariantWithInlineRecords =\n | SomeStuff({offline: bool})",
"signature": "type someVariantWithInlineRecords =\n | SomeStuff({offline: bool, online?: bool})",
"docstrings": ["Trying how it looks with an inline record in a variant."],
"detail":
{
Expand All @@ -134,7 +136,21 @@ extracting docs for src/DocExtractionRes.res
{
"name": "SomeStuff",
"docstrings": ["This has inline records..."],
"signature": "SomeStuff"
"signature": "SomeStuff({offline: bool, online?: bool})",
"payload": {
"kind": "inlineRecord",
"fields": [{
"name": "offline",
"optional": false,
"docstrings": [],
"signature": "bool"
}, {
"name": "online",
"optional": true,
"docstrings": ["Is the user online?"],
"signature": "option<bool>"
}]
}
}]
}
},
Expand All @@ -150,6 +166,7 @@ extracting docs for src/DocExtractionRes.res
"id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported",
"name": "ModuleWithThingsThatShouldNotBeExported",
"kind": "module",
"docstrings": [],
"items": [
{
"id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t",
Expand Down
1 change: 1 addition & 0 deletions tools/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#### :bug: Bug Fix

- Support inline record fields in constructors. https://github.com/rescript-lang/rescript-vscode/pull/889
- Fix docstrings for module alias. Get internal docstrings of module file. https://github.com/rescript-lang/rescript-vscode/pull/878
- Fix extracted docs of types include escaped linebreaks in signature. https://github.com/rescript-lang/rescript-vscode/pull/891

Expand Down
Loading

0 comments on commit ddf14cf

Please sign in to comment.