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