@f3liz/rescript-autogen-openapi 0.3.1
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/LICENSE +373 -0
- package/README.md +111 -0
- package/lib/es6/src/Codegen.d.ts +28 -0
- package/lib/es6/src/Codegen.mjs +423 -0
- package/lib/es6/src/Types.d.ts +286 -0
- package/lib/es6/src/Types.mjs +20 -0
- package/lib/es6/src/bindings/Toposort.mjs +12 -0
- package/lib/es6/src/core/CodegenUtils.mjs +261 -0
- package/lib/es6/src/core/DocOverride.mjs +399 -0
- package/lib/es6/src/core/FileSystem.d.ts +4 -0
- package/lib/es6/src/core/FileSystem.mjs +78 -0
- package/lib/es6/src/core/IRBuilder.mjs +201 -0
- package/lib/es6/src/core/OpenAPIParser.mjs +168 -0
- package/lib/es6/src/core/Pipeline.d.ts +6 -0
- package/lib/es6/src/core/Pipeline.mjs +150 -0
- package/lib/es6/src/core/ReferenceResolver.mjs +41 -0
- package/lib/es6/src/core/Result.mjs +378 -0
- package/lib/es6/src/core/SchemaIR.mjs +425 -0
- package/lib/es6/src/core/SchemaIRParser.mjs +683 -0
- package/lib/es6/src/core/SchemaRefResolver.mjs +146 -0
- package/lib/es6/src/core/SchemaRegistry.mjs +92 -0
- package/lib/es6/src/core/SpecDiffer.mjs +251 -0
- package/lib/es6/src/core/SpecMerger.mjs +237 -0
- package/lib/es6/src/generators/ComponentSchemaGenerator.mjs +207 -0
- package/lib/es6/src/generators/DiffReportGenerator.mjs +155 -0
- package/lib/es6/src/generators/EndpointGenerator.mjs +173 -0
- package/lib/es6/src/generators/IRToSuryGenerator.mjs +543 -0
- package/lib/es6/src/generators/IRToTypeGenerator.mjs +592 -0
- package/lib/es6/src/generators/IRToTypeScriptGenerator.mjs +143 -0
- package/lib/es6/src/generators/ModuleGenerator.mjs +285 -0
- package/lib/es6/src/generators/SchemaCodeGenerator.mjs +77 -0
- package/lib/es6/src/generators/ThinWrapperGenerator.mjs +97 -0
- package/lib/es6/src/generators/TypeScriptDtsGenerator.mjs +172 -0
- package/lib/es6/src/generators/TypeScriptWrapperGenerator.mjs +145 -0
- package/lib/es6/src/types/CodegenError.d.ts +66 -0
- package/lib/es6/src/types/CodegenError.mjs +79 -0
- package/lib/es6/src/types/Config.d.ts +31 -0
- package/lib/es6/src/types/Config.mjs +42 -0
- package/lib/es6/src/types/GenerationContext.mjs +47 -0
- package/package.json +53 -0
- package/rescript.json +26 -0
- package/src/Codegen.res +231 -0
- package/src/Types.res +222 -0
- package/src/bindings/Toposort.res +16 -0
- package/src/core/CodegenUtils.res +180 -0
- package/src/core/DocOverride.res +504 -0
- package/src/core/FileSystem.res +63 -0
- package/src/core/IRBuilder.res +66 -0
- package/src/core/OpenAPIParser.res +144 -0
- package/src/core/Pipeline.res +52 -0
- package/src/core/ReferenceResolver.res +41 -0
- package/src/core/Result.res +187 -0
- package/src/core/SchemaIR.res +291 -0
- package/src/core/SchemaIRParser.res +454 -0
- package/src/core/SchemaRefResolver.res +143 -0
- package/src/core/SchemaRegistry.res +107 -0
- package/src/core/SpecDiffer.res +270 -0
- package/src/core/SpecMerger.res +245 -0
- package/src/generators/ComponentSchemaGenerator.res +210 -0
- package/src/generators/DiffReportGenerator.res +152 -0
- package/src/generators/EndpointGenerator.res +176 -0
- package/src/generators/IRToSuryGenerator.res +386 -0
- package/src/generators/IRToTypeGenerator.res +423 -0
- package/src/generators/IRToTypeScriptGenerator.res +77 -0
- package/src/generators/ModuleGenerator.res +363 -0
- package/src/generators/SchemaCodeGenerator.res +84 -0
- package/src/generators/ThinWrapperGenerator.res +124 -0
- package/src/generators/TypeScriptDtsGenerator.res +193 -0
- package/src/generators/TypeScriptWrapperGenerator.res +166 -0
- package/src/types/CodegenError.res +85 -0
- package/src/types/Config.res +95 -0
- package/src/types/GenerationContext.res +56 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as FileSystem from "../core/FileSystem.mjs";
|
|
4
|
+
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
5
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
|
+
import * as OpenAPIParser from "../core/OpenAPIParser.mjs";
|
|
7
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
+
import * as SchemaIRParser from "../core/SchemaIRParser.mjs";
|
|
9
|
+
import * as JsConvertCase from "js-convert-case";
|
|
10
|
+
import * as IRToTypeScriptGenerator from "./IRToTypeScriptGenerator.mjs";
|
|
11
|
+
|
|
12
|
+
function getFirstJsonSchema(contentDict) {
|
|
13
|
+
return Stdlib_Option.flatMap(Stdlib_Option.flatMap(Object.keys(contentDict)[0], contentType => contentDict[contentType]), mediaType => mediaType.schema);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function generateTypeScriptType(name, description, schema) {
|
|
17
|
+
let match = SchemaIRParser.parseJsonSchema(undefined, schema);
|
|
18
|
+
return IRToTypeScriptGenerator.generateNamedType({
|
|
19
|
+
name: name,
|
|
20
|
+
description: description,
|
|
21
|
+
type_: match[0]
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function generateRequestInterface(endpoint, functionName) {
|
|
26
|
+
let requestTypeName = JsConvertCase.toPascalCase(functionName) + `Request`;
|
|
27
|
+
return Stdlib_Option.flatMap(endpoint.requestBody, body => Stdlib_Option.map(getFirstJsonSchema(body.content), schema => generateTypeScriptType(requestTypeName, body.description, schema)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function generateResponseInterface(endpoint, functionName) {
|
|
31
|
+
let responseTypeName = JsConvertCase.toPascalCase(functionName) + `Response`;
|
|
32
|
+
let successCodes = [
|
|
33
|
+
"200",
|
|
34
|
+
"201",
|
|
35
|
+
"202",
|
|
36
|
+
"204"
|
|
37
|
+
];
|
|
38
|
+
let successResponse = Stdlib_Array.filterMap(successCodes, code => endpoint.responses[code])[0];
|
|
39
|
+
return Stdlib_Option.getOr(Stdlib_Option.flatMap(successResponse, response => Stdlib_Option.map(Stdlib_Option.flatMap(response.content, getFirstJsonSchema), schema => generateTypeScriptType(responseTypeName, response.description, schema))), `export type ` + responseTypeName + ` = void;`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function generateMethodSignature(endpoint, functionName) {
|
|
43
|
+
let params = Stdlib_Option.isSome(endpoint.requestBody) ? `client: MisskeyClient, request: ` + JsConvertCase.toPascalCase(functionName) + `Request` : "client: MisskeyClient";
|
|
44
|
+
let docLines = Stdlib_Option.mapOr(endpoint.summary, [], summary => {
|
|
45
|
+
let lines = [
|
|
46
|
+
" /**",
|
|
47
|
+
` * ` + summary
|
|
48
|
+
];
|
|
49
|
+
Stdlib_Option.forEach(endpoint.description, description => {
|
|
50
|
+
if (description !== summary) {
|
|
51
|
+
lines.push(` * ` + description);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
lines.push(" */");
|
|
56
|
+
return lines;
|
|
57
|
+
});
|
|
58
|
+
let code = `
|
|
59
|
+
|` + docLines.join("\n") + `
|
|
60
|
+
| ` + functionName + `(` + params + `): Promise<` + JsConvertCase.toPascalCase(functionName) + `Response>;`;
|
|
61
|
+
return CodegenUtils.trimMargin(code, undefined);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function generateModuleDts(moduleName, endpoints) {
|
|
65
|
+
let interfaces = endpoints.map(endpoint => {
|
|
66
|
+
let functionName = CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method);
|
|
67
|
+
let requestPart = Stdlib_Option.getOr(generateRequestInterface(endpoint, functionName), "");
|
|
68
|
+
let responsePart = generateResponseInterface(endpoint, functionName);
|
|
69
|
+
return [
|
|
70
|
+
requestPart,
|
|
71
|
+
responsePart
|
|
72
|
+
].filter(s => s !== "").join("\n");
|
|
73
|
+
}).join("\n\n");
|
|
74
|
+
let methodSignatures = endpoints.map(endpoint => generateMethodSignature(endpoint, CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method))).join("\n");
|
|
75
|
+
let header = CodegenUtils.trimMargin(`
|
|
76
|
+
|// TypeScript definitions for ` + moduleName + `
|
|
77
|
+
|// Generated by @f3liz/rescript-autogen-openapi
|
|
78
|
+
|// DO NOT EDIT
|
|
79
|
+
|
|
|
80
|
+
|import { MisskeyClient } from './index';
|
|
81
|
+
|import * as ComponentSchemas from './ComponentSchemas';
|
|
82
|
+
|`, undefined);
|
|
83
|
+
return CodegenUtils.trimMargin(`
|
|
84
|
+
|` + header + `
|
|
85
|
+
|
|
|
86
|
+
|` + interfaces + `
|
|
87
|
+
|
|
|
88
|
+
|export interface ` + moduleName + `Module {
|
|
89
|
+
|` + methodSignatures + `
|
|
90
|
+
|}
|
|
91
|
+
|
|
|
92
|
+
|export const ` + moduleName + `: ` + moduleName + `Module;
|
|
93
|
+
|`, undefined);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function generateComponentSchemasDts(schemas) {
|
|
97
|
+
let content = Object.entries(schemas).map(param => {
|
|
98
|
+
let schema = param[1];
|
|
99
|
+
return generateTypeScriptType(param[0], schema.description, schema);
|
|
100
|
+
}).join("\n\n");
|
|
101
|
+
return CodegenUtils.trimMargin(`
|
|
102
|
+
|// TypeScript definitions for ComponentSchemas
|
|
103
|
+
|// Generated by @f3liz/rescript-autogen-openapi
|
|
104
|
+
|// DO NOT EDIT
|
|
105
|
+
|
|
|
106
|
+
|` + content + `
|
|
107
|
+
|`, undefined);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function generateIndexDts(moduleNames) {
|
|
111
|
+
let imports = moduleNames.map(m => `import { ` + m + `Module } from './` + m + `';`).join("\n");
|
|
112
|
+
let $$exports = moduleNames.map(m => `export const ` + m + `: ` + m + `Module;`).join("\n");
|
|
113
|
+
return CodegenUtils.trimMargin(`
|
|
114
|
+
|// TypeScript definitions
|
|
115
|
+
|// Generated by @f3liz/rescript-autogen-openapi
|
|
116
|
+
|// DO NOT EDIT
|
|
117
|
+
|
|
|
118
|
+
|` + imports + `
|
|
119
|
+
|
|
|
120
|
+
|export class MisskeyClient {
|
|
121
|
+
| constructor(baseUrl: string, token?: string);
|
|
122
|
+
| readonly baseUrl: string;
|
|
123
|
+
| readonly token?: string;
|
|
124
|
+
|}
|
|
125
|
+
|
|
|
126
|
+
|` + $$exports + `
|
|
127
|
+
|`, undefined);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function generate(spec, endpoints, outputDir) {
|
|
131
|
+
let endpointsByTag = OpenAPIParser.groupByTag(endpoints);
|
|
132
|
+
let moduleNames = [];
|
|
133
|
+
let files = Stdlib_Array.filterMap(Object.entries(endpointsByTag), param => {
|
|
134
|
+
let tagEndpoints = param[1];
|
|
135
|
+
if (tagEndpoints.length === 0) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
let name = JsConvertCase.toPascalCase(param[0]);
|
|
139
|
+
moduleNames.push(name);
|
|
140
|
+
return {
|
|
141
|
+
path: FileSystem.makePath(outputDir, `types/` + name + `.d.ts`),
|
|
142
|
+
content: generateModuleDts(name, tagEndpoints)
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
Stdlib_Option.forEach(Stdlib_Option.flatMap(spec.components, c => c.schemas), schemas => {
|
|
146
|
+
files.push({
|
|
147
|
+
path: FileSystem.makePath(outputDir, "types/ComponentSchemas.d.ts"),
|
|
148
|
+
content: generateComponentSchemasDts(schemas)
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
files.push({
|
|
152
|
+
path: FileSystem.makePath(outputDir, "types/index.d.ts"),
|
|
153
|
+
content: generateIndexDts(moduleNames)
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
files: files,
|
|
157
|
+
warnings: []
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
getFirstJsonSchema,
|
|
163
|
+
generateTypeScriptType,
|
|
164
|
+
generateRequestInterface,
|
|
165
|
+
generateResponseInterface,
|
|
166
|
+
generateMethodSignature,
|
|
167
|
+
generateModuleDts,
|
|
168
|
+
generateComponentSchemasDts,
|
|
169
|
+
generateIndexDts,
|
|
170
|
+
generate,
|
|
171
|
+
}
|
|
172
|
+
/* FileSystem Not a pure module */
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Pipeline from "../core/Pipeline.mjs";
|
|
4
|
+
import * as FileSystem from "../core/FileSystem.mjs";
|
|
5
|
+
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
6
|
+
import * as OpenAPIParser from "../core/OpenAPIParser.mjs";
|
|
7
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
+
import * as JsConvertCase from "js-convert-case";
|
|
9
|
+
|
|
10
|
+
let misskeyClientJsCode = CodegenUtils.trimMargin(`
|
|
11
|
+
|export class MisskeyClient {
|
|
12
|
+
| constructor(baseUrl, token) {
|
|
13
|
+
| this.baseUrl = baseUrl;
|
|
14
|
+
| this.token = token;
|
|
15
|
+
| }
|
|
16
|
+
|
|
|
17
|
+
| async _fetch(url, method, body) {
|
|
18
|
+
| const headers = { 'Content-Type': 'application/json' };
|
|
19
|
+
| if (this.token) {
|
|
20
|
+
| headers['Authorization'] = \`Bearer \${this.token}\`;
|
|
21
|
+
| }
|
|
22
|
+
| const response = await fetch(this.baseUrl + url, {
|
|
23
|
+
| method,
|
|
24
|
+
| headers,
|
|
25
|
+
| body: body ? JSON.stringify(body) : undefined,
|
|
26
|
+
| });
|
|
27
|
+
| return response.json();
|
|
28
|
+
| }
|
|
29
|
+
|}`, undefined);
|
|
30
|
+
|
|
31
|
+
function generateWrapperMjs(endpoints, generatedModulePath) {
|
|
32
|
+
let endpointsByTag = OpenAPIParser.groupByTag(endpoints);
|
|
33
|
+
let tags = Object.keys(endpointsByTag);
|
|
34
|
+
let imports = tags.map(tag => {
|
|
35
|
+
let moduleName = JsConvertCase.toPascalCase(tag);
|
|
36
|
+
return `import * as ` + moduleName + ` from '` + generatedModulePath + `/` + moduleName + `.mjs';`;
|
|
37
|
+
}).join("\n");
|
|
38
|
+
let wrappers = tags.map(tag => {
|
|
39
|
+
let moduleName = JsConvertCase.toPascalCase(tag);
|
|
40
|
+
let methods = Stdlib_Option.getOr(endpointsByTag[tag], []).map(endpoint => {
|
|
41
|
+
let functionName = CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method);
|
|
42
|
+
let hasRequestBody = Stdlib_Option.isSome(endpoint.requestBody);
|
|
43
|
+
let bodyArg = hasRequestBody ? "body: request, " : "";
|
|
44
|
+
return `
|
|
45
|
+
| async ` + functionName + `(client` + (
|
|
46
|
+
hasRequestBody ? ", request" : ""
|
|
47
|
+
) + `) {
|
|
48
|
+
| return ` + moduleName + `.` + functionName + `({
|
|
49
|
+
| ` + bodyArg + `fetch: (url, method, body) => client._fetch(url, method, body)
|
|
50
|
+
| });
|
|
51
|
+
| },`;
|
|
52
|
+
}).join("\n");
|
|
53
|
+
return `
|
|
54
|
+
|export const ` + moduleName + ` = {
|
|
55
|
+
|` + methods + `
|
|
56
|
+
|};`;
|
|
57
|
+
}).join("\n\n");
|
|
58
|
+
return CodegenUtils.trimMargin(`
|
|
59
|
+
|// Generated wrapper
|
|
60
|
+
|` + imports + `
|
|
61
|
+
|
|
|
62
|
+
|` + misskeyClientJsCode + `
|
|
63
|
+
|
|
|
64
|
+
|` + wrappers + `
|
|
65
|
+
|`, undefined);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function generateWrapperDts(endpoints) {
|
|
69
|
+
let endpointsByTag = OpenAPIParser.groupByTag(endpoints);
|
|
70
|
+
let tags = Object.keys(endpointsByTag);
|
|
71
|
+
let imports = tags.map(tag => {
|
|
72
|
+
let moduleName = JsConvertCase.toPascalCase(tag);
|
|
73
|
+
let typesToImport = Stdlib_Option.getOr(endpointsByTag[tag], []).flatMap(endpoint => {
|
|
74
|
+
let pascalName = JsConvertCase.toPascalCase(CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method));
|
|
75
|
+
if (Stdlib_Option.isSome(endpoint.requestBody)) {
|
|
76
|
+
return [
|
|
77
|
+
` ` + pascalName + `Request,`,
|
|
78
|
+
` ` + pascalName + `Response,`
|
|
79
|
+
];
|
|
80
|
+
} else {
|
|
81
|
+
return [` ` + pascalName + `Response,`];
|
|
82
|
+
}
|
|
83
|
+
}).join("\n");
|
|
84
|
+
return `import type {
|
|
85
|
+
` + typesToImport + `
|
|
86
|
+
} from '../types/` + moduleName + `.d.ts';`;
|
|
87
|
+
}).join("\n");
|
|
88
|
+
let namespaces = tags.map(tag => {
|
|
89
|
+
let moduleName = JsConvertCase.toPascalCase(tag);
|
|
90
|
+
let functions = Stdlib_Option.getOr(endpointsByTag[tag], []).map(endpoint => {
|
|
91
|
+
let functionName = CodegenUtils.generateOperationName(endpoint.operationId, endpoint.path, endpoint.method);
|
|
92
|
+
let pascalName = JsConvertCase.toPascalCase(functionName);
|
|
93
|
+
let docComment = Stdlib_Option.mapOr(endpoint.summary, "", summary => {
|
|
94
|
+
let descriptionPart = Stdlib_Option.mapOr(endpoint.description, "", description => {
|
|
95
|
+
if (description === summary) {
|
|
96
|
+
return "";
|
|
97
|
+
} else {
|
|
98
|
+
return " - " + description;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return ` /** ` + summary + descriptionPart + ` */\n`;
|
|
102
|
+
});
|
|
103
|
+
let requestParam = Stdlib_Option.isSome(endpoint.requestBody) ? `, request: ` + pascalName + `Request` : "";
|
|
104
|
+
return docComment + ` export function ` + functionName + `(client: MisskeyClient` + requestParam + `): Promise<` + pascalName + `Response>;`;
|
|
105
|
+
}).join("\n");
|
|
106
|
+
return `
|
|
107
|
+
|export namespace ` + moduleName + ` {
|
|
108
|
+
|` + functions + `
|
|
109
|
+
|}`;
|
|
110
|
+
}).join("\n\n");
|
|
111
|
+
return CodegenUtils.trimMargin(`
|
|
112
|
+
|// Generated TypeScript definitions for wrapper
|
|
113
|
+
|` + imports + `
|
|
114
|
+
|
|
|
115
|
+
|export class MisskeyClient {
|
|
116
|
+
| constructor(baseUrl: string, token?: string);
|
|
117
|
+
| readonly baseUrl: string;
|
|
118
|
+
| readonly token?: string;
|
|
119
|
+
|}
|
|
120
|
+
|
|
|
121
|
+
|` + namespaces + `
|
|
122
|
+
|`, undefined);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function generate(endpoints, outputDir, generatedModulePathOpt) {
|
|
126
|
+
let generatedModulePath = generatedModulePathOpt !== undefined ? generatedModulePathOpt : "../generated";
|
|
127
|
+
return Pipeline.fromFilesAndWarnings([
|
|
128
|
+
{
|
|
129
|
+
path: FileSystem.makePath(outputDir, "wrapper/index.mjs"),
|
|
130
|
+
content: generateWrapperMjs(endpoints, generatedModulePath)
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
path: FileSystem.makePath(outputDir, "wrapper/index.d.ts"),
|
|
134
|
+
content: generateWrapperDts(endpoints)
|
|
135
|
+
}
|
|
136
|
+
], []);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
misskeyClientJsCode,
|
|
141
|
+
generateWrapperMjs,
|
|
142
|
+
generateWrapperDts,
|
|
143
|
+
generate,
|
|
144
|
+
}
|
|
145
|
+
/* misskeyClientJsCode Not a pure module */
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type context = {
|
|
2
|
+
readonly path: string;
|
|
3
|
+
readonly operation: string;
|
|
4
|
+
readonly schema: (undefined | unknown);
|
|
5
|
+
};
|
|
6
|
+
export type t = {
|
|
7
|
+
TAG: "SpecResolutionError";
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
} | {
|
|
11
|
+
TAG: "SchemaParseError";
|
|
12
|
+
readonly context: context;
|
|
13
|
+
readonly reason: string;
|
|
14
|
+
} | {
|
|
15
|
+
TAG: "ReferenceError";
|
|
16
|
+
readonly ref: string;
|
|
17
|
+
readonly context: context;
|
|
18
|
+
} | {
|
|
19
|
+
TAG: "ValidationError";
|
|
20
|
+
readonly schema: string;
|
|
21
|
+
readonly input: unknown;
|
|
22
|
+
readonly issues: string[];
|
|
23
|
+
} | {
|
|
24
|
+
TAG: "CircularSchemaError";
|
|
25
|
+
readonly ref: string;
|
|
26
|
+
readonly depth: number;
|
|
27
|
+
readonly path: string;
|
|
28
|
+
} | {
|
|
29
|
+
TAG: "FileWriteError";
|
|
30
|
+
readonly filePath: string;
|
|
31
|
+
readonly message: string;
|
|
32
|
+
} | {
|
|
33
|
+
TAG: "InvalidConfigError";
|
|
34
|
+
readonly field: string;
|
|
35
|
+
readonly message: string;
|
|
36
|
+
} | {
|
|
37
|
+
TAG: "UnknownError";
|
|
38
|
+
readonly message: string;
|
|
39
|
+
readonly context: (undefined | context);
|
|
40
|
+
};
|
|
41
|
+
export type Warning_t = {
|
|
42
|
+
TAG: "FallbackToJson";
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
readonly context: context;
|
|
45
|
+
} | {
|
|
46
|
+
TAG: "UnsupportedFeature";
|
|
47
|
+
readonly feature: string;
|
|
48
|
+
readonly fallback: string;
|
|
49
|
+
readonly location: string;
|
|
50
|
+
} | {
|
|
51
|
+
TAG: "DepthLimitReached";
|
|
52
|
+
readonly depth: number;
|
|
53
|
+
readonly path: string;
|
|
54
|
+
} | {
|
|
55
|
+
TAG: "MissingSchema";
|
|
56
|
+
readonly ref: string;
|
|
57
|
+
readonly location: string;
|
|
58
|
+
} | {
|
|
59
|
+
TAG: "IntersectionNotFullySupported";
|
|
60
|
+
readonly location: string;
|
|
61
|
+
readonly note: string;
|
|
62
|
+
} | {
|
|
63
|
+
TAG: "ComplexUnionSimplified";
|
|
64
|
+
readonly location: string;
|
|
65
|
+
readonly types: string;
|
|
66
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function toString(w) {
|
|
5
|
+
switch (w.TAG) {
|
|
6
|
+
case "FallbackToJson" :
|
|
7
|
+
let context = w.context;
|
|
8
|
+
return `⚠️ Falling back to JSON.t at '` + context.path + `' (` + context.operation + `): ` + w.reason;
|
|
9
|
+
case "UnsupportedFeature" :
|
|
10
|
+
return `⚠️ Unsupported feature '` + w.feature + `' at '` + w.location + `', using fallback: ` + w.fallback;
|
|
11
|
+
case "DepthLimitReached" :
|
|
12
|
+
return `⚠️ Depth limit ` + w.depth.toString() + ` reached at '` + w.path + `', using simplified type`;
|
|
13
|
+
case "MissingSchema" :
|
|
14
|
+
return `⚠️ Schema reference '` + w.ref + `' not found at '` + w.location + `'`;
|
|
15
|
+
case "IntersectionNotFullySupported" :
|
|
16
|
+
return `⚠️ Intersection type at '` + w.location + `' not fully supported: ` + w.note;
|
|
17
|
+
case "ComplexUnionSimplified" :
|
|
18
|
+
return `⚠️ Complex union at '` + w.location + `' simplified (types: ` + w.types + `)`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function print(warnings) {
|
|
23
|
+
if (warnings.length !== 0) {
|
|
24
|
+
console.log("\n⚠️ Warnings:");
|
|
25
|
+
warnings.forEach(w => {
|
|
26
|
+
console.log(toString(w));
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let Warning = {
|
|
33
|
+
toString: toString,
|
|
34
|
+
print: print
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function toString$1(e) {
|
|
38
|
+
switch (e.TAG) {
|
|
39
|
+
case "SpecResolutionError" :
|
|
40
|
+
return `Failed to resolve spec from '` + e.url + `': ` + e.message;
|
|
41
|
+
case "SchemaParseError" :
|
|
42
|
+
let context = e.context;
|
|
43
|
+
return `Failed to parse schema at '` + context.path + `' (` + context.operation + `): ` + e.reason;
|
|
44
|
+
case "ReferenceError" :
|
|
45
|
+
let context$1 = e.context;
|
|
46
|
+
return `Failed to resolve reference '` + e.ref + `' at '` + context$1.path + `' (` + context$1.operation + `)`;
|
|
47
|
+
case "ValidationError" :
|
|
48
|
+
return `Validation failed for schema '` + e.schema + `': ` + e.issues.join(", ");
|
|
49
|
+
case "CircularSchemaError" :
|
|
50
|
+
return `Circular schema detected for '` + e.ref + `' at depth ` + e.depth.toString() + ` (path: ` + e.path + `)`;
|
|
51
|
+
case "FileWriteError" :
|
|
52
|
+
return `Failed to write file '` + e.filePath + `': ` + e.message;
|
|
53
|
+
case "InvalidConfigError" :
|
|
54
|
+
return `Invalid configuration for field '` + e.field + `': ` + e.message;
|
|
55
|
+
case "UnknownError" :
|
|
56
|
+
let context$2 = e.context;
|
|
57
|
+
let message = e.message;
|
|
58
|
+
if (context$2 !== undefined) {
|
|
59
|
+
return `Unknown error at '` + context$2.path + `' (` + context$2.operation + `): ` + message;
|
|
60
|
+
} else {
|
|
61
|
+
return `Unknown error: ` + message;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function makeContext(path, operation, schema, param) {
|
|
67
|
+
return {
|
|
68
|
+
path: path,
|
|
69
|
+
operation: operation,
|
|
70
|
+
schema: schema
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
Warning,
|
|
76
|
+
toString$1 as toString,
|
|
77
|
+
makeContext,
|
|
78
|
+
}
|
|
79
|
+
/* No side effect */
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type generationStrategy = "Separate" | "SharedBase";
|
|
2
|
+
export type breakingChangeHandling = "Error" | "Warn" | "Ignore";
|
|
3
|
+
export type forkSpecConfig = {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly specPath: string;
|
|
6
|
+
};
|
|
7
|
+
export type generationTargets = {
|
|
8
|
+
readonly rescriptApi: boolean;
|
|
9
|
+
readonly rescriptWrapper: boolean;
|
|
10
|
+
readonly typescriptDts: boolean;
|
|
11
|
+
readonly typescriptWrapper: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type t = {
|
|
14
|
+
readonly specPath: string;
|
|
15
|
+
readonly forkSpecs: (undefined | forkSpecConfig[]);
|
|
16
|
+
readonly outputDir: string;
|
|
17
|
+
readonly strategy: generationStrategy;
|
|
18
|
+
readonly modulePerTag: boolean;
|
|
19
|
+
readonly includeTags: (undefined | string[]);
|
|
20
|
+
readonly excludeTags: (undefined | string[]);
|
|
21
|
+
readonly generateDiffReport: boolean;
|
|
22
|
+
readonly breakingChangeHandling: breakingChangeHandling;
|
|
23
|
+
readonly generateDocOverrides: (undefined | boolean);
|
|
24
|
+
readonly docOverrideDir: (undefined | string);
|
|
25
|
+
readonly targets: (undefined | generationTargets);
|
|
26
|
+
readonly dtsOutputDir: (undefined | string);
|
|
27
|
+
readonly wrapperOutputDir: (undefined | string);
|
|
28
|
+
readonly baseInstanceName: (undefined | string);
|
|
29
|
+
readonly baseModulePrefix: (undefined | string);
|
|
30
|
+
};
|
|
31
|
+
export declare const make: (specPath: string, outputDir: string, strategy: (undefined | generationStrategy), modulePerTag: (undefined | boolean), includeTags: (undefined | string[]), excludeTags: (undefined | string[]), generateDiffReport: (undefined | boolean), breakingChangeHandling: (undefined | breakingChangeHandling), forkSpecs: (undefined | forkSpecConfig[]), generateDocOverrides: (undefined | boolean), docOverrideDir: (undefined | string), targets: (undefined | generationTargets), dtsOutputDir: (undefined | string), wrapperOutputDir: (undefined | string), baseInstanceName: (undefined | string), baseModulePrefix: (undefined | string), _17: void) => t;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function make(specPath, outputDir, strategyOpt, modulePerTagOpt, includeTags, excludeTags, generateDiffReportOpt, breakingChangeHandlingOpt, forkSpecs, generateDocOverrides, docOverrideDir, targets, dtsOutputDir, wrapperOutputDir, baseInstanceName, baseModulePrefix, param) {
|
|
5
|
+
let strategy = strategyOpt !== undefined ? strategyOpt : "SharedBase";
|
|
6
|
+
let modulePerTag = modulePerTagOpt !== undefined ? modulePerTagOpt : true;
|
|
7
|
+
let generateDiffReport = generateDiffReportOpt !== undefined ? generateDiffReportOpt : true;
|
|
8
|
+
let breakingChangeHandling = breakingChangeHandlingOpt !== undefined ? breakingChangeHandlingOpt : "Warn";
|
|
9
|
+
return {
|
|
10
|
+
specPath: specPath,
|
|
11
|
+
forkSpecs: forkSpecs,
|
|
12
|
+
outputDir: outputDir,
|
|
13
|
+
strategy: strategy,
|
|
14
|
+
modulePerTag: modulePerTag,
|
|
15
|
+
includeTags: includeTags,
|
|
16
|
+
excludeTags: excludeTags,
|
|
17
|
+
generateDiffReport: generateDiffReport,
|
|
18
|
+
breakingChangeHandling: breakingChangeHandling,
|
|
19
|
+
generateDocOverrides: generateDocOverrides,
|
|
20
|
+
docOverrideDir: docOverrideDir,
|
|
21
|
+
targets: targets,
|
|
22
|
+
dtsOutputDir: dtsOutputDir,
|
|
23
|
+
wrapperOutputDir: wrapperOutputDir,
|
|
24
|
+
baseInstanceName: baseInstanceName,
|
|
25
|
+
baseModulePrefix: baseModulePrefix
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function defaultTargets() {
|
|
30
|
+
return {
|
|
31
|
+
rescriptApi: true,
|
|
32
|
+
rescriptWrapper: false,
|
|
33
|
+
typescriptDts: false,
|
|
34
|
+
typescriptWrapper: false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
make,
|
|
40
|
+
defaultTargets,
|
|
41
|
+
}
|
|
42
|
+
/* No side effect */
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as SchemaIR from "../core/SchemaIR.mjs";
|
|
4
|
+
|
|
5
|
+
function make(path, insideComponentSchemasOpt, availableSchemas, modulePrefixOpt, selfRefName, param) {
|
|
6
|
+
let insideComponentSchemas = insideComponentSchemasOpt !== undefined ? insideComponentSchemasOpt : false;
|
|
7
|
+
let modulePrefix = modulePrefixOpt !== undefined ? modulePrefixOpt : "";
|
|
8
|
+
return {
|
|
9
|
+
warnings: [],
|
|
10
|
+
extractedTypes: [],
|
|
11
|
+
extractCounter: 0,
|
|
12
|
+
path: path,
|
|
13
|
+
insideComponentSchemas: insideComponentSchemas,
|
|
14
|
+
availableSchemas: availableSchemas,
|
|
15
|
+
modulePrefix: modulePrefix,
|
|
16
|
+
selfRefName: selfRefName
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function addWarning(ctx, warning) {
|
|
21
|
+
ctx.warnings.push(warning);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function extractType(ctx, baseName, isUnboxedOpt, irType) {
|
|
25
|
+
let isUnboxed = isUnboxedOpt !== undefined ? isUnboxedOpt : false;
|
|
26
|
+
let existing = ctx.extractedTypes.find(param => SchemaIR.equals(param.irType, irType));
|
|
27
|
+
if (existing !== undefined) {
|
|
28
|
+
return existing.typeName;
|
|
29
|
+
}
|
|
30
|
+
ctx.extractCounter = ctx.extractCounter + 1 | 0;
|
|
31
|
+
let first = baseName.charAt(0);
|
|
32
|
+
let lowerBaseName = first === "" ? "extracted" : first.toLowerCase() + baseName.slice(1);
|
|
33
|
+
let typeName = lowerBaseName + `_` + ctx.extractCounter.toString();
|
|
34
|
+
ctx.extractedTypes.push({
|
|
35
|
+
typeName: typeName,
|
|
36
|
+
irType: irType,
|
|
37
|
+
isUnboxed: isUnboxed
|
|
38
|
+
});
|
|
39
|
+
return typeName;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
make,
|
|
44
|
+
addWarning,
|
|
45
|
+
extractType,
|
|
46
|
+
}
|
|
47
|
+
/* No side effect */
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@f3liz/rescript-autogen-openapi",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Generate ReScript code with Sury schemas from OpenAPI 3.1 specs. Supports multiple forks with diff/merge capabilities.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"rescript",
|
|
7
|
+
"openapi",
|
|
8
|
+
"codegen",
|
|
9
|
+
"sury",
|
|
10
|
+
"schema",
|
|
11
|
+
"misskey",
|
|
12
|
+
"api",
|
|
13
|
+
"generator"
|
|
14
|
+
],
|
|
15
|
+
"author": "NyanRus",
|
|
16
|
+
"license": "MPL-2.0",
|
|
17
|
+
"files": [
|
|
18
|
+
"src/**/*.res",
|
|
19
|
+
"lib/es6/src/**/*.mjs",
|
|
20
|
+
"lib/es6/src/**/*.d.ts",
|
|
21
|
+
"rescript.json",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"url": "https://github.com/f3liz-dev/rescript-autogen-openapi"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "rescript && node scripts/generate-dts.mjs",
|
|
30
|
+
"clean": "rescript clean",
|
|
31
|
+
"watch": "rescript build -w",
|
|
32
|
+
"test": "node --test",
|
|
33
|
+
"prepublishOnly": "npm run build && npm test"
|
|
34
|
+
},
|
|
35
|
+
"main": "lib/es6/src/Codegen.mjs",
|
|
36
|
+
"types": "lib/es6/src/Codegen.d.ts",
|
|
37
|
+
"type": "module",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@readme/openapi-parser": "^5.5.0",
|
|
40
|
+
"js-convert-case": "^4.2.0",
|
|
41
|
+
"pathe": "^2.0.3",
|
|
42
|
+
"toposort": "^2.0.2"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"rescript": "^12.1.0",
|
|
46
|
+
"sury": "11.0.0-alpha.4",
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"rescript": "^12.0.0",
|
|
51
|
+
"sury": ">=11.0.0-alpha.4"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/rescript.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@f3liz/rescript-autogen-openapi",
|
|
3
|
+
"sources": [
|
|
4
|
+
{
|
|
5
|
+
"dir": "src",
|
|
6
|
+
"subdirs": true
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"package-specs": [
|
|
10
|
+
{
|
|
11
|
+
"module": "esmodule",
|
|
12
|
+
"in-source": false
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"suffix": ".mjs",
|
|
16
|
+
"gentypeconfig": {
|
|
17
|
+
"language": "typescript",
|
|
18
|
+
"module": "es6",
|
|
19
|
+
"importPath": "relative",
|
|
20
|
+
"generatedFileExtension": ".gen.ts"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": [],
|
|
23
|
+
"warnings": {
|
|
24
|
+
"number": "-44-102"
|
|
25
|
+
}
|
|
26
|
+
}
|