Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inline record fields in doc extraction #889

Merged
merged 5 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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