@f3liz/rescript-autogen-openapi 0.1.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/LICENSE +339 -0
- package/README.md +98 -0
- package/lib/es6/src/Codegen.mjs +423 -0
- package/lib/es6/src/Types.mjs +20 -0
- package/lib/es6/src/core/CodegenUtils.mjs +186 -0
- package/lib/es6/src/core/DocOverride.mjs +399 -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.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 +355 -0
- package/lib/es6/src/core/SchemaIRParser.mjs +490 -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 +125 -0
- package/lib/es6/src/generators/DiffReportGenerator.mjs +155 -0
- package/lib/es6/src/generators/EndpointGenerator.mjs +172 -0
- package/lib/es6/src/generators/IRToSuryGenerator.mjs +233 -0
- package/lib/es6/src/generators/IRToTypeGenerator.mjs +241 -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.mjs +79 -0
- package/lib/es6/src/types/Config.mjs +42 -0
- package/lib/es6/src/types/GenerationContext.mjs +24 -0
- package/package.json +44 -0
- package/rescript.json +20 -0
- package/src/Codegen.res +222 -0
- package/src/Types.res +195 -0
- package/src/core/CodegenUtils.res +130 -0
- package/src/core/DocOverride.res +504 -0
- package/src/core/FileSystem.res +62 -0
- package/src/core/IRBuilder.res +66 -0
- package/src/core/OpenAPIParser.res +144 -0
- package/src/core/Pipeline.res +51 -0
- package/src/core/ReferenceResolver.res +41 -0
- package/src/core/Result.res +187 -0
- package/src/core/SchemaIR.res +258 -0
- package/src/core/SchemaIRParser.res +360 -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 +127 -0
- package/src/generators/DiffReportGenerator.res +152 -0
- package/src/generators/EndpointGenerator.res +172 -0
- package/src/generators/IRToSuryGenerator.res +199 -0
- package/src/generators/IRToTypeGenerator.res +199 -0
- package/src/generators/IRToTypeScriptGenerator.res +72 -0
- package/src/generators/ModuleGenerator.res +362 -0
- package/src/generators/SchemaCodeGenerator.res +83 -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 +82 -0
- package/src/types/Config.res +89 -0
- package/src/types/GenerationContext.res +23 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
|
|
5
|
+
function fromSpec(spec) {
|
|
6
|
+
let components = spec.components;
|
|
7
|
+
let schemas;
|
|
8
|
+
if (components !== undefined) {
|
|
9
|
+
let s = components.schemas;
|
|
10
|
+
schemas = s !== undefined ? s : ({});
|
|
11
|
+
} else {
|
|
12
|
+
schemas = {};
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
schemas: schemas,
|
|
16
|
+
visiting: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function empty() {
|
|
21
|
+
return {
|
|
22
|
+
schemas: {},
|
|
23
|
+
visiting: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function extractSchemaName(ref) {
|
|
28
|
+
let prefix = "#/components/schemas/";
|
|
29
|
+
if (ref.startsWith(prefix)) {
|
|
30
|
+
return ref.slice(prefix.length);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isVisiting(registry, name) {
|
|
35
|
+
return registry.visiting.includes(name);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function startVisiting(registry, name) {
|
|
39
|
+
registry.visiting = registry.visiting.concat([name]);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function stopVisiting(registry, name) {
|
|
43
|
+
registry.visiting = registry.visiting.filter(n => n !== name);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getSchema(registry, name) {
|
|
47
|
+
return registry.schemas[name];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resolveRef(registry, ref) {
|
|
51
|
+
let name = extractSchemaName(ref);
|
|
52
|
+
if (name !== undefined) {
|
|
53
|
+
return registry.schemas[name];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getSchemaNames(registry) {
|
|
58
|
+
return Object.keys(registry.schemas);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function hasSchema(registry, name) {
|
|
62
|
+
return Stdlib_Option.isSome(registry.schemas[name]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function addSchema(registry, name, schema) {
|
|
66
|
+
registry.schemas[name] = schema;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function merge(registry, other) {
|
|
70
|
+
Object.entries(other.schemas).forEach(param => {
|
|
71
|
+
let name = param[0];
|
|
72
|
+
if (!hasSchema(registry, name)) {
|
|
73
|
+
return addSchema(registry, name, param[1]);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
fromSpec,
|
|
80
|
+
empty,
|
|
81
|
+
extractSchemaName,
|
|
82
|
+
isVisiting,
|
|
83
|
+
startVisiting,
|
|
84
|
+
stopVisiting,
|
|
85
|
+
getSchema,
|
|
86
|
+
resolveRef,
|
|
87
|
+
getSchemaNames,
|
|
88
|
+
hasSchema,
|
|
89
|
+
addSchema,
|
|
90
|
+
merge,
|
|
91
|
+
}
|
|
92
|
+
/* No side effect */
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
6
|
+
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
7
|
+
|
|
8
|
+
function makeEndpointKey(method, path) {
|
|
9
|
+
return method + `:` + path;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function schemasEqual(schema1, schema2) {
|
|
13
|
+
let match = schema1.type;
|
|
14
|
+
let match$1 = schema2.type;
|
|
15
|
+
let typeMatches = match !== undefined ? (
|
|
16
|
+
match$1 !== undefined ? Primitive_object.equal(match, match$1) : false
|
|
17
|
+
) : match$1 === undefined;
|
|
18
|
+
if (!typeMatches) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (Primitive_object.notequal(schema1.format, schema2.format)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (Primitive_object.notequal(schema1.nullable, schema2.nullable)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (Primitive_object.notequal(schema1.enum, schema2.enum)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
let match$2 = schema1.properties;
|
|
31
|
+
let match$3 = schema2.properties;
|
|
32
|
+
if (match$2 === undefined) {
|
|
33
|
+
return match$3 === undefined;
|
|
34
|
+
}
|
|
35
|
+
if (match$3 === undefined) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
let keys1 = Object.keys(match$2).toSorted(Primitive_string.compare);
|
|
39
|
+
let keys2 = Object.keys(match$3).toSorted(Primitive_string.compare);
|
|
40
|
+
if (Primitive_object.notequal(keys1, keys2)) {
|
|
41
|
+
return false;
|
|
42
|
+
} else {
|
|
43
|
+
return keys1.every(key => {
|
|
44
|
+
let match$4 = match$2[key];
|
|
45
|
+
let match$5 = match$3[key];
|
|
46
|
+
if (match$4 !== undefined && match$5 !== undefined) {
|
|
47
|
+
return schemasEqual(match$4, match$5);
|
|
48
|
+
} else {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function compareEndpoints(endpoint1, endpoint2) {
|
|
56
|
+
let match = endpoint1.requestBody;
|
|
57
|
+
let match$1 = endpoint2.requestBody;
|
|
58
|
+
let hasRequestBodyChanged;
|
|
59
|
+
if (match !== undefined) {
|
|
60
|
+
if (match$1 !== undefined) {
|
|
61
|
+
let keys1 = Object.keys(match.content).toSorted(Primitive_string.compare);
|
|
62
|
+
let keys2 = Object.keys(match$1.content).toSorted(Primitive_string.compare);
|
|
63
|
+
hasRequestBodyChanged = Primitive_object.notequal(keys1, keys2) ? true : keys1.some(contentType => {
|
|
64
|
+
let match$2 = match.content[contentType];
|
|
65
|
+
let match$3 = match$1.content[contentType];
|
|
66
|
+
if (match$2 === undefined) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (match$3 === undefined) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
let match$4 = match$2.schema;
|
|
73
|
+
let match$5 = match$3.schema;
|
|
74
|
+
if (match$4 !== undefined && match$5 !== undefined) {
|
|
75
|
+
return !schemasEqual(match$4, match$5);
|
|
76
|
+
} else {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
hasRequestBodyChanged = true;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
hasRequestBodyChanged = match$1 !== undefined;
|
|
85
|
+
}
|
|
86
|
+
let codes1 = Object.keys(endpoint1.responses).toSorted(Primitive_string.compare);
|
|
87
|
+
let codes2 = Object.keys(endpoint2.responses).toSorted(Primitive_string.compare);
|
|
88
|
+
let hasResponseChanged = Primitive_object.notequal(codes1, codes2) ? true : codes1.some(code => {
|
|
89
|
+
let match = endpoint1.responses[code];
|
|
90
|
+
let match$1 = endpoint2.responses[code];
|
|
91
|
+
if (match === undefined) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (match$1 === undefined) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
let match$2 = match.content;
|
|
98
|
+
let match$3 = match$1.content;
|
|
99
|
+
if (match$2 === undefined) {
|
|
100
|
+
return match$3 !== undefined;
|
|
101
|
+
}
|
|
102
|
+
if (match$3 === undefined) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
let contentKeys1 = Object.keys(match$2).toSorted(Primitive_string.compare);
|
|
106
|
+
let contentKeys2 = Object.keys(match$3).toSorted(Primitive_string.compare);
|
|
107
|
+
if (Primitive_object.notequal(contentKeys1, contentKeys2)) {
|
|
108
|
+
return true;
|
|
109
|
+
} else {
|
|
110
|
+
return contentKeys1.some(contentType => {
|
|
111
|
+
let match$4 = match$2[contentType];
|
|
112
|
+
let match$5 = match$3[contentType];
|
|
113
|
+
if (match$4 === undefined) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (match$5 === undefined) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
let match$6 = match$4.schema;
|
|
120
|
+
let match$7 = match$5.schema;
|
|
121
|
+
if (match$6 !== undefined && match$7 !== undefined) {
|
|
122
|
+
return !schemasEqual(match$6, match$7);
|
|
123
|
+
} else {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
if (hasRequestBodyChanged || hasResponseChanged) {
|
|
130
|
+
return {
|
|
131
|
+
path: endpoint1.path,
|
|
132
|
+
method: endpoint1.method,
|
|
133
|
+
requestBodyChanged: hasRequestBodyChanged,
|
|
134
|
+
responseChanged: hasResponseChanged,
|
|
135
|
+
breakingChange: hasResponseChanged
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function compareEndpointLists(baseEndpoints, forkEndpoints) {
|
|
141
|
+
let baseMap = {};
|
|
142
|
+
baseEndpoints.forEach(ep => {
|
|
143
|
+
let key = makeEndpointKey(ep.method, ep.path);
|
|
144
|
+
baseMap[key] = ep;
|
|
145
|
+
});
|
|
146
|
+
let forkMap = {};
|
|
147
|
+
forkEndpoints.forEach(ep => {
|
|
148
|
+
let key = makeEndpointKey(ep.method, ep.path);
|
|
149
|
+
forkMap[key] = ep;
|
|
150
|
+
});
|
|
151
|
+
let baseKeys = new Set(Object.keys(baseMap));
|
|
152
|
+
let forkKeys = new Set(Object.keys(forkMap));
|
|
153
|
+
let added = Stdlib_Array.filterMap(Array.from(forkKeys.difference(baseKeys)), key => forkMap[key]);
|
|
154
|
+
let removed = Stdlib_Array.filterMap(Array.from(baseKeys.difference(forkKeys)), key => baseMap[key]);
|
|
155
|
+
let modified = Stdlib_Array.filterMap(Array.from(baseKeys.intersection(forkKeys)), key => {
|
|
156
|
+
let match = baseMap[key];
|
|
157
|
+
let match$1 = forkMap[key];
|
|
158
|
+
if (match !== undefined && match$1 !== undefined) {
|
|
159
|
+
return compareEndpoints(match, match$1);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return [
|
|
163
|
+
added,
|
|
164
|
+
removed,
|
|
165
|
+
modified
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function compareComponentSchemas(baseSchemas, forkSchemas) {
|
|
170
|
+
if (baseSchemas === undefined) {
|
|
171
|
+
if (forkSchemas !== undefined) {
|
|
172
|
+
return [
|
|
173
|
+
Object.keys(forkSchemas),
|
|
174
|
+
[],
|
|
175
|
+
[]
|
|
176
|
+
];
|
|
177
|
+
} else {
|
|
178
|
+
return [
|
|
179
|
+
[],
|
|
180
|
+
[],
|
|
181
|
+
[]
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (forkSchemas === undefined) {
|
|
186
|
+
return [
|
|
187
|
+
[],
|
|
188
|
+
Object.keys(baseSchemas),
|
|
189
|
+
[]
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
let baseKeys = new Set(Object.keys(baseSchemas));
|
|
193
|
+
let forkKeys = new Set(Object.keys(forkSchemas));
|
|
194
|
+
let added = Array.from(forkKeys.difference(baseKeys));
|
|
195
|
+
let removed = Array.from(baseKeys.difference(forkKeys));
|
|
196
|
+
let modified = Stdlib_Array.filterMap(Array.from(baseKeys.intersection(forkKeys)), name => {
|
|
197
|
+
let match = baseSchemas[name];
|
|
198
|
+
let match$1 = forkSchemas[name];
|
|
199
|
+
if (match !== undefined && match$1 !== undefined && !schemasEqual(match, match$1)) {
|
|
200
|
+
return {
|
|
201
|
+
name: name,
|
|
202
|
+
breakingChange: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
return [
|
|
207
|
+
added,
|
|
208
|
+
removed,
|
|
209
|
+
modified
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function generateDiff(baseSpec, forkSpec, baseEndpoints, forkEndpoints) {
|
|
214
|
+
let match = compareEndpointLists(baseEndpoints, forkEndpoints);
|
|
215
|
+
let match$1 = compareComponentSchemas(Stdlib_Option.flatMap(baseSpec.components, c => c.schemas), Stdlib_Option.flatMap(forkSpec.components, c => c.schemas));
|
|
216
|
+
return {
|
|
217
|
+
addedEndpoints: match[0],
|
|
218
|
+
removedEndpoints: match[1],
|
|
219
|
+
modifiedEndpoints: match[2],
|
|
220
|
+
addedSchemas: match$1[0],
|
|
221
|
+
removedSchemas: match$1[1],
|
|
222
|
+
modifiedSchemas: match$1[2]
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function hasBreakingChanges(diff) {
|
|
227
|
+
let hasRemovedEndpoints = diff.removedEndpoints.length !== 0;
|
|
228
|
+
let hasBreakingEndpointChanges = diff.modifiedEndpoints.some(d => d.breakingChange);
|
|
229
|
+
let hasBreakingSchemaChanges = diff.modifiedSchemas.some(d => d.breakingChange);
|
|
230
|
+
if (hasRemovedEndpoints || hasBreakingEndpointChanges) {
|
|
231
|
+
return true;
|
|
232
|
+
} else {
|
|
233
|
+
return hasBreakingSchemaChanges;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function countChanges(diff) {
|
|
238
|
+
return ((((diff.addedEndpoints.length + diff.removedEndpoints.length | 0) + diff.modifiedEndpoints.length | 0) + diff.addedSchemas.length | 0) + diff.removedSchemas.length | 0) + diff.modifiedSchemas.length | 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export {
|
|
242
|
+
makeEndpointKey,
|
|
243
|
+
schemasEqual,
|
|
244
|
+
compareEndpoints,
|
|
245
|
+
compareEndpointLists,
|
|
246
|
+
compareComponentSchemas,
|
|
247
|
+
generateDiff,
|
|
248
|
+
hasBreakingChanges,
|
|
249
|
+
countChanges,
|
|
250
|
+
}
|
|
251
|
+
/* No side effect */
|
|
@@ -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,125 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Pipeline from "../core/Pipeline.mjs";
|
|
4
|
+
import * as Text from "@std/text";
|
|
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 Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
12
|
+
import * as GenerationContext from "../types/GenerationContext.mjs";
|
|
13
|
+
import * as IRToSuryGenerator from "./IRToSuryGenerator.mjs";
|
|
14
|
+
import * as IRToTypeGenerator from "./IRToTypeGenerator.mjs";
|
|
15
|
+
|
|
16
|
+
function extractReferencedSchemaNames(_irType) {
|
|
17
|
+
while (true) {
|
|
18
|
+
let irType = _irType;
|
|
19
|
+
if (typeof irType !== "object") {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
switch (irType.TAG) {
|
|
23
|
+
case "Array" :
|
|
24
|
+
_irType = irType.items;
|
|
25
|
+
continue;
|
|
26
|
+
case "Object" :
|
|
27
|
+
return irType.properties.flatMap(param => extractReferencedSchemaNames(param[1]));
|
|
28
|
+
case "Union" :
|
|
29
|
+
case "Intersection" :
|
|
30
|
+
return irType._0.flatMap(extractReferencedSchemaNames);
|
|
31
|
+
case "Reference" :
|
|
32
|
+
let parts = irType._0.split("/");
|
|
33
|
+
return [Stdlib_Option.getOr(parts[parts.length - 1 | 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 dependencyMap = Stdlib_Array.reduce(schemas, {}, (acc, schema) => {
|
|
60
|
+
let references = extractReferencedSchemaNames(schema.type_).filter(name => {
|
|
61
|
+
if (name in schemaNameMap) {
|
|
62
|
+
return name !== schema.name;
|
|
63
|
+
} else {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
acc[schema.name] = references;
|
|
68
|
+
return acc;
|
|
69
|
+
});
|
|
70
|
+
let sortedSchemas = [];
|
|
71
|
+
let inDegreeMap = Stdlib_Array.reduce(schemas, {}, (acc, schema) => {
|
|
72
|
+
let degree = Stdlib_Option.mapOr(dependencyMap[schema.name], 0, prim => prim.length);
|
|
73
|
+
acc[schema.name] = degree;
|
|
74
|
+
return acc;
|
|
75
|
+
});
|
|
76
|
+
let queue = schemas.filter(schema => Stdlib_Option.getOr(inDegreeMap[schema.name], 0) === 0);
|
|
77
|
+
while (queue.length !== 0) {
|
|
78
|
+
let v = queue.shift();
|
|
79
|
+
let schema = v !== undefined ? v : schemas[0];
|
|
80
|
+
sortedSchemas.push(schema);
|
|
81
|
+
schemas.forEach(otherSchema => {
|
|
82
|
+
let dependsOnCurrent = Stdlib_Option.getOr(dependencyMap[otherSchema.name], []).some(name => name === schema.name);
|
|
83
|
+
if (!dependsOnCurrent) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let currentDegree = Stdlib_Option.getOr(inDegreeMap[otherSchema.name], 0);
|
|
87
|
+
let newDegree = currentDegree - 1 | 0;
|
|
88
|
+
inDegreeMap[otherSchema.name] = newDegree;
|
|
89
|
+
if (newDegree === 0) {
|
|
90
|
+
queue.push(otherSchema);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
let sortedNames = sortedSchemas.map(s => s.name);
|
|
96
|
+
let remainingSchemas = schemas.filter(s => !sortedNames.some(name => name === s.name)).toSorted((a, b) => Primitive_string.compare(a.name, b.name));
|
|
97
|
+
let finalSortedSchemas = sortedSchemas.concat(remainingSchemas);
|
|
98
|
+
let availableSchemaNames = finalSortedSchemas.map(s => s.name);
|
|
99
|
+
let warnings = match[1].slice();
|
|
100
|
+
let moduleCodes = finalSortedSchemas.map(schema => {
|
|
101
|
+
let typeCtx = GenerationContext.make(`ComponentSchemas.` + schema.name, true, availableSchemaNames, undefined, undefined);
|
|
102
|
+
let schemaCtx = GenerationContext.make(`ComponentSchemas.` + schema.name, true, availableSchemaNames, undefined, undefined);
|
|
103
|
+
let typeCode = IRToTypeGenerator.generateTypeWithContext(typeCtx, 0, schema.type_);
|
|
104
|
+
let schemaCode = IRToSuryGenerator.generateSchemaWithContext(schemaCtx, 0, schema.type_);
|
|
105
|
+
warnings.push(...typeCtx.warnings);
|
|
106
|
+
warnings.push(...schemaCtx.warnings);
|
|
107
|
+
let docComment = Stdlib_Option.mapOr(schema.description, "", d => CodegenUtils.generateDocString(undefined, d, undefined));
|
|
108
|
+
return docComment + `module ` + Text.toPascalCase(schema.name) + ` = {
|
|
109
|
+
type t = ` + typeCode + `
|
|
110
|
+
let schema = ` + schemaCode + `
|
|
111
|
+
}`;
|
|
112
|
+
});
|
|
113
|
+
let fileHeader = CodegenUtils.generateFileHeader("Shared component schemas");
|
|
114
|
+
let fileContent = fileHeader + `\n\n` + moduleCodes.join("\n\n");
|
|
115
|
+
return Pipeline.fromFilesAndWarnings([{
|
|
116
|
+
path: FileSystem.makePath(outputDir, "ComponentSchemas.res"),
|
|
117
|
+
content: fileContent
|
|
118
|
+
}], warnings);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
extractReferencedSchemaNames,
|
|
123
|
+
generate,
|
|
124
|
+
}
|
|
125
|
+
/* @std/text Not a pure module */
|