diff --git a/packages/openapi-generator/src/codec.ts b/packages/openapi-generator/src/codec.ts index 7c687471..0c6b672c 100644 --- a/packages/openapi-generator/src/codec.ts +++ b/packages/openapi-generator/src/codec.ts @@ -188,7 +188,31 @@ function parseArrayExpression( if (E.isLeft(valueE)) { return valueE; } - result.push(valueE.right); + // swc sometimes sets this to `null` even though it is supposed to be `undefined` + if (element.spread) { + let init = valueE.right; + if (init.type === 'ref') { + const realInitE = findSymbolInitializer(project, source, init.name); + if (E.isLeft(realInitE)) { + return realInitE; + } + const schemaE = parsePlainInitializer( + project, + realInitE.right[0], + realInitE.right[1], + ); + if (E.isLeft(schemaE)) { + return schemaE; + } + init = schemaE.right; + } + if (init.type !== 'tuple') { + return E.left('Spread element must be array literal'); + } + result.push(...init.schemas); + } else { + result.push(valueE.right); + } } return E.right({ type: 'tuple', schemas: result }); } diff --git a/packages/openapi-generator/test/codec.test.ts b/packages/openapi-generator/test/codec.test.ts index cfe1b1b0..b79726e3 100644 --- a/packages/openapi-generator/test/codec.test.ts +++ b/packages/openapi-generator/test/codec.test.ts @@ -227,6 +227,44 @@ testCase('union type is parsed', UNION, { }, }); +const UNION_SPREAD = ` +import * as t from 'io-ts'; + +const common = [t.string]; + +export const FOO = t.union([...common, t.number]); +`; + +testCase('union type with spread is parsed', UNION_SPREAD, { + FOO: { + type: 'union', + schemas: [ + { type: 'primitive', value: 'string' }, + { type: 'primitive', value: 'number' }, + ], + }, + common: { + type: 'tuple', + schemas: [{ type: 'primitive', value: 'string' }], + }, +}); + +const UNION_INLINE_SPREAD = ` +import * as t from 'io-ts'; + +export const FOO = t.union([...[t.string], t.number]); +`; + +testCase('union type with inline spread is parsed', UNION_INLINE_SPREAD, { + FOO: { + type: 'union', + schemas: [ + { type: 'primitive', value: 'string' }, + { type: 'primitive', value: 'number' }, + ], + }, +}); + const INTERSECTION = ` import * as t from 'io-ts'; export const FOO = t.intersection([t.type({ foo: t.number }), t.partial({ bar: t.string })]);