Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/openapi-generator/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,9 @@ export function parseCodecInitializer(
if (E.isRight(calleeInitE)) {
const [calleeSourceFile, calleeInit] = calleeInitE.right;
if (calleeInit !== null && calleeInit.type === 'ArrowFunctionExpression') {
const bodyResult = parseFunctionBody(project, calleeSourceFile, calleeInit);
if (E.isRight(bodyResult)) {
return bodyResult;
const hasNoParameters = calleeInit.params.length === 0;
if (hasNoParameters) {
return parseFunctionBody(project, calleeSourceFile, calleeInit);
Comment on lines +513 to +515
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding this correctly; parseFunctionBody fails on functions with parameters. The fix is to only parse the function body if it has no parameters.

My question:

Is the fact that parseFunctionBody fails on arrow functions with parameters a flaw with the way we defined parseFunctionBody? Or is this intended behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f I'm understanding this correctly; parseFunctionBody fails on functions with parameters. The fix is to only parse the function body if it has no parameters.

Correct

Copy link
Contributor Author

@yanxue-22 yanxue-22 Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the fact that parseFunctionBody fails on arrow functions with parameters a flaw with the way we defined parseFunctionBody? Or is this intended behaviour?

I think it is intended that parseFunctionBody only handles zero-parameter functions, since that was the case that surfaced the need for function. Arrow functions with parameters are left to be handled via custom codec definitions in knownImports, which I believe manually defines the schema transformation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for answering my questions!

}
}
}
Expand Down
125 changes: 125 additions & 0 deletions packages/openapi-generator/test/arrowFunctionWithParameter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as E from 'fp-ts/lib/Either';
import assert from 'node:assert/strict';
import test from 'node:test';

import { TestProject } from './testProject';
import { parsePlainInitializer, type Schema } from '../src';
import { KNOWN_IMPORTS, type KnownImports } from '../src/knownImports';

const ARROW_WITH_PARAMS_MAIN = `
import * as t from 'io-ts';
import { NonEmptyString } from './types';
import { arrayFromArrayOrSingle } from './codecs';

export const UpdateShardKeyRequestBody = {
shardKey: t.string,
collectionType: t.union([
t.literal('user'),
t.literal('enterprise'),
t.literal('enterpriseTemplate')
]),
ids: arrayFromArrayOrSingle(NonEmptyString),
enterpriseUpdateUsers: t.boolean,
} as const;
`;

const ARROW_WITH_PARAMS_TYPES = `
import * as t from 'io-ts';

export const NonEmptyString = t.string;
`;

const ARROW_WITH_PARAMS_CODECS = `
import * as t from 'io-ts';

export const arrayFromArrayOrSingle = <C extends t.Mixed>(codec: C) =>
t.array(codec);
`;

test('arrow function with parameters uses custom codec definition', async () => {
const files = {
'/src/main.ts': ARROW_WITH_PARAMS_MAIN,
'/src/types.ts': ARROW_WITH_PARAMS_TYPES,
'/src/codecs.ts': ARROW_WITH_PARAMS_CODECS,
};

// Custom codec for arrayFromArrayOrSingle, merged with default io-ts codecs
const knownImports: KnownImports = {
...KNOWN_IMPORTS,
'.': {
...KNOWN_IMPORTS['.'],
arrayFromArrayOrSingle: (_deref, innerSchema): E.Either<string, Schema> =>
E.right({ type: 'array', items: innerSchema }),
},
};

const project = new TestProject(files, knownImports);
await project.parseEntryPoint('/src/main.ts');
const sourceFile = project.get('/src/main.ts');

assert.ok(sourceFile !== undefined, 'Source file not found');

const declaration = sourceFile.symbols.declarations.find(
(s) => s.name === 'UpdateShardKeyRequestBody',
);
assert.ok(declaration?.init !== undefined, 'Declaration not found');

const result = parsePlainInitializer(project, sourceFile, declaration.init);

assert.ok(
E.isRight(result),
`Expected success, got: "${E.isLeft(result) ? result.left : ''}"`,
);
assert.equal(result.right.type, 'object');
if (result.right.type === 'object') {
assert.equal(
result.right.properties?.ids?.type,
'array',
'ids field should be array (from custom codec)',
);
}
});

test('arrow function with parameters without custom codec returns ref', async () => {
const files = {
'/src/main.ts': `
import * as t from 'io-ts';
import { NonEmptyString } from './types';
import { arrayFromArrayOrSingle } from './codecs';

export const TestBody = {
ids: arrayFromArrayOrSingle(NonEmptyString),
} as const;
`,
'/src/types.ts': ARROW_WITH_PARAMS_TYPES,
'/src/codecs.ts': ARROW_WITH_PARAMS_CODECS,
};

// No custom codec for arrayFromArrayOrSingle
const project = new TestProject(files, KNOWN_IMPORTS);
await project.parseEntryPoint('/src/main.ts');
const sourceFile = project.get('/src/main.ts');

assert.ok(sourceFile !== undefined, 'Source file not found');

const declaration = sourceFile.symbols.declarations.find(
(s) => s.name === 'TestBody',
);
assert.ok(declaration?.init !== undefined, 'Declaration not found');

const result = parsePlainInitializer(project, sourceFile, declaration.init);

// Without custom codec, should return a ref (not an error)
assert.ok(
E.isRight(result),
`Expected success, got: "${E.isLeft(result) ? result.left : ''}"`,
);
assert.equal(result.right.type, 'object');
if (result.right.type === 'object') {
assert.equal(
result.right.properties?.ids?.type,
'ref',
'ids field should be ref (no custom codec)',
);
}
});