Skip to content

Commit 8b539fe

Browse files
authored
fix: support arrow functions in OpenAPI generator
2 parents c5000de + cec1e8b commit 8b539fe

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

packages/openapi-generator/src/codec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,20 @@ export function parsePlainInitializer(
450450
}
451451
}
452452

453+
function parseFunctionBody(
454+
project: Project,
455+
source: SourceFile,
456+
func: swc.ArrowFunctionExpression,
457+
): E.Either<string, Schema> {
458+
if (func.body === undefined) {
459+
return errorLeft('Function body is undefined');
460+
}
461+
if (func.body.type === 'BlockStatement') {
462+
return errorLeft('BlockStatement arrow functions are not yet supported');
463+
}
464+
return parseCodecInitializer(project, source, func.body);
465+
}
466+
453467
export function parseCodecInitializer(
454468
project: Project,
455469
source: SourceFile,
@@ -471,8 +485,29 @@ export function parseCodecInitializer(
471485
} else if (init.type === 'CallExpression') {
472486
const callee = init.callee;
473487
if (callee.type !== 'Identifier' && callee.type !== 'MemberExpression') {
474-
return errorLeft(`Unimplemented callee type ${init.callee.type}`);
488+
return errorLeft(`Unimplemented callee type ${callee.type}`);
489+
}
490+
491+
let calleeName: string | [string, string] | undefined;
492+
if (callee.type === 'Identifier') {
493+
calleeName = callee.value;
494+
} else if (
495+
callee.object.type === 'Identifier' &&
496+
callee.property.type === 'Identifier'
497+
) {
498+
calleeName = [callee.object.value, callee.property.value];
499+
}
500+
501+
if (calleeName !== undefined) {
502+
const calleeInitE = findSymbolInitializer(project, source, calleeName);
503+
if (E.isRight(calleeInitE)) {
504+
const [calleeSourceFile, calleeInit] = calleeInitE.right;
505+
if (calleeInit !== null && calleeInit.type === 'ArrowFunctionExpression') {
506+
return parseFunctionBody(project, calleeSourceFile, calleeInit);
507+
}
508+
}
475509
}
510+
476511
const identifierE = codecIdentifier(project, source, callee);
477512
if (E.isLeft(identifierE)) {
478513
return identifierE;

packages/openapi-generator/test/externalModuleApiSpec.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,46 @@ testCase(
368368
},
369369
[],
370370
);
371+
372+
testCase(
373+
'simple api spec with util type functions',
374+
'test/sample-types/apiSpecWithArrow.ts',
375+
{
376+
openapi: '3.0.3',
377+
info: {
378+
title: 'simple api spec with util type functions',
379+
version: '1.0.0',
380+
description: 'simple api spec with util type functions',
381+
},
382+
paths: {
383+
'/test': {
384+
get: {
385+
parameters: [],
386+
responses: {
387+
200: {
388+
description: 'OK',
389+
content: {
390+
'application/json': {
391+
schema: {
392+
type: 'object',
393+
properties: {
394+
hasLargeNumberOfAddresses: {
395+
nullable: true,
396+
type: 'boolean',
397+
},
398+
},
399+
required: ['hasLargeNumberOfAddresses'],
400+
},
401+
},
402+
},
403+
},
404+
},
405+
},
406+
},
407+
},
408+
components: {
409+
schemas: {},
410+
},
411+
},
412+
[],
413+
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as h from '@api-ts/io-ts-http';
2+
import * as t from 'io-ts';
3+
import { BooleanFromString, fromNullable } from 'io-ts-types';
4+
5+
const BooleanFromNullableWithFallback = () =>
6+
fromNullable(t.union([BooleanFromString, t.boolean]), false);
7+
8+
export const TEST_ROUTE = h.httpRoute({
9+
path: '/test',
10+
method: 'GET',
11+
request: h.httpRequest({}),
12+
response: {
13+
200: t.type({
14+
hasLargeNumberOfAddresses: BooleanFromNullableWithFallback(),
15+
}),
16+
},
17+
});
18+
19+
export const apiSpec = h.apiSpec({
20+
'api.test': {
21+
get: TEST_ROUTE,
22+
},
23+
});

0 commit comments

Comments
 (0)