Skip to content

Commit 3d35bbe

Browse files
olupclaude
andcommitted
refactor: address code review feedback
- Move isTypeDefType variable inside match.with block for Json type - Reuse prismaTypeToOpenAPIType method to avoid duplication - Change Json from { type: 'string', format: 'json' } to empty schema {} - Update test assertion for nullable metadata field These changes improve code quality by reducing duplication and aligning with OpenAPI specification best practices for JSON schema representation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 364ede9 commit 3d35bbe

File tree

2 files changed

+26
-20
lines changed

2 files changed

+26
-20
lines changed

packages/plugins/openapi/src/rpc-generator.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator
22

33
import { PluginError, PluginOptions, analyzePolicies, requireOption, resolvePath } from '@zenstackhq/sdk';
4-
import { DataModel, Enum, Model, TypeDef, TypeDefField, TypeDefFieldType, isDataModel, isEnum, isTypeDef } from '@zenstackhq/sdk/ast';
4+
import { DataModel, Model, TypeDef, TypeDefField, TypeDefFieldType, isDataModel, isEnum, isTypeDef } from '@zenstackhq/sdk/ast';
55
import {
66
AggregateOperationSupport,
77
addMissingInputObjectTypesForAggregate,
@@ -865,23 +865,18 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
865865
}
866866

867867
private typeDefFieldTypeToOpenAPISchema(type: TypeDefFieldType): OAPI.ReferenceObject | OAPI.SchemaObject {
868+
// For references to other types (TypeDef, Enum, Model)
869+
if (type.reference?.ref) {
870+
return this.ref(type.reference.ref.name, true);
871+
}
872+
873+
// For scalar types, reuse the existing mapping logic
874+
// Note: Json type is handled as empty schema for consistency
868875
return match(type.type)
869-
.with('String', () => ({ type: 'string' } as OAPI.SchemaObject))
870-
.with(P.union('Int', 'BigInt'), () => ({ type: 'integer' } as OAPI.SchemaObject))
871-
.with('Float', () => ({ type: 'number' } as OAPI.SchemaObject))
872-
.with('Decimal', () => this.oneOf({ type: 'string' }, { type: 'number' }))
873-
.with('Boolean', () => ({ type: 'boolean' } as OAPI.SchemaObject))
874-
.with('DateTime', () => ({ type: 'string', format: 'date-time' } as OAPI.SchemaObject))
875-
.with('Bytes', () => ({ type: 'string', format: 'byte' } as OAPI.SchemaObject))
876-
.with('Json', () => ({ type: 'string', format: 'json' } as OAPI.SchemaObject))
877-
.otherwise(() => {
878-
// It's a reference to another TypeDef, Enum, or Model
879-
const fieldDecl = type.reference?.ref;
880-
if (fieldDecl) {
881-
return this.ref(fieldDecl.name, true);
882-
}
883-
// Fallback for unknown types
884-
return { type: 'string' } as OAPI.SchemaObject;
876+
.with('Json', () => ({} as OAPI.SchemaObject))
877+
.otherwise((t) => {
878+
// Delegate to prismaTypeToOpenAPIType for all other scalar types
879+
return this.prismaTypeToOpenAPIType(String(t), false);
885880
});
886881
}
887882

@@ -900,9 +895,6 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
900895
}
901896

902897
private prismaTypeToOpenAPIType(type: string, nullable: boolean): OAPI.ReferenceObject | OAPI.SchemaObject {
903-
// Check if this type is a TypeDef
904-
const isTypeDefType = this.model.declarations.some(d => isTypeDef(d) && d.name === type);
905-
906898
const result = match(type)
907899
.with('String', () => ({ type: 'string' }))
908900
.with(P.union('Int', 'BigInt'), () => ({ type: 'integer' }))
@@ -914,6 +906,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {
914906
.with(P.union('JSON', 'Json'), () => {
915907
// For Json fields, check if there's a specific TypeDef reference
916908
// Otherwise, return empty schema for arbitrary JSON
909+
const isTypeDefType = this.model.declarations.some(d => isTypeDef(d) && d.name === type);
917910
return isTypeDefType ? this.ref(type, false) : {};
918911
})
919912
.otherwise((type) => this.ref(type.toString(), false));

packages/plugins/openapi/tests/openapi-rpc.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,19 @@ model Product {
489489
// Verify enum reference in TypeDef
490490
expect(parsed.components.schemas.ReviewItem.properties.status.$ref).toBe('#/components/schemas/Status');
491491

492+
// Json field inside a TypeDef should remain generic (wrapped with nullable since it's optional)
493+
// OpenAPI 3.1 uses oneOf with null type, while 3.0 uses nullable: true
494+
if (specVersion === '3.1.0') {
495+
expect(parsed.components.schemas.ReviewItem.properties.metadata).toEqual({
496+
oneOf: [
497+
{ type: 'null' },
498+
{}
499+
]
500+
});
501+
} else {
502+
expect(parsed.components.schemas.ReviewItem.properties.metadata).toEqual({ nullable: true });
503+
}
504+
492505
// Verify nested TypeDef references
493506
expect(parsed.components.schemas.ContactInfo.properties.addresses.type).toBe('array');
494507
expect(parsed.components.schemas.ContactInfo.properties.addresses.items.$ref).toBe('#/components/schemas/Address');

0 commit comments

Comments
 (0)