@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,423 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Config from "./types/Config.mjs";
|
|
4
|
+
import * as Pipeline from "./core/Pipeline.mjs";
|
|
5
|
+
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
6
|
+
import * as FileSystem from "./core/FileSystem.mjs";
|
|
7
|
+
import * as SpecDiffer from "./core/SpecDiffer.mjs";
|
|
8
|
+
import * as SpecMerger from "./core/SpecMerger.mjs";
|
|
9
|
+
import * as DocOverride from "./core/DocOverride.mjs";
|
|
10
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
11
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
12
|
+
import * as OpenAPIParser from "./core/OpenAPIParser.mjs";
|
|
13
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
14
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
15
|
+
import * as ModuleGenerator from "./generators/ModuleGenerator.mjs";
|
|
16
|
+
import * as JsConvertCase from "js-convert-case";
|
|
17
|
+
import * as SchemaRefResolver from "./core/SchemaRefResolver.mjs";
|
|
18
|
+
import * as DiffReportGenerator from "./generators/DiffReportGenerator.mjs";
|
|
19
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
20
|
+
import * as ThinWrapperGenerator from "./generators/ThinWrapperGenerator.mjs";
|
|
21
|
+
import * as TypeScriptDtsGenerator from "./generators/TypeScriptDtsGenerator.mjs";
|
|
22
|
+
import * as ComponentSchemaGenerator from "./generators/ComponentSchemaGenerator.mjs";
|
|
23
|
+
import * as TypeScriptWrapperGenerator from "./generators/TypeScriptWrapperGenerator.mjs";
|
|
24
|
+
|
|
25
|
+
function generateSingleSpecPure(spec, config) {
|
|
26
|
+
try {
|
|
27
|
+
let targets = Stdlib_Option.getOr(config.targets, Config.defaultTargets());
|
|
28
|
+
let allEndpoints = OpenAPIParser.getAllEndpoints(spec);
|
|
29
|
+
let includeTags = config.includeTags;
|
|
30
|
+
let endpoints = includeTags !== undefined ? OpenAPIParser.filterByTags(allEndpoints, includeTags, Stdlib_Option.getOr(config.excludeTags, [])) : allEndpoints;
|
|
31
|
+
let baseOutput = targets.rescriptApi ? Pipeline.combine([
|
|
32
|
+
ComponentSchemaGenerator.generate(spec, config.outputDir),
|
|
33
|
+
config.modulePerTag ? ModuleGenerator.generateTagModuleFiles(endpoints, config.outputDir, undefined, config.docOverrideDir) : ModuleGenerator.generateFlatModuleFile("API", endpoints, config.outputDir, config.docOverrideDir)
|
|
34
|
+
]) : Pipeline.empty;
|
|
35
|
+
let wrapperOutput = targets.rescriptWrapper ? ThinWrapperGenerator.generateWrapper(spec, endpoints, undefined, config.outputDir, JsConvertCase.toPascalCase(spec.info.title) + "Wrapper", "", undefined) : Pipeline.empty;
|
|
36
|
+
let dtsOutput = targets.typescriptDts ? TypeScriptDtsGenerator.generate(spec, endpoints, Stdlib_Option.getOr(config.dtsOutputDir, config.outputDir)) : Pipeline.empty;
|
|
37
|
+
let tsWrapperOutput = targets.typescriptWrapper ? TypeScriptWrapperGenerator.generate(endpoints, Stdlib_Option.getOr(config.wrapperOutputDir, config.outputDir), "../generated") : Pipeline.empty;
|
|
38
|
+
return {
|
|
39
|
+
TAG: "Ok",
|
|
40
|
+
_0: Pipeline.combine([
|
|
41
|
+
baseOutput,
|
|
42
|
+
wrapperOutput,
|
|
43
|
+
dtsOutput,
|
|
44
|
+
tsWrapperOutput
|
|
45
|
+
])
|
|
46
|
+
};
|
|
47
|
+
} catch (raw_err) {
|
|
48
|
+
let err = Primitive_exceptions.internalToException(raw_err);
|
|
49
|
+
if (err.RE_EXN_ID === "JsExn") {
|
|
50
|
+
return {
|
|
51
|
+
TAG: "Error",
|
|
52
|
+
_0: {
|
|
53
|
+
TAG: "UnknownError",
|
|
54
|
+
message: Stdlib_Option.getOr(Stdlib_JsExn.message(err._1), "Unknown error"),
|
|
55
|
+
context: undefined
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
return {
|
|
60
|
+
TAG: "Error",
|
|
61
|
+
_0: {
|
|
62
|
+
TAG: "UnknownError",
|
|
63
|
+
message: "Unknown error",
|
|
64
|
+
context: undefined
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function generateSingleSpec(spec, config) {
|
|
72
|
+
let err = generateSingleSpecPure(spec, config);
|
|
73
|
+
if (err.TAG !== "Ok") {
|
|
74
|
+
return {
|
|
75
|
+
TAG: "Error",
|
|
76
|
+
_0: err._0
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
let output = err._0;
|
|
80
|
+
let errors = FileSystem.writeFiles(output.files);
|
|
81
|
+
if (errors.TAG !== "Ok") {
|
|
82
|
+
return {
|
|
83
|
+
TAG: "Error",
|
|
84
|
+
_0: {
|
|
85
|
+
TAG: "UnknownError",
|
|
86
|
+
message: `Failed to write files: ` + errors._0.join(", "),
|
|
87
|
+
context: undefined
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
let match = config.generateDocOverrides;
|
|
92
|
+
let overrideFiles;
|
|
93
|
+
if (match !== undefined) {
|
|
94
|
+
if (match) {
|
|
95
|
+
let allEndpoints = OpenAPIParser.getAllEndpoints(spec);
|
|
96
|
+
let includeTags = config.includeTags;
|
|
97
|
+
let endpoints = includeTags !== undefined ? OpenAPIParser.filterByTags(allEndpoints, includeTags, Stdlib_Option.getOr(config.excludeTags, [])) : allEndpoints;
|
|
98
|
+
let files = DocOverride.generateOverrideFiles(spec, endpoints, Stdlib_Option.getOr(config.docOverrideDir, "./docs"), spec.info.title, config.modulePerTag, undefined);
|
|
99
|
+
overrideFiles = Stdlib_Result.getOr(FileSystem.writeFiles(files), []);
|
|
100
|
+
} else {
|
|
101
|
+
overrideFiles = [];
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
overrideFiles = [];
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
TAG: "Ok",
|
|
108
|
+
_0: {
|
|
109
|
+
generatedFiles: errors._0.concat(overrideFiles),
|
|
110
|
+
diff: undefined,
|
|
111
|
+
warnings: output.warnings
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function processForkPure(baseSpec, baseEndpoints, fork, config) {
|
|
117
|
+
try {
|
|
118
|
+
let forkEndpoints = OpenAPIParser.getAllEndpoints(fork.spec);
|
|
119
|
+
let diff = SpecDiffer.generateDiff(baseSpec, fork.spec, baseEndpoints, forkEndpoints);
|
|
120
|
+
let diffReportFile = config.generateDiffReport ? ({
|
|
121
|
+
path: FileSystem.makePath(config.outputDir, fork.name + `-diff.md`),
|
|
122
|
+
content: DiffReportGenerator.generateMarkdownReport(diff, "base", fork.name)
|
|
123
|
+
}) : undefined;
|
|
124
|
+
let match = SpecMerger.mergeSpecs(baseSpec, fork.spec, baseEndpoints, forkEndpoints, config.strategy);
|
|
125
|
+
let sharedSpec = match[0];
|
|
126
|
+
let sharedEndpoints = OpenAPIParser.getAllEndpoints(sharedSpec);
|
|
127
|
+
let extensionEndpoints = OpenAPIParser.getAllEndpoints(match[1]);
|
|
128
|
+
let mergeReportFile_path = FileSystem.makePath(config.outputDir, fork.name + `-merge.md`);
|
|
129
|
+
let mergeReportFile_content = DiffReportGenerator.generateMergeReport(SpecMerger.getMergeStats(baseEndpoints, forkEndpoints, Stdlib_Option.flatMap(baseSpec.components, c => c.schemas), Stdlib_Option.flatMap(fork.spec.components, c => c.schemas)), "base", fork.name);
|
|
130
|
+
let mergeReportFile = {
|
|
131
|
+
path: mergeReportFile_path,
|
|
132
|
+
content: mergeReportFile_content
|
|
133
|
+
};
|
|
134
|
+
let match$1 = config.strategy;
|
|
135
|
+
let codeOutput;
|
|
136
|
+
if (match$1 === "Separate") {
|
|
137
|
+
codeOutput = Pipeline.fromFile({
|
|
138
|
+
path: FileSystem.makePath(config.outputDir, fork.name + `.res`),
|
|
139
|
+
content: ModuleGenerator.generateFlatModuleCode(JsConvertCase.toPascalCase(fork.name), forkEndpoints, config.docOverrideDir)
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
let baseName = Stdlib_Option.getOrThrow(config.baseInstanceName, "baseInstanceName required");
|
|
143
|
+
let basePrefix = Stdlib_Option.getOr(config.baseModulePrefix, JsConvertCase.toPascalCase(baseName));
|
|
144
|
+
codeOutput = ModuleGenerator.generateSeparatePerTagModules(baseName, basePrefix, fork.name, undefined, sharedEndpoints, extensionEndpoints, Stdlib_Option.flatMap(sharedSpec.components, c => c.schemas), Stdlib_Option.flatMap(fork.spec.components, c => c.schemas), config.outputDir, config.docOverrideDir);
|
|
145
|
+
}
|
|
146
|
+
let targets = Stdlib_Option.getOr(config.targets, {
|
|
147
|
+
rescriptApi: true,
|
|
148
|
+
rescriptWrapper: false,
|
|
149
|
+
typescriptDts: false,
|
|
150
|
+
typescriptWrapper: false
|
|
151
|
+
});
|
|
152
|
+
let match$2 = config.strategy;
|
|
153
|
+
let match$3;
|
|
154
|
+
match$3 = match$2 === "Separate" ? [
|
|
155
|
+
fork.spec,
|
|
156
|
+
forkEndpoints,
|
|
157
|
+
[],
|
|
158
|
+
""
|
|
159
|
+
] : [
|
|
160
|
+
sharedSpec,
|
|
161
|
+
sharedEndpoints,
|
|
162
|
+
extensionEndpoints,
|
|
163
|
+
Stdlib_Option.getOr(config.baseModulePrefix, Stdlib_Option.getOr(Stdlib_Option.map(config.baseInstanceName, prim => JsConvertCase.toPascalCase(prim)), ""))
|
|
164
|
+
];
|
|
165
|
+
let wExt = match$3[2];
|
|
166
|
+
let wShared = match$3[1];
|
|
167
|
+
let wSpec = match$3[0];
|
|
168
|
+
let wrapperOutput = targets.rescriptWrapper ? ThinWrapperGenerator.generateWrapper(wSpec, wShared, wExt, FileSystem.makePath(config.outputDir, fork.name), JsConvertCase.toPascalCase(fork.name) + "Wrapper", JsConvertCase.toPascalCase(fork.name), match$3[3]) : Pipeline.empty;
|
|
169
|
+
let allWEndpoints = wShared.concat(wExt);
|
|
170
|
+
let dtsOutput = targets.typescriptDts ? TypeScriptDtsGenerator.generate(wSpec, allWEndpoints, FileSystem.makePath(Stdlib_Option.getOr(config.dtsOutputDir, config.outputDir), fork.name)) : Pipeline.empty;
|
|
171
|
+
let tsWrapperOutput = targets.typescriptWrapper ? TypeScriptWrapperGenerator.generate(allWEndpoints, FileSystem.makePath(Stdlib_Option.getOr(config.wrapperOutputDir, config.outputDir), fork.name), `../../generated/` + fork.name) : Pipeline.empty;
|
|
172
|
+
let reports = Pipeline.fromFiles(Belt_Array.concatMany([
|
|
173
|
+
[mergeReportFile],
|
|
174
|
+
Stdlib_Option.getOr(Stdlib_Option.map(diffReportFile, f => [f]), [])
|
|
175
|
+
]));
|
|
176
|
+
return {
|
|
177
|
+
TAG: "Ok",
|
|
178
|
+
_0: Pipeline.combine([
|
|
179
|
+
reports,
|
|
180
|
+
codeOutput,
|
|
181
|
+
wrapperOutput,
|
|
182
|
+
dtsOutput,
|
|
183
|
+
tsWrapperOutput
|
|
184
|
+
])
|
|
185
|
+
};
|
|
186
|
+
} catch (raw_err) {
|
|
187
|
+
let err = Primitive_exceptions.internalToException(raw_err);
|
|
188
|
+
if (err.RE_EXN_ID === "JsExn") {
|
|
189
|
+
return {
|
|
190
|
+
TAG: "Error",
|
|
191
|
+
_0: {
|
|
192
|
+
TAG: "UnknownError",
|
|
193
|
+
message: Stdlib_Option.getOr(Stdlib_JsExn.message(err._1), "Unknown error"),
|
|
194
|
+
context: undefined
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
} else {
|
|
198
|
+
return {
|
|
199
|
+
TAG: "Error",
|
|
200
|
+
_0: {
|
|
201
|
+
TAG: "UnknownError",
|
|
202
|
+
message: "Unknown error",
|
|
203
|
+
context: undefined
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function generateMultiSpecPure(baseSpec, forkSpecs, config) {
|
|
211
|
+
try {
|
|
212
|
+
let baseEndpoints = OpenAPIParser.getAllEndpoints(baseSpec);
|
|
213
|
+
let forkResults = forkSpecs.map(fork => processForkPure(baseSpec, baseEndpoints, fork, config));
|
|
214
|
+
let match = forkResults.find(Stdlib_Result.isError);
|
|
215
|
+
let exit = 0;
|
|
216
|
+
if (match !== undefined) {
|
|
217
|
+
if (match.TAG !== "Ok") {
|
|
218
|
+
return {
|
|
219
|
+
TAG: "Error",
|
|
220
|
+
_0: match._0
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
exit = 1;
|
|
224
|
+
} else {
|
|
225
|
+
exit = 1;
|
|
226
|
+
}
|
|
227
|
+
if (exit === 1) {
|
|
228
|
+
let outputs = Stdlib_Array.filterMap(forkResults, res => {
|
|
229
|
+
if (res.TAG === "Ok") {
|
|
230
|
+
return res._0;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
let targets = Stdlib_Option.getOr(config.targets, Config.defaultTargets());
|
|
234
|
+
let baseName = Stdlib_Option.getOrThrow(config.baseInstanceName, "baseInstanceName required");
|
|
235
|
+
let basePrefix = Stdlib_Option.getOr(config.baseModulePrefix, JsConvertCase.toPascalCase(baseName));
|
|
236
|
+
let baseOutputDir = FileSystem.makePath(config.outputDir, baseName);
|
|
237
|
+
let baseWrappers = Pipeline.combine([
|
|
238
|
+
targets.rescriptWrapper ? ThinWrapperGenerator.generateWrapper(baseSpec, baseEndpoints, undefined, baseOutputDir, basePrefix + "Wrapper", basePrefix, undefined) : Pipeline.empty,
|
|
239
|
+
targets.typescriptDts ? TypeScriptDtsGenerator.generate(baseSpec, baseEndpoints, FileSystem.makePath(Stdlib_Option.getOr(config.dtsOutputDir, config.outputDir), baseName)) : Pipeline.empty,
|
|
240
|
+
targets.typescriptWrapper ? TypeScriptWrapperGenerator.generate(baseEndpoints, FileSystem.makePath(Stdlib_Option.getOr(config.wrapperOutputDir, config.outputDir), baseName), `../../generated/` + baseName) : Pipeline.empty
|
|
241
|
+
]);
|
|
242
|
+
return {
|
|
243
|
+
TAG: "Ok",
|
|
244
|
+
_0: Pipeline.combine(outputs.concat([baseWrappers]))
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
} catch (raw_err) {
|
|
248
|
+
let err = Primitive_exceptions.internalToException(raw_err);
|
|
249
|
+
if (err.RE_EXN_ID === "JsExn") {
|
|
250
|
+
return {
|
|
251
|
+
TAG: "Error",
|
|
252
|
+
_0: {
|
|
253
|
+
TAG: "UnknownError",
|
|
254
|
+
message: Stdlib_Option.getOr(Stdlib_JsExn.message(err._1), "Unknown error"),
|
|
255
|
+
context: undefined
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
} else {
|
|
259
|
+
return {
|
|
260
|
+
TAG: "Error",
|
|
261
|
+
_0: {
|
|
262
|
+
TAG: "UnknownError",
|
|
263
|
+
message: "Unknown error",
|
|
264
|
+
context: undefined
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function generateMultiSpec(baseSpec, forkSpecs, config) {
|
|
272
|
+
let err = generateMultiSpecPure(baseSpec, forkSpecs, config);
|
|
273
|
+
if (err.TAG !== "Ok") {
|
|
274
|
+
return {
|
|
275
|
+
TAG: "Error",
|
|
276
|
+
_0: err._0
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
let output = err._0;
|
|
280
|
+
return Stdlib_Result.mapError(Stdlib_Result.map(FileSystem.writeFiles(output.files), filePaths => ({
|
|
281
|
+
generatedFiles: filePaths,
|
|
282
|
+
diff: undefined,
|
|
283
|
+
warnings: output.warnings
|
|
284
|
+
})), errors => ({
|
|
285
|
+
TAG: "UnknownError",
|
|
286
|
+
message: `Failed to write files: ` + errors.join(", "),
|
|
287
|
+
context: undefined
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function compareSpecs(baseSpec, forkSpec, baseNameOpt, forkNameOpt, outputPath) {
|
|
292
|
+
let baseName = baseNameOpt !== undefined ? baseNameOpt : "base";
|
|
293
|
+
let forkName = forkNameOpt !== undefined ? forkNameOpt : "fork";
|
|
294
|
+
let diff = SpecDiffer.generateDiff(baseSpec, forkSpec, OpenAPIParser.getAllEndpoints(baseSpec), OpenAPIParser.getAllEndpoints(forkSpec));
|
|
295
|
+
Stdlib_Option.forEach(outputPath, path => {
|
|
296
|
+
FileSystem.writeFile({
|
|
297
|
+
path: path,
|
|
298
|
+
content: DiffReportGenerator.generateMarkdownReport(diff, baseName, forkName)
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
return diff;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async function generate(config) {
|
|
305
|
+
let message = await SchemaRefResolver.resolve(config.specPath, undefined);
|
|
306
|
+
if (message.TAG !== "Ok") {
|
|
307
|
+
return {
|
|
308
|
+
TAG: "Error",
|
|
309
|
+
_0: {
|
|
310
|
+
TAG: "SpecResolutionError",
|
|
311
|
+
url: config.specPath,
|
|
312
|
+
message: message._0
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
let baseSpec = message._0;
|
|
317
|
+
let forkConfigs = config.forkSpecs;
|
|
318
|
+
if (forkConfigs === undefined) {
|
|
319
|
+
return await generateSingleSpec(baseSpec, config);
|
|
320
|
+
}
|
|
321
|
+
if (forkConfigs.length === 0) {
|
|
322
|
+
return await generateSingleSpec(baseSpec, config);
|
|
323
|
+
}
|
|
324
|
+
let forkResults = await Promise.all(forkConfigs.map(async f => Stdlib_Result.map(await SchemaRefResolver.resolve(f.specPath, undefined), spec => ({
|
|
325
|
+
name: f.name,
|
|
326
|
+
spec: spec
|
|
327
|
+
}))));
|
|
328
|
+
let match = forkResults.find(Stdlib_Result.isError);
|
|
329
|
+
if (match !== undefined && match.TAG !== "Ok") {
|
|
330
|
+
return {
|
|
331
|
+
TAG: "Error",
|
|
332
|
+
_0: {
|
|
333
|
+
TAG: "SpecResolutionError",
|
|
334
|
+
url: "",
|
|
335
|
+
message: match._0
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return await generateMultiSpec(baseSpec, Stdlib_Array.filterMap(forkResults, res => {
|
|
340
|
+
if (res.TAG === "Ok") {
|
|
341
|
+
return res._0;
|
|
342
|
+
}
|
|
343
|
+
}), config);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function createDefaultConfig(url, outputDir) {
|
|
347
|
+
return {
|
|
348
|
+
specPath: url,
|
|
349
|
+
forkSpecs: undefined,
|
|
350
|
+
outputDir: outputDir,
|
|
351
|
+
strategy: "SharedBase",
|
|
352
|
+
modulePerTag: true,
|
|
353
|
+
includeTags: undefined,
|
|
354
|
+
excludeTags: undefined,
|
|
355
|
+
generateDiffReport: true,
|
|
356
|
+
breakingChangeHandling: "Warn",
|
|
357
|
+
generateDocOverrides: undefined,
|
|
358
|
+
docOverrideDir: undefined,
|
|
359
|
+
targets: undefined,
|
|
360
|
+
dtsOutputDir: undefined,
|
|
361
|
+
wrapperOutputDir: undefined,
|
|
362
|
+
baseInstanceName: undefined,
|
|
363
|
+
baseModulePrefix: undefined
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function generateFromUrl(url, outputDir, config) {
|
|
368
|
+
let init = Stdlib_Option.getOr(config, createDefaultConfig(url, outputDir));
|
|
369
|
+
return await generate({
|
|
370
|
+
specPath: url,
|
|
371
|
+
forkSpecs: init.forkSpecs,
|
|
372
|
+
outputDir: init.outputDir,
|
|
373
|
+
strategy: init.strategy,
|
|
374
|
+
modulePerTag: init.modulePerTag,
|
|
375
|
+
includeTags: init.includeTags,
|
|
376
|
+
excludeTags: init.excludeTags,
|
|
377
|
+
generateDiffReport: init.generateDiffReport,
|
|
378
|
+
breakingChangeHandling: init.breakingChangeHandling,
|
|
379
|
+
generateDocOverrides: init.generateDocOverrides,
|
|
380
|
+
docOverrideDir: init.docOverrideDir,
|
|
381
|
+
targets: init.targets,
|
|
382
|
+
dtsOutputDir: init.dtsOutputDir,
|
|
383
|
+
wrapperOutputDir: init.wrapperOutputDir,
|
|
384
|
+
baseInstanceName: init.baseInstanceName,
|
|
385
|
+
baseModulePrefix: init.baseModulePrefix
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function generateFromFile(filePath, outputDir, config) {
|
|
390
|
+
let init = Stdlib_Option.getOr(config, createDefaultConfig(filePath, outputDir));
|
|
391
|
+
return await generate({
|
|
392
|
+
specPath: filePath,
|
|
393
|
+
forkSpecs: init.forkSpecs,
|
|
394
|
+
outputDir: init.outputDir,
|
|
395
|
+
strategy: init.strategy,
|
|
396
|
+
modulePerTag: init.modulePerTag,
|
|
397
|
+
includeTags: init.includeTags,
|
|
398
|
+
excludeTags: init.excludeTags,
|
|
399
|
+
generateDiffReport: init.generateDiffReport,
|
|
400
|
+
breakingChangeHandling: init.breakingChangeHandling,
|
|
401
|
+
generateDocOverrides: init.generateDocOverrides,
|
|
402
|
+
docOverrideDir: init.docOverrideDir,
|
|
403
|
+
targets: init.targets,
|
|
404
|
+
dtsOutputDir: init.dtsOutputDir,
|
|
405
|
+
wrapperOutputDir: init.wrapperOutputDir,
|
|
406
|
+
baseInstanceName: init.baseInstanceName,
|
|
407
|
+
baseModulePrefix: init.baseModulePrefix
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export {
|
|
412
|
+
generateSingleSpecPure,
|
|
413
|
+
generateSingleSpec,
|
|
414
|
+
processForkPure,
|
|
415
|
+
generateMultiSpecPure,
|
|
416
|
+
generateMultiSpec,
|
|
417
|
+
compareSpecs,
|
|
418
|
+
generate,
|
|
419
|
+
createDefaultConfig,
|
|
420
|
+
generateFromUrl,
|
|
421
|
+
generateFromFile,
|
|
422
|
+
}
|
|
423
|
+
/* FileSystem Not a pure module */
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import type { t as Config_t } from './types/Config';
|
|
2
|
+
export type jsonSchemaType = "String" | "Number" | "Integer" | "Boolean" | "Object" | "Null" | "Unknown" | {
|
|
3
|
+
TAG: "Array";
|
|
4
|
+
_0: jsonSchemaType;
|
|
5
|
+
};
|
|
6
|
+
export type jsonSchema = {
|
|
7
|
+
readonly type: (undefined | jsonSchemaType);
|
|
8
|
+
readonly properties: (undefined | {
|
|
9
|
+
[id: string]: jsonSchema;
|
|
10
|
+
});
|
|
11
|
+
readonly items: (undefined | jsonSchema);
|
|
12
|
+
readonly required: (undefined | string[]);
|
|
13
|
+
readonly enum: (undefined | unknown[]);
|
|
14
|
+
readonly "$ref": (undefined | string);
|
|
15
|
+
readonly allOf: (undefined | jsonSchema[]);
|
|
16
|
+
readonly oneOf: (undefined | jsonSchema[]);
|
|
17
|
+
readonly anyOf: (undefined | jsonSchema[]);
|
|
18
|
+
readonly description: (undefined | string);
|
|
19
|
+
readonly format: (undefined | string);
|
|
20
|
+
readonly minLength: (undefined | number);
|
|
21
|
+
readonly maxLength: (undefined | number);
|
|
22
|
+
readonly minimum: (undefined | number);
|
|
23
|
+
readonly maximum: (undefined | number);
|
|
24
|
+
readonly pattern: (undefined | string);
|
|
25
|
+
readonly nullable: (undefined | boolean);
|
|
26
|
+
};
|
|
27
|
+
export type httpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
28
|
+
export type mediaType = {
|
|
29
|
+
readonly schema: (undefined | jsonSchema);
|
|
30
|
+
readonly example: (undefined | unknown);
|
|
31
|
+
readonly examples: (undefined | {
|
|
32
|
+
[id: string]: unknown;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
export type requestBody = {
|
|
36
|
+
readonly description: (undefined | string);
|
|
37
|
+
readonly content: {
|
|
38
|
+
[id: string]: mediaType;
|
|
39
|
+
};
|
|
40
|
+
readonly required: (undefined | boolean);
|
|
41
|
+
};
|
|
42
|
+
export type response = {
|
|
43
|
+
readonly description: string;
|
|
44
|
+
readonly content: (undefined | {
|
|
45
|
+
[id: string]: mediaType;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export type parameter = {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly in: string;
|
|
51
|
+
readonly description: (undefined | string);
|
|
52
|
+
readonly required: (undefined | boolean);
|
|
53
|
+
readonly schema: (undefined | jsonSchema);
|
|
54
|
+
};
|
|
55
|
+
export type operation = {
|
|
56
|
+
readonly operationId: (undefined | string);
|
|
57
|
+
readonly summary: (undefined | string);
|
|
58
|
+
readonly description: (undefined | string);
|
|
59
|
+
readonly tags: (undefined | string[]);
|
|
60
|
+
readonly requestBody: (undefined | requestBody);
|
|
61
|
+
readonly responses: {
|
|
62
|
+
[id: string]: response;
|
|
63
|
+
};
|
|
64
|
+
readonly parameters: (undefined | parameter[]);
|
|
65
|
+
};
|
|
66
|
+
export type endpoint = {
|
|
67
|
+
readonly path: string;
|
|
68
|
+
readonly method: string;
|
|
69
|
+
readonly operationId: (undefined | string);
|
|
70
|
+
readonly summary: (undefined | string);
|
|
71
|
+
readonly description: (undefined | string);
|
|
72
|
+
readonly tags: (undefined | string[]);
|
|
73
|
+
readonly requestBody: (undefined | requestBody);
|
|
74
|
+
readonly responses: {
|
|
75
|
+
[id: string]: response;
|
|
76
|
+
};
|
|
77
|
+
readonly parameters: (undefined | parameter[]);
|
|
78
|
+
};
|
|
79
|
+
export type pathItem = {
|
|
80
|
+
readonly get: (undefined | operation);
|
|
81
|
+
readonly post: (undefined | operation);
|
|
82
|
+
readonly put: (undefined | operation);
|
|
83
|
+
readonly patch: (undefined | operation);
|
|
84
|
+
readonly delete: (undefined | operation);
|
|
85
|
+
readonly head: (undefined | operation);
|
|
86
|
+
readonly options: (undefined | operation);
|
|
87
|
+
readonly parameters: (undefined | parameter[]);
|
|
88
|
+
};
|
|
89
|
+
export type components = {
|
|
90
|
+
readonly schemas: (undefined | {
|
|
91
|
+
[id: string]: jsonSchema;
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
export type info = {
|
|
95
|
+
readonly title: string;
|
|
96
|
+
readonly version: string;
|
|
97
|
+
readonly description: (undefined | string);
|
|
98
|
+
};
|
|
99
|
+
export type openAPISpec = {
|
|
100
|
+
readonly openapi: string;
|
|
101
|
+
readonly info: info;
|
|
102
|
+
readonly paths: {
|
|
103
|
+
[id: string]: pathItem;
|
|
104
|
+
};
|
|
105
|
+
readonly components: (undefined | components);
|
|
106
|
+
};
|
|
107
|
+
export type generationStrategy = "Separate" | "SharedBase";
|
|
108
|
+
export type breakingChangeHandling = "Error" | "Warn" | "Ignore";
|
|
109
|
+
export type forkSpecConfig = {
|
|
110
|
+
readonly name: string;
|
|
111
|
+
readonly specPath: string;
|
|
112
|
+
};
|
|
113
|
+
export type generationTargets = {
|
|
114
|
+
readonly rescriptApi: boolean;
|
|
115
|
+
readonly rescriptWrapper: boolean;
|
|
116
|
+
readonly typescriptDts: boolean;
|
|
117
|
+
readonly typescriptWrapper: boolean;
|
|
118
|
+
};
|
|
119
|
+
export type generationConfig = Config_t;
|
|
120
|
+
export type forkSpec = {
|
|
121
|
+
readonly name: string;
|
|
122
|
+
readonly spec: openAPISpec;
|
|
123
|
+
};
|
|
124
|
+
export type errorContext = {
|
|
125
|
+
readonly path: string;
|
|
126
|
+
readonly operation: string;
|
|
127
|
+
readonly schema: (undefined | unknown);
|
|
128
|
+
};
|
|
129
|
+
export type codegenError = {
|
|
130
|
+
TAG: "SpecResolutionError";
|
|
131
|
+
readonly url: string;
|
|
132
|
+
readonly message: string;
|
|
133
|
+
} | {
|
|
134
|
+
TAG: "SchemaParseError";
|
|
135
|
+
readonly context: errorContext;
|
|
136
|
+
readonly reason: string;
|
|
137
|
+
} | {
|
|
138
|
+
TAG: "ReferenceError";
|
|
139
|
+
readonly ref: string;
|
|
140
|
+
readonly context: errorContext;
|
|
141
|
+
} | {
|
|
142
|
+
TAG: "ValidationError";
|
|
143
|
+
readonly schema: string;
|
|
144
|
+
readonly input: unknown;
|
|
145
|
+
readonly issues: string[];
|
|
146
|
+
} | {
|
|
147
|
+
TAG: "CircularSchemaError";
|
|
148
|
+
readonly ref: string;
|
|
149
|
+
readonly depth: number;
|
|
150
|
+
readonly path: string;
|
|
151
|
+
} | {
|
|
152
|
+
TAG: "FileWriteError";
|
|
153
|
+
readonly filePath: string;
|
|
154
|
+
readonly message: string;
|
|
155
|
+
} | {
|
|
156
|
+
TAG: "InvalidConfigError";
|
|
157
|
+
readonly field: string;
|
|
158
|
+
readonly message: string;
|
|
159
|
+
} | {
|
|
160
|
+
TAG: "UnknownError";
|
|
161
|
+
readonly message: string;
|
|
162
|
+
readonly context: (undefined | errorContext);
|
|
163
|
+
};
|
|
164
|
+
export type warning = {
|
|
165
|
+
TAG: "FallbackToJson";
|
|
166
|
+
readonly reason: string;
|
|
167
|
+
readonly context: errorContext;
|
|
168
|
+
} | {
|
|
169
|
+
TAG: "UnsupportedFeature";
|
|
170
|
+
readonly feature: string;
|
|
171
|
+
readonly fallback: string;
|
|
172
|
+
readonly location: string;
|
|
173
|
+
} | {
|
|
174
|
+
TAG: "DepthLimitReached";
|
|
175
|
+
readonly depth: number;
|
|
176
|
+
readonly path: string;
|
|
177
|
+
} | {
|
|
178
|
+
TAG: "MissingSchema";
|
|
179
|
+
readonly ref: string;
|
|
180
|
+
readonly location: string;
|
|
181
|
+
} | {
|
|
182
|
+
TAG: "IntersectionNotFullySupported";
|
|
183
|
+
readonly location: string;
|
|
184
|
+
readonly note: string;
|
|
185
|
+
} | {
|
|
186
|
+
TAG: "ComplexUnionSimplified";
|
|
187
|
+
readonly location: string;
|
|
188
|
+
readonly types: string;
|
|
189
|
+
};
|
|
190
|
+
export type endpointDiff = {
|
|
191
|
+
readonly path: string;
|
|
192
|
+
readonly method: string;
|
|
193
|
+
readonly requestBodyChanged: boolean;
|
|
194
|
+
readonly responseChanged: boolean;
|
|
195
|
+
readonly breakingChange: boolean;
|
|
196
|
+
};
|
|
197
|
+
export type schemaDiff = {
|
|
198
|
+
readonly name: string;
|
|
199
|
+
readonly breakingChange: boolean;
|
|
200
|
+
};
|
|
201
|
+
export type specDiff = {
|
|
202
|
+
readonly addedEndpoints: endpoint[];
|
|
203
|
+
readonly removedEndpoints: endpoint[];
|
|
204
|
+
readonly modifiedEndpoints: endpointDiff[];
|
|
205
|
+
readonly addedSchemas: string[];
|
|
206
|
+
readonly removedSchemas: string[];
|
|
207
|
+
readonly modifiedSchemas: schemaDiff[];
|
|
208
|
+
};
|
|
209
|
+
export type generationSuccess = {
|
|
210
|
+
readonly generatedFiles: string[];
|
|
211
|
+
readonly diff: (undefined | specDiff);
|
|
212
|
+
readonly warnings: warning[];
|
|
213
|
+
};
|
|
214
|
+
export type generationResult = {
|
|
215
|
+
TAG: "Ok";
|
|
216
|
+
_0: generationSuccess;
|
|
217
|
+
} | {
|
|
218
|
+
TAG: "Error";
|
|
219
|
+
_0: codegenError;
|
|
220
|
+
};
|
|
221
|
+
export type CodegenError_context = {
|
|
222
|
+
readonly path: string;
|
|
223
|
+
readonly operation: string;
|
|
224
|
+
readonly schema: (undefined | unknown);
|
|
225
|
+
};
|
|
226
|
+
export type CodegenError_t = {
|
|
227
|
+
TAG: "SpecResolutionError";
|
|
228
|
+
readonly url: string;
|
|
229
|
+
readonly message: string;
|
|
230
|
+
} | {
|
|
231
|
+
TAG: "SchemaParseError";
|
|
232
|
+
readonly context: CodegenError_context;
|
|
233
|
+
readonly reason: string;
|
|
234
|
+
} | {
|
|
235
|
+
TAG: "ReferenceError";
|
|
236
|
+
readonly ref: string;
|
|
237
|
+
readonly context: CodegenError_context;
|
|
238
|
+
} | {
|
|
239
|
+
TAG: "ValidationError";
|
|
240
|
+
readonly schema: string;
|
|
241
|
+
readonly input: unknown;
|
|
242
|
+
readonly issues: string[];
|
|
243
|
+
} | {
|
|
244
|
+
TAG: "CircularSchemaError";
|
|
245
|
+
readonly ref: string;
|
|
246
|
+
readonly depth: number;
|
|
247
|
+
readonly path: string;
|
|
248
|
+
} | {
|
|
249
|
+
TAG: "FileWriteError";
|
|
250
|
+
readonly filePath: string;
|
|
251
|
+
readonly message: string;
|
|
252
|
+
} | {
|
|
253
|
+
TAG: "InvalidConfigError";
|
|
254
|
+
readonly field: string;
|
|
255
|
+
readonly message: string;
|
|
256
|
+
} | {
|
|
257
|
+
TAG: "UnknownError";
|
|
258
|
+
readonly message: string;
|
|
259
|
+
readonly context: (undefined | CodegenError_context);
|
|
260
|
+
};
|
|
261
|
+
export type Warning_t = {
|
|
262
|
+
TAG: "FallbackToJson";
|
|
263
|
+
readonly reason: string;
|
|
264
|
+
readonly context: CodegenError_context;
|
|
265
|
+
} | {
|
|
266
|
+
TAG: "UnsupportedFeature";
|
|
267
|
+
readonly feature: string;
|
|
268
|
+
readonly fallback: string;
|
|
269
|
+
readonly location: string;
|
|
270
|
+
} | {
|
|
271
|
+
TAG: "DepthLimitReached";
|
|
272
|
+
readonly depth: number;
|
|
273
|
+
readonly path: string;
|
|
274
|
+
} | {
|
|
275
|
+
TAG: "MissingSchema";
|
|
276
|
+
readonly ref: string;
|
|
277
|
+
readonly location: string;
|
|
278
|
+
} | {
|
|
279
|
+
TAG: "IntersectionNotFullySupported";
|
|
280
|
+
readonly location: string;
|
|
281
|
+
readonly note: string;
|
|
282
|
+
} | {
|
|
283
|
+
TAG: "ComplexUnionSimplified";
|
|
284
|
+
readonly location: string;
|
|
285
|
+
readonly types: string;
|
|
286
|
+
};
|