@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.
- 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 +341 -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 +25 -31
- 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 +330 -0
- package/src/generators/ComponentSchemaGenerator.res +8 -4
- package/src/generators/DiffReportGenerator.res +11 -29
- package/src/generators/EndpointGenerator.res +32 -28
- 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,43 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Module from "module";
|
|
4
|
+
|
|
5
|
+
let _require = Module.createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
let handlebars = _require("handlebars");
|
|
8
|
+
|
|
9
|
+
let convert = _require("js-convert-case");
|
|
10
|
+
|
|
11
|
+
let _render = ((function(Handlebars, convert) {
|
|
12
|
+
var instance = Handlebars.create();
|
|
13
|
+
|
|
14
|
+
instance.registerHelper('indent', function(content, level) {
|
|
15
|
+
if (typeof content !== 'string') return '';
|
|
16
|
+
var spaces = ' '.repeat(typeof level === 'number' ? level : 1);
|
|
17
|
+
return content.split('\n').map(function(line) {
|
|
18
|
+
return line.trim() === '' ? '' : spaces + line;
|
|
19
|
+
}).join('\n');
|
|
20
|
+
});
|
|
21
|
+
instance.registerHelper('pascalCase', function(s) { return typeof s === 'string' ? convert.toPascalCase(s) : ''; });
|
|
22
|
+
instance.registerHelper('camelCase', function(s) { return typeof s === 'string' ? convert.toCamelCase(s) : ''; });
|
|
23
|
+
instance.registerHelper('upperCase', function(s) { return typeof s === 'string' ? s.toUpperCase() : ''; });
|
|
24
|
+
instance.registerHelper('eq', function(a, b) { return a === b; });
|
|
25
|
+
instance.registerHelper('ne', function(a, b) { return a !== b; });
|
|
26
|
+
|
|
27
|
+
var cache = {};
|
|
28
|
+
return function render(template, data) {
|
|
29
|
+
if (!cache[template]) cache[template] = instance.compile(template, { noEscape: true });
|
|
30
|
+
return cache[template](data);
|
|
31
|
+
};
|
|
32
|
+
}))(handlebars, convert);
|
|
33
|
+
|
|
34
|
+
function render(template, data) {
|
|
35
|
+
return _render(template, data);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
_require,
|
|
40
|
+
_render,
|
|
41
|
+
render,
|
|
42
|
+
}
|
|
43
|
+
/* _require Not a pure module */
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Templates from "./Templates.mjs";
|
|
4
|
+
import * as Handlebars from "../bindings/Handlebars.mjs";
|
|
5
|
+
import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
|
|
3
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
7
|
import * as JsConvertCase from "js-convert-case";
|
|
5
8
|
|
|
@@ -91,12 +94,9 @@ function escapeRegexPattern(str) {
|
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
function generateFileHeader(description) {
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
S.enableJson()
|
|
99
|
-
`;
|
|
97
|
+
return Handlebars.render(Templates.fileHeader, {
|
|
98
|
+
description: description
|
|
99
|
+
});
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function indent(code, level) {
|
|
@@ -110,18 +110,6 @@ function indent(code, level) {
|
|
|
110
110
|
}).join("\n");
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function trimMargin(text, marginPrefixOpt) {
|
|
114
|
-
let marginPrefix = marginPrefixOpt !== undefined ? marginPrefixOpt : "|";
|
|
115
|
-
return text.split("\n").map(line => {
|
|
116
|
-
let trimmed = line.trimStart();
|
|
117
|
-
if (trimmed.startsWith(marginPrefix)) {
|
|
118
|
-
return trimmed.slice(marginPrefix.length);
|
|
119
|
-
} else {
|
|
120
|
-
return line;
|
|
121
|
-
}
|
|
122
|
-
}).join("\n").trim();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
113
|
let rescriptKeywords = [
|
|
126
114
|
"and",
|
|
127
115
|
"as",
|
|
@@ -185,17 +173,10 @@ function escapeKeyword(name) {
|
|
|
185
173
|
}
|
|
186
174
|
|
|
187
175
|
function generateDocComment(summary, description, param) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return `// ` + summary + `\n`;
|
|
193
|
-
}
|
|
194
|
-
} else if (description !== undefined) {
|
|
195
|
-
return `// ` + description + `\n`;
|
|
196
|
-
} else {
|
|
197
|
-
return "";
|
|
198
|
-
}
|
|
176
|
+
return Handlebars.render(Templates.docComment, {
|
|
177
|
+
summary: Stdlib_Null.fromOption(summary),
|
|
178
|
+
description: Stdlib_Null.fromOption(description)
|
|
179
|
+
});
|
|
199
180
|
}
|
|
200
181
|
|
|
201
182
|
function generateDocString(summary, description, param) {
|
|
@@ -211,19 +192,17 @@ function generateDocString(summary, description, param) {
|
|
|
211
192
|
let len = lines.length;
|
|
212
193
|
if (len !== 1) {
|
|
213
194
|
if (len !== 0) {
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else {
|
|
218
|
-
return ` * ` + l;
|
|
219
|
-
}
|
|
220
|
-
}).join("\n") + "\n */\n";
|
|
195
|
+
return Handlebars.render(Templates.docCommentMulti, {
|
|
196
|
+
lines: lines
|
|
197
|
+
});
|
|
221
198
|
} else {
|
|
222
199
|
return "";
|
|
223
200
|
}
|
|
224
201
|
}
|
|
225
202
|
let line = lines[0];
|
|
226
|
-
return
|
|
203
|
+
return Handlebars.render(Templates.docCommentSingle, {
|
|
204
|
+
content: line
|
|
205
|
+
});
|
|
227
206
|
}), "");
|
|
228
207
|
}
|
|
229
208
|
|
|
@@ -310,7 +289,6 @@ export {
|
|
|
310
289
|
escapeRegexPattern,
|
|
311
290
|
generateFileHeader,
|
|
312
291
|
indent,
|
|
313
|
-
trimMargin,
|
|
314
292
|
rescriptKeywords,
|
|
315
293
|
escapeKeyword,
|
|
316
294
|
generateDocComment,
|
|
@@ -319,4 +297,4 @@ export {
|
|
|
319
297
|
variantConstructorName,
|
|
320
298
|
deduplicateNames,
|
|
321
299
|
}
|
|
322
|
-
/*
|
|
300
|
+
/* Handlebars Not a pure module */
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Fs from "fs";
|
|
4
4
|
import * as Js_string from "@rescript/runtime/lib/es6/Js_string.js";
|
|
5
|
+
import * as Templates from "./Templates.mjs";
|
|
5
6
|
import * as FileSystem from "./FileSystem.mjs";
|
|
7
|
+
import * as Handlebars from "../bindings/Handlebars.mjs";
|
|
6
8
|
import * as CodegenUtils from "./CodegenUtils.mjs";
|
|
7
9
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
8
10
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
@@ -105,28 +107,14 @@ function generateOverrideMarkdown(endpoint, host, version, param) {
|
|
|
105
107
|
Stdlib_Option.map(endpoint.operationId, id => `operationId: ` + id),
|
|
106
108
|
"---"
|
|
107
109
|
], x => x));
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
|
117
|
-
|## Default Description
|
|
118
|
-
|
|
|
119
|
-
|` + defaultDesc + `
|
|
120
|
-
|
|
|
121
|
-
|## Override
|
|
122
|
-
|
|
|
123
|
-
|Add your custom documentation here. If this code block is empty, the default description will be used.
|
|
124
|
-
|
|
|
125
|
-
|\`\`\`
|
|
126
|
-
|<!-- Empty - no override -->
|
|
127
|
-
|\`\`\`
|
|
128
|
-
|`;
|
|
129
|
-
return CodegenUtils.trimMargin(content, undefined);
|
|
110
|
+
return Handlebars.render(Templates.overrideMarkdown, {
|
|
111
|
+
metadataBlock: metadata.join("\n"),
|
|
112
|
+
title: Stdlib_Option.getOr(endpoint.summary, endpoint.path),
|
|
113
|
+
path: endpoint.path,
|
|
114
|
+
methodUpper: endpoint.method.toUpperCase(),
|
|
115
|
+
operationName: operationName,
|
|
116
|
+
defaultDesc: defaultDesc
|
|
117
|
+
});
|
|
130
118
|
}
|
|
131
119
|
|
|
132
120
|
function validateOverride(override, currentHash) {
|
|
@@ -281,107 +269,10 @@ function generateOverrideFiles(spec, endpoints, outputDir, host, groupByTagOpt,
|
|
|
281
269
|
function generateOverrideReadme(host, version, param) {
|
|
282
270
|
let hostInfo = Stdlib_Option.getOr(host, "Not specified");
|
|
283
271
|
let versionInfo = Stdlib_Option.getOr(version, "Not specified");
|
|
284
|
-
return
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
|
289
|
-
|## Global Information
|
|
290
|
-
|
|
|
291
|
-
|- **Host**: ` + hostInfo + `
|
|
292
|
-
|- **Version**: ` + versionInfo + `
|
|
293
|
-
|
|
|
294
|
-
|## Structure
|
|
295
|
-
|
|
|
296
|
-
|Each module has its own directory, and each endpoint has its own markdown file:
|
|
297
|
-
|
|
|
298
|
-
|\`\`\`
|
|
299
|
-
|docs/
|
|
300
|
-
|├── README.md (this file)
|
|
301
|
-
|├── Account/
|
|
302
|
-
|│ ├── postBlockingCreate.md
|
|
303
|
-
|│ ├── postBlockingDelete.md
|
|
304
|
-
|│ └── ...
|
|
305
|
-
|├── Notes/
|
|
306
|
-
|│ ├── postNotesCreate.md
|
|
307
|
-
|│ └── ...
|
|
308
|
-
|└── ...
|
|
309
|
-
|\`\`\`
|
|
310
|
-
|
|
|
311
|
-
|## How to Override
|
|
312
|
-
|
|
|
313
|
-
|1. Find the endpoint you want to document in its module directory
|
|
314
|
-
|2. Open the markdown file
|
|
315
|
-
|3. Edit the code block under the "## Override" section
|
|
316
|
-
|4. Add your custom documentation (supports markdown)
|
|
317
|
-
|5. Regenerate the code - your custom documentation will be used instead of the default
|
|
318
|
-
|
|
|
319
|
-
|## File Format
|
|
320
|
-
|
|
|
321
|
-
|Each file contains:
|
|
322
|
-
|
|
|
323
|
-
|### Frontmatter
|
|
324
|
-
|- \`endpoint\`: The API endpoint path
|
|
325
|
-
|- \`method\`: HTTP method (GET, POST, etc.)
|
|
326
|
-
|- \`hash\`: Hash of the endpoint for change detection
|
|
327
|
-
|- \`host\`: API host URL
|
|
328
|
-
|- \`version\`: API version
|
|
329
|
-
|- \`operationId\`: OpenAPI operation ID
|
|
330
|
-
|
|
|
331
|
-
|### Default Description
|
|
332
|
-
|The original description from the OpenAPI spec.
|
|
333
|
-
|
|
|
334
|
-
|### Override Section
|
|
335
|
-
|A code block where you can add your custom documentation. If empty, the default description is used.
|
|
336
|
-
|
|
|
337
|
-
|## Example
|
|
338
|
-
|
|
|
339
|
-
|\`\`\`markdown
|
|
340
|
-
|---
|
|
341
|
-
|endpoint: /blocking/create
|
|
342
|
-
|method: POST
|
|
343
|
-
|hash: abc123
|
|
344
|
-
|host: https://misskey.io
|
|
345
|
-
|version: 1.0.0
|
|
346
|
-
|---
|
|
347
|
-
|
|
|
348
|
-
|# blocking/create
|
|
349
|
-
|
|
|
350
|
-
|**Path**: \`/blocking/create\`
|
|
351
|
-
|**Method**: \`POST\`
|
|
352
|
-
|
|
|
353
|
-
|## Default Description
|
|
354
|
-
|
|
|
355
|
-
|No description provided.
|
|
356
|
-
|
|
|
357
|
-
|**Credential required**: *Yes* / **Permission**: *write:blocks*
|
|
358
|
-
|
|
|
359
|
-
|## Override
|
|
360
|
-
|
|
|
361
|
-
|\`\`\`
|
|
362
|
-
|Create a blocking relationship with another user.
|
|
363
|
-
|
|
|
364
|
-
|This endpoint allows you to block a user by their user ID. Once blocked:
|
|
365
|
-
|- The user will not be able to see your posts
|
|
366
|
-
|- You will not see their posts in your timeline
|
|
367
|
-
|- They cannot follow you
|
|
368
|
-
|
|
|
369
|
-
|**Parameters:**
|
|
370
|
-
|- \`userId\`: The ID of the user to block
|
|
371
|
-
|
|
|
372
|
-
|**Example:**
|
|
373
|
-
|\`\`\`typescript
|
|
374
|
-
|await client.blocking.create({ userId: "user123" })
|
|
375
|
-
|\`\`\`
|
|
376
|
-
|\`\`\`
|
|
377
|
-
|\`\`\`
|
|
378
|
-
|
|
|
379
|
-
|## Notes
|
|
380
|
-
|
|
|
381
|
-
|- The hash is used to detect if the endpoint has changed in the OpenAPI spec
|
|
382
|
-
|- If the endpoint changes, you may need to update your override
|
|
383
|
-
|- Empty override blocks (with just \`<!-- Empty - no override -->\`) are ignored
|
|
384
|
-
|`, undefined);
|
|
272
|
+
return Handlebars.render(Templates.overrideReadme, {
|
|
273
|
+
hostInfo: hostInfo,
|
|
274
|
+
versionInfo: versionInfo
|
|
275
|
+
});
|
|
385
276
|
}
|
|
386
277
|
|
|
387
278
|
export {
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let fileHeader = `// {{{description}}}
|
|
5
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
6
|
+
// DO NOT EDIT - This file is auto-generated
|
|
7
|
+
|
|
8
|
+
S.enableJson()
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
let docCommentSingle = `/** {{{content}}} */
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
let docCommentMulti = `/**
|
|
15
|
+
{{#each lines}}{{{this}}}
|
|
16
|
+
{{/each}}*/
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
let docComment = `{{#if summary}}// {{{summary}}}
|
|
20
|
+
{{/if}}{{#if description}}// {{{description}}}
|
|
21
|
+
{{/if}}`;
|
|
22
|
+
|
|
23
|
+
let endpointFunction = `{{{docComment}}}let {{{functionName}}} = ({{{bodyParam}}}{{{paramSep}}}~fetch: {{{fetchTypeSignature}}}): promise<{{{functionName}}}Response> => {
|
|
24
|
+
{{{bodyValueConversion}}}
|
|
25
|
+
fetch(
|
|
26
|
+
~url="{{{path}}}",
|
|
27
|
+
~method_="{{{methodUpper}}}",
|
|
28
|
+
~body={{{bodyArg}}},
|
|
29
|
+
)->Promise.then(response => {
|
|
30
|
+
{{{responseHandling}}}
|
|
31
|
+
->Promise.resolve
|
|
32
|
+
})
|
|
33
|
+
}`;
|
|
34
|
+
|
|
35
|
+
let moduleWrapped = `{{{header}}}
|
|
36
|
+
|
|
37
|
+
module {{{moduleName}}} = {
|
|
38
|
+
{{{body}}}
|
|
39
|
+
}`;
|
|
40
|
+
|
|
41
|
+
let moduleUnwrapped = `{{{header}}}
|
|
42
|
+
|
|
43
|
+
{{{body}}}`;
|
|
44
|
+
|
|
45
|
+
let indexModule = `{{{header}}}
|
|
46
|
+
|
|
47
|
+
module {{{moduleName}}} = {
|
|
48
|
+
{{#each tags}} module {{{modulePascal}}} = {{{modulePascal}}}
|
|
49
|
+
{{/each}}}`;
|
|
50
|
+
|
|
51
|
+
let combinedModule = `{{{header}}}
|
|
52
|
+
|
|
53
|
+
{{{shared}}}
|
|
54
|
+
|
|
55
|
+
{{{extension}}}`;
|
|
56
|
+
|
|
57
|
+
let clientType = `type client = {
|
|
58
|
+
baseUrl: string,
|
|
59
|
+
token: option<string>,
|
|
60
|
+
fetch: {{{fetchTypeSignature}}},
|
|
61
|
+
}`;
|
|
62
|
+
|
|
63
|
+
let connectFunction = `/** Create a client for {{{title}}} */
|
|
64
|
+
let connect = (~baseUrl: string, ~token: option<string>=?, ~fetch: {{{fetchTypeSignature}}}, ()): client => {
|
|
65
|
+
baseUrl,
|
|
66
|
+
token,
|
|
67
|
+
fetch,
|
|
68
|
+
}`;
|
|
69
|
+
|
|
70
|
+
let wrapperFunction = `{{{docComment}}} {{{signature}}}: promise<{{{generatedModuleName}}}.{{{operationName}}}Response> =>
|
|
71
|
+
{{{generatedModuleName}}}.{{{operationName}}}({{{callArguments}}}~fetch=client.fetch)`;
|
|
72
|
+
|
|
73
|
+
let wrapperFile = `// Generated thin wrapper
|
|
74
|
+
|
|
75
|
+
{{{clientTypeCode}}}
|
|
76
|
+
|
|
77
|
+
{{{connectFunctionCode}}}
|
|
78
|
+
|
|
79
|
+
{{{modulesCode}}}`;
|
|
80
|
+
|
|
81
|
+
let methodSignature = `{{{docLines}}}
|
|
82
|
+
{{{functionName}}}({{{params}}}): Promise<{{{responsePascalName}}}Response>;`;
|
|
83
|
+
|
|
84
|
+
let moduleDts = `// TypeScript definitions for {{{moduleName}}}
|
|
85
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
86
|
+
// DO NOT EDIT
|
|
87
|
+
|
|
88
|
+
import { MisskeyClient } from './index';
|
|
89
|
+
import * as ComponentSchemas from './ComponentSchemas';
|
|
90
|
+
|
|
91
|
+
{{{interfaces}}}
|
|
92
|
+
|
|
93
|
+
export interface {{{moduleName}}}Module {
|
|
94
|
+
{{{methodSignatures}}}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const {{{moduleName}}}: {{{moduleName}}}Module;`;
|
|
98
|
+
|
|
99
|
+
let componentSchemasDts = `// TypeScript definitions for ComponentSchemas
|
|
100
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
101
|
+
// DO NOT EDIT
|
|
102
|
+
|
|
103
|
+
{{{content}}}`;
|
|
104
|
+
|
|
105
|
+
let indexDts = `// TypeScript definitions
|
|
106
|
+
// Generated by @f3liz/rescript-autogen-openapi
|
|
107
|
+
// DO NOT EDIT
|
|
108
|
+
|
|
109
|
+
{{#each modules}}{{{importLine}}}
|
|
110
|
+
{{/each}}
|
|
111
|
+
export class MisskeyClient {
|
|
112
|
+
constructor(baseUrl: string, token?: string);
|
|
113
|
+
readonly baseUrl: string;
|
|
114
|
+
readonly token?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
{{#each modules}}{{{exportLine}}}
|
|
118
|
+
{{/each}}`;
|
|
119
|
+
|
|
120
|
+
let wrapperMjsMethod = ` async {{{functionName}}}(client{{{requestArg}}}) {
|
|
121
|
+
return {{{moduleName}}}.{{{functionName}}}({
|
|
122
|
+
{{{bodyArg}}}fetch: (url, method, body) => client._fetch(url, method, body)
|
|
123
|
+
});
|
|
124
|
+
},`;
|
|
125
|
+
|
|
126
|
+
let wrapperMjsNamespace = `export const {{{moduleName}}} = {
|
|
127
|
+
{{{methods}}}
|
|
128
|
+
};`;
|
|
129
|
+
|
|
130
|
+
let wrapperMjs = `// Generated wrapper
|
|
131
|
+
{{#each tags}}{{{importLine}}}
|
|
132
|
+
{{/each}}
|
|
133
|
+
{{{clientCode}}}
|
|
134
|
+
|
|
135
|
+
{{#each tags}}{{{namespace}}}
|
|
136
|
+
|
|
137
|
+
{{/each}}`;
|
|
138
|
+
|
|
139
|
+
let wrapperDtsFunction = `{{{docComment}}} export function {{{functionName}}}(client: MisskeyClient{{{requestParam}}}): Promise<{{{pascalName}}}Response>;`;
|
|
140
|
+
|
|
141
|
+
let wrapperDtsNamespace = `export namespace {{{moduleName}}} {
|
|
142
|
+
{{{functions}}}
|
|
143
|
+
}`;
|
|
144
|
+
|
|
145
|
+
let wrapperDts = `// Generated TypeScript definitions for wrapper
|
|
146
|
+
{{#each tags}}{{{importBlock}}}
|
|
147
|
+
{{/each}}
|
|
148
|
+
export class MisskeyClient {
|
|
149
|
+
constructor(baseUrl: string, token?: string);
|
|
150
|
+
readonly baseUrl: string;
|
|
151
|
+
readonly token?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
{{#each tags}}{{{namespace}}}
|
|
155
|
+
|
|
156
|
+
{{/each}}`;
|
|
157
|
+
|
|
158
|
+
let mergeReport = `# Merge Report: {{{baseName}}} + {{{forkName}}}
|
|
159
|
+
|
|
160
|
+
## Shared Code
|
|
161
|
+
|
|
162
|
+
- **Shared Endpoints**: {{{sharedEndpoints}}}
|
|
163
|
+
- **Shared Schemas**: {{{sharedSchemas}}}
|
|
164
|
+
|
|
165
|
+
## {{{forkName}}} Extensions
|
|
166
|
+
|
|
167
|
+
- **Extension Endpoints**: {{{extensionEndpoints}}}
|
|
168
|
+
- **Extension Schemas**: {{{extensionSchemas}}}
|
|
169
|
+
|
|
170
|
+
## Summary
|
|
171
|
+
|
|
172
|
+
The shared base contains {{{sharedEndpoints}}} endpoints and {{{sharedSchemas}}} schemas.
|
|
173
|
+
|
|
174
|
+
{{{forkName}}} adds {{{extensionEndpoints}}} endpoints and {{{extensionSchemas}}} schemas.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
*Generated on {{{timestamp}}}*`;
|
|
178
|
+
|
|
179
|
+
let endpointModule = `{{{docComment}}}module {{{moduleName}}} = {
|
|
180
|
+
{{{schemasCode}}}
|
|
181
|
+
|
|
182
|
+
let endpoint = "{{{path}}}"
|
|
183
|
+
let method = #{{{methodStr}}}
|
|
184
|
+
}`;
|
|
185
|
+
|
|
186
|
+
let overrideMarkdown = `{{{metadataBlock}}}
|
|
187
|
+
|
|
188
|
+
# {{{title}}}
|
|
189
|
+
|
|
190
|
+
**Path**: \`{{{path}}}\`
|
|
191
|
+
**Method**: \`{{{methodUpper}}}\`
|
|
192
|
+
**Operation**: \`{{{operationName}}}\`
|
|
193
|
+
|
|
194
|
+
## Default Description
|
|
195
|
+
|
|
196
|
+
{{{defaultDesc}}}
|
|
197
|
+
|
|
198
|
+
## Override
|
|
199
|
+
|
|
200
|
+
Add your custom documentation here. If this code block is empty, the default description will be used.
|
|
201
|
+
|
|
202
|
+
\`\`\`
|
|
203
|
+
<!-- Empty - no override -->
|
|
204
|
+
\`\`\``;
|
|
205
|
+
|
|
206
|
+
let overrideReadme = `# API Documentation Overrides
|
|
207
|
+
|
|
208
|
+
This directory contains markdown files that allow you to override the auto-generated documentation.
|
|
209
|
+
|
|
210
|
+
## Global Information
|
|
211
|
+
|
|
212
|
+
- **Host**: {{{hostInfo}}}
|
|
213
|
+
- **Version**: {{{versionInfo}}}
|
|
214
|
+
|
|
215
|
+
## Structure
|
|
216
|
+
|
|
217
|
+
Each module has its own directory, and each endpoint has its own markdown file:
|
|
218
|
+
|
|
219
|
+
\`\`\`
|
|
220
|
+
docs/
|
|
221
|
+
├── README.md (this file)
|
|
222
|
+
├── Account/
|
|
223
|
+
│ ├── postBlockingCreate.md
|
|
224
|
+
│ ├── postBlockingDelete.md
|
|
225
|
+
│ └── ...
|
|
226
|
+
├── Notes/
|
|
227
|
+
│ ├── postNotesCreate.md
|
|
228
|
+
│ └── ...
|
|
229
|
+
└── ...
|
|
230
|
+
\`\`\`
|
|
231
|
+
|
|
232
|
+
## How to Override
|
|
233
|
+
|
|
234
|
+
1. Find the endpoint you want to document in its module directory
|
|
235
|
+
2. Open the markdown file
|
|
236
|
+
3. Edit the code block under the "## Override" section
|
|
237
|
+
4. Add your custom documentation (supports markdown)
|
|
238
|
+
5. Regenerate the code - your custom documentation will be used instead of the default
|
|
239
|
+
|
|
240
|
+
## File Format
|
|
241
|
+
|
|
242
|
+
Each file contains:
|
|
243
|
+
|
|
244
|
+
### Frontmatter
|
|
245
|
+
- \`endpoint\`: The API endpoint path
|
|
246
|
+
- \`method\`: HTTP method (GET, POST, etc.)
|
|
247
|
+
- \`hash\`: Hash of the endpoint for change detection
|
|
248
|
+
- \`host\`: API host URL
|
|
249
|
+
- \`version\`: API version
|
|
250
|
+
- \`operationId\`: OpenAPI operation ID
|
|
251
|
+
|
|
252
|
+
### Default Description
|
|
253
|
+
The original description from the OpenAPI spec.
|
|
254
|
+
|
|
255
|
+
### Override Section
|
|
256
|
+
A code block where you can add your custom documentation. If empty, the default description is used.
|
|
257
|
+
|
|
258
|
+
## Example
|
|
259
|
+
|
|
260
|
+
\`\`\`markdown
|
|
261
|
+
---
|
|
262
|
+
endpoint: /blocking/create
|
|
263
|
+
method: POST
|
|
264
|
+
hash: abc123
|
|
265
|
+
host: https://misskey.io
|
|
266
|
+
version: 1.0.0
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
# blocking/create
|
|
270
|
+
|
|
271
|
+
**Path**: \`/blocking/create\`
|
|
272
|
+
**Method**: \`POST\`
|
|
273
|
+
|
|
274
|
+
## Default Description
|
|
275
|
+
|
|
276
|
+
No description provided.
|
|
277
|
+
|
|
278
|
+
**Credential required**: *Yes* / **Permission**: *write:blocks*
|
|
279
|
+
|
|
280
|
+
## Override
|
|
281
|
+
|
|
282
|
+
\`\`\`
|
|
283
|
+
Create a blocking relationship with another user.
|
|
284
|
+
|
|
285
|
+
This endpoint allows you to block a user by their user ID. Once blocked:
|
|
286
|
+
- The user will not be able to see your posts
|
|
287
|
+
- You will not see their posts in your timeline
|
|
288
|
+
- They cannot follow you
|
|
289
|
+
|
|
290
|
+
**Parameters:**
|
|
291
|
+
- \`userId\`: The ID of the user to block
|
|
292
|
+
|
|
293
|
+
**Example:**
|
|
294
|
+
\`\`\`typescript
|
|
295
|
+
await client.blocking.create({ userId: "user123" })
|
|
296
|
+
\`\`\`
|
|
297
|
+
\`\`\`
|
|
298
|
+
\`\`\`
|
|
299
|
+
|
|
300
|
+
## Notes
|
|
301
|
+
|
|
302
|
+
- The hash is used to detect if the endpoint has changed in the OpenAPI spec
|
|
303
|
+
- If the endpoint changes, you may need to update your override
|
|
304
|
+
- Empty override blocks (with just \`<!-- Empty - no override -->\`) are ignored`;
|
|
305
|
+
|
|
306
|
+
let componentSchemaModule = `{{{docComment}}}module {{{moduleName}}} = {
|
|
307
|
+
{{{extractedBlock}}}{{{typeKeyword}}} = {{{typeCode}}}
|
|
308
|
+
let schema = {{{schemaCode}}}
|
|
309
|
+
}`;
|
|
310
|
+
|
|
311
|
+
export {
|
|
312
|
+
fileHeader,
|
|
313
|
+
docCommentSingle,
|
|
314
|
+
docCommentMulti,
|
|
315
|
+
docComment,
|
|
316
|
+
endpointFunction,
|
|
317
|
+
moduleWrapped,
|
|
318
|
+
moduleUnwrapped,
|
|
319
|
+
indexModule,
|
|
320
|
+
combinedModule,
|
|
321
|
+
clientType,
|
|
322
|
+
connectFunction,
|
|
323
|
+
wrapperFunction,
|
|
324
|
+
wrapperFile,
|
|
325
|
+
methodSignature,
|
|
326
|
+
moduleDts,
|
|
327
|
+
componentSchemasDts,
|
|
328
|
+
indexDts,
|
|
329
|
+
wrapperMjsMethod,
|
|
330
|
+
wrapperMjsNamespace,
|
|
331
|
+
wrapperMjs,
|
|
332
|
+
wrapperDtsFunction,
|
|
333
|
+
wrapperDtsNamespace,
|
|
334
|
+
wrapperDts,
|
|
335
|
+
mergeReport,
|
|
336
|
+
endpointModule,
|
|
337
|
+
overrideMarkdown,
|
|
338
|
+
overrideReadme,
|
|
339
|
+
componentSchemaModule,
|
|
340
|
+
}
|
|
341
|
+
/* No side effect */
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Pipeline from "../core/Pipeline.mjs";
|
|
4
4
|
import * as Toposort from "../bindings/Toposort.mjs";
|
|
5
|
+
import * as Templates from "../core/Templates.mjs";
|
|
5
6
|
import * as FileSystem from "../core/FileSystem.mjs";
|
|
7
|
+
import * as Handlebars from "../bindings/Handlebars.mjs";
|
|
6
8
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
7
9
|
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
8
10
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -187,10 +189,14 @@ function generate(spec, outputDir) {
|
|
|
187
189
|
let extractedBlock = extractedTypeDefs.length !== 0 ? extractedTypeDefs.join("\n") + "\n" : "";
|
|
188
190
|
let typeKeyword = isSelfRef ? "type rec t" : "type t";
|
|
189
191
|
let finalSchemaCode = isSelfRef ? `S.recursive("` + schema.name + `", schema => ` + schemaCode + `)` : schemaCode;
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
return Handlebars.render(Templates.componentSchemaModule, {
|
|
193
|
+
docComment: docComment,
|
|
194
|
+
moduleName: JsConvertCase.toPascalCase(schema.name),
|
|
195
|
+
extractedBlock: extractedBlock,
|
|
196
|
+
typeKeyword: ` ` + typeKeyword,
|
|
197
|
+
typeCode: typeCode,
|
|
198
|
+
schemaCode: finalSchemaCode
|
|
199
|
+
});
|
|
194
200
|
});
|
|
195
201
|
let fileHeader = CodegenUtils.generateFileHeader("Shared component schemas");
|
|
196
202
|
let fileContent = fileHeader + `\n\n` + moduleCodes.join("\n\n");
|