@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,237 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as SpecDiffer from "./SpecDiffer.mjs";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
|
|
6
|
+
function makeEndpointKey(endpoint) {
|
|
7
|
+
return endpoint.method + `:` + endpoint.path;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function extractSharedEndpoints(baseEndpoints, _forkEndpoints) {
|
|
11
|
+
return baseEndpoints;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function extractForkExtensions(baseEndpoints, forkEndpoints) {
|
|
15
|
+
let baseMap = {};
|
|
16
|
+
baseEndpoints.forEach(ep => {
|
|
17
|
+
let key = makeEndpointKey(ep);
|
|
18
|
+
baseMap[key] = ep;
|
|
19
|
+
});
|
|
20
|
+
return forkEndpoints.filter(forkEp => {
|
|
21
|
+
let key = makeEndpointKey(forkEp);
|
|
22
|
+
let baseEp = baseMap[key];
|
|
23
|
+
if (baseEp !== undefined) {
|
|
24
|
+
return SpecDiffer.compareEndpoints(baseEp, forkEp) !== undefined;
|
|
25
|
+
} else {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function extractSharedSchemas(baseSchemas, _forkSchemas) {
|
|
32
|
+
return baseSchemas;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function extractForkSchemas(baseSchemas, forkSchemas) {
|
|
36
|
+
if (forkSchemas === undefined) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (baseSchemas === undefined) {
|
|
40
|
+
return forkSchemas;
|
|
41
|
+
}
|
|
42
|
+
let extensions = {};
|
|
43
|
+
Object.keys(forkSchemas).forEach(name => {
|
|
44
|
+
let match = baseSchemas[name];
|
|
45
|
+
let match$1 = forkSchemas[name];
|
|
46
|
+
if (match !== undefined) {
|
|
47
|
+
if (match$1 !== undefined && !SpecDiffer.schemasEqual(match, match$1)) {
|
|
48
|
+
extensions[name] = match$1;
|
|
49
|
+
return;
|
|
50
|
+
} else {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
} else if (match$1 !== undefined) {
|
|
54
|
+
extensions[name] = match$1;
|
|
55
|
+
return;
|
|
56
|
+
} else {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (Object.keys(extensions).length !== 0) {
|
|
61
|
+
return extensions;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function createSpecWithEndpoints(baseSpec, endpoints, schemas) {
|
|
66
|
+
let pathsDict = {};
|
|
67
|
+
endpoints.forEach(ep => {
|
|
68
|
+
let existing = pathsDict[ep.path];
|
|
69
|
+
let pathItem = existing !== undefined ? existing : ({
|
|
70
|
+
get: undefined,
|
|
71
|
+
post: undefined,
|
|
72
|
+
put: undefined,
|
|
73
|
+
patch: undefined,
|
|
74
|
+
delete: undefined,
|
|
75
|
+
head: undefined,
|
|
76
|
+
options: undefined,
|
|
77
|
+
parameters: undefined
|
|
78
|
+
});
|
|
79
|
+
let operation_operationId = ep.operationId;
|
|
80
|
+
let operation_summary = ep.summary;
|
|
81
|
+
let operation_description = ep.description;
|
|
82
|
+
let operation_tags = ep.tags;
|
|
83
|
+
let operation_requestBody = ep.requestBody;
|
|
84
|
+
let operation_responses = ep.responses;
|
|
85
|
+
let operation_parameters = ep.parameters;
|
|
86
|
+
let operation = {
|
|
87
|
+
operationId: operation_operationId,
|
|
88
|
+
summary: operation_summary,
|
|
89
|
+
description: operation_description,
|
|
90
|
+
tags: operation_tags,
|
|
91
|
+
requestBody: operation_requestBody,
|
|
92
|
+
responses: operation_responses,
|
|
93
|
+
parameters: operation_parameters
|
|
94
|
+
};
|
|
95
|
+
let match = ep.method.toLowerCase();
|
|
96
|
+
let updatedPathItem;
|
|
97
|
+
switch (match) {
|
|
98
|
+
case "delete" :
|
|
99
|
+
updatedPathItem = {
|
|
100
|
+
get: pathItem.get,
|
|
101
|
+
post: pathItem.post,
|
|
102
|
+
put: pathItem.put,
|
|
103
|
+
patch: pathItem.patch,
|
|
104
|
+
delete: operation,
|
|
105
|
+
head: pathItem.head,
|
|
106
|
+
options: pathItem.options,
|
|
107
|
+
parameters: pathItem.parameters
|
|
108
|
+
};
|
|
109
|
+
break;
|
|
110
|
+
case "get" :
|
|
111
|
+
updatedPathItem = {
|
|
112
|
+
get: operation,
|
|
113
|
+
post: pathItem.post,
|
|
114
|
+
put: pathItem.put,
|
|
115
|
+
patch: pathItem.patch,
|
|
116
|
+
delete: pathItem.delete,
|
|
117
|
+
head: pathItem.head,
|
|
118
|
+
options: pathItem.options,
|
|
119
|
+
parameters: pathItem.parameters
|
|
120
|
+
};
|
|
121
|
+
break;
|
|
122
|
+
case "patch" :
|
|
123
|
+
updatedPathItem = {
|
|
124
|
+
get: pathItem.get,
|
|
125
|
+
post: pathItem.post,
|
|
126
|
+
put: pathItem.put,
|
|
127
|
+
patch: operation,
|
|
128
|
+
delete: pathItem.delete,
|
|
129
|
+
head: pathItem.head,
|
|
130
|
+
options: pathItem.options,
|
|
131
|
+
parameters: pathItem.parameters
|
|
132
|
+
};
|
|
133
|
+
break;
|
|
134
|
+
case "post" :
|
|
135
|
+
updatedPathItem = {
|
|
136
|
+
get: pathItem.get,
|
|
137
|
+
post: operation,
|
|
138
|
+
put: pathItem.put,
|
|
139
|
+
patch: pathItem.patch,
|
|
140
|
+
delete: pathItem.delete,
|
|
141
|
+
head: pathItem.head,
|
|
142
|
+
options: pathItem.options,
|
|
143
|
+
parameters: pathItem.parameters
|
|
144
|
+
};
|
|
145
|
+
break;
|
|
146
|
+
case "put" :
|
|
147
|
+
updatedPathItem = {
|
|
148
|
+
get: pathItem.get,
|
|
149
|
+
post: pathItem.post,
|
|
150
|
+
put: operation,
|
|
151
|
+
patch: pathItem.patch,
|
|
152
|
+
delete: pathItem.delete,
|
|
153
|
+
head: pathItem.head,
|
|
154
|
+
options: pathItem.options,
|
|
155
|
+
parameters: pathItem.parameters
|
|
156
|
+
};
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
updatedPathItem = pathItem;
|
|
160
|
+
}
|
|
161
|
+
pathsDict[ep.path] = updatedPathItem;
|
|
162
|
+
});
|
|
163
|
+
let match = baseSpec.components;
|
|
164
|
+
let components = match !== undefined ? (
|
|
165
|
+
schemas !== undefined ? ({
|
|
166
|
+
schemas: schemas
|
|
167
|
+
}) : ({
|
|
168
|
+
schemas: undefined
|
|
169
|
+
})
|
|
170
|
+
) : (
|
|
171
|
+
schemas !== undefined ? ({
|
|
172
|
+
schemas: schemas
|
|
173
|
+
}) : undefined
|
|
174
|
+
);
|
|
175
|
+
return {
|
|
176
|
+
openapi: baseSpec.openapi,
|
|
177
|
+
info: baseSpec.info,
|
|
178
|
+
paths: pathsDict,
|
|
179
|
+
components: components
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function mergeWithSharedBase(baseSpec, forkSpec, baseEndpoints, forkEndpoints) {
|
|
184
|
+
let forkExtensions = extractForkExtensions(baseEndpoints, forkEndpoints);
|
|
185
|
+
let baseSchemas = Stdlib_Option.flatMap(baseSpec.components, c => c.schemas);
|
|
186
|
+
let forkSchemas = Stdlib_Option.flatMap(forkSpec.components, c => c.schemas);
|
|
187
|
+
let extensionSchemas = extractForkSchemas(baseSchemas, forkSchemas);
|
|
188
|
+
let sharedSpec = createSpecWithEndpoints(baseSpec, baseEndpoints, baseSchemas);
|
|
189
|
+
let extensionsSpec = createSpecWithEndpoints(forkSpec, forkExtensions, extensionSchemas);
|
|
190
|
+
return [
|
|
191
|
+
sharedSpec,
|
|
192
|
+
extensionsSpec
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function mergeWithSeparate(baseSpec, forkSpec) {
|
|
197
|
+
return [
|
|
198
|
+
baseSpec,
|
|
199
|
+
forkSpec
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function mergeSpecs(baseSpec, forkSpec, baseEndpoints, forkEndpoints, strategy) {
|
|
204
|
+
if (strategy === "Separate") {
|
|
205
|
+
return [
|
|
206
|
+
baseSpec,
|
|
207
|
+
forkSpec
|
|
208
|
+
];
|
|
209
|
+
} else {
|
|
210
|
+
return mergeWithSharedBase(baseSpec, forkSpec, baseEndpoints, forkEndpoints);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getMergeStats(baseEndpoints, forkEndpoints, baseSchemas, forkSchemas) {
|
|
215
|
+
let extensions = extractForkExtensions(baseEndpoints, forkEndpoints);
|
|
216
|
+
let extensionSchemas = extractForkSchemas(baseSchemas, forkSchemas);
|
|
217
|
+
return {
|
|
218
|
+
sharedEndpointCount: baseEndpoints.length,
|
|
219
|
+
forkExtensionCount: extensions.length,
|
|
220
|
+
sharedSchemaCount: Stdlib_Option.mapOr(baseSchemas, 0, s => Object.keys(s).length),
|
|
221
|
+
forkSchemaCount: Stdlib_Option.mapOr(extensionSchemas, 0, s => Object.keys(s).length)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export {
|
|
226
|
+
makeEndpointKey,
|
|
227
|
+
extractSharedEndpoints,
|
|
228
|
+
extractForkExtensions,
|
|
229
|
+
extractSharedSchemas,
|
|
230
|
+
extractForkSchemas,
|
|
231
|
+
createSpecWithEndpoints,
|
|
232
|
+
mergeWithSharedBase,
|
|
233
|
+
mergeWithSeparate,
|
|
234
|
+
mergeSpecs,
|
|
235
|
+
getMergeStats,
|
|
236
|
+
}
|
|
237
|
+
/* No side effect */
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Pipeline from "../core/Pipeline.mjs";
|
|
4
|
+
import * as Toposort from "../bindings/Toposort.mjs";
|
|
5
|
+
import * as FileSystem from "../core/FileSystem.mjs";
|
|
6
|
+
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
7
|
+
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
8
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
9
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
|
+
import * as SchemaIRParser from "../core/SchemaIRParser.mjs";
|
|
11
|
+
import * as JsConvertCase from "js-convert-case";
|
|
12
|
+
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
13
|
+
import * as GenerationContext from "../types/GenerationContext.mjs";
|
|
14
|
+
import * as IRToSuryGenerator from "./IRToSuryGenerator.mjs";
|
|
15
|
+
import * as IRToTypeGenerator from "./IRToTypeGenerator.mjs";
|
|
16
|
+
|
|
17
|
+
function extractReferencedSchemaNames(_irType) {
|
|
18
|
+
while (true) {
|
|
19
|
+
let irType = _irType;
|
|
20
|
+
if (typeof irType !== "object") {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
switch (irType.TAG) {
|
|
24
|
+
case "Array" :
|
|
25
|
+
_irType = irType.items;
|
|
26
|
+
continue;
|
|
27
|
+
case "Object" :
|
|
28
|
+
return irType.properties.flatMap(param => extractReferencedSchemaNames(param[1]));
|
|
29
|
+
case "Union" :
|
|
30
|
+
case "Intersection" :
|
|
31
|
+
return irType._0.flatMap(extractReferencedSchemaNames);
|
|
32
|
+
case "Reference" :
|
|
33
|
+
return [irType._0];
|
|
34
|
+
case "Option" :
|
|
35
|
+
_irType = irType._0;
|
|
36
|
+
continue;
|
|
37
|
+
default:
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function generate(spec, outputDir) {
|
|
44
|
+
let match = Stdlib_Option.mapOr(Stdlib_Option.flatMap(spec.components, components => components.schemas), [
|
|
45
|
+
{
|
|
46
|
+
schemas: {}
|
|
47
|
+
},
|
|
48
|
+
[]
|
|
49
|
+
], SchemaIRParser.parseComponentSchemas);
|
|
50
|
+
let context = match[0];
|
|
51
|
+
if (Stdlib_Dict.size(context.schemas) === 0) {
|
|
52
|
+
return Pipeline.empty;
|
|
53
|
+
}
|
|
54
|
+
let schemas = Object.values(context.schemas);
|
|
55
|
+
let schemaNameMap = Object.fromEntries(schemas.map(s => [
|
|
56
|
+
s.name,
|
|
57
|
+
s
|
|
58
|
+
]));
|
|
59
|
+
let allNodes = schemas.map(s => s.name);
|
|
60
|
+
let edges = schemas.flatMap(schema => {
|
|
61
|
+
let references = extractReferencedSchemaNames(schema.type_).filter(name => {
|
|
62
|
+
if (name in schemaNameMap) {
|
|
63
|
+
return name !== schema.name;
|
|
64
|
+
} else {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return references.map(dep => [
|
|
69
|
+
schema.name,
|
|
70
|
+
dep
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
let sortedNames;
|
|
74
|
+
try {
|
|
75
|
+
sortedNames = Toposort.sortArray(allNodes, edges).toReversed();
|
|
76
|
+
} catch (exn) {
|
|
77
|
+
let visited = {};
|
|
78
|
+
let inStack = {};
|
|
79
|
+
let cycleEdges = [];
|
|
80
|
+
let dfs = node => {
|
|
81
|
+
if (Stdlib_Option.getOr(inStack[node], false) || Stdlib_Option.getOr(visited[node], false)) {
|
|
82
|
+
return;
|
|
83
|
+
} else {
|
|
84
|
+
visited[node] = true;
|
|
85
|
+
inStack[node] = true;
|
|
86
|
+
edges.forEach(param => {
|
|
87
|
+
let from = param[0];
|
|
88
|
+
if (from !== node) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let to = param[1];
|
|
92
|
+
if (Stdlib_Option.getOr(inStack[to], false)) {
|
|
93
|
+
cycleEdges.push([
|
|
94
|
+
from,
|
|
95
|
+
to
|
|
96
|
+
]);
|
|
97
|
+
return;
|
|
98
|
+
} else {
|
|
99
|
+
return dfs(to);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
inStack[node] = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
allNodes.forEach(dfs);
|
|
107
|
+
let nonCycleEdges = edges.filter(param => {
|
|
108
|
+
let to = param[1];
|
|
109
|
+
let from = param[0];
|
|
110
|
+
return !cycleEdges.some(param => {
|
|
111
|
+
if (param[0] === from) {
|
|
112
|
+
return param[1] === to;
|
|
113
|
+
} else {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
try {
|
|
119
|
+
sortedNames = Toposort.sortArray(allNodes, nonCycleEdges).toReversed();
|
|
120
|
+
} catch (exn$1) {
|
|
121
|
+
sortedNames = allNodes.toSorted(Primitive_string.compare);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
let finalSortedSchemas = Stdlib_Array.filterMap(sortedNames, name => schemaNameMap[name]);
|
|
125
|
+
let availableSchemaNames = finalSortedSchemas.map(s => s.name);
|
|
126
|
+
let warnings = match[1].slice();
|
|
127
|
+
let selfRefSchemas = {};
|
|
128
|
+
finalSortedSchemas.forEach(schema => {
|
|
129
|
+
let refs = extractReferencedSchemaNames(schema.type_);
|
|
130
|
+
if (refs.some(name => name === schema.name)) {
|
|
131
|
+
selfRefSchemas[schema.name] = true;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
let moduleCodes = finalSortedSchemas.map(schema => {
|
|
136
|
+
let isSelfRef = Stdlib_Option.getOr(selfRefSchemas[schema.name], false);
|
|
137
|
+
let selfRefName = isSelfRef ? schema.name : undefined;
|
|
138
|
+
let typeCtx = GenerationContext.make(`ComponentSchemas.` + schema.name, true, availableSchemaNames, undefined, selfRefName, undefined);
|
|
139
|
+
let typeCode = IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, undefined, schema.type_);
|
|
140
|
+
let processed = 0;
|
|
141
|
+
while (processed < typeCtx.extractedTypes.length) {
|
|
142
|
+
let idx = processed;
|
|
143
|
+
let match = typeCtx.extractedTypes[idx];
|
|
144
|
+
let irType = match.irType;
|
|
145
|
+
if (match.isUnboxed && typeof irType === "object" && irType.TAG === "Union") {
|
|
146
|
+
irType._0.forEach(memberType => {
|
|
147
|
+
IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, true, memberType);
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, false, irType);
|
|
151
|
+
}
|
|
152
|
+
processed = idx + 1 | 0;
|
|
153
|
+
};
|
|
154
|
+
let allExtracted = typeCtx.extractedTypes.slice().toReversed();
|
|
155
|
+
let extractedTypeMap = allExtracted.length !== 0 ? allExtracted : undefined;
|
|
156
|
+
let schemaCtx = GenerationContext.make(`ComponentSchemas.` + schema.name, true, availableSchemaNames, undefined, selfRefName, undefined);
|
|
157
|
+
let schemaCode = IRToSuryGenerator.generateSchemaWithContext(schemaCtx, 0, extractedTypeMap, schema.type_);
|
|
158
|
+
warnings.push(...typeCtx.warnings);
|
|
159
|
+
warnings.push(...schemaCtx.warnings);
|
|
160
|
+
let extractedTypeDefs = allExtracted.map(param => {
|
|
161
|
+
let irType = param.irType;
|
|
162
|
+
let typeName = param.typeName;
|
|
163
|
+
let auxTypeCode;
|
|
164
|
+
if (param.isUnboxed) {
|
|
165
|
+
let exit = 0;
|
|
166
|
+
if (typeof irType !== "object" || irType.TAG !== "Union") {
|
|
167
|
+
exit = 1;
|
|
168
|
+
} else {
|
|
169
|
+
let body = IRToTypeGenerator.generateUnboxedVariantBody(typeCtx, irType._0);
|
|
170
|
+
auxTypeCode = `@unboxed type ` + typeName + ` = ` + body;
|
|
171
|
+
}
|
|
172
|
+
if (exit === 1) {
|
|
173
|
+
let auxType = IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, undefined, irType);
|
|
174
|
+
auxTypeCode = `type ` + typeName + ` = ` + auxType;
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
let auxType$1 = IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, undefined, irType);
|
|
178
|
+
auxTypeCode = `type ` + typeName + ` = ` + auxType$1;
|
|
179
|
+
}
|
|
180
|
+
let auxSchemaCtx = GenerationContext.make(`ComponentSchemas.` + schema.name + `.` + typeName, true, availableSchemaNames, undefined, undefined, undefined);
|
|
181
|
+
let filteredMap = allExtracted.filter(param => param.typeName !== typeName);
|
|
182
|
+
let auxExtractedTypeMap = filteredMap.length !== 0 ? filteredMap : undefined;
|
|
183
|
+
let auxSchema = IRToSuryGenerator.generateSchemaWithContext(auxSchemaCtx, 0, auxExtractedTypeMap, irType);
|
|
184
|
+
return ` ` + auxTypeCode + `\n let ` + typeName + `Schema = ` + auxSchema;
|
|
185
|
+
});
|
|
186
|
+
let docComment = Stdlib_Option.mapOr(schema.description, "", d => CodegenUtils.generateDocString(undefined, d, undefined));
|
|
187
|
+
let extractedBlock = extractedTypeDefs.length !== 0 ? extractedTypeDefs.join("\n") + "\n" : "";
|
|
188
|
+
let typeKeyword = isSelfRef ? "type rec t" : "type t";
|
|
189
|
+
let finalSchemaCode = isSelfRef ? `S.recursive("` + schema.name + `", schema => ` + schemaCode + `)` : schemaCode;
|
|
190
|
+
return docComment + `module ` + JsConvertCase.toPascalCase(schema.name) + ` = {
|
|
191
|
+
` + extractedBlock + ` ` + typeKeyword + ` = ` + typeCode + `
|
|
192
|
+
let schema = ` + finalSchemaCode + `
|
|
193
|
+
}`;
|
|
194
|
+
});
|
|
195
|
+
let fileHeader = CodegenUtils.generateFileHeader("Shared component schemas");
|
|
196
|
+
let fileContent = fileHeader + `\n\n` + moduleCodes.join("\n\n");
|
|
197
|
+
return Pipeline.fromFilesAndWarnings([{
|
|
198
|
+
path: FileSystem.makePath(outputDir, "ComponentSchemas.res"),
|
|
199
|
+
content: fileContent
|
|
200
|
+
}], warnings);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
extractReferencedSchemaNames,
|
|
205
|
+
generate,
|
|
206
|
+
}
|
|
207
|
+
/* Toposort Not a pure module */
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as SpecDiffer from "../core/SpecDiffer.mjs";
|
|
4
|
+
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
7
|
+
|
|
8
|
+
function formatEndpointName(endpoint) {
|
|
9
|
+
let methodPart = endpoint.method.toUpperCase();
|
|
10
|
+
let operationIdPart = Stdlib_Option.mapOr(endpoint.operationId, "", id => ` (` + id + `)`);
|
|
11
|
+
return methodPart + ` ` + endpoint.path + operationIdPart;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function formatTags(tags) {
|
|
15
|
+
return Stdlib_Option.mapOr(tags, "", tagList => {
|
|
16
|
+
if (tagList.length === 0) {
|
|
17
|
+
return "";
|
|
18
|
+
} else {
|
|
19
|
+
return ` [` + tagList.join(", ") + `]`;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function generateMarkdownReport(diff, baseName, forkName) {
|
|
25
|
+
let generateSection = (title, items, formatter) => {
|
|
26
|
+
if (items.length === 0) {
|
|
27
|
+
return "";
|
|
28
|
+
} else {
|
|
29
|
+
return `\n### ` + title + `\n\n` + items.map(formatter).join("\n") + `\n`;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
let totalChanges = SpecDiffer.countChanges(diff);
|
|
33
|
+
let breakingChangesText = SpecDiffer.hasBreakingChanges(diff) ? "⚠️ Yes" : "✓ No";
|
|
34
|
+
let summaryLines = [
|
|
35
|
+
`- **Total Changes**: ` + totalChanges.toString(),
|
|
36
|
+
`- **Added Endpoints**: ` + diff.addedEndpoints.length.toString(),
|
|
37
|
+
`- **Removed Endpoints**: ` + diff.removedEndpoints.length.toString(),
|
|
38
|
+
`- **Modified Endpoints**: ` + diff.modifiedEndpoints.length.toString(),
|
|
39
|
+
`- **Added Schemas**: ` + diff.addedSchemas.length.toString(),
|
|
40
|
+
`- **Removed Schemas**: ` + diff.removedSchemas.length.toString(),
|
|
41
|
+
`- **Modified Schemas**: ` + diff.modifiedSchemas.length.toString(),
|
|
42
|
+
`- **Breaking Changes**: ` + breakingChangesText
|
|
43
|
+
].join("\n");
|
|
44
|
+
let reportParts = [
|
|
45
|
+
`# API Diff Report: ` + baseName + ` → ` + forkName + `\n\n## Summary\n\n` + summaryLines,
|
|
46
|
+
generateSection("Added Endpoints", diff.addedEndpoints, endpoint => {
|
|
47
|
+
let endpointName = formatEndpointName(endpoint);
|
|
48
|
+
let tags = formatTags(endpoint.tags);
|
|
49
|
+
let summary = Stdlib_Option.mapOr(endpoint.summary, "", summary => `\n ` + summary);
|
|
50
|
+
return `- **` + endpointName + `**` + tags + summary;
|
|
51
|
+
}),
|
|
52
|
+
generateSection("Removed Endpoints", diff.removedEndpoints, endpoint => {
|
|
53
|
+
let endpointName = formatEndpointName(endpoint);
|
|
54
|
+
let tags = formatTags(endpoint.tags);
|
|
55
|
+
return `- **` + endpointName + `**` + tags;
|
|
56
|
+
}),
|
|
57
|
+
generateSection("Modified Endpoints", diff.modifiedEndpoints, endpointDiff => {
|
|
58
|
+
let methodPart = endpointDiff.method.toUpperCase();
|
|
59
|
+
let breakingText = endpointDiff.breakingChange ? " **⚠️ BREAKING**" : "";
|
|
60
|
+
let changes = [
|
|
61
|
+
endpointDiff.requestBodyChanged ? "body" : "",
|
|
62
|
+
endpointDiff.responseChanged ? "response" : ""
|
|
63
|
+
].filter(x => x !== "").join(", ");
|
|
64
|
+
return `- **` + methodPart + ` ` + endpointDiff.path + `**` + breakingText + `: Changed ` + changes;
|
|
65
|
+
}),
|
|
66
|
+
generateSection("Added Schemas", diff.addedSchemas, schemaName => `- \`` + schemaName + `\``),
|
|
67
|
+
generateSection("Removed Schemas", diff.removedSchemas, schemaName => `- \`` + schemaName + `\``),
|
|
68
|
+
generateSection("Modified Schemas", diff.modifiedSchemas, schemaDiff => {
|
|
69
|
+
let breakingText = schemaDiff.breakingChange ? " **⚠️ BREAKING**" : "";
|
|
70
|
+
return `- \`` + schemaDiff.name + `\`` + breakingText;
|
|
71
|
+
}),
|
|
72
|
+
`\n---\n*Generated on ` + new Date().toISOString() + `*`
|
|
73
|
+
];
|
|
74
|
+
return reportParts.filter(part => part !== "").join("\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function generateCompactSummary(diff) {
|
|
78
|
+
let totalChanges = SpecDiffer.countChanges(diff);
|
|
79
|
+
let addedCount = diff.addedEndpoints.length;
|
|
80
|
+
let removedCount = diff.removedEndpoints.length;
|
|
81
|
+
let modifiedCount = diff.modifiedEndpoints.length;
|
|
82
|
+
let breakingText = SpecDiffer.hasBreakingChanges(diff) ? " (BREAKING)" : "";
|
|
83
|
+
return `Found ` + totalChanges.toString() + ` changes: +` + addedCount.toString() + ` -` + removedCount.toString() + ` ~` + modifiedCount.toString() + ` endpoints` + breakingText;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function generateMergeReport(stats, baseName, forkName) {
|
|
87
|
+
let sharedEndpoints = stats.sharedEndpointCount.toString();
|
|
88
|
+
let sharedSchemas = stats.sharedSchemaCount.toString();
|
|
89
|
+
let extensionEndpoints = stats.forkExtensionCount.toString();
|
|
90
|
+
let extensionSchemas = stats.forkSchemaCount.toString();
|
|
91
|
+
return CodegenUtils.trimMargin(`
|
|
92
|
+
|# Merge Report: ` + baseName + ` + ` + forkName + `
|
|
93
|
+
|
|
|
94
|
+
|## Shared Code
|
|
95
|
+
|
|
|
96
|
+
|- **Shared Endpoints**: ` + sharedEndpoints + `
|
|
97
|
+
|- **Shared Schemas**: ` + sharedSchemas + `
|
|
98
|
+
|
|
|
99
|
+
|## ` + forkName + ` Extensions
|
|
100
|
+
|
|
|
101
|
+
|- **Extension Endpoints**: ` + extensionEndpoints + `
|
|
102
|
+
|- **Extension Schemas**: ` + extensionSchemas + `
|
|
103
|
+
|
|
|
104
|
+
|## Summary
|
|
105
|
+
|
|
|
106
|
+
|The shared base contains ` + sharedEndpoints + ` endpoints and ` + sharedSchemas + ` schemas.
|
|
107
|
+
|
|
|
108
|
+
|` + forkName + ` adds ` + extensionEndpoints + ` endpoints and ` + extensionSchemas + ` schemas.
|
|
109
|
+
|
|
|
110
|
+
|---
|
|
111
|
+
|*Generated on ` + new Date().toISOString() + `*
|
|
112
|
+
|`, undefined);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function generateEndpointsByTagReport(endpoints) {
|
|
116
|
+
let endpointsByTag = {};
|
|
117
|
+
let untaggedEndpoints = [];
|
|
118
|
+
endpoints.forEach(endpoint => {
|
|
119
|
+
let tags = endpoint.tags;
|
|
120
|
+
if (tags !== undefined && tags.length !== 0) {
|
|
121
|
+
tags.forEach(tag => {
|
|
122
|
+
let existing = Stdlib_Option.getOr(endpointsByTag[tag], []);
|
|
123
|
+
existing.push(endpoint);
|
|
124
|
+
endpointsByTag[tag] = existing;
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
untaggedEndpoints.push(endpoint);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
let tagSections = Object.keys(endpointsByTag).toSorted(Primitive_string.compare).map(tag => {
|
|
131
|
+
let tagEndpoints = Stdlib_Option.getOr(endpointsByTag[tag], []);
|
|
132
|
+
let count = tagEndpoints.length.toString();
|
|
133
|
+
let endpointList = tagEndpoints.map(endpoint => `- ` + formatEndpointName(endpoint)).join("\n");
|
|
134
|
+
return `### ` + tag + ` (` + count + `)\n\n` + endpointList;
|
|
135
|
+
}).join("\n\n");
|
|
136
|
+
let untaggedSection;
|
|
137
|
+
if (untaggedEndpoints.length !== 0) {
|
|
138
|
+
let count = untaggedEndpoints.length.toString();
|
|
139
|
+
let endpointList = untaggedEndpoints.map(endpoint => `- ` + formatEndpointName(endpoint)).join("\n");
|
|
140
|
+
untaggedSection = `\n\n### Untagged (` + count + `)\n\n` + endpointList;
|
|
141
|
+
} else {
|
|
142
|
+
untaggedSection = "";
|
|
143
|
+
}
|
|
144
|
+
return `## Endpoints by Tag\n\n` + tagSections + untaggedSection;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
formatEndpointName,
|
|
149
|
+
formatTags,
|
|
150
|
+
generateMarkdownReport,
|
|
151
|
+
generateCompactSummary,
|
|
152
|
+
generateMergeReport,
|
|
153
|
+
generateEndpointsByTagReport,
|
|
154
|
+
}
|
|
155
|
+
/* CodegenUtils Not a pure module */
|