Skip to content

Commit a8b658b

Browse files
committed
fix: add support for non-object types as component schemas (ie oneOfs)
closes #2
1 parent 31e0c6e commit a8b658b

3 files changed

Lines changed: 76 additions & 10 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`nullables 1`] = `
4+
"import type { Jsonifiable } from 'type-fest';
5+
import type { JsonifiableObject } from 'type-fest/source/jsonifiable.js';
6+
7+
export type MySchemaLolOrNullable = "lol" | "kek" | null;
8+
"
9+
`;

__tests__/nullables.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { test } from '@jest/globals';
2+
import { processOpenApiDocument } from '../lib/process-document.js';
3+
4+
test('nullables', async () => {
5+
const result = await processOpenApiDocument(
6+
'/tmp', // if we dont call .save() it doesnt matter
7+
{
8+
openapi: '3.0.0',
9+
info: {
10+
title: 'Test',
11+
version: '1.0.0',
12+
},
13+
paths: {},
14+
components: {
15+
schemas: {
16+
MySchemaLolOrNullable: {
17+
oneOf: [
18+
{
19+
type: 'string',
20+
enum: ['lol', 'kek'],
21+
},
22+
{
23+
nullable: true,
24+
},
25+
],
26+
},
27+
},
28+
},
29+
},
30+
[],
31+
);
32+
33+
expect(result.typesFile.getText()).toMatchSnapshot();
34+
});

lib/process-schema.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,24 @@ import {
1313
type WriterFunction,
1414
} from 'ts-morph';
1515
import {
16+
isNotNullOrUndefined,
1617
isNotReferenceObject,
1718
isReferenceObject,
1819
pascalCase,
1920
wordWrap,
2021
} from './utils.js';
2122

2223
function withNullUnion(type: string | WriterFunction, nullable = false) {
23-
return nullable ? Writers.unionType(type, 'null') : type;
24+
return nullable && type !== 'null' ? Writers.unionType(type, 'null') : type;
2425
}
2526

2627
function maybeWithUndefined(
2728
type: string | WriterFunction,
2829
withUndefined: boolean,
2930
) {
30-
return withUndefined ? Writers.unionType(type, 'undefined') : type;
31+
return withUndefined && type !== 'undefined'
32+
? Writers.unionType(type, 'undefined')
33+
: type;
3134
}
3235

3336
export function schemaToType(
@@ -114,6 +117,7 @@ export function schemaToType(
114117

115118
const docs: (OptionalKind<JSDocStructure> | string)[] =
116119
Object.keys(maybeJsDoc).length > 1 ? [maybeJsDoc] : [];
120+
117121
if (schemaObject.type === 'array') {
118122
const type = schemaToType(
119123
typesAndInterfaces,
@@ -347,11 +351,14 @@ export function schemaToType(
347351
};
348352
}
349353

350-
const type = schemaObject.type?.toString() || ('never' as const);
354+
const type =
355+
schemaObject.type?.toString() ||
356+
('nullable' in schemaObject && 'null') ||
357+
'never';
351358

352359
if (type === 'never') {
353360
console.warn(
354-
'unsupported type in %j with parent %j',
361+
'WARN: unsupported type in %j with parent %j',
355362
schemaObject,
356363
parentSchema,
357364
);
@@ -420,6 +427,7 @@ export function registerTypesFromSchema(
420427

421428
const objectTypesFromNonRefSchemas = schemaItems
422429
.filter(isNotReferenceObject)
430+
.filter((schema) => schema.type === 'object')
423431
.map((subSchemaObject) =>
424432
Writers.objectType({
425433
properties: Object.entries(subSchemaObject.properties || {}).map(
@@ -432,13 +440,29 @@ export function registerTypesFromSchema(
432440
),
433441
),
434442
}),
435-
);
443+
)
444+
.filter(isNotNullOrUndefined);
445+
446+
const nonObjectTypesFromNonRefSchemas = schemaItems
447+
.filter(isNotReferenceObject)
448+
.filter((schema) => schema.type !== 'object')
449+
.map(
450+
(subSchemaObject) =>
451+
schemaToType(
452+
typesAndInterfaces,
453+
{}, // no parent schema
454+
schemaName,
455+
subSchemaObject,
456+
).type,
457+
)
458+
.filter(isNotNullOrUndefined);
436459

437460
// concat and dedupe
438461
const typeArgs = [
439462
...new Set([
440463
...typeAliases.map((t) => t.getName()),
441-
...objectTypesFromNonRefSchemas.filter(Boolean),
464+
...objectTypesFromNonRefSchemas,
465+
...nonObjectTypesFromNonRefSchemas,
442466
]),
443467
];
444468

@@ -450,10 +474,9 @@ export function registerTypesFromSchema(
450474
const typeAlias = typesFile.addTypeAlias({
451475
name: pascalCase(schemaName),
452476
isExported: true,
453-
type:
454-
firstType && secondType
455-
? writerType.call(Writers, firstType, secondType, ...restTypes)
456-
: firstType,
477+
type: secondType
478+
? writerType.call(Writers, firstType, secondType, ...restTypes)
479+
: firstType,
457480
});
458481

459482
if (schemaObject.description) {

0 commit comments

Comments
 (0)