1
1
open Node
2
2
3
- module Docgen = RescriptTools .Docgen
4
-
5
- type example = {
6
- id : string ,
7
- kind : string ,
8
- name : string ,
9
- docstrings : array <string >,
10
- }
11
-
12
3
// Only major version
13
4
let nodeVersion =
14
5
Process .version
@@ -49,189 +40,21 @@ let getOutput = buffer =>
49
40
let extractDocFromFile = async file => {
50
41
let toolsBin = Path .join ([Process .cwd (), "cli" , "rescript-tools.js" ])
51
42
52
- let {stdout } = await SpawnAsync .run (~command = toolsBin , ~args = ["doc" , file ])
43
+ let {stdout } = await SpawnAsync .run (
44
+ ~command = toolsBin ,
45
+ ~args = ["extract-codeblocks" , file , "--transform-assert-equal" ],
46
+ )
53
47
54
48
try {
55
49
stdout
56
50
-> getOutput
57
51
-> JSON .parseOrThrow
58
- -> Docgen .decodeFromJson
52
+ -> RescriptTools . ExtractCodeBlocks .decodeFromJson
59
53
} catch {
60
- | JsExn (_ ) => JsError .panic (` Failed to generate docstrings from ${file}` )
61
- | _ => assert (false )
62
- }
63
- }
64
-
65
- let getExamples = ({items }: Docgen .doc ) => {
66
- let rec loop = (items : list <Docgen .item >, acc : list <example >) => {
67
- switch items {
68
- | list {Value ({docstrings , id , name }), ... rest } =>
69
- loop (rest , list {{id , name , docstrings , kind : "value" }, ... acc })
70
- | list {Type ({docstrings , id , name }), ... rest } =>
71
- loop (rest , list {{id , name , docstrings , kind : "type" }, ... acc })
72
- | list {Module ({id , name , docstrings , items }), ... rest } =>
73
- loop (
74
- list {... rest , ... List .fromArray (items )},
75
- list {{id , name , docstrings , kind : "module" }, ... acc },
76
- )
77
- | list {ModuleType ({id , name , docstrings , items }), ... rest } =>
78
- loop (
79
- list {... rest , ... List .fromArray (items )},
80
- list {{id , name , docstrings , kind : "moduleType" }, ... acc },
81
- )
82
- | list {ModuleAlias ({id , name , docstrings , items }), ... rest } =>
83
- loop (
84
- list {... rest , ... List .fromArray (items )},
85
- list {{id , name , docstrings , kind : "moduleAlias" }, ... acc },
86
- )
87
- | list {} => acc
88
- }
54
+ | JsExn (e ) =>
55
+ Console .error (e )
56
+ JsError .panic (` Failed to extract code blocks from ${file}` )
89
57
}
90
-
91
- items
92
- -> List .fromArray
93
- -> loop (list {})
94
- -> List .toArray
95
- -> Array .filter (({docstrings }) => Array .length (docstrings ) > 0 )
96
- }
97
-
98
- let getCodeBlocks = example => {
99
- let rec loopEndCodeBlock = (lines , acc ) => {
100
- switch lines {
101
- | list {hd , ... rest } =>
102
- if (
103
- hd
104
- -> String .trim
105
- -> String .endsWith ("```" )
106
- ) {
107
- acc
108
- } else {
109
- loopEndCodeBlock (rest , list {hd , ... acc })
110
- }
111
- | list {} => panic (` Failed to find end of code block for ${example.kind}: ${example.id}` )
112
- }
113
- }
114
-
115
- // Transform lines that contain == patterns to use assertEqual
116
- let transformEqualityAssertions = code => {
117
- let lines = code -> String .split ("\n " )
118
- lines
119
- -> Array .mapWithIndex ((line , idx ) => {
120
- let trimmedLine = line -> String .trim
121
-
122
- // Check if the line contains == and is not inside a comment
123
- if (
124
- trimmedLine -> String .includes ("==" ) &&
125
- ! (trimmedLine -> String .startsWith ("//" )) &&
126
- ! (trimmedLine -> String .startsWith ("/*" )) &&
127
- // Not an expression line
128
- ! (trimmedLine -> String .startsWith ("if" )) &&
129
- ! (trimmedLine -> String .startsWith ("|" )) &&
130
- ! (trimmedLine -> String .startsWith ("let" )) &&
131
- ! (trimmedLine -> String .startsWith ("~" )) &&
132
- ! (trimmedLine -> String .startsWith ("module" )) &&
133
- ! (trimmedLine -> String .startsWith ("->" )) &&
134
- ! (trimmedLine -> String .endsWith ("," ))
135
- ) {
136
- // Split string at == (not ===) and transform to assertEqual
137
- let parts = {
138
- let rec searchFrom = (currentLine : string , startIndex : int ): option <(string , string )> => {
139
- if startIndex >= currentLine -> String .length {
140
- // Base case: reached end of string without finding a suitable "=="
141
- None
142
- } else {
143
- let lineSuffix = currentLine -> String .sliceToEnd (~start = startIndex )
144
- let idxEqEqInSuffix = lineSuffix -> String .indexOfOpt ("==" )
145
- let idxEqEqEqInSuffix = lineSuffix -> String .indexOfOpt ("===" )
146
-
147
- switch (idxEqEqInSuffix , idxEqEqEqInSuffix ) {
148
- | (None , _ ) =>
149
- // No "==" found in the rest of the string.
150
- None
151
- | (Some (iEqEq ), None ) =>
152
- // Found "==" but no "===" in the suffix.
153
- // This "==" must be standalone.
154
- // Calculate its absolute index in the original `currentLine`.
155
- let actualIdx = startIndex + iEqEq
156
- let left = currentLine -> String .slice (~start = 0 , ~end = actualIdx )
157
- let right = currentLine -> String .sliceToEnd (~start = actualIdx + 2 )
158
- Some ((left , right ))
159
- | (Some (iEqEq ), Some (iEqEqEq )) =>
160
- // Found both "==" and "===" in the suffix.
161
- if iEqEq < iEqEqEq {
162
- // The "==" occurs before "===". This "==" is standalone.
163
- // Example: "a == b === c". In suffix "a == b === c", iEqEq is for "a ==".
164
- let actualIdx = startIndex + iEqEq
165
- let left = currentLine -> String .slice (~start = 0 , ~end = actualIdx )
166
- let right = currentLine -> String .sliceToEnd (~start = actualIdx + 2 )
167
- Some ((left , right ))
168
- } else {
169
- // iEqEq >= iEqEqEq
170
- // This means the first "==" encountered (at iEqEq relative to suffix)
171
- // is part of or comes after the first "===" encountered (at iEqEqEq relative to suffix).
172
- // Example: "a === b". In suffix "a === b", iEqEqEq is for "a ===", iEqEq is also for "a ==".
173
- // We must skip over the "===" found at iEqEqEq and search again.
174
- // The next search should start after this "===".
175
- // The "===" starts at (startIndex + iEqEqEq) in the original line. It has length 3.
176
- searchFrom (currentLine , startIndex + iEqEqEq + 3 )
177
- }
178
- }
179
- }
180
- }
181
- searchFrom (line , 0 )
182
- }
183
- let parts = switch parts {
184
- | Some ((left , right )) if right -> String .trim -> String .length === 0 =>
185
- Some ((
186
- left ,
187
- lines
188
- -> Array .get (idx + 1 )
189
- -> Option .getOrThrow (
190
- ~message = "Expected to have an expected expression on the next line" ,
191
- ),
192
- ))
193
- | _ => parts
194
- }
195
- switch parts {
196
- | Some ((left , right )) if ! (right -> String .includes (")" ) || right -> String .includes ("//" )) =>
197
- ` (${left-> String.trim})->assertEqual(${right-> String.trim})`
198
- | _ => line
199
- }
200
- } else {
201
- line
202
- }
203
- })
204
- -> Array .join ("\n " )
205
- }
206
-
207
- let rec loop = (lines : list <string >, acc : list <string >) => {
208
- switch lines {
209
- | list {hd , ... rest } =>
210
- switch hd
211
- -> String .trim
212
- -> String .startsWith ("```res" ) {
213
- | true =>
214
- let code = loopEndCodeBlock (rest , list {})
215
- let codeString =
216
- code
217
- -> List .reverse
218
- -> List .toArray
219
- -> Array .join ("\n " )
220
- -> transformEqualityAssertions
221
- loop (rest , list {codeString , ... acc })
222
- | false => loop (rest , acc )
223
- }
224
- | list {} => acc
225
- }
226
- }
227
-
228
- example .docstrings
229
- -> Array .reduce ([], (acc , docstring ) => acc -> Array .concat (docstring -> String .split ("\n " )))
230
- -> List .fromArray
231
- -> loop (list {})
232
- -> List .toArray
233
- -> Belt .Array .reverse
234
- -> Array .join ("\n\n " )
235
58
}
236
59
237
60
let batchSize = OS .cpus ()-> Array .length
@@ -258,7 +81,10 @@ let extractExamples = async () => {
258
81
let examples = []
259
82
await docFiles -> ArrayUtils .forEachAsyncInBatches (~batchSize , async f => {
260
83
let doc = await extractDocFromFile (Path .join (["runtime" , f ]))
261
- examples -> Array .pushMany (doc -> getExamples )
84
+ switch doc {
85
+ | Ok (doc ) => examples -> Array .pushMany (doc )
86
+ | Error (e ) => Console .error (e )
87
+ }
262
88
})
263
89
264
90
examples -> Array .sort ((a , b ) => String .compare (a .id , b .id ))
@@ -303,7 +129,7 @@ let main = async () => {
303
129
)
304
130
None
305
131
} else {
306
- let code = getCodeBlocks ( example )
132
+ let code = example . code
307
133
308
134
if code -> String .length === 0 {
309
135
None
0 commit comments