11import { Source } from "@fern-api/openapi-ir" ;
22import { TaskContext } from "@fern-api/task-context" ;
3- import { OpenAPIV3 } from "openapi-types" ;
3+ import { OpenAPIV3 , OpenAPIV3_1 } from "openapi-types" ;
44import { describe , expect , it , vi } from "vitest" ;
55import { OpenAPIV3ParserContext } from "../openapi/v3/OpenAPIV3ParserContext.js" ;
66import { DEFAULT_PARSE_OPENAPI_SETTINGS } from "../options.js" ;
@@ -17,9 +17,9 @@ function createMockTaskContext(): TaskContext {
1717 } as unknown as TaskContext ;
1818}
1919
20- function createContext ( document : OpenAPIV3 . Document , source : Source ) : OpenAPIV3ParserContext {
20+ function createContext ( document : OpenAPIV3 . Document | OpenAPIV3_1 . Document , source : Source ) : OpenAPIV3ParserContext {
2121 return new OpenAPIV3ParserContext ( {
22- document,
22+ document : document as OpenAPIV3 . Document ,
2323 taskContext : createMockTaskContext ( ) ,
2424 authHeaders : new Set ( ) ,
2525 options : DEFAULT_PARSE_OPENAPI_SETTINGS ,
@@ -31,6 +31,68 @@ function createContext(document: OpenAPIV3.Document, source: Source): OpenAPIV3P
3131describe ( "convertReferenceObject nullability" , ( ) => {
3232 const source : Source = Source . openapi ( { file : "test.yaml" } ) ;
3333
34+ it ( "preserves type-array nullability after converting a documented allOf reference" , ( ) => {
35+ const nullableDetails = {
36+ type : [ "object" , "null" ] ,
37+ properties : {
38+ value : { type : "string" }
39+ } ,
40+ required : [ "value" ]
41+ } satisfies OpenAPIV3_1 . SchemaObject ;
42+ const firstProfile : OpenAPIV3 . SchemaObject = {
43+ type : "object" ,
44+ properties : {
45+ details : { $ref : "#/components/schemas/NullableDetails" }
46+ } ,
47+ required : [ "details" ]
48+ } ;
49+ const composedProfile : OpenAPIV3 . SchemaObject = {
50+ type : "object" ,
51+ properties : {
52+ details : {
53+ allOf : [ { $ref : "#/components/schemas/NullableDetails" } , { description : "Nullable details" } ]
54+ }
55+ } ,
56+ required : [ "details" ]
57+ } ;
58+ const secondProfile : OpenAPIV3 . SchemaObject = {
59+ type : "object" ,
60+ properties : {
61+ details : { $ref : "#/components/schemas/NullableDetails" }
62+ } ,
63+ required : [ "details" ]
64+ } ;
65+ const document = {
66+ openapi : "3.1.0" ,
67+ info : { title : "Test API" , version : "1.0.0" } ,
68+ paths : { } ,
69+ components : {
70+ schemas : {
71+ FirstProfile : firstProfile ,
72+ ComposedProfile : composedProfile ,
73+ SecondProfile : secondProfile ,
74+ NullableDetails : nullableDetails
75+ }
76+ }
77+ } satisfies OpenAPIV3_1 . Document ;
78+ const context = createContext ( document , source ) ;
79+
80+ const convertedProfiles = [ firstProfile , composedProfile , secondProfile ] . map ( ( profile , index ) =>
81+ convertSchema ( profile , false , false , context , [ `Profile${ index + 1 } ` ] , source , undefined )
82+ ) ;
83+
84+ expect (
85+ convertedProfiles . map ( ( profile ) => {
86+ expect ( profile . type ) . toBe ( "object" ) ;
87+ if ( profile . type !== "object" ) {
88+ return undefined ;
89+ }
90+ return profile . properties . find ( ( property ) => property . key === "details" ) ?. schema . type ;
91+ } )
92+ ) . toEqual ( [ "nullable" , "nullable" , "nullable" ] ) ;
93+ expect ( nullableDetails . type ) . toEqual ( [ "object" , "null" ] ) ;
94+ } ) ;
95+
3496 it ( "propagates nullability from a referenced anyOf that includes a { type: null } branch" , ( ) => {
3597 const document : OpenAPIV3 . Document = {
3698 openapi : "3.0.0" ,
0 commit comments