Skip to content

Commit ddf14cf

Browse files
authored
Support inline record fields in doc extraction (#889)
* 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
1 parent d39e28c commit ddf14cf

9 files changed

+113
-212
lines changed

analysis/src/CompletionBackEnd.ml

+12-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@ open SharedTypes
33
let showConstructor {Constructor.cname = {txt}; args; res} =
44
txt
55
^ (match args with
6-
| Args [] | InlineRecord _ -> ""
6+
| Args [] -> ""
7+
| InlineRecord fields ->
8+
"({"
9+
^ (fields
10+
|> List.map (fun (field : field) ->
11+
Printf.sprintf "%s%s: %s" field.fname.txt
12+
(if field.optional then "?" else "")
13+
(Shared.typeToString
14+
(if field.optional then Utils.unwrapIfOption field.typ
15+
else field.typ)))
16+
|> String.concat ", ")
17+
^ "})"
718
| Args args ->
819
"("
920
^ (args

analysis/src/DocExtraction.ml

+63-31
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ type fieldDoc = {
66
deprecated: string option;
77
}
88

9+
type constructorPayload = InlineRecord of {fieldDocs: fieldDoc list}
10+
911
type constructorDoc = {
1012
constructorName: string;
1113
docstrings: string list;
1214
signature: string;
1315
deprecated: string option;
16+
items: constructorPayload option;
1417
}
1518

1619
type docItemDetail =
@@ -54,6 +57,35 @@ let stringifyDocstrings docstrings =
5457
|> List.map (fun docstring -> docstring |> String.trim |> wrapInQuotes)
5558
|> array
5659

60+
let stringifyFieldDoc ~indentation (fieldDoc : fieldDoc) =
61+
let open Protocol in
62+
stringifyObject ~indentation:(indentation + 1)
63+
[
64+
("name", Some (wrapInQuotes fieldDoc.fieldName));
65+
( "deprecated",
66+
match fieldDoc.deprecated with
67+
| Some d -> Some (wrapInQuotes d)
68+
| None -> None );
69+
("optional", Some (string_of_bool fieldDoc.optional));
70+
("docstrings", Some (stringifyDocstrings fieldDoc.docstrings));
71+
("signature", Some (wrapInQuotes fieldDoc.signature));
72+
]
73+
74+
let stringifyConstructorPayload ~indentation
75+
(constructorPayload : constructorPayload) =
76+
let open Protocol in
77+
match constructorPayload with
78+
| InlineRecord {fieldDocs} ->
79+
stringifyObject ~indentation:(indentation + 1)
80+
[
81+
("kind", Some (wrapInQuotes "inlineRecord"));
82+
( "fields",
83+
Some
84+
(fieldDocs
85+
|> List.map (stringifyFieldDoc ~indentation:(indentation + 1))
86+
|> array) );
87+
]
88+
5789
let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
5890
let open Protocol in
5991
match detail with
@@ -62,22 +94,8 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
6294
[
6395
("kind", Some (wrapInQuotes "record"));
6496
( "items",
65-
Some
66-
(fieldDocs
67-
|> List.map (fun fieldDoc ->
68-
stringifyObject ~indentation:(indentation + 1)
69-
[
70-
("name", Some (wrapInQuotes fieldDoc.fieldName));
71-
( "deprecated",
72-
match fieldDoc.deprecated with
73-
| Some d -> Some (wrapInQuotes d)
74-
| None -> None );
75-
("optional", Some (string_of_bool fieldDoc.optional));
76-
( "docstrings",
77-
Some (stringifyDocstrings fieldDoc.docstrings) );
78-
("signature", Some (wrapInQuotes fieldDoc.signature));
79-
])
80-
|> array) );
97+
Some (fieldDocs |> List.map (stringifyFieldDoc ~indentation) |> array)
98+
);
8199
]
82100
| Variant {constructorDocs} ->
83101
stringifyObject ~startOnNewline:true ~indentation
@@ -100,6 +118,14 @@ let stringifyDetail ?(indentation = 0) (detail : docItemDetail) =
100118
Some (stringifyDocstrings constructorDoc.docstrings) );
101119
( "signature",
102120
Some (wrapInQuotes constructorDoc.signature) );
121+
( "payload",
122+
match constructorDoc.items with
123+
| None -> None
124+
| Some constructorPayload ->
125+
Some
126+
(stringifyConstructorPayload
127+
~indentation:(indentation + 1)
128+
constructorPayload) );
103129
])
104130
|> array) );
105131
]
@@ -145,6 +171,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) =
145171
("id", Some (wrapInQuotes m.id));
146172
("name", Some (wrapInQuotes m.name));
147173
("kind", Some (wrapInQuotes "module"));
174+
("docstrings", Some (stringifyDocstrings m.docstring));
148175
( "items",
149176
Some
150177
(m.items
@@ -185,24 +212,20 @@ and stringifyDocsForModule ?(indentation = 0) ~originalEnv (d : docsForModule) =
185212
|> array) );
186213
]
187214

215+
let fieldToFieldDoc (field : SharedTypes.field) : fieldDoc =
216+
{
217+
fieldName = field.fname.txt;
218+
docstrings = field.docstring;
219+
optional = field.optional;
220+
signature = Shared.typeToString field.typ;
221+
deprecated = field.deprecated;
222+
}
223+
188224
let typeDetail typ ~env ~full =
189225
let open SharedTypes in
190226
match TypeUtils.extractTypeFromResolvedType ~env ~full typ with
191227
| Some (Trecord {fields}) ->
192-
Some
193-
(Record
194-
{
195-
fieldDocs =
196-
fields
197-
|> List.map (fun (field : field) ->
198-
{
199-
fieldName = field.fname.txt;
200-
docstrings = field.docstring;
201-
optional = field.optional;
202-
signature = Shared.typeToString field.typ;
203-
deprecated = field.deprecated;
204-
});
205-
})
228+
Some (Record {fieldDocs = fields |> List.map fieldToFieldDoc})
206229
| Some (Tvariant {constructors}) ->
207230
Some
208231
(Variant
@@ -215,6 +238,13 @@ let typeDetail typ ~env ~full =
215238
docstrings = c.docstring;
216239
signature = CompletionBackEnd.showConstructor c;
217240
deprecated = c.deprecated;
241+
items =
242+
(match c.args with
243+
| InlineRecord fields ->
244+
Some
245+
(InlineRecord
246+
{fieldDocs = fields |> List.map fieldToFieldDoc})
247+
| _ -> None);
218248
});
219249
})
220250
| _ -> None
@@ -312,7 +342,9 @@ let extractDocs ~path ~debug =
312342
id;
313343
name = item.name;
314344
items;
315-
docstring = item.docstring @ internalDocstrings |> List.map String.trim;
345+
docstring =
346+
item.docstring @ internalDocstrings
347+
|> List.map String.trim;
316348
})
317349
| Module (Structure m) ->
318350
(* module Whatever = {} in res or module Whatever: {} in resi. *)

analysis/tests/src/DocExtractionRes.res

+6-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ module AnotherModule = {
4949
let isGoodStatus = (status: SomeInnerModule.status) => status == Stopped
5050
5151
/** Trying how it looks with an inline record in a variant. */
52-
type someVariantWithInlineRecords = | /** This has inline records...*/ SomeStuff({offline: bool})
52+
type someVariantWithInlineRecords =
53+
| /** This has inline records...*/
54+
SomeStuff({
55+
offline: bool,
56+
/** Is the user online? */ online?: bool,
57+
})
5358
5459
open ReactDOM
5560

analysis/tests/src/expected/DocExtraction2.res.txt

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ preferring found resi file for impl: src/DocExtraction2.resi
2424
"id": "DocExtraction2.InnerModule",
2525
"name": "InnerModule",
2626
"kind": "module",
27+
"docstrings": [],
2728
"items": [
2829
{
2930
"id": "DocExtraction2.InnerModule.t",

analysis/tests/src/expected/DocExtraction2.resi.txt

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extracting docs for src/DocExtraction2.resi
2323
"id": "DocExtraction2.InnerModule",
2424
"name": "InnerModule",
2525
"kind": "module",
26+
"docstrings": [],
2627
"items": [
2728
{
2829
"id": "DocExtraction2.InnerModule.t",

analysis/tests/src/expected/DocExtractionRes.res.txt

+19-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ extracting docs for src/DocExtractionRes.res
5252
"id": "DocExtractionRes.SomeInnerModule",
5353
"name": "SomeInnerModule",
5454
"kind": "module",
55+
"docstrings": ["Another module level docstring here."],
5556
"items": [
5657
{
5758
"id": "DocExtractionRes.SomeInnerModule.status",
@@ -99,6 +100,7 @@ extracting docs for src/DocExtractionRes.res
99100
"id": "DocExtractionRes.AnotherModule",
100101
"name": "AnotherModule",
101102
"kind": "module",
103+
"docstrings": ["Mighty fine module here too!"],
102104
"items": [
103105
{
104106
"id": "DocExtractionRes.LinkedModule",
@@ -125,7 +127,7 @@ extracting docs for src/DocExtractionRes.res
125127
"id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords",
126128
"kind": "type",
127129
"name": "someVariantWithInlineRecords",
128-
"signature": "type someVariantWithInlineRecords =\n | SomeStuff({offline: bool})",
130+
"signature": "type someVariantWithInlineRecords =\n | SomeStuff({offline: bool, online?: bool})",
129131
"docstrings": ["Trying how it looks with an inline record in a variant."],
130132
"detail":
131133
{
@@ -134,7 +136,21 @@ extracting docs for src/DocExtractionRes.res
134136
{
135137
"name": "SomeStuff",
136138
"docstrings": ["This has inline records..."],
137-
"signature": "SomeStuff"
139+
"signature": "SomeStuff({offline: bool, online?: bool})",
140+
"payload": {
141+
"kind": "inlineRecord",
142+
"fields": [{
143+
"name": "offline",
144+
"optional": false,
145+
"docstrings": [],
146+
"signature": "bool"
147+
}, {
148+
"name": "online",
149+
"optional": true,
150+
"docstrings": ["Is the user online?"],
151+
"signature": "option<bool>"
152+
}]
153+
}
138154
}]
139155
}
140156
},
@@ -150,6 +166,7 @@ extracting docs for src/DocExtractionRes.res
150166
"id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported",
151167
"name": "ModuleWithThingsThatShouldNotBeExported",
152168
"kind": "module",
169+
"docstrings": [],
153170
"items": [
154171
{
155172
"id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t",

tools/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#### :bug: Bug Fix
1616

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

0 commit comments

Comments
 (0)