@f3liz/rescript-autogen-openapi 0.1.6 → 0.1.7
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/README.md +15 -2
- package/lib/es6/src/Codegen.d.ts +28 -0
- package/lib/es6/src/Types.d.ts +286 -0
- package/lib/es6/src/core/FileSystem.d.ts +4 -0
- package/lib/es6/src/core/Pipeline.d.ts +6 -0
- package/lib/es6/src/types/CodegenError.d.ts +66 -0
- package/lib/es6/src/types/Config.d.ts +31 -0
- package/package.json +11 -7
- package/rescript.json +6 -0
- package/src/Codegen.res +9 -0
- package/src/Types.res +27 -0
- package/src/core/FileSystem.res +1 -0
- package/src/core/Pipeline.res +1 -0
- package/src/types/CodegenError.res +3 -0
- package/src/types/Config.res +6 -0
package/README.md
CHANGED
|
@@ -9,12 +9,25 @@ Generate ReScript code with [Sury](https://github.com/DZakh/rescript-schema) sch
|
|
|
9
9
|
* **Multi-Fork Support**: Intelligently handles multiple API forks (like Misskey, Cherrypick, Firefish) by extracting shared code and generating fork-specific extensions.
|
|
10
10
|
* **Unified IR Pipeline**: Advanced type inference with a unified intermediate representation that generates both types and schemas.
|
|
11
11
|
* **Diff & Merge**: Compare specs, generate diff reports, and optimize code reuse across variants.
|
|
12
|
-
* **TypeScript Support**:
|
|
12
|
+
* **TypeScript Support**: First-class TypeScript support via `genType`. Exported functions and types are idiomatic and fully typed for use in TypeScript projects.
|
|
13
13
|
|
|
14
14
|
## 📦 Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npm install @f3liz/rescript-autogen-openapi sury
|
|
17
|
+
npm install @f3liz/rescript-autogen-openapi sury
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Important**: This library has a peer dependency on `sury` (ReScript Schema). You must install it in your project because the generated code directly depends on it for runtime validation.
|
|
21
|
+
|
|
22
|
+
### Configure `rescript.json`
|
|
23
|
+
|
|
24
|
+
Add `sury` to your project dependencies:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"name": "my-project",
|
|
29
|
+
"dependencies": ["sury"]
|
|
30
|
+
}
|
|
18
31
|
```
|
|
19
32
|
|
|
20
33
|
Ensure you have `rescript` (^12.0.0) installed.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { codegenError as Types_codegenError } from './Types';
|
|
2
|
+
import type { forkSpec as Types_forkSpec } from './Types';
|
|
3
|
+
import type { generationConfig as Types_generationConfig } from './Types';
|
|
4
|
+
import type { generationResult as Types_generationResult } from './Types';
|
|
5
|
+
import type { openAPISpec as Types_openAPISpec } from './Types';
|
|
6
|
+
import type { specDiff as Types_specDiff } from './Types';
|
|
7
|
+
import type { t as Pipeline_t } from './core/Pipeline';
|
|
8
|
+
export declare const generateSingleSpecPure: (spec: Types_openAPISpec, config: Types_generationConfig) => {
|
|
9
|
+
TAG: "Ok";
|
|
10
|
+
_0: Pipeline_t;
|
|
11
|
+
} | {
|
|
12
|
+
TAG: "Error";
|
|
13
|
+
_0: Types_codegenError;
|
|
14
|
+
};
|
|
15
|
+
export declare const generateSingleSpec: (spec: Types_openAPISpec, config: Types_generationConfig) => Promise<Types_generationResult>;
|
|
16
|
+
export declare const generateMultiSpecPure: (baseSpec: Types_openAPISpec, forkSpecs: Types_forkSpec[], config: Types_generationConfig) => {
|
|
17
|
+
TAG: "Ok";
|
|
18
|
+
_0: Pipeline_t;
|
|
19
|
+
} | {
|
|
20
|
+
TAG: "Error";
|
|
21
|
+
_0: Types_codegenError;
|
|
22
|
+
};
|
|
23
|
+
export declare const generateMultiSpec: (baseSpec: Types_openAPISpec, forkSpecs: Types_forkSpec[], config: Types_generationConfig) => Promise<Types_generationResult>;
|
|
24
|
+
export declare const compareSpecs: (baseSpec: Types_openAPISpec, forkSpec: Types_openAPISpec, baseName: (undefined | string), forkName: (undefined | string), outputPath: (undefined | string)) => Promise<Types_specDiff>;
|
|
25
|
+
export declare const generate: (config: Types_generationConfig) => Promise<Types_generationResult>;
|
|
26
|
+
export declare const createDefaultConfig: (url: string, outputDir: string) => Types_generationConfig;
|
|
27
|
+
export declare const generateFromUrl: (url: string, outputDir: string, config: (undefined | Types_generationConfig)) => Promise<Types_generationResult>;
|
|
28
|
+
export declare const generateFromFile: (filePath: string, outputDir: string, config: (undefined | Types_generationConfig)) => Promise<Types_generationResult>;
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type context = {
|
|
2
|
+
readonly path: string;
|
|
3
|
+
readonly operation: string;
|
|
4
|
+
readonly schema: (undefined | unknown);
|
|
5
|
+
};
|
|
6
|
+
export type t = {
|
|
7
|
+
TAG: "SpecResolutionError";
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
} | {
|
|
11
|
+
TAG: "SchemaParseError";
|
|
12
|
+
readonly context: context;
|
|
13
|
+
readonly reason: string;
|
|
14
|
+
} | {
|
|
15
|
+
TAG: "ReferenceError";
|
|
16
|
+
readonly ref: string;
|
|
17
|
+
readonly context: context;
|
|
18
|
+
} | {
|
|
19
|
+
TAG: "ValidationError";
|
|
20
|
+
readonly schema: string;
|
|
21
|
+
readonly input: unknown;
|
|
22
|
+
readonly issues: string[];
|
|
23
|
+
} | {
|
|
24
|
+
TAG: "CircularSchemaError";
|
|
25
|
+
readonly ref: string;
|
|
26
|
+
readonly depth: number;
|
|
27
|
+
readonly path: string;
|
|
28
|
+
} | {
|
|
29
|
+
TAG: "FileWriteError";
|
|
30
|
+
readonly filePath: string;
|
|
31
|
+
readonly message: string;
|
|
32
|
+
} | {
|
|
33
|
+
TAG: "InvalidConfigError";
|
|
34
|
+
readonly field: string;
|
|
35
|
+
readonly message: string;
|
|
36
|
+
} | {
|
|
37
|
+
TAG: "UnknownError";
|
|
38
|
+
readonly message: string;
|
|
39
|
+
readonly context: (undefined | context);
|
|
40
|
+
};
|
|
41
|
+
export type Warning_t = {
|
|
42
|
+
TAG: "FallbackToJson";
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
readonly context: context;
|
|
45
|
+
} | {
|
|
46
|
+
TAG: "UnsupportedFeature";
|
|
47
|
+
readonly feature: string;
|
|
48
|
+
readonly fallback: string;
|
|
49
|
+
readonly location: string;
|
|
50
|
+
} | {
|
|
51
|
+
TAG: "DepthLimitReached";
|
|
52
|
+
readonly depth: number;
|
|
53
|
+
readonly path: string;
|
|
54
|
+
} | {
|
|
55
|
+
TAG: "MissingSchema";
|
|
56
|
+
readonly ref: string;
|
|
57
|
+
readonly location: string;
|
|
58
|
+
} | {
|
|
59
|
+
TAG: "IntersectionNotFullySupported";
|
|
60
|
+
readonly location: string;
|
|
61
|
+
readonly note: string;
|
|
62
|
+
} | {
|
|
63
|
+
TAG: "ComplexUnionSimplified";
|
|
64
|
+
readonly location: string;
|
|
65
|
+
readonly types: string;
|
|
66
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type generationStrategy = "Separate" | "SharedBase";
|
|
2
|
+
export type breakingChangeHandling = "Error" | "Warn" | "Ignore";
|
|
3
|
+
export type forkSpecConfig = {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly specPath: string;
|
|
6
|
+
};
|
|
7
|
+
export type generationTargets = {
|
|
8
|
+
readonly rescriptApi: boolean;
|
|
9
|
+
readonly rescriptWrapper: boolean;
|
|
10
|
+
readonly typescriptDts: boolean;
|
|
11
|
+
readonly typescriptWrapper: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type t = {
|
|
14
|
+
readonly specPath: string;
|
|
15
|
+
readonly forkSpecs: (undefined | forkSpecConfig[]);
|
|
16
|
+
readonly outputDir: string;
|
|
17
|
+
readonly strategy: generationStrategy;
|
|
18
|
+
readonly modulePerTag: boolean;
|
|
19
|
+
readonly includeTags: (undefined | string[]);
|
|
20
|
+
readonly excludeTags: (undefined | string[]);
|
|
21
|
+
readonly generateDiffReport: boolean;
|
|
22
|
+
readonly breakingChangeHandling: breakingChangeHandling;
|
|
23
|
+
readonly generateDocOverrides: (undefined | boolean);
|
|
24
|
+
readonly docOverrideDir: (undefined | string);
|
|
25
|
+
readonly targets: (undefined | generationTargets);
|
|
26
|
+
readonly dtsOutputDir: (undefined | string);
|
|
27
|
+
readonly wrapperOutputDir: (undefined | string);
|
|
28
|
+
readonly baseInstanceName: (undefined | string);
|
|
29
|
+
readonly baseModulePrefix: (undefined | string);
|
|
30
|
+
};
|
|
31
|
+
export declare const make: (specPath: string, outputDir: string, strategy: (undefined | generationStrategy), modulePerTag: (undefined | boolean), includeTags: (undefined | string[]), excludeTags: (undefined | string[]), generateDiffReport: (undefined | boolean), breakingChangeHandling: (undefined | breakingChangeHandling), forkSpecs: (undefined | forkSpecConfig[]), generateDocOverrides: (undefined | boolean), docOverrideDir: (undefined | string), targets: (undefined | generationTargets), dtsOutputDir: (undefined | string), wrapperOutputDir: (undefined | string), baseInstanceName: (undefined | string), baseModulePrefix: (undefined | string), _17: void) => t;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@f3liz/rescript-autogen-openapi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Generate ReScript code with Sury schemas from OpenAPI 3.1 specs. Supports multiple forks with diff/merge capabilities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rescript",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"license": "MPL-2.0",
|
|
17
17
|
"files": [
|
|
18
18
|
"src/**/*.res",
|
|
19
|
-
"lib/es6/**/*.mjs",
|
|
19
|
+
"lib/es6/src/**/*.mjs",
|
|
20
|
+
"lib/es6/src/**/*.d.ts",
|
|
20
21
|
"rescript.json",
|
|
21
22
|
"README.md",
|
|
22
23
|
"LICENSE"
|
|
@@ -25,23 +26,26 @@
|
|
|
25
26
|
"url": "https://github.com/f3liz-dev/rescript-autogen-openapi"
|
|
26
27
|
},
|
|
27
28
|
"scripts": {
|
|
28
|
-
"build": "rescript",
|
|
29
|
+
"build": "rescript && node scripts/generate-dts.mjs",
|
|
29
30
|
"clean": "rescript clean",
|
|
30
31
|
"watch": "rescript build -w",
|
|
31
32
|
"test": "node --test"
|
|
32
33
|
},
|
|
33
34
|
"main": "lib/es6/src/Codegen.mjs",
|
|
35
|
+
"types": "lib/es6/src/Codegen.d.ts",
|
|
34
36
|
"type": "module",
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"@readme/openapi-parser": "^5.5.0",
|
|
37
39
|
"js-convert-case": "^4.2.0",
|
|
38
|
-
"pathe": "^2.0.3"
|
|
39
|
-
"sury": "11.0.0-alpha.4"
|
|
40
|
+
"pathe": "^2.0.3"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"rescript": "^12.1.0"
|
|
43
|
+
"rescript": "^12.1.0",
|
|
44
|
+
"sury": "11.0.0-alpha.4",
|
|
45
|
+
"typescript": "^5.9.3"
|
|
43
46
|
},
|
|
44
47
|
"peerDependencies": {
|
|
45
|
-
"rescript": "^12.0.0"
|
|
48
|
+
"rescript": "^12.0.0",
|
|
49
|
+
"sury": ">=11.0.0-alpha.4"
|
|
46
50
|
}
|
|
47
51
|
}
|
package/rescript.json
CHANGED
package/src/Codegen.res
CHANGED
|
@@ -7,6 +7,7 @@ open Types
|
|
|
7
7
|
@val external promiseAll: array<promise<'a>> => promise<array<'a>> = "Promise.all"
|
|
8
8
|
|
|
9
9
|
// Generate code from a single spec (pure - returns data)
|
|
10
|
+
@genType
|
|
10
11
|
let generateSingleSpecPure = (~spec: openAPISpec, ~config: generationConfig): result<Pipeline.t, codegenError> => {
|
|
11
12
|
try {
|
|
12
13
|
let targets = config.targets->Option.getOr(Config.defaultTargets())
|
|
@@ -54,6 +55,7 @@ let generateSingleSpecPure = (~spec: openAPISpec, ~config: generationConfig): re
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
// Generate code from a single spec (with side effects)
|
|
58
|
+
@genType
|
|
57
59
|
let generateSingleSpec = async (~spec: openAPISpec, ~config: generationConfig): generationResult => {
|
|
58
60
|
switch generateSingleSpecPure(~spec, ~config) {
|
|
59
61
|
| Result.Error(err) => Result.Error(err)
|
|
@@ -140,6 +142,7 @@ let processForkPure = (~baseSpec: openAPISpec, ~baseEndpoints: array<endpoint>,
|
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
// Generate code from multiple specs (pure - returns data)
|
|
145
|
+
@genType
|
|
143
146
|
let generateMultiSpecPure = (~baseSpec: openAPISpec, ~forkSpecs: array<forkSpec>, ~config: generationConfig): result<Pipeline.t, codegenError> => {
|
|
144
147
|
try {
|
|
145
148
|
let baseEndpoints = OpenAPIParser.getAllEndpoints(baseSpec)
|
|
@@ -169,6 +172,7 @@ let generateMultiSpecPure = (~baseSpec: openAPISpec, ~forkSpecs: array<forkSpec>
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
// Generate code from multiple specs (with side effects)
|
|
175
|
+
@genType
|
|
172
176
|
let generateMultiSpec = async (~baseSpec: openAPISpec, ~forkSpecs: array<forkSpec>, ~config: generationConfig): generationResult =>
|
|
173
177
|
switch generateMultiSpecPure(~baseSpec, ~forkSpecs, ~config) {
|
|
174
178
|
| Result.Error(err) => Result.Error(err)
|
|
@@ -179,6 +183,7 @@ let generateMultiSpec = async (~baseSpec: openAPISpec, ~forkSpecs: array<forkSpe
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
// Compare two specs and generate diff report
|
|
186
|
+
@genType
|
|
182
187
|
let compareSpecs = async (~baseSpec, ~forkSpec, ~baseName="base", ~forkName="fork", ~outputPath=?) => {
|
|
183
188
|
let diff = SpecDiffer.generateDiff(~baseSpec, ~forkSpec, ~baseEndpoints=OpenAPIParser.getAllEndpoints(baseSpec), ~forkEndpoints=OpenAPIParser.getAllEndpoints(forkSpec))
|
|
184
189
|
outputPath->Option.forEach(path => {
|
|
@@ -188,6 +193,7 @@ let compareSpecs = async (~baseSpec, ~forkSpec, ~baseName="base", ~forkName="for
|
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
// Main generation function
|
|
196
|
+
@genType
|
|
191
197
|
let generate = async (config: generationConfig): generationResult => {
|
|
192
198
|
switch await SchemaRefResolver.resolve(config.specPath) {
|
|
193
199
|
| Result.Error(message) => Result.Error(SpecResolutionError({url: config.specPath, message}))
|
|
@@ -207,6 +213,7 @@ let generate = async (config: generationConfig): generationResult => {
|
|
|
207
213
|
}
|
|
208
214
|
}
|
|
209
215
|
|
|
216
|
+
@genType
|
|
210
217
|
let createDefaultConfig = (url, outputDir): generationConfig => ({
|
|
211
218
|
specPath: url, outputDir, strategy: SharedBase, includeTags: None, excludeTags: None,
|
|
212
219
|
modulePerTag: true, generateDiffReport: true, breakingChangeHandling: Warn,
|
|
@@ -215,8 +222,10 @@ let createDefaultConfig = (url, outputDir): generationConfig => ({
|
|
|
215
222
|
baseInstanceName: None, baseModulePrefix: None,
|
|
216
223
|
})
|
|
217
224
|
|
|
225
|
+
@genType
|
|
218
226
|
let generateFromUrl = async (~url, ~outputDir, ~config=?) =>
|
|
219
227
|
await generate({...config->Option.getOr(createDefaultConfig(url, outputDir)), specPath: url})
|
|
220
228
|
|
|
229
|
+
@genType
|
|
221
230
|
let generateFromFile = async (~filePath, ~outputDir, ~config=?) =>
|
|
222
231
|
await generate({...config->Option.getOr(createDefaultConfig(filePath, outputDir)), specPath: filePath})
|
package/src/Types.res
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Types.res - Core OpenAPI and generation types (refactored & compact)
|
|
4
4
|
|
|
5
5
|
// ============= JSON Schema Types =============
|
|
6
|
+
@genType
|
|
6
7
|
type rec jsonSchemaType =
|
|
7
8
|
| String
|
|
8
9
|
| Number
|
|
@@ -13,6 +14,7 @@ type rec jsonSchemaType =
|
|
|
13
14
|
| Null
|
|
14
15
|
| Unknown
|
|
15
16
|
|
|
17
|
+
@genType
|
|
16
18
|
and jsonSchema = {
|
|
17
19
|
@as("type") type_: option<jsonSchemaType>,
|
|
18
20
|
properties: option<dict<jsonSchema>>,
|
|
@@ -34,25 +36,30 @@ and jsonSchema = {
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
// ============= OpenAPI 3.1 Types =============
|
|
39
|
+
@genType
|
|
37
40
|
type httpMethod = [#GET | #POST | #PUT | #PATCH | #DELETE | #HEAD | #OPTIONS]
|
|
38
41
|
|
|
42
|
+
@genType
|
|
39
43
|
type mediaType = {
|
|
40
44
|
schema: option<jsonSchema>,
|
|
41
45
|
example: option<JSON.t>,
|
|
42
46
|
examples: option<dict<JSON.t>>,
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
@genType
|
|
45
50
|
type requestBody = {
|
|
46
51
|
description: option<string>,
|
|
47
52
|
content: dict<mediaType>,
|
|
48
53
|
required: option<bool>,
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
@genType
|
|
51
57
|
type response = {
|
|
52
58
|
description: string,
|
|
53
59
|
content: option<dict<mediaType>>,
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
@genType
|
|
56
63
|
type parameter = {
|
|
57
64
|
name: string,
|
|
58
65
|
@as("in") in_: string,
|
|
@@ -61,6 +68,7 @@ type parameter = {
|
|
|
61
68
|
schema: option<jsonSchema>,
|
|
62
69
|
}
|
|
63
70
|
|
|
71
|
+
@genType
|
|
64
72
|
type operation = {
|
|
65
73
|
operationId: option<string>,
|
|
66
74
|
summary: option<string>,
|
|
@@ -71,6 +79,7 @@ type operation = {
|
|
|
71
79
|
parameters: option<array<parameter>>,
|
|
72
80
|
}
|
|
73
81
|
|
|
82
|
+
@genType
|
|
74
83
|
type endpoint = {
|
|
75
84
|
path: string,
|
|
76
85
|
method: string,
|
|
@@ -83,6 +92,7 @@ type endpoint = {
|
|
|
83
92
|
parameters: option<array<parameter>>,
|
|
84
93
|
}
|
|
85
94
|
|
|
95
|
+
@genType
|
|
86
96
|
type pathItem = {
|
|
87
97
|
get: option<operation>,
|
|
88
98
|
post: option<operation>,
|
|
@@ -94,14 +104,17 @@ type pathItem = {
|
|
|
94
104
|
parameters: option<array<parameter>>,
|
|
95
105
|
}
|
|
96
106
|
|
|
107
|
+
@genType
|
|
97
108
|
type components = {schemas: option<dict<jsonSchema>>}
|
|
98
109
|
|
|
110
|
+
@genType
|
|
99
111
|
type info = {
|
|
100
112
|
title: string,
|
|
101
113
|
version: string,
|
|
102
114
|
description: option<string>,
|
|
103
115
|
}
|
|
104
116
|
|
|
117
|
+
@genType
|
|
105
118
|
type openAPISpec = {
|
|
106
119
|
openapi: string,
|
|
107
120
|
info: info,
|
|
@@ -111,32 +124,40 @@ type openAPISpec = {
|
|
|
111
124
|
|
|
112
125
|
// ============= Re-exports from focused modules =============
|
|
113
126
|
// Config types
|
|
127
|
+
@genType
|
|
114
128
|
type generationStrategy = Config.generationStrategy =
|
|
115
129
|
| Separate
|
|
116
130
|
| SharedBase
|
|
117
131
|
|
|
132
|
+
@genType
|
|
118
133
|
type breakingChangeHandling = Config.breakingChangeHandling = | Error | Warn | Ignore
|
|
134
|
+
@genType
|
|
119
135
|
type forkSpecConfig = Config.forkSpecConfig = {name: string, specPath: string}
|
|
136
|
+
@genType
|
|
120
137
|
type generationTargets = Config.generationTargets = {
|
|
121
138
|
rescriptApi: bool,
|
|
122
139
|
rescriptWrapper: bool,
|
|
123
140
|
typescriptDts: bool,
|
|
124
141
|
typescriptWrapper: bool,
|
|
125
142
|
}
|
|
143
|
+
@genType
|
|
126
144
|
type generationConfig = Config.t
|
|
127
145
|
|
|
146
|
+
@genType
|
|
128
147
|
type forkSpec = {
|
|
129
148
|
name: string,
|
|
130
149
|
spec: openAPISpec,
|
|
131
150
|
}
|
|
132
151
|
|
|
133
152
|
// Error types - use `=` syntax to re-export constructors
|
|
153
|
+
@genType
|
|
134
154
|
type errorContext = CodegenError.context = {
|
|
135
155
|
path: string,
|
|
136
156
|
operation: string,
|
|
137
157
|
schema: option<JSON.t>,
|
|
138
158
|
}
|
|
139
159
|
|
|
160
|
+
@genType
|
|
140
161
|
type codegenError = CodegenError.t =
|
|
141
162
|
| SpecResolutionError({url: string, message: string})
|
|
142
163
|
| SchemaParseError({context: errorContext, reason: string})
|
|
@@ -147,6 +168,7 @@ type codegenError = CodegenError.t =
|
|
|
147
168
|
| InvalidConfigError({field: string, message: string})
|
|
148
169
|
| UnknownError({message: string, context: option<errorContext>})
|
|
149
170
|
|
|
171
|
+
@genType
|
|
150
172
|
type warning = CodegenError.Warning.t =
|
|
151
173
|
| FallbackToJson({reason: string, context: errorContext})
|
|
152
174
|
| UnsupportedFeature({feature: string, fallback: string, location: string})
|
|
@@ -156,6 +178,7 @@ type warning = CodegenError.Warning.t =
|
|
|
156
178
|
| ComplexUnionSimplified({location: string, types: string})
|
|
157
179
|
|
|
158
180
|
// ============= Diff Types =============
|
|
181
|
+
@genType
|
|
159
182
|
type endpointDiff = {
|
|
160
183
|
path: string,
|
|
161
184
|
method: string,
|
|
@@ -164,11 +187,13 @@ type endpointDiff = {
|
|
|
164
187
|
breakingChange: bool,
|
|
165
188
|
}
|
|
166
189
|
|
|
190
|
+
@genType
|
|
167
191
|
type schemaDiff = {
|
|
168
192
|
name: string,
|
|
169
193
|
breakingChange: bool,
|
|
170
194
|
}
|
|
171
195
|
|
|
196
|
+
@genType
|
|
172
197
|
type specDiff = {
|
|
173
198
|
addedEndpoints: array<endpoint>,
|
|
174
199
|
removedEndpoints: array<endpoint>,
|
|
@@ -179,12 +204,14 @@ type specDiff = {
|
|
|
179
204
|
}
|
|
180
205
|
|
|
181
206
|
// ============= Generation Result Types =============
|
|
207
|
+
@genType
|
|
182
208
|
type generationSuccess = {
|
|
183
209
|
generatedFiles: array<string>,
|
|
184
210
|
diff: option<specDiff>,
|
|
185
211
|
warnings: array<warning>,
|
|
186
212
|
}
|
|
187
213
|
|
|
214
|
+
@genType
|
|
188
215
|
type generationResult = result<generationSuccess, codegenError>
|
|
189
216
|
|
|
190
217
|
// ============= Re-export helper modules =============
|
package/src/core/FileSystem.res
CHANGED
package/src/core/Pipeline.res
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Error.res - Compact error and warning types with helpers
|
|
4
4
|
|
|
5
5
|
// Error context for debugging (defined here to avoid circular dependency)
|
|
6
|
+
@genType
|
|
6
7
|
type context = {
|
|
7
8
|
path: string,
|
|
8
9
|
operation: string,
|
|
@@ -10,6 +11,7 @@ type context = {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
// Structured error types (keep original names for backward compat)
|
|
14
|
+
@genType
|
|
13
15
|
type t =
|
|
14
16
|
| SpecResolutionError({url: string, message: string})
|
|
15
17
|
| SchemaParseError({context: context, reason: string})
|
|
@@ -22,6 +24,7 @@ type t =
|
|
|
22
24
|
|
|
23
25
|
// Warning types
|
|
24
26
|
module Warning = {
|
|
27
|
+
@genType
|
|
25
28
|
type t =
|
|
26
29
|
| FallbackToJson({reason: string, context: context})
|
|
27
30
|
| UnsupportedFeature({feature: string, fallback: string, location: string})
|
package/src/types/Config.res
CHANGED
|
@@ -2,20 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
// Config.res - Generation configuration types
|
|
4
4
|
|
|
5
|
+
@genType
|
|
5
6
|
type generationStrategy =
|
|
6
7
|
| Separate
|
|
7
8
|
| SharedBase
|
|
8
9
|
|
|
10
|
+
@genType
|
|
9
11
|
type breakingChangeHandling =
|
|
10
12
|
| Error
|
|
11
13
|
| Warn
|
|
12
14
|
| Ignore
|
|
13
15
|
|
|
16
|
+
@genType
|
|
14
17
|
type forkSpecConfig = {
|
|
15
18
|
name: string,
|
|
16
19
|
specPath: string,
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
@genType
|
|
19
23
|
type generationTargets = {
|
|
20
24
|
rescriptApi: bool, // Generate base ReScript API (always true by default)
|
|
21
25
|
rescriptWrapper: bool, // Generate ReScript thin wrapper (pipe-first)
|
|
@@ -23,6 +27,7 @@ type generationTargets = {
|
|
|
23
27
|
typescriptWrapper: bool, // Generate TypeScript/JavaScript wrapper
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
@genType
|
|
26
31
|
type t = {
|
|
27
32
|
specPath: string,
|
|
28
33
|
forkSpecs: option<array<forkSpecConfig>>,
|
|
@@ -43,6 +48,7 @@ type t = {
|
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
// Default configuration
|
|
51
|
+
@genType
|
|
46
52
|
let make = (
|
|
47
53
|
~specPath,
|
|
48
54
|
~outputDir,
|