@f3liz/rescript-autogen-openapi 0.1.6 → 0.2.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/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/generators/IRToSuryGenerator.mjs +100 -27
- package/lib/es6/src/generators/IRToTypeGenerator.mjs +167 -22
- package/lib/es6/src/types/CodegenError.d.ts +66 -0
- package/lib/es6/src/types/Config.d.ts +31 -0
- package/package.json +13 -8
- 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/generators/IRToSuryGenerator.res +87 -35
- package/src/generators/IRToTypeGenerator.res +121 -46
- 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
|
+
};
|
|
@@ -97,7 +97,22 @@ function generateSchemaWithContext(ctx, depthOpt, irType) {
|
|
|
97
97
|
}
|
|
98
98
|
case "Union" :
|
|
99
99
|
let types = irType._0;
|
|
100
|
-
let
|
|
100
|
+
let nonNullTypes = types.filter(t => {
|
|
101
|
+
if (typeof t !== "object") {
|
|
102
|
+
return t !== "Null";
|
|
103
|
+
}
|
|
104
|
+
if (t.TAG !== "Literal") {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
let tmp = t._0;
|
|
108
|
+
return typeof tmp === "object";
|
|
109
|
+
});
|
|
110
|
+
let hasNull = nonNullTypes.length < types.length;
|
|
111
|
+
if (hasNull && nonNullTypes.length === 1) {
|
|
112
|
+
return `S.nullableAsOption(` + recurse(nonNullTypes[0]) + `)`;
|
|
113
|
+
}
|
|
114
|
+
let effectiveTypes = hasNull ? nonNullTypes : types;
|
|
115
|
+
let match = Stdlib_Array.reduce(effectiveTypes, [
|
|
101
116
|
false,
|
|
102
117
|
false,
|
|
103
118
|
undefined,
|
|
@@ -122,39 +137,97 @@ function generateSchemaWithContext(ctx, depthOpt, irType) {
|
|
|
122
137
|
}
|
|
123
138
|
});
|
|
124
139
|
let arrayItemType = match[2];
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
140
|
+
let result = match[0] && match[1] && effectiveTypes.length === 2 && SchemaIR.equals(Stdlib_Option.getOr(arrayItemType, "Unknown"), Stdlib_Option.getOr(match[3], "Unknown")) ? `S.array(` + recurse(Stdlib_Option.getOr(arrayItemType, "Unknown")) + `)` : (
|
|
141
|
+
effectiveTypes.every(t => {
|
|
142
|
+
if (typeof t !== "object") {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if (t.TAG !== "Literal") {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
let tmp = t._0;
|
|
149
|
+
if (typeof tmp !== "object") {
|
|
150
|
+
return false;
|
|
151
|
+
} else {
|
|
152
|
+
return tmp.TAG === "StringLiteral";
|
|
153
|
+
}
|
|
154
|
+
}) && effectiveTypes.length !== 0 && effectiveTypes.length <= 50 ? `S.union([` + effectiveTypes.map(recurse).join(", ") + `])` : (
|
|
155
|
+
effectiveTypes.length !== 0 ? `S.union([` + effectiveTypes.map(recurse).join(", ") + `])` : "S.json"
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
if (hasNull) {
|
|
159
|
+
return `S.nullableAsOption(` + result + `)`;
|
|
160
|
+
} else {
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
case "Intersection" :
|
|
164
|
+
let types$1 = irType._0;
|
|
165
|
+
if (types$1.every(t => {
|
|
128
166
|
if (typeof t !== "object") {
|
|
129
167
|
return false;
|
|
168
|
+
} else {
|
|
169
|
+
return t.TAG === "Reference";
|
|
130
170
|
}
|
|
131
|
-
|
|
132
|
-
|
|
171
|
+
}) && types$1.length !== 0) {
|
|
172
|
+
return recurse(Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown"));
|
|
173
|
+
}
|
|
174
|
+
let match$1 = Stdlib_Array.reduce(types$1, [
|
|
175
|
+
[],
|
|
176
|
+
[]
|
|
177
|
+
], (param, t) => {
|
|
178
|
+
let nonObj = param[1];
|
|
179
|
+
let props = param[0];
|
|
180
|
+
if (typeof t !== "object") {
|
|
181
|
+
return [
|
|
182
|
+
props,
|
|
183
|
+
nonObj.concat([t])
|
|
184
|
+
];
|
|
185
|
+
} else if (t.TAG === "Object") {
|
|
186
|
+
return [
|
|
187
|
+
props.concat(t.properties),
|
|
188
|
+
nonObj
|
|
189
|
+
];
|
|
190
|
+
} else {
|
|
191
|
+
return [
|
|
192
|
+
props,
|
|
193
|
+
nonObj.concat([t])
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
let nonObjectTypes = match$1[1];
|
|
198
|
+
let objectProps = match$1[0];
|
|
199
|
+
if (objectProps.length !== 0 && nonObjectTypes.length === 0) {
|
|
200
|
+
let fields$1 = objectProps.map(param => {
|
|
201
|
+
let name = param[0];
|
|
202
|
+
let schemaCode = recurse(param[1]);
|
|
203
|
+
let camelName = CodegenUtils.escapeKeyword(JsConvertCase.toCamelCase(name));
|
|
204
|
+
if (param[2]) {
|
|
205
|
+
return ` ` + camelName + `: s.field("` + name + `", ` + schemaCode + `),`;
|
|
206
|
+
} else {
|
|
207
|
+
return ` ` + camelName + `: s.fieldOr("` + name + `", S.nullableAsOption(` + schemaCode + `), None),`;
|
|
133
208
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}) && types.length !== 0 && types.length <= 50) {
|
|
137
|
-
return `S.union([` + types.map(recurse).join(", ") + `])`;
|
|
138
|
-
} else {
|
|
139
|
-
GenerationContext.addWarning(ctx, {
|
|
140
|
-
TAG: "ComplexUnionSimplified",
|
|
141
|
-
location: ctx.path,
|
|
142
|
-
types: types.map(SchemaIR.toString).join(" | ")
|
|
143
|
-
});
|
|
144
|
-
return "S.json";
|
|
209
|
+
}).join("\n");
|
|
210
|
+
return `S.object(s => {\n` + fields$1 + `\n })`;
|
|
145
211
|
}
|
|
146
|
-
|
|
147
|
-
let types$1 = irType._0;
|
|
148
|
-
if (types$1.every(t => typeof t !== "object" ? false : t.TAG === "Reference") && types$1.length !== 0) {
|
|
212
|
+
if (nonObjectTypes.length !== 0 && objectProps.length === 0) {
|
|
149
213
|
return recurse(Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown"));
|
|
150
|
-
} else {
|
|
151
|
-
GenerationContext.addWarning(ctx, {
|
|
152
|
-
TAG: "IntersectionNotFullySupported",
|
|
153
|
-
location: ctx.path,
|
|
154
|
-
note: "Complex intersection"
|
|
155
|
-
});
|
|
156
|
-
return "S.json";
|
|
157
214
|
}
|
|
215
|
+
GenerationContext.addWarning(ctx, {
|
|
216
|
+
TAG: "IntersectionNotFullySupported",
|
|
217
|
+
location: ctx.path,
|
|
218
|
+
note: "Mixed object/non-object intersection"
|
|
219
|
+
});
|
|
220
|
+
let fields$2 = objectProps.map(param => {
|
|
221
|
+
let name = param[0];
|
|
222
|
+
let schemaCode = recurse(param[1]);
|
|
223
|
+
let camelName = CodegenUtils.escapeKeyword(JsConvertCase.toCamelCase(name));
|
|
224
|
+
if (param[2]) {
|
|
225
|
+
return ` ` + camelName + `: s.field("` + name + `", ` + schemaCode + `),`;
|
|
226
|
+
} else {
|
|
227
|
+
return ` ` + camelName + `: s.fieldOr("` + name + `", S.nullableAsOption(` + schemaCode + `), None),`;
|
|
228
|
+
}
|
|
229
|
+
}).join("\n");
|
|
230
|
+
return `S.object(s => {\n` + fields$2 + `\n })`;
|
|
158
231
|
case "Reference" :
|
|
159
232
|
let ref = irType._0;
|
|
160
233
|
let available = ctx.availableSchemas;
|