@f3liz/rescript-autogen-openapi 0.5.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/es6/src/bindings/Handlebars.mjs +43 -0
- package/lib/es6/src/core/CodegenUtils.mjs +17 -39
- package/lib/es6/src/core/DocOverride.mjs +14 -123
- package/lib/es6/src/core/Templates.mjs +339 -0
- package/lib/es6/src/generators/ComponentSchemaGenerator.mjs +10 -4
- package/lib/es6/src/generators/DiffReportGenerator.mjs +12 -28
- package/lib/es6/src/generators/EndpointGenerator.mjs +27 -33
- package/lib/es6/src/generators/ModuleGenerator.mjs +29 -37
- package/lib/es6/src/generators/SchemaCodeGenerator.mjs +10 -7
- package/lib/es6/src/generators/ThinWrapperGenerator.mjs +21 -24
- package/lib/es6/src/generators/TypeScriptDtsGenerator.mjs +52 -58
- package/lib/es6/src/generators/TypeScriptWrapperGenerator.mjs +76 -80
- package/package.json +2 -1
- package/src/bindings/Handlebars.res +43 -0
- package/src/core/CodegenUtils.res +9 -33
- package/src/core/DocOverride.res +10 -124
- package/src/core/Templates.res +328 -0
- package/src/generators/ComponentSchemaGenerator.res +8 -4
- package/src/generators/DiffReportGenerator.res +11 -29
- package/src/generators/EndpointGenerator.res +34 -30
- package/src/generators/ModuleGenerator.res +41 -39
- package/src/generators/SchemaCodeGenerator.res +8 -6
- package/src/generators/ThinWrapperGenerator.res +24 -24
- package/src/generators/TypeScriptDtsGenerator.res +41 -61
- package/src/generators/TypeScriptWrapperGenerator.res +58 -83
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
|
|
3
|
+
// Templates.res - All Handlebars templates in one place
|
|
4
|
+
|
|
5
|
+
// === CodegenUtils ===
|
|
6
|
+
|
|
7
|
+
let fileHeader = `// {{{description}}}
|
|
8
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
9
|
+
// DO NOT EDIT - This file is auto-generated
|
|
10
|
+
|
|
11
|
+
S.enableJson()
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
let docCommentSingle = `/** {{{content}}} */
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
let docCommentMulti = `/**
|
|
18
|
+
{{#each lines}}{{{this}}}
|
|
19
|
+
{{/each}}*/
|
|
20
|
+
`
|
|
21
|
+
|
|
22
|
+
let docComment = `{{#if summary}}// {{{summary}}}
|
|
23
|
+
{{/if}}{{#if description}}// {{{description}}}
|
|
24
|
+
{{/if}}`
|
|
25
|
+
|
|
26
|
+
// === EndpointGenerator ===
|
|
27
|
+
|
|
28
|
+
let endpointFunction = `{{{docComment}}}let {{{functionName}}} = async ({{{bodyParam}}}{{{paramSep}}}~fetch: {{{fetchTypeSignature}}}): {{{functionName}}}Response => {
|
|
29
|
+
{{{bodyValueConversion}}}
|
|
30
|
+
let response = await fetch(
|
|
31
|
+
~url="{{{path}}}",
|
|
32
|
+
~method_="{{{methodUpper}}}",
|
|
33
|
+
~body={{{bodyArg}}},
|
|
34
|
+
)
|
|
35
|
+
{{{responseHandling}}}
|
|
36
|
+
}`
|
|
37
|
+
|
|
38
|
+
let moduleWrapped = `{{{header}}}
|
|
39
|
+
|
|
40
|
+
module {{{moduleName}}} = {
|
|
41
|
+
{{{body}}}
|
|
42
|
+
}`
|
|
43
|
+
|
|
44
|
+
let moduleUnwrapped = `{{{header}}}
|
|
45
|
+
|
|
46
|
+
{{{body}}}`
|
|
47
|
+
|
|
48
|
+
// === ModuleGenerator ===
|
|
49
|
+
|
|
50
|
+
let indexModule = `{{{header}}}
|
|
51
|
+
|
|
52
|
+
module {{{moduleName}}} = {
|
|
53
|
+
{{#each tags}} module {{{modulePascal}}} = {{{modulePascal}}}
|
|
54
|
+
{{/each}}}`
|
|
55
|
+
|
|
56
|
+
let combinedModule = `{{{header}}}
|
|
57
|
+
|
|
58
|
+
{{{shared}}}
|
|
59
|
+
|
|
60
|
+
{{{extension}}}`
|
|
61
|
+
|
|
62
|
+
// === ThinWrapperGenerator ===
|
|
63
|
+
|
|
64
|
+
let clientType = `type client = {
|
|
65
|
+
baseUrl: string,
|
|
66
|
+
token: option<string>,
|
|
67
|
+
fetch: {{{fetchTypeSignature}}},
|
|
68
|
+
}`
|
|
69
|
+
|
|
70
|
+
let connectFunction = `/** Create a client for {{{title}}} */
|
|
71
|
+
let connect = (~baseUrl: string, ~token: option<string>=?, ~fetch: {{{fetchTypeSignature}}}, ()): client => {
|
|
72
|
+
baseUrl,
|
|
73
|
+
token,
|
|
74
|
+
fetch,
|
|
75
|
+
}`
|
|
76
|
+
|
|
77
|
+
let wrapperFunction = `{{{docComment}}} {{{signature}}}: promise<{{{generatedModuleName}}}.{{{operationName}}}Response> =>
|
|
78
|
+
{{{generatedModuleName}}}.{{{operationName}}}({{{callArguments}}}~fetch=client.fetch)`
|
|
79
|
+
|
|
80
|
+
let wrapperFile = `// Generated thin wrapper
|
|
81
|
+
|
|
82
|
+
{{{clientTypeCode}}}
|
|
83
|
+
|
|
84
|
+
{{{connectFunctionCode}}}
|
|
85
|
+
|
|
86
|
+
{{{modulesCode}}}`
|
|
87
|
+
|
|
88
|
+
// === TypeScriptDtsGenerator ===
|
|
89
|
+
|
|
90
|
+
let methodSignature = `{{{docLines}}}
|
|
91
|
+
{{{functionName}}}({{{params}}}): Promise<{{{responsePascalName}}}Response>;`
|
|
92
|
+
|
|
93
|
+
let moduleDts = `// TypeScript definitions for {{{moduleName}}}
|
|
94
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
95
|
+
// DO NOT EDIT
|
|
96
|
+
|
|
97
|
+
import { MisskeyClient } from './index';
|
|
98
|
+
import * as ComponentSchemas from './ComponentSchemas';
|
|
99
|
+
|
|
100
|
+
{{{interfaces}}}
|
|
101
|
+
|
|
102
|
+
export interface {{{moduleName}}}Module {
|
|
103
|
+
{{{methodSignatures}}}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const {{{moduleName}}}: {{{moduleName}}}Module;`
|
|
107
|
+
|
|
108
|
+
let componentSchemasDts = `// TypeScript definitions for ComponentSchemas
|
|
109
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
110
|
+
// DO NOT EDIT
|
|
111
|
+
|
|
112
|
+
{{{content}}}`
|
|
113
|
+
|
|
114
|
+
let indexDts = `// TypeScript definitions
|
|
115
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
116
|
+
// DO NOT EDIT
|
|
117
|
+
|
|
118
|
+
{{#each modules}}{{{importLine}}}
|
|
119
|
+
{{/each}}
|
|
120
|
+
export class MisskeyClient {
|
|
121
|
+
constructor(baseUrl: string, token?: string);
|
|
122
|
+
readonly baseUrl: string;
|
|
123
|
+
readonly token?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
{{#each modules}}{{{exportLine}}}
|
|
127
|
+
{{/each}}`
|
|
128
|
+
|
|
129
|
+
// === TypeScriptWrapperGenerator ===
|
|
130
|
+
|
|
131
|
+
let wrapperMjsMethod = ` async {{{functionName}}}(client{{{requestArg}}}) {
|
|
132
|
+
return {{{moduleName}}}.{{{functionName}}}({
|
|
133
|
+
{{{bodyArg}}}fetch: (url, method, body) => client._fetch(url, method, body)
|
|
134
|
+
});
|
|
135
|
+
},`
|
|
136
|
+
|
|
137
|
+
let wrapperMjsNamespace = `export const {{{moduleName}}} = {
|
|
138
|
+
{{{methods}}}
|
|
139
|
+
};`
|
|
140
|
+
|
|
141
|
+
let wrapperMjs = `// Generated wrapper
|
|
142
|
+
{{#each tags}}{{{importLine}}}
|
|
143
|
+
{{/each}}
|
|
144
|
+
{{{clientCode}}}
|
|
145
|
+
|
|
146
|
+
{{#each tags}}{{{namespace}}}
|
|
147
|
+
|
|
148
|
+
{{/each}}`
|
|
149
|
+
|
|
150
|
+
let wrapperDtsFunction = `{{{docComment}}} export function {{{functionName}}}(client: MisskeyClient{{{requestParam}}}): Promise<{{{pascalName}}}Response>;`
|
|
151
|
+
|
|
152
|
+
let wrapperDtsNamespace = `export namespace {{{moduleName}}} {
|
|
153
|
+
{{{functions}}}
|
|
154
|
+
}`
|
|
155
|
+
|
|
156
|
+
let wrapperDts = `// Generated TypeScript definitions for wrapper
|
|
157
|
+
{{#each tags}}{{{importBlock}}}
|
|
158
|
+
{{/each}}
|
|
159
|
+
export class MisskeyClient {
|
|
160
|
+
constructor(baseUrl: string, token?: string);
|
|
161
|
+
readonly baseUrl: string;
|
|
162
|
+
readonly token?: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
{{#each tags}}{{{namespace}}}
|
|
166
|
+
|
|
167
|
+
{{/each}}`
|
|
168
|
+
|
|
169
|
+
// === DiffReportGenerator ===
|
|
170
|
+
|
|
171
|
+
let mergeReport = `# Merge Report: {{{baseName}}} + {{{forkName}}}
|
|
172
|
+
|
|
173
|
+
## Shared Code
|
|
174
|
+
|
|
175
|
+
- **Shared Endpoints**: {{{sharedEndpoints}}}
|
|
176
|
+
- **Shared Schemas**: {{{sharedSchemas}}}
|
|
177
|
+
|
|
178
|
+
## {{{forkName}}} Extensions
|
|
179
|
+
|
|
180
|
+
- **Extension Endpoints**: {{{extensionEndpoints}}}
|
|
181
|
+
- **Extension Schemas**: {{{extensionSchemas}}}
|
|
182
|
+
|
|
183
|
+
## Summary
|
|
184
|
+
|
|
185
|
+
The shared base contains {{{sharedEndpoints}}} endpoints and {{{sharedSchemas}}} schemas.
|
|
186
|
+
|
|
187
|
+
{{{forkName}}} adds {{{extensionEndpoints}}} endpoints and {{{extensionSchemas}}} schemas.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
*Generated on {{{timestamp}}}*`
|
|
191
|
+
|
|
192
|
+
// === SchemaCodeGenerator ===
|
|
193
|
+
|
|
194
|
+
let endpointModule = `{{{docComment}}}module {{{moduleName}}} = {
|
|
195
|
+
{{{schemasCode}}}
|
|
196
|
+
|
|
197
|
+
let endpoint = "{{{path}}}"
|
|
198
|
+
let method = #{{{methodStr}}}
|
|
199
|
+
}`
|
|
200
|
+
|
|
201
|
+
// === DocOverride ===
|
|
202
|
+
|
|
203
|
+
let overrideMarkdown = `{{{metadataBlock}}}
|
|
204
|
+
|
|
205
|
+
# {{{title}}}
|
|
206
|
+
|
|
207
|
+
**Path**: \`{{{path}}}\`
|
|
208
|
+
**Method**: \`{{{methodUpper}}}\`
|
|
209
|
+
**Operation**: \`{{{operationName}}}\`
|
|
210
|
+
|
|
211
|
+
## Default Description
|
|
212
|
+
|
|
213
|
+
{{{defaultDesc}}}
|
|
214
|
+
|
|
215
|
+
## Override
|
|
216
|
+
|
|
217
|
+
Add your custom documentation here. If this code block is empty, the default description will be used.
|
|
218
|
+
|
|
219
|
+
\`\`\`
|
|
220
|
+
<!-- Empty - no override -->
|
|
221
|
+
\`\`\``
|
|
222
|
+
|
|
223
|
+
let overrideReadme = `# API Documentation Overrides
|
|
224
|
+
|
|
225
|
+
This directory contains markdown files that allow you to override the auto-generated documentation.
|
|
226
|
+
|
|
227
|
+
## Global Information
|
|
228
|
+
|
|
229
|
+
- **Host**: {{{hostInfo}}}
|
|
230
|
+
- **Version**: {{{versionInfo}}}
|
|
231
|
+
|
|
232
|
+
## Structure
|
|
233
|
+
|
|
234
|
+
Each module has its own directory, and each endpoint has its own markdown file:
|
|
235
|
+
|
|
236
|
+
\`\`\`
|
|
237
|
+
docs/
|
|
238
|
+
├── README.md (this file)
|
|
239
|
+
├── Account/
|
|
240
|
+
│ ├── postBlockingCreate.md
|
|
241
|
+
│ ├── postBlockingDelete.md
|
|
242
|
+
│ └── ...
|
|
243
|
+
├── Notes/
|
|
244
|
+
│ ├── postNotesCreate.md
|
|
245
|
+
│ └── ...
|
|
246
|
+
└── ...
|
|
247
|
+
\`\`\`
|
|
248
|
+
|
|
249
|
+
## How to Override
|
|
250
|
+
|
|
251
|
+
1. Find the endpoint you want to document in its module directory
|
|
252
|
+
2. Open the markdown file
|
|
253
|
+
3. Edit the code block under the "## Override" section
|
|
254
|
+
4. Add your custom documentation (supports markdown)
|
|
255
|
+
5. Regenerate the code - your custom documentation will be used instead of the default
|
|
256
|
+
|
|
257
|
+
## File Format
|
|
258
|
+
|
|
259
|
+
Each file contains:
|
|
260
|
+
|
|
261
|
+
### Frontmatter
|
|
262
|
+
- \`endpoint\`: The API endpoint path
|
|
263
|
+
- \`method\`: HTTP method (GET, POST, etc.)
|
|
264
|
+
- \`hash\`: Hash of the endpoint for change detection
|
|
265
|
+
- \`host\`: API host URL
|
|
266
|
+
- \`version\`: API version
|
|
267
|
+
- \`operationId\`: OpenAPI operation ID
|
|
268
|
+
|
|
269
|
+
### Default Description
|
|
270
|
+
The original description from the OpenAPI spec.
|
|
271
|
+
|
|
272
|
+
### Override Section
|
|
273
|
+
A code block where you can add your custom documentation. If empty, the default description is used.
|
|
274
|
+
|
|
275
|
+
## Example
|
|
276
|
+
|
|
277
|
+
\`\`\`markdown
|
|
278
|
+
---
|
|
279
|
+
endpoint: /blocking/create
|
|
280
|
+
method: POST
|
|
281
|
+
hash: abc123
|
|
282
|
+
host: https://misskey.io
|
|
283
|
+
version: 1.0.0
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
# blocking/create
|
|
287
|
+
|
|
288
|
+
**Path**: \`/blocking/create\`
|
|
289
|
+
**Method**: \`POST\`
|
|
290
|
+
|
|
291
|
+
## Default Description
|
|
292
|
+
|
|
293
|
+
No description provided.
|
|
294
|
+
|
|
295
|
+
**Credential required**: *Yes* / **Permission**: *write:blocks*
|
|
296
|
+
|
|
297
|
+
## Override
|
|
298
|
+
|
|
299
|
+
\`\`\`
|
|
300
|
+
Create a blocking relationship with another user.
|
|
301
|
+
|
|
302
|
+
This endpoint allows you to block a user by their user ID. Once blocked:
|
|
303
|
+
- The user will not be able to see your posts
|
|
304
|
+
- You will not see their posts in your timeline
|
|
305
|
+
- They cannot follow you
|
|
306
|
+
|
|
307
|
+
**Parameters:**
|
|
308
|
+
- \`userId\`: The ID of the user to block
|
|
309
|
+
|
|
310
|
+
**Example:**
|
|
311
|
+
\`\`\`typescript
|
|
312
|
+
await client.blocking.create({ userId: "user123" })
|
|
313
|
+
\`\`\`
|
|
314
|
+
\`\`\`
|
|
315
|
+
\`\`\`
|
|
316
|
+
|
|
317
|
+
## Notes
|
|
318
|
+
|
|
319
|
+
- The hash is used to detect if the endpoint has changed in the OpenAPI spec
|
|
320
|
+
- If the endpoint changes, you may need to update your override
|
|
321
|
+
- Empty override blocks (with just \`<!-- Empty - no override -->\`) are ignored`
|
|
322
|
+
|
|
323
|
+
// === ComponentSchemaGenerator ===
|
|
324
|
+
|
|
325
|
+
let componentSchemaModule = `{{{docComment}}}module {{{moduleName}}} = {
|
|
326
|
+
{{{extractedBlock}}}{{{typeKeyword}}} = {{{typeCode}}}
|
|
327
|
+
let schema = {{{schemaCode}}}
|
|
328
|
+
}`
|
|
@@ -193,10 +193,14 @@ let generate = (~spec, ~outputDir) => {
|
|
|
193
193
|
? `S.recursive("${schema.name}", schema => ${schemaCode})`
|
|
194
194
|
: schemaCode
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
Handlebars.render(Templates.componentSchemaModule, {
|
|
197
|
+
"docComment": docComment,
|
|
198
|
+
"moduleName": CodegenUtils.toPascalCase(schema.name),
|
|
199
|
+
"extractedBlock": extractedBlock,
|
|
200
|
+
"typeKeyword": ` ${typeKeyword}`,
|
|
201
|
+
"typeCode": typeCode,
|
|
202
|
+
"schemaCode": finalSchemaCode,
|
|
203
|
+
})
|
|
200
204
|
})
|
|
201
205
|
|
|
202
206
|
let fileHeader = CodegenUtils.generateFileHeader(~description="Shared component schemas")
|
|
@@ -76,35 +76,17 @@ let generateCompactSummary = (diff: specDiff) => {
|
|
|
76
76
|
`Found ${totalChanges->Int.toString} changes: +${addedCount->Int.toString} -${removedCount->Int.toString} ~${modifiedCount->Int.toString} endpoints${breakingText}`
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
let generateMergeReport = (~stats: SpecMerger.mergeStats, ~baseName, ~forkName) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|- **Shared Endpoints**: ${sharedEndpoints}
|
|
91
|
-
|- **Shared Schemas**: ${sharedSchemas}
|
|
92
|
-
|
|
|
93
|
-
|## ${forkName} Extensions
|
|
94
|
-
|
|
|
95
|
-
|- **Extension Endpoints**: ${extensionEndpoints}
|
|
96
|
-
|- **Extension Schemas**: ${extensionSchemas}
|
|
97
|
-
|
|
|
98
|
-
|## Summary
|
|
99
|
-
|
|
|
100
|
-
|The shared base contains ${sharedEndpoints} endpoints and ${sharedSchemas} schemas.
|
|
101
|
-
|
|
|
102
|
-
|${forkName} adds ${extensionEndpoints} endpoints and ${extensionSchemas} schemas.
|
|
103
|
-
|
|
|
104
|
-
|---
|
|
105
|
-
|*Generated on ${Date.make()->Date.toISOString}*
|
|
106
|
-
|`->CodegenUtils.trimMargin
|
|
107
|
-
}
|
|
79
|
+
let generateMergeReport = (~stats: SpecMerger.mergeStats, ~baseName, ~forkName) =>
|
|
80
|
+
Handlebars.render(Templates.mergeReport, {
|
|
81
|
+
"baseName": baseName,
|
|
82
|
+
"forkName": forkName,
|
|
83
|
+
"sharedEndpoints": stats.sharedEndpointCount->Int.toString,
|
|
84
|
+
"sharedSchemas": stats.sharedSchemaCount->Int.toString,
|
|
85
|
+
"extensionEndpoints": stats.forkExtensionCount->Int.toString,
|
|
86
|
+
"extensionSchemas": stats.forkSchemaCount->Int.toString,
|
|
87
|
+
"timestamp": Date.make()->Date.toISOString,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
108
90
|
|
|
109
91
|
let generateEndpointsByTagReport = (endpoints: array<endpoint>) => {
|
|
110
92
|
let endpointsByTag = Dict.make()
|
|
@@ -53,9 +53,9 @@ let generateEndpointFunction = (endpoint: endpoint, ~overrideDir=?, ~moduleName=
|
|
|
53
53
|
->Array.get(0)
|
|
54
54
|
|
|
55
55
|
let responseHandling = successResponse->Option.mapOr(" response", response =>
|
|
56
|
-
response.content->Option.mapOr(" let _ = response
|
|
56
|
+
response.content->Option.mapOr(" let _ = response", content =>
|
|
57
57
|
Dict.toArray(content)->Array.length > 0
|
|
58
|
-
? `
|
|
58
|
+
? ` response->S.parseOrThrow(${functionName}ResponseSchema)`
|
|
59
59
|
: " response"
|
|
60
60
|
)
|
|
61
61
|
)
|
|
@@ -85,21 +85,23 @@ let generateEndpointFunction = (endpoint: endpoint, ~overrideDir=?, ~moduleName=
|
|
|
85
85
|
(),
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
let code =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
88
|
+
let code = Handlebars.render(
|
|
89
|
+
Templates.endpointFunction,
|
|
90
|
+
{
|
|
91
|
+
"docComment": docComment,
|
|
92
|
+
"functionName": functionName,
|
|
93
|
+
"bodyParam": bodyParam,
|
|
94
|
+
"paramSep": paramSep,
|
|
95
|
+
"fetchTypeSignature": CodegenUtils.fetchTypeSignature,
|
|
96
|
+
"bodyValueConversion": bodyValueConversion,
|
|
97
|
+
"path": endpoint.path,
|
|
98
|
+
"methodUpper": endpoint.method->String.toUpperCase,
|
|
99
|
+
"bodyArg": hasRequestBody ? "Some(jsonBody)" : "None",
|
|
100
|
+
"responseHandling": responseHandling,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
101
103
|
|
|
102
|
-
code
|
|
104
|
+
code
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
let generateEndpointCode = (endpoint, ~overrideDir=?, ~moduleName=?, ~modulePrefix="") => {
|
|
@@ -143,13 +145,14 @@ let generateEndpointCode = (endpoint, ~overrideDir=?, ~moduleName=?, ~modulePref
|
|
|
143
145
|
let generateEndpointModule = (~endpoint, ~modulePrefix="") => {
|
|
144
146
|
let functionName = CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method)
|
|
145
147
|
let header = CodegenUtils.generateFileHeader(~description=endpoint.summary->Option.getOr(`API: ${endpoint.path}`))
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
Handlebars.render(
|
|
149
|
+
Templates.moduleWrapped,
|
|
150
|
+
{
|
|
151
|
+
"header": header->String.trimEnd,
|
|
152
|
+
"moduleName": CodegenUtils.toPascalCase(functionName),
|
|
153
|
+
"body": generateEndpointCode(endpoint, ~modulePrefix)->CodegenUtils.indent(2),
|
|
154
|
+
},
|
|
155
|
+
)
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
let generateEndpointsModule = (~moduleName, ~endpoints, ~description=?, ~overrideDir=?, ~modulePrefix="") => {
|
|
@@ -159,13 +162,14 @@ let generateEndpointsModule = (~moduleName, ~endpoints, ~description=?, ~overrid
|
|
|
159
162
|
->Array.map(ep => generateEndpointCode(ep, ~overrideDir?, ~moduleName, ~modulePrefix)->CodegenUtils.indent(2))
|
|
160
163
|
->Array.join("\n\n")
|
|
161
164
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
Handlebars.render(
|
|
166
|
+
Templates.moduleWrapped,
|
|
167
|
+
{
|
|
168
|
+
"header": header->String.trimEnd,
|
|
169
|
+
"moduleName": moduleName,
|
|
170
|
+
"body": body,
|
|
171
|
+
},
|
|
172
|
+
)
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
let generateEndpointSignature = (endpoint) => {
|
|
@@ -63,19 +63,22 @@ let generateTagModuleFile = (
|
|
|
63
63
|
->Array.join("\n\n")
|
|
64
64
|
|
|
65
65
|
if wrapInModule {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
Handlebars.render(
|
|
67
|
+
Templates.moduleWrapped,
|
|
68
|
+
{
|
|
69
|
+
"header": header->String.trimEnd,
|
|
70
|
+
"moduleName": moduleName,
|
|
71
|
+
"body": body->CodegenUtils.indent(2),
|
|
72
|
+
},
|
|
73
|
+
)
|
|
73
74
|
} else {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
Handlebars.render(
|
|
76
|
+
Templates.moduleUnwrapped,
|
|
77
|
+
{
|
|
78
|
+
"header": header->String.trimEnd,
|
|
79
|
+
"body": body,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -96,22 +99,19 @@ let generateAllTagModules = (
|
|
|
96
99
|
|
|
97
100
|
let generateIndexModule = (~tags, ~moduleName="API") => {
|
|
98
101
|
let header = CodegenUtils.generateFileHeader(~description="Main API module index")
|
|
99
|
-
let
|
|
102
|
+
let tagData =
|
|
100
103
|
tags
|
|
101
104
|
->Array.toSorted(String.compare)
|
|
102
|
-
->Array.map(tag => {
|
|
103
|
-
let m = CodegenUtils.toPascalCase(tag)
|
|
104
|
-
` module ${m} = ${m}`
|
|
105
|
-
})
|
|
106
|
-
->Array.join("\n")
|
|
105
|
+
->Array.map(tag => {"modulePascal": CodegenUtils.toPascalCase(tag)})
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
Handlebars.render(
|
|
108
|
+
Templates.indexModule,
|
|
109
|
+
{
|
|
110
|
+
"header": header->String.trimEnd,
|
|
111
|
+
"moduleName": moduleName,
|
|
112
|
+
"tags": tagData,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
let generateFlatModuleCode = (~moduleName, ~endpoints, ~overrideDir=?) => {
|
|
@@ -127,13 +127,14 @@ let generateFlatModuleCode = (~moduleName, ~endpoints, ~overrideDir=?) => {
|
|
|
127
127
|
)
|
|
128
128
|
->Array.join("\n\n")
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
Handlebars.render(
|
|
131
|
+
Templates.moduleWrapped,
|
|
132
|
+
{
|
|
133
|
+
"header": header->String.trimEnd,
|
|
134
|
+
"moduleName": moduleName,
|
|
135
|
+
"body": body,
|
|
136
|
+
},
|
|
137
|
+
)
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
let internalGenerateIntegratedModule = (
|
|
@@ -220,13 +221,14 @@ let generateCombinedModule = (
|
|
|
220
221
|
~includeHeader=false,
|
|
221
222
|
)
|
|
222
223
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
224
|
+
Handlebars.render(
|
|
225
|
+
Templates.combinedModule,
|
|
226
|
+
{
|
|
227
|
+
"header": header->String.trimEnd,
|
|
228
|
+
"shared": shared,
|
|
229
|
+
"extension": extension,
|
|
230
|
+
},
|
|
231
|
+
)
|
|
230
232
|
}
|
|
231
233
|
|
|
232
234
|
let generateTagModuleFiles = (~endpoints, ~outputDir, ~wrapInModule=false, ~overrideDir=?) => {
|
|
@@ -75,10 +75,12 @@ let generateEndpointModule = (path, method, operation: Types.operation) => {
|
|
|
75
75
|
}
|
|
76
76
|
let schemasCode = generateOperationSchemas(operationId, operation)
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
Handlebars.render(Templates.endpointModule, {
|
|
79
|
+
"docComment": docComment,
|
|
80
|
+
"moduleName": CodegenUtils.toPascalCase(operationId),
|
|
81
|
+
"schemasCode": schemasCode->CodegenUtils.indent(2),
|
|
82
|
+
"path": path,
|
|
83
|
+
"methodStr": methodStr,
|
|
84
|
+
},
|
|
85
|
+
)
|
|
84
86
|
}
|
|
@@ -3,23 +3,14 @@
|
|
|
3
3
|
// ThinWrapperGenerator.res - Generate ReScript thin wrappers with pipe-first ergonomics
|
|
4
4
|
open Types
|
|
5
5
|
|
|
6
|
-
let clientTypeCode =
|
|
7
|
-
|
|
8
|
-
| baseUrl: string,
|
|
9
|
-
| token: option<string>,
|
|
10
|
-
| fetch: ${CodegenUtils.fetchTypeSignature},
|
|
11
|
-
|}
|
|
12
|
-
|`->CodegenUtils.trimMargin
|
|
6
|
+
let clientTypeCode =
|
|
7
|
+
Handlebars.render(Templates.clientType, {"fetchTypeSignature": CodegenUtils.fetchTypeSignature})
|
|
13
8
|
|
|
14
9
|
let generateConnectFunction = (title) =>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| token,
|
|
20
|
-
| fetch,
|
|
21
|
-
|}
|
|
22
|
-
|`->CodegenUtils.trimMargin
|
|
10
|
+
Handlebars.render(
|
|
11
|
+
Templates.connectFunction,
|
|
12
|
+
{"title": title, "fetchTypeSignature": CodegenUtils.fetchTypeSignature},
|
|
13
|
+
)
|
|
23
14
|
|
|
24
15
|
let generateWrapperFunction = (~endpoint: endpoint, ~generatedModuleName: string) => {
|
|
25
16
|
let operationName = CodegenUtils.generateOperationName(
|
|
@@ -41,8 +32,16 @@ let generateWrapperFunction = (~endpoint: endpoint, ~generatedModuleName: string
|
|
|
41
32
|
|
|
42
33
|
let callArguments = hasRequestBody ? "~body=request, " : ""
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
Handlebars.render(
|
|
36
|
+
Templates.wrapperFunction,
|
|
37
|
+
{
|
|
38
|
+
"docComment": docComment,
|
|
39
|
+
"signature": signature,
|
|
40
|
+
"generatedModuleName": generatedModuleName,
|
|
41
|
+
"operationName": operationName,
|
|
42
|
+
"callArguments": callArguments,
|
|
43
|
+
},
|
|
44
|
+
)
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
let generateWrapper = (
|
|
@@ -109,13 +108,14 @@ let generateWrapper = (
|
|
|
109
108
|
})
|
|
110
109
|
->Array.join("\n\n")
|
|
111
110
|
|
|
112
|
-
let fileContent =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
let fileContent = Handlebars.render(
|
|
112
|
+
Templates.wrapperFile,
|
|
113
|
+
{
|
|
114
|
+
"clientTypeCode": clientTypeCode,
|
|
115
|
+
"connectFunctionCode": generateConnectFunction(spec.info.title),
|
|
116
|
+
"modulesCode": modulesCode,
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
119
|
|
|
120
120
|
Pipeline.fromFilesAndWarnings(
|
|
121
121
|
[{path: FileSystem.makePath(outputDir, `${wrapperModuleName}.res`), content: fileContent}],
|