Skip to content

Commit 81ac730

Browse files
committed
fix: support BlockStatement arrow functions in codec parser
Previously, only implicit-return arrow functions were supported: ```typescript const factory = () => t.string; // ✅ Worked BlockStatement arrow functions with explicit returns would fail: const factory = () => { return t.string; // ❌ Error: "BlockStatement arrow functions are not yet supported" }; ``` This fix: - Searches BlockStatement.stmts for ReturnStatement nodes - Extracts the return value expression (returnStmt.argument) - Passes it to parseCodecInitializer() for recursive parsing - Validates that a return statement exists with a non-undefined argument Both styles now produce identical schemas since they converge on the same parseCodecInitializer() call with the return value expression. Test case added using BooleanFromNullableWithFallback() with explicit block syntax to verify the parser handles both arrow function styles.
1 parent 97d7cee commit 81ac730

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

packages/openapi-generator/src/codec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,14 @@ function parseFunctionBody(
459459
return errorLeft('Function body is undefined');
460460
}
461461
if (func.body.type === 'BlockStatement') {
462-
return errorLeft('BlockStatement arrow functions are not yet supported');
462+
const returnStmt = func.body.stmts.find((s) => s.type === 'ReturnStatement');
463+
if (!returnStmt || returnStmt.type !== 'ReturnStatement') {
464+
return errorLeft('BlockStatement must contain a return statement');
465+
}
466+
if (!returnStmt.argument) {
467+
return errorLeft('Return statement must have an argument');
468+
}
469+
return parseCodecInitializer(project, source, returnStmt.argument);
463470
}
464471
return parseCodecInitializer(project, source, func.body);
465472
}

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,46 @@ testCase(
411411
},
412412
[],
413413
);
414+
415+
testCase(
416+
'simple api spec with block statement arrow functions',
417+
'test/sample-types/apiSpecWithBlockArrow.ts',
418+
{
419+
openapi: '3.0.3',
420+
info: {
421+
title: 'simple api spec with block statement arrow functions',
422+
version: '1.0.0',
423+
description: 'simple api spec with block statement arrow functions',
424+
},
425+
paths: {
426+
'/test': {
427+
get: {
428+
parameters: [],
429+
responses: {
430+
200: {
431+
description: 'OK',
432+
content: {
433+
'application/json': {
434+
schema: {
435+
type: 'object',
436+
properties: {
437+
hasLargeNumberOfAddresses: {
438+
nullable: true,
439+
type: 'boolean',
440+
},
441+
},
442+
required: ['hasLargeNumberOfAddresses'],
443+
},
444+
},
445+
},
446+
},
447+
},
448+
},
449+
},
450+
},
451+
components: {
452+
schemas: {},
453+
},
454+
},
455+
[],
456+
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
return fromNullable(t.union([BooleanFromString, t.boolean]), false);
7+
};
8+
9+
export const TEST_ROUTE = h.httpRoute({
10+
path: '/test',
11+
method: 'GET',
12+
request: h.httpRequest({}),
13+
response: {
14+
200: t.type({
15+
hasLargeNumberOfAddresses: BooleanFromNullableWithFallback(),
16+
}),
17+
},
18+
});
19+
20+
export const apiSpec = h.apiSpec({
21+
'api.test': {
22+
get: TEST_ROUTE,
23+
},
24+
});

0 commit comments

Comments
 (0)