@f3liz/rescript-autogen-openapi 0.2.0 → 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.

@@ -10,318 +10,490 @@ import * as GenerationContext from "../types/GenerationContext.mjs";
10
10
  import * as IRToSuryGenerator from "./IRToSuryGenerator.mjs";
11
11
  import * as ReferenceResolver from "../core/ReferenceResolver.mjs";
12
12
 
13
- function generateTypeWithContext(ctx, depthOpt, irType) {
14
- let depth = depthOpt !== undefined ? depthOpt : 0;
15
- if (depth > 100) {
16
- GenerationContext.addWarning(ctx, {
17
- TAG: "DepthLimitReached",
18
- depth: depth,
19
- path: ctx.path
20
- });
21
- return "JSON.t";
22
- }
23
- let recurse = nextIrType => generateTypeWithContext(ctx, depth + 1 | 0, nextIrType);
24
- if (typeof irType !== "object") {
25
- switch (irType) {
26
- case "Boolean" :
27
- return "bool";
28
- case "Null" :
29
- return "unit";
30
- case "Unknown" :
31
- return "JSON.t";
13
+ function generateTypeWithContext(ctx, _depthOpt, _inlineOpt, _irType) {
14
+ while (true) {
15
+ let depthOpt = _depthOpt;
16
+ let inlineOpt = _inlineOpt;
17
+ let irType = _irType;
18
+ let depth = depthOpt !== undefined ? depthOpt : 0;
19
+ let inline = inlineOpt !== undefined ? inlineOpt : false;
20
+ if (depth > 100) {
21
+ GenerationContext.addWarning(ctx, {
22
+ TAG: "DepthLimitReached",
23
+ depth: depth,
24
+ path: ctx.path
25
+ });
26
+ return "JSON.t";
32
27
  }
33
- } else {
34
- switch (irType.TAG) {
35
- case "String" :
36
- return "string";
37
- case "Number" :
38
- return "float";
39
- case "Integer" :
40
- return "int";
41
- case "Array" :
42
- return `array<` + recurse(irType.items) + `>`;
43
- case "Object" :
44
- let additionalProperties = irType.additionalProperties;
45
- let properties = irType.properties;
46
- if (properties.length === 0) {
47
- if (additionalProperties !== undefined) {
48
- return `dict<` + recurse(additionalProperties) + `>`;
49
- } else {
50
- return "JSON.t";
51
- }
52
- }
53
- let fields = properties.map(param => {
54
- let name = param[0];
55
- let typeCode = recurse(param[1]);
56
- let finalType = param[2] ? typeCode : `option<` + typeCode + `>`;
57
- let camelName = JsConvertCase.toCamelCase(name);
58
- let escapedName = CodegenUtils.escapeKeyword(camelName);
59
- let aliasAnnotation = escapedName !== name ? `@as("` + name + `") ` : "";
60
- return ` ` + aliasAnnotation + escapedName + `: ` + finalType + `,`;
61
- }).join("\n");
62
- return `{\n` + fields + `\n}`;
63
- case "Literal" :
64
- let tmp = irType._0;
65
- if (typeof tmp !== "object") {
28
+ let recurseInline = nextIrType => generateTypeWithContext(ctx, depth + 1 | 0, true, nextIrType);
29
+ if (typeof irType !== "object") {
30
+ switch (irType) {
31
+ case "Boolean" :
32
+ return "bool";
33
+ case "Null" :
66
34
  return "unit";
67
- }
68
- switch (tmp.TAG) {
69
- case "StringLiteral" :
70
- return "string";
71
- case "NumberLiteral" :
72
- return "float";
73
- case "BooleanLiteral" :
74
- return "bool";
75
- }
76
- case "Union" :
77
- let types = irType._0;
78
- let nonNullTypes = types.filter(t => {
79
- if (typeof t !== "object") {
80
- return t !== "Null";
35
+ case "Unknown" :
36
+ return "JSON.t";
37
+ }
38
+ } else {
39
+ switch (irType.TAG) {
40
+ case "String" :
41
+ return "string";
42
+ case "Number" :
43
+ return "float";
44
+ case "Integer" :
45
+ return "int";
46
+ case "Array" :
47
+ return `array<` + recurseInline(irType.items) + `>`;
48
+ case "Object" :
49
+ let additionalProperties = irType.additionalProperties;
50
+ let properties = irType.properties;
51
+ if (properties.length === 0) {
52
+ if (additionalProperties !== undefined) {
53
+ return `dict<` + recurseInline(additionalProperties) + `>`;
54
+ } else {
55
+ return "dict<JSON.t>";
56
+ }
81
57
  }
82
- if (t.TAG !== "Literal") {
83
- return true;
58
+ if (inline) {
59
+ let baseName = Stdlib_Option.getOr(ctx.path.split(".")[ctx.path.split(".").length - 1 | 0], "item");
60
+ return GenerationContext.extractType(ctx, baseName, undefined, irType);
84
61
  }
85
- let tmp = t._0;
86
- return typeof tmp === "object";
87
- });
88
- let hasNull = nonNullTypes.length < types.length;
89
- if (hasNull && nonNullTypes.length === 1) {
90
- let inner = recurse(nonNullTypes[0]);
91
- return `option<` + inner + `>`;
92
- }
93
- let effectiveTypes = hasNull ? nonNullTypes : types;
94
- let match = Stdlib_Array.reduce(effectiveTypes, [
95
- false,
96
- false,
97
- undefined,
98
- undefined
99
- ], (param, t) => {
100
- let arrItem = param[2];
101
- let hArr = param[0];
102
- if (typeof t !== "object" || t.TAG !== "Array") {
103
- return [
104
- hArr,
105
- true,
106
- arrItem,
107
- t
108
- ];
109
- } else {
110
- return [
111
- true,
112
- param[1],
113
- t.items,
114
- param[3]
115
- ];
62
+ let fields = properties.map(param => {
63
+ let fieldType = param[1];
64
+ let name = param[0];
65
+ let typeCode = recurseInline(fieldType);
66
+ let alreadyNullable = true;
67
+ if (!typeCode.startsWith("option<")) {
68
+ let tmp;
69
+ if (typeof fieldType !== "object") {
70
+ tmp = false;
71
+ } else {
72
+ switch (fieldType.TAG) {
73
+ case "Union" :
74
+ tmp = fieldType._0.some(t => {
75
+ if (typeof t !== "object") {
76
+ return t === "Null";
77
+ }
78
+ if (t.TAG !== "Literal") {
79
+ return false;
80
+ }
81
+ let tmp = t._0;
82
+ return typeof tmp !== "object";
83
+ });
84
+ break;
85
+ case "Option" :
86
+ tmp = true;
87
+ break;
88
+ default:
89
+ tmp = false;
90
+ }
91
+ }
92
+ alreadyNullable = tmp;
93
+ }
94
+ let finalType = param[2] || alreadyNullable ? typeCode : `option<` + typeCode + `>`;
95
+ let camelName = JsConvertCase.toCamelCase(name);
96
+ let escapedName = CodegenUtils.escapeKeyword(camelName);
97
+ let aliasAnnotation = escapedName !== name ? `@as("` + name + `") ` : "";
98
+ return ` ` + aliasAnnotation + escapedName + `: ` + finalType + `,`;
99
+ }).join("\n");
100
+ return `{\n` + fields + `\n}`;
101
+ case "Literal" :
102
+ let tmp = irType._0;
103
+ if (typeof tmp !== "object") {
104
+ return "unit";
116
105
  }
117
- });
118
- let arrayItemType = match[2];
119
- let result;
120
- if (match[0] && match[1] && effectiveTypes.length === 2 && SchemaIR.equals(Stdlib_Option.getOr(arrayItemType, "Unknown"), Stdlib_Option.getOr(match[3], "Unknown"))) {
121
- result = `array<` + recurse(Stdlib_Option.getOr(arrayItemType, "Unknown")) + `>`;
122
- } else if (effectiveTypes.every(t => {
106
+ switch (tmp.TAG) {
107
+ case "StringLiteral" :
108
+ return "string";
109
+ case "NumberLiteral" :
110
+ return "float";
111
+ case "BooleanLiteral" :
112
+ return "bool";
113
+ }
114
+ case "Union" :
115
+ let types = irType._0;
116
+ let nonNullTypes = types.filter(t => {
123
117
  if (typeof t !== "object") {
124
- return false;
118
+ return t !== "Null";
125
119
  }
126
120
  if (t.TAG !== "Literal") {
127
- return false;
121
+ return true;
128
122
  }
129
123
  let tmp = t._0;
130
- if (typeof tmp !== "object") {
131
- return false;
124
+ return typeof tmp === "object";
125
+ });
126
+ let hasNull = nonNullTypes.length < types.length;
127
+ if (hasNull && nonNullTypes.length === 1) {
128
+ let inner = generateTypeWithContext(ctx, depth + 1 | 0, true, nonNullTypes[0]);
129
+ return `option<` + inner + `>`;
130
+ }
131
+ let effectiveTypes = hasNull ? nonNullTypes : types;
132
+ let match = Stdlib_Array.reduce(effectiveTypes, [
133
+ false,
134
+ false,
135
+ undefined,
136
+ undefined
137
+ ], (param, t) => {
138
+ let arrItem = param[2];
139
+ let hArr = param[0];
140
+ if (typeof t !== "object" || t.TAG !== "Array") {
141
+ return [
142
+ hArr,
143
+ true,
144
+ arrItem,
145
+ t
146
+ ];
132
147
  } else {
133
- return tmp.TAG === "StringLiteral";
134
- }
135
- }) && effectiveTypes.length !== 0 && effectiveTypes.length <= 50) {
136
- let variants = effectiveTypes.map(t => {
137
- if (typeof t !== "object") {
138
- return "#Unknown";
139
- }
140
- if (t.TAG !== "Literal") {
141
- return "#Unknown";
148
+ return [
149
+ true,
150
+ param[1],
151
+ t.items,
152
+ param[3]
153
+ ];
142
154
  }
143
- let s = t._0;
144
- if (typeof s !== "object" || s.TAG !== "StringLiteral") {
145
- return "#Unknown";
155
+ });
156
+ let arrayItemType = match[2];
157
+ let result;
158
+ if (match[0] && match[1] && effectiveTypes.length === 2 && SchemaIR.equals(Stdlib_Option.getOr(arrayItemType, "Unknown"), Stdlib_Option.getOr(match[3], "Unknown"))) {
159
+ result = `array<` + recurseInline(Stdlib_Option.getOr(arrayItemType, "Unknown")) + `>`;
160
+ } else if (effectiveTypes.every(t => {
161
+ if (typeof t !== "object") {
162
+ return false;
163
+ }
164
+ if (t.TAG !== "Literal") {
165
+ return false;
166
+ }
167
+ let tmp = t._0;
168
+ if (typeof tmp !== "object") {
169
+ return false;
170
+ } else {
171
+ return tmp.TAG === "StringLiteral";
172
+ }
173
+ }) && effectiveTypes.length !== 0 && effectiveTypes.length <= 50) {
174
+ let variants = effectiveTypes.map(t => {
175
+ if (typeof t !== "object") {
176
+ return "#Unknown";
177
+ }
178
+ if (t.TAG !== "Literal") {
179
+ return "#Unknown";
180
+ }
181
+ let s = t._0;
182
+ if (typeof s !== "object" || s.TAG !== "StringLiteral") {
183
+ return "#Unknown";
184
+ } else {
185
+ return `#` + JsConvertCase.toPascalCase(s._0);
186
+ }
187
+ }).join(" | ");
188
+ result = `[` + variants + `]`;
189
+ } else if (effectiveTypes.length !== 0) {
190
+ let runtimeKinds = {};
191
+ effectiveTypes.forEach(t => {
192
+ let kind;
193
+ if (typeof t !== "object") {
194
+ switch (t) {
195
+ case "Boolean" :
196
+ kind = "boolean";
197
+ break;
198
+ case "Null" :
199
+ kind = "null";
200
+ break;
201
+ default:
202
+ kind = "unknown";
203
+ }
204
+ } else {
205
+ switch (t.TAG) {
206
+ case "String" :
207
+ kind = "string";
208
+ break;
209
+ case "Number" :
210
+ case "Integer" :
211
+ kind = "number";
212
+ break;
213
+ case "Array" :
214
+ kind = "array";
215
+ break;
216
+ case "Literal" :
217
+ let tmp = t._0;
218
+ if (typeof tmp !== "object") {
219
+ kind = "null";
220
+ } else {
221
+ switch (tmp.TAG) {
222
+ case "StringLiteral" :
223
+ kind = "string";
224
+ break;
225
+ case "NumberLiteral" :
226
+ kind = "number";
227
+ break;
228
+ case "BooleanLiteral" :
229
+ kind = "boolean";
230
+ break;
231
+ }
232
+ }
233
+ break;
234
+ case "Object" :
235
+ case "Intersection" :
236
+ case "Reference" :
237
+ kind = "object";
238
+ break;
239
+ default:
240
+ kind = "unknown";
241
+ }
242
+ }
243
+ let count = Stdlib_Option.getOr(runtimeKinds[kind], 0);
244
+ runtimeKinds[kind] = count + 1 | 0;
245
+ });
246
+ let canUnbox = Object.values(runtimeKinds).every(count => count <= 1);
247
+ if (canUnbox) {
248
+ let extractIR = hasNull ? ({
249
+ TAG: "Union",
250
+ _0: effectiveTypes
251
+ }) : irType;
252
+ let baseName$1 = Stdlib_Option.getOr(ctx.path.split(".")[ctx.path.split(".").length - 1 | 0], "union");
253
+ result = GenerationContext.extractType(ctx, baseName$1, true, extractIR);
146
254
  } else {
147
- return `#` + JsConvertCase.toPascalCase(s._0);
255
+ result = recurseInline(effectiveTypes[effectiveTypes.length - 1 | 0]);
148
256
  }
149
- }).join(" | ");
150
- result = `[` + variants + `]`;
151
- } else if (effectiveTypes.length !== 0) {
152
- let hasPrimitives = {
153
- contents: false
154
- };
155
- let variantCases = effectiveTypes.map((t, i) => {
156
- let match;
157
- let exit = 0;
158
- if (typeof t !== "object") {
159
- if (t === "Boolean") {
160
- hasPrimitives.contents = true;
161
- match = [
162
- "Bool",
163
- "bool"
164
- ];
257
+ } else {
258
+ result = "JSON.t";
259
+ }
260
+ if (hasNull) {
261
+ return `option<` + result + `>`;
262
+ } else {
263
+ return result;
264
+ }
265
+ case "Intersection" :
266
+ let types$1 = irType._0;
267
+ if (types$1.every(t => {
268
+ if (typeof t !== "object") {
269
+ return false;
165
270
  } else {
166
- exit = 1;
271
+ return t.TAG === "Reference";
167
272
  }
273
+ }) && types$1.length !== 0) {
274
+ _irType = Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown");
275
+ _inlineOpt = inline;
276
+ _depthOpt = depth + 1 | 0;
277
+ continue;
278
+ }
279
+ if (inline) {
280
+ let baseName$2 = Stdlib_Option.getOr(ctx.path.split(".")[ctx.path.split(".").length - 1 | 0], "intersection");
281
+ return GenerationContext.extractType(ctx, baseName$2, undefined, irType);
282
+ }
283
+ let match$1 = Stdlib_Array.reduce(types$1, [
284
+ [],
285
+ []
286
+ ], (param, t) => {
287
+ let nonObj = param[1];
288
+ let props = param[0];
289
+ if (typeof t !== "object") {
290
+ return [
291
+ props,
292
+ nonObj.concat([t])
293
+ ];
294
+ } else if (t.TAG === "Object") {
295
+ return [
296
+ props.concat(t.properties),
297
+ nonObj
298
+ ];
168
299
  } else {
169
- switch (t.TAG) {
170
- case "String" :
171
- hasPrimitives.contents = true;
172
- match = [
173
- "String",
174
- "string"
175
- ];
176
- break;
177
- case "Number" :
178
- hasPrimitives.contents = true;
179
- match = [
180
- "Float",
181
- "float"
182
- ];
183
- break;
184
- case "Integer" :
185
- hasPrimitives.contents = true;
186
- match = [
187
- "Int",
188
- "int"
189
- ];
190
- break;
191
- case "Array" :
192
- match = [
193
- "Array",
194
- `array<` + recurse(t.items) + `>`
195
- ];
196
- break;
197
- case "Object" :
198
- match = [
199
- "Object",
200
- recurse(t)
201
- ];
202
- break;
203
- case "Reference" :
204
- let ref = t._0;
205
- let name = Stdlib_Option.getOr(ref.split("/")[ref.split("/").length - 1 | 0], "");
206
- match = [
207
- JsConvertCase.toPascalCase(name),
208
- recurse(t)
209
- ];
210
- break;
211
- default:
212
- exit = 1;
213
- }
214
- }
215
- if (exit === 1) {
216
- match = [
217
- `V` + i.toString(),
218
- recurse(t)
300
+ return [
301
+ props,
302
+ nonObj.concat([t])
219
303
  ];
220
304
  }
221
- return ` | ` + match[0] + `(` + match[1] + `)`;
222
305
  });
223
- let unboxedAttr = hasPrimitives.contents ? "@unboxed " : "";
224
- result = unboxedAttr + `[\n` + variantCases.join("\n") + `\n]`;
225
- } else {
226
- result = "JSON.t";
227
- }
228
- if (hasNull) {
229
- return `option<` + result + `>`;
230
- } else {
231
- return result;
232
- }
233
- case "Intersection" :
234
- let types$1 = irType._0;
235
- if (types$1.every(t => {
236
- if (typeof t !== "object") {
237
- return false;
238
- } else {
239
- return t.TAG === "Reference";
240
- }
241
- }) && types$1.length !== 0) {
242
- return recurse(Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown"));
243
- }
244
- let match$1 = Stdlib_Array.reduce(types$1, [
245
- [],
246
- []
247
- ], (param, t) => {
248
- let nonObj = param[1];
249
- let props = param[0];
250
- if (typeof t !== "object") {
251
- return [
252
- props,
253
- nonObj.concat([t])
254
- ];
255
- } else if (t.TAG === "Object") {
256
- return [
257
- props.concat(t.properties),
258
- nonObj
259
- ];
260
- } else {
261
- return [
262
- props,
263
- nonObj.concat([t])
264
- ];
306
+ let nonObjectTypes = match$1[1];
307
+ let objectProps = match$1[0];
308
+ if (objectProps.length !== 0 && nonObjectTypes.length === 0) {
309
+ let fields$1 = objectProps.map(param => {
310
+ let fieldType = param[1];
311
+ let name = param[0];
312
+ let typeCode = recurseInline(fieldType);
313
+ let alreadyNullable = true;
314
+ if (!typeCode.startsWith("option<")) {
315
+ let tmp;
316
+ if (typeof fieldType !== "object") {
317
+ tmp = false;
318
+ } else {
319
+ switch (fieldType.TAG) {
320
+ case "Union" :
321
+ tmp = fieldType._0.some(t => {
322
+ if (typeof t !== "object") {
323
+ return t === "Null";
324
+ }
325
+ if (t.TAG !== "Literal") {
326
+ return false;
327
+ }
328
+ let tmp = t._0;
329
+ return typeof tmp !== "object";
330
+ });
331
+ break;
332
+ case "Option" :
333
+ tmp = true;
334
+ break;
335
+ default:
336
+ tmp = false;
337
+ }
338
+ }
339
+ alreadyNullable = tmp;
340
+ }
341
+ let finalType = param[2] || alreadyNullable ? typeCode : `option<` + typeCode + `>`;
342
+ let camelName = JsConvertCase.toCamelCase(name);
343
+ let escapedName = CodegenUtils.escapeKeyword(camelName);
344
+ let aliasAnnotation = escapedName !== name ? `@as("` + name + `") ` : "";
345
+ return ` ` + aliasAnnotation + escapedName + `: ` + finalType + `,`;
346
+ }).join("\n");
347
+ return `{\n` + fields$1 + `\n}`;
348
+ }
349
+ if (nonObjectTypes.length !== 0 && objectProps.length === 0) {
350
+ _irType = Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown");
351
+ _inlineOpt = inline;
352
+ _depthOpt = depth + 1 | 0;
353
+ continue;
265
354
  }
266
- });
267
- let nonObjectTypes = match$1[1];
268
- let objectProps = match$1[0];
269
- if (objectProps.length !== 0 && nonObjectTypes.length === 0) {
270
- let fields$1 = objectProps.map(param => {
355
+ GenerationContext.addWarning(ctx, {
356
+ TAG: "IntersectionNotFullySupported",
357
+ location: ctx.path,
358
+ note: "Mixed object/non-object intersection"
359
+ });
360
+ let fields$2 = objectProps.map(param => {
361
+ let fieldType = param[1];
271
362
  let name = param[0];
272
- let typeCode = recurse(param[1]);
273
- let finalType = param[2] ? typeCode : `option<` + typeCode + `>`;
363
+ let typeCode = recurseInline(fieldType);
364
+ let alreadyNullable = true;
365
+ if (!typeCode.startsWith("option<")) {
366
+ let tmp;
367
+ if (typeof fieldType !== "object") {
368
+ tmp = false;
369
+ } else {
370
+ switch (fieldType.TAG) {
371
+ case "Union" :
372
+ tmp = fieldType._0.some(t => {
373
+ if (typeof t !== "object") {
374
+ return t === "Null";
375
+ }
376
+ if (t.TAG !== "Literal") {
377
+ return false;
378
+ }
379
+ let tmp = t._0;
380
+ return typeof tmp !== "object";
381
+ });
382
+ break;
383
+ case "Option" :
384
+ tmp = true;
385
+ break;
386
+ default:
387
+ tmp = false;
388
+ }
389
+ }
390
+ alreadyNullable = tmp;
391
+ }
392
+ let finalType = param[2] || alreadyNullable ? typeCode : `option<` + typeCode + `>`;
274
393
  let camelName = JsConvertCase.toCamelCase(name);
275
394
  let escapedName = CodegenUtils.escapeKeyword(camelName);
276
395
  let aliasAnnotation = escapedName !== name ? `@as("` + name + `") ` : "";
277
396
  return ` ` + aliasAnnotation + escapedName + `: ` + finalType + `,`;
278
397
  }).join("\n");
279
- return `{\n` + fields$1 + `\n}`;
280
- }
281
- if (nonObjectTypes.length !== 0 && objectProps.length === 0) {
282
- return recurse(Stdlib_Option.getOr(types$1[types$1.length - 1 | 0], "Unknown"));
398
+ return `{\n` + fields$2 + `\n}`;
399
+ case "Reference" :
400
+ let ref = irType._0;
401
+ let refName = ref.includes("/") ? Stdlib_Option.getOr(ref.split("/")[ref.split("/").length - 1 | 0], "") : ref;
402
+ let selfName = ctx.selfRefName;
403
+ let isSelfRef = selfName !== undefined ? refName === selfName : false;
404
+ if (isSelfRef) {
405
+ return "t";
406
+ }
407
+ let available = ctx.availableSchemas;
408
+ let typePath = available !== undefined ? (
409
+ available.includes(refName) ? JsConvertCase.toPascalCase(refName) + `.t` : `ComponentSchemas.` + JsConvertCase.toPascalCase(refName) + `.t`
410
+ ) : Stdlib_Option.getOr(ReferenceResolver.refToTypePath(ctx.insideComponentSchemas, ctx.modulePrefix, ref), "JSON.t");
411
+ if (typePath === "JSON.t") {
412
+ GenerationContext.addWarning(ctx, {
413
+ TAG: "FallbackToJson",
414
+ reason: `Unresolved ref: ` + ref,
415
+ context: {
416
+ path: ctx.path,
417
+ operation: "gen ref",
418
+ schema: undefined
419
+ }
420
+ });
421
+ }
422
+ return typePath;
423
+ case "Option" :
424
+ return `option<` + recurseInline(irType._0) + `>`;
425
+ }
426
+ }
427
+ };
428
+ }
429
+
430
+ function generateUnboxedVariantBody(ctx, types) {
431
+ let rawNames = types.map(CodegenUtils.variantConstructorName);
432
+ let names = CodegenUtils.deduplicateNames(rawNames);
433
+ return types.map((irType, i) => {
434
+ let constructorName = names[i];
435
+ let payloadType;
436
+ let exit = 0;
437
+ if (typeof irType !== "object" || irType.TAG !== "Object") {
438
+ exit = 1;
439
+ } else {
440
+ let additionalProperties = irType.additionalProperties;
441
+ let properties = irType.properties;
442
+ if (properties.length === 0) {
443
+ if (additionalProperties !== undefined) {
444
+ let innerType = generateTypeWithContext(ctx, 1, true, additionalProperties);
445
+ payloadType = `(dict<` + innerType + `>)`;
446
+ } else {
447
+ payloadType = `(dict<JSON.t>)`;
283
448
  }
284
- GenerationContext.addWarning(ctx, {
285
- TAG: "IntersectionNotFullySupported",
286
- location: ctx.path,
287
- note: "Mixed object/non-object intersection"
288
- });
289
- let fields$2 = objectProps.map(param => {
449
+ } else {
450
+ let fields = properties.map(param => {
451
+ let fieldType = param[1];
290
452
  let name = param[0];
291
- let typeCode = recurse(param[1]);
292
- let finalType = param[2] ? typeCode : `option<` + typeCode + `>`;
453
+ let typeCode = generateTypeWithContext(ctx, 1, true, fieldType);
454
+ let alreadyNullable = true;
455
+ if (!typeCode.startsWith("option<")) {
456
+ let tmp;
457
+ if (typeof fieldType !== "object") {
458
+ tmp = false;
459
+ } else {
460
+ switch (fieldType.TAG) {
461
+ case "Union" :
462
+ tmp = fieldType._0.some(t => {
463
+ if (typeof t !== "object") {
464
+ return t === "Null";
465
+ }
466
+ if (t.TAG !== "Literal") {
467
+ return false;
468
+ }
469
+ let tmp = t._0;
470
+ return typeof tmp !== "object";
471
+ });
472
+ break;
473
+ case "Option" :
474
+ tmp = true;
475
+ break;
476
+ default:
477
+ tmp = false;
478
+ }
479
+ }
480
+ alreadyNullable = tmp;
481
+ }
482
+ let finalType = param[2] || alreadyNullable ? typeCode : `option<` + typeCode + `>`;
293
483
  let camelName = JsConvertCase.toCamelCase(name);
294
484
  let escapedName = CodegenUtils.escapeKeyword(camelName);
295
485
  let aliasAnnotation = escapedName !== name ? `@as("` + name + `") ` : "";
296
- return ` ` + aliasAnnotation + escapedName + `: ` + finalType + `,`;
297
- }).join("\n");
298
- return `{\n` + fields$2 + `\n}`;
299
- case "Reference" :
300
- let ref = irType._0;
301
- let available = ctx.availableSchemas;
302
- let typePath;
303
- if (available !== undefined) {
304
- let name = Stdlib_Option.getOr(ref.split("/")[ref.split("/").length - 1 | 0], "");
305
- typePath = available.includes(name) ? JsConvertCase.toPascalCase(name) + `.t` : `ComponentSchemas.` + JsConvertCase.toPascalCase(name) + `.t`;
306
- } else {
307
- typePath = Stdlib_Option.getOr(ReferenceResolver.refToTypePath(ctx.insideComponentSchemas, ctx.modulePrefix, ref), "JSON.t");
308
- }
309
- if (typePath === "JSON.t") {
310
- GenerationContext.addWarning(ctx, {
311
- TAG: "FallbackToJson",
312
- reason: `Unresolved ref: ` + ref,
313
- context: {
314
- path: ctx.path,
315
- operation: "gen ref",
316
- schema: undefined
317
- }
318
- });
319
- }
320
- return typePath;
321
- case "Option" :
322
- return `option<` + recurse(irType._0) + `>`;
486
+ return aliasAnnotation + escapedName + `: ` + finalType;
487
+ }).join(", ");
488
+ payloadType = `({` + fields + `})`;
489
+ }
490
+ }
491
+ if (exit === 1) {
492
+ let innerType$1 = generateTypeWithContext(ctx, 1, true, irType);
493
+ payloadType = `(` + innerType$1 + `)`;
323
494
  }
324
- }
495
+ return constructorName + payloadType;
496
+ }).join(" | ");
325
497
  }
326
498
 
327
499
  function generateType(depthOpt, pathOpt, insideComponentSchemasOpt, availableSchemas, modulePrefixOpt, irType) {
@@ -329,9 +501,9 @@ function generateType(depthOpt, pathOpt, insideComponentSchemasOpt, availableSch
329
501
  let path = pathOpt !== undefined ? pathOpt : "";
330
502
  let insideComponentSchemas = insideComponentSchemasOpt !== undefined ? insideComponentSchemasOpt : false;
331
503
  let modulePrefix = modulePrefixOpt !== undefined ? modulePrefixOpt : "";
332
- let ctx = GenerationContext.make(path, insideComponentSchemas, availableSchemas, modulePrefix, undefined);
504
+ let ctx = GenerationContext.make(path, insideComponentSchemas, availableSchemas, modulePrefix, undefined, undefined);
333
505
  return [
334
- generateTypeWithContext(ctx, depth, irType),
506
+ generateTypeWithContext(ctx, depth, undefined, irType),
335
507
  ctx.warnings
336
508
  ];
337
509
  }
@@ -339,12 +511,45 @@ function generateType(depthOpt, pathOpt, insideComponentSchemasOpt, availableSch
339
511
  function generateNamedType(namedSchema, insideComponentSchemasOpt, availableSchemas, modulePrefixOpt) {
340
512
  let insideComponentSchemas = insideComponentSchemasOpt !== undefined ? insideComponentSchemasOpt : false;
341
513
  let modulePrefix = modulePrefixOpt !== undefined ? modulePrefixOpt : "";
342
- let ctx = GenerationContext.make(`type.` + namedSchema.name, insideComponentSchemas, availableSchemas, modulePrefix, undefined);
514
+ let ctx = GenerationContext.make(`type.` + namedSchema.name, insideComponentSchemas, availableSchemas, modulePrefix, undefined, undefined);
343
515
  let d = namedSchema.description;
344
516
  let doc = d !== undefined ? CodegenUtils.generateDocString(undefined, d, undefined) : "";
517
+ let mainType = generateTypeWithContext(ctx, 0, undefined, namedSchema.type_);
518
+ let processed = 0;
519
+ while (processed < ctx.extractedTypes.length) {
520
+ let idx = processed;
521
+ let match = ctx.extractedTypes[idx];
522
+ let irType = match.irType;
523
+ if (match.isUnboxed && typeof irType === "object" && irType.TAG === "Union") {
524
+ irType._0.forEach(memberType => {
525
+ generateTypeWithContext(ctx, 0, true, memberType);
526
+ });
527
+ } else {
528
+ generateTypeWithContext(ctx, 0, false, irType);
529
+ }
530
+ processed = idx + 1 | 0;
531
+ };
532
+ let allExtracted = ctx.extractedTypes.slice();
533
+ let extractedDefs = allExtracted.map(param => {
534
+ let irType = param.irType;
535
+ let typeName = param.typeName;
536
+ if (param.isUnboxed) {
537
+ if (typeof irType === "object" && irType.TAG === "Union") {
538
+ let body = generateUnboxedVariantBody(ctx, irType._0);
539
+ return `@unboxed type ` + typeName + ` = ` + body;
540
+ }
541
+ let auxType = generateTypeWithContext(ctx, 0, undefined, irType);
542
+ return `type ` + typeName + ` = ` + auxType;
543
+ }
544
+ let auxType$1 = generateTypeWithContext(ctx, 0, undefined, irType);
545
+ return `type ` + typeName + ` = ` + auxType$1;
546
+ });
547
+ let reversedExtracted = allExtracted.toReversed();
548
+ let allDefs = extractedDefs.toReversed().concat([doc + `type ` + namedSchema.name + ` = ` + mainType]);
345
549
  return [
346
- doc + `type ` + namedSchema.name + ` = ` + generateTypeWithContext(ctx, 0, namedSchema.type_),
347
- ctx.warnings
550
+ allDefs.join("\n\n"),
551
+ ctx.warnings,
552
+ reversedExtracted
348
553
  ];
349
554
  }
350
555
 
@@ -363,7 +568,7 @@ function generateAllTypes(context) {
363
568
 
364
569
  function generateTypeAndSchema(namedSchema) {
365
570
  let match = generateNamedType(namedSchema, undefined, undefined, undefined);
366
- let match$1 = IRToSuryGenerator.generateNamedSchema(namedSchema, undefined, undefined, undefined);
571
+ let match$1 = IRToSuryGenerator.generateNamedSchema(namedSchema, undefined, undefined, undefined, match[2]);
367
572
  return [
368
573
  [
369
574
  match[0],
@@ -378,6 +583,7 @@ let addWarning = GenerationContext.addWarning;
378
583
  export {
379
584
  addWarning,
380
585
  generateTypeWithContext,
586
+ generateUnboxedVariantBody,
381
587
  generateType,
382
588
  generateNamedType,
383
589
  generateAllTypes,