@f3liz/rescript-autogen-openapi 0.1.7 → 0.3.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.
Potentially problematic release.
This version of @f3liz/rescript-autogen-openapi might be problematic. Click here for more details.
- package/lib/es6/src/bindings/Toposort.mjs +12 -0
- package/lib/es6/src/core/CodegenUtils.mjs +75 -0
- package/lib/es6/src/core/SchemaIR.mjs +72 -2
- package/lib/es6/src/core/SchemaIRParser.mjs +244 -51
- package/lib/es6/src/generators/ComponentSchemaGenerator.mjs +118 -36
- package/lib/es6/src/generators/EndpointGenerator.mjs +4 -3
- package/lib/es6/src/generators/IRToSuryGenerator.mjs +348 -38
- package/lib/es6/src/generators/IRToTypeGenerator.mjs +503 -152
- package/lib/es6/src/generators/IRToTypeScriptGenerator.mjs +1 -1
- package/lib/es6/src/generators/ModuleGenerator.mjs +1 -1
- package/lib/es6/src/generators/SchemaCodeGenerator.mjs +1 -1
- package/lib/es6/src/types/GenerationContext.mjs +25 -2
- package/package.json +5 -3
- package/src/bindings/Toposort.res +16 -0
- package/src/core/CodegenUtils.res +50 -0
- package/src/core/SchemaIR.res +33 -0
- package/src/core/SchemaIRParser.res +96 -2
- package/src/generators/ComponentSchemaGenerator.res +133 -50
- package/src/generators/EndpointGenerator.res +7 -3
- package/src/generators/IRToSuryGenerator.res +254 -67
- package/src/generators/IRToTypeGenerator.res +308 -84
- package/src/generators/IRToTypeScriptGenerator.res +6 -1
- package/src/generators/ModuleGenerator.res +2 -1
- package/src/generators/SchemaCodeGenerator.res +2 -1
- package/src/types/GenerationContext.res +34 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Pipeline from "../core/Pipeline.mjs";
|
|
4
|
+
import * as Toposort from "../bindings/Toposort.mjs";
|
|
4
5
|
import * as FileSystem from "../core/FileSystem.mjs";
|
|
5
6
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
6
7
|
import * as CodegenUtils from "../core/CodegenUtils.mjs";
|
|
@@ -29,8 +30,7 @@ function extractReferencedSchemaNames(_irType) {
|
|
|
29
30
|
case "Intersection" :
|
|
30
31
|
return irType._0.flatMap(extractReferencedSchemaNames);
|
|
31
32
|
case "Reference" :
|
|
32
|
-
|
|
33
|
-
return [Stdlib_Option.getOr(parts[parts.length - 1 | 0], "")];
|
|
33
|
+
return [irType._0];
|
|
34
34
|
case "Option" :
|
|
35
35
|
_irType = irType._0;
|
|
36
36
|
continue;
|
|
@@ -56,7 +56,8 @@ function generate(spec, outputDir) {
|
|
|
56
56
|
s.name,
|
|
57
57
|
s
|
|
58
58
|
]));
|
|
59
|
-
let
|
|
59
|
+
let allNodes = schemas.map(s => s.name);
|
|
60
|
+
let edges = schemas.flatMap(schema => {
|
|
60
61
|
let references = extractReferencedSchemaNames(schema.type_).filter(name => {
|
|
61
62
|
if (name in schemaNameMap) {
|
|
62
63
|
return name !== schema.name;
|
|
@@ -64,50 +65,131 @@ function generate(spec, outputDir) {
|
|
|
64
65
|
return false;
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
return references.map(dep => [
|
|
69
|
+
schema.name,
|
|
70
|
+
dep
|
|
71
|
+
]);
|
|
69
72
|
});
|
|
70
|
-
let
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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) {
|
|
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)) {
|
|
84
82
|
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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;
|
|
91
103
|
return;
|
|
92
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
|
+
});
|
|
93
117
|
});
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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]);
|
|
98
125
|
let availableSchemaNames = finalSortedSchemas.map(s => s.name);
|
|
99
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
|
+
});
|
|
100
135
|
let moduleCodes = finalSortedSchemas.map(schema => {
|
|
101
|
-
let
|
|
102
|
-
let
|
|
103
|
-
let
|
|
104
|
-
let
|
|
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_);
|
|
105
158
|
warnings.push(...typeCtx.warnings);
|
|
106
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
|
+
});
|
|
107
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;
|
|
108
190
|
return docComment + `module ` + JsConvertCase.toPascalCase(schema.name) + ` = {
|
|
109
|
-
|
|
110
|
-
let schema = ` +
|
|
191
|
+
` + extractedBlock + ` ` + typeKeyword + ` = ` + typeCode + `
|
|
192
|
+
let schema = ` + finalSchemaCode + `
|
|
111
193
|
}`;
|
|
112
194
|
});
|
|
113
195
|
let fileHeader = CodegenUtils.generateFileHeader("Shared component schemas");
|
|
@@ -122,4 +204,4 @@ export {
|
|
|
122
204
|
extractReferencedSchemaNames,
|
|
123
205
|
generate,
|
|
124
206
|
}
|
|
125
|
-
/*
|
|
207
|
+
/* Toposort Not a pure module */
|
|
@@ -26,7 +26,7 @@ function generateTypeCodeAndSchemaCode(jsonSchema, typeName, schemaName, moduleP
|
|
|
26
26
|
name: schemaName,
|
|
27
27
|
description: jsonSchema.description,
|
|
28
28
|
type_: ir
|
|
29
|
-
}, undefined, undefined, modulePrefix);
|
|
29
|
+
}, undefined, undefined, modulePrefix, match$1[2]);
|
|
30
30
|
return [
|
|
31
31
|
match$1[0],
|
|
32
32
|
match$2[0]
|
|
@@ -45,7 +45,8 @@ function generateEndpointFunction(endpoint, overrideDir, moduleName) {
|
|
|
45
45
|
let isRequestBodyRequired = Stdlib_Option.getOr(requestBody.required, false);
|
|
46
46
|
let bodyParam = hasRequestBody ? (
|
|
47
47
|
isRequestBodyRequired ? `~body: ` + requestTypeName : `~body: option<` + requestTypeName + `>=?`
|
|
48
|
-
) : "
|
|
48
|
+
) : "";
|
|
49
|
+
let paramSep = hasRequestBody ? ", " : "";
|
|
49
50
|
let bodyValueConversion = hasRequestBody ? (
|
|
50
51
|
isRequestBodyRequired ? ` let jsonBody = body->S.reverseConvertToJsonOrThrow(` + functionName + `RequestSchema)` : ` let jsonBody = body->Option.map(b => b->S.reverseConvertToJsonOrThrow(` + functionName + `RequestSchema))`
|
|
51
52
|
) : "";
|
|
@@ -86,7 +87,7 @@ function generateEndpointFunction(endpoint, overrideDir, moduleName) {
|
|
|
86
87
|
let docComment = CodegenUtils.generateDocString(endpoint.summary, description, undefined);
|
|
87
88
|
let code = `
|
|
88
89
|
|` + docComment.trimEnd() + `
|
|
89
|
-
|let ` + functionName + ` = (` + bodyParam +
|
|
90
|
+
|let ` + functionName + ` = (` + bodyParam + paramSep + `~fetch: ` + CodegenUtils.fetchTypeSignature + `): promise<` + functionName + `Response> => {
|
|
90
91
|
|` + bodyValueConversion + `
|
|
91
92
|
| fetch(
|
|
92
93
|
| ~url="` + endpoint.path + `",
|