@@ -648,7 +648,7 @@ describe('SchemaModifier', () => {
648648 expect ( schema . $ref ) . toBe ( '#/components/schemas/SortOrderSingleMap' ) ;
649649 expect ( schema . type ) . toBeUndefined ( ) ;
650650 expect ( schema . properties ) . toBeUndefined ( ) ;
651-
651+
652652 // New SortOrderSingleMap schema should be created
653653 expect ( doc . components ! . schemas ! . SortOrderSingleMap ) . toBeDefined ( ) ;
654654 const mapSchema = doc . components ! . schemas ! . SortOrderSingleMap as OpenAPIV3 . SchemaObject ;
@@ -737,6 +737,71 @@ describe('SchemaModifier', () => {
737737
738738 expect ( schema . additionalProperties ) . toBeDefined ( ) ;
739739 } ) ;
740+
741+ it ( 'should use inline modification for QueryContainer properties' , ( ) => {
742+ const doc = createDocument ( ) ;
743+ doc . components ! . schemas ! . BoolQuery = {
744+ type : 'object' ,
745+ properties : {
746+ must : {
747+ type : 'array' ,
748+ items : { type : 'string' }
749+ }
750+ }
751+ } ;
752+
753+ const modifier = new SchemaModifier ( doc ) ;
754+ const visit = new Set ( ) ;
755+
756+ const schema : any = {
757+ type : 'object' ,
758+ additionalProperties : {
759+ $ref : '#/components/schemas/BoolQuery'
760+ } ,
761+ minProperties : 1 ,
762+ maxProperties : 1
763+ } ;
764+
765+ // Pass 'QueryContainer' as parent schema name
766+ modifier . simplifySingleMapSchema ( schema , visit , 'QueryContainer' ) ;
767+
768+ // Should use old inline behavior - becomes a $ref directly (no SingleMap wrapper)
769+ expect ( schema . $ref ) . toBe ( '#/components/schemas/BoolQuery' ) ;
770+ expect ( doc . components ! . schemas ! . BoolQuerySingleMap ) . toBeUndefined ( ) ;
771+
772+ // Properties should be deleted
773+ expect ( schema . type ) . toBeUndefined ( ) ;
774+ expect ( schema . additionalProperties ) . toBeUndefined ( ) ;
775+ expect ( schema . minProperties ) . toBeUndefined ( ) ;
776+ expect ( schema . maxProperties ) . toBeUndefined ( ) ;
777+ } ) ;
778+
779+ it ( 'should create SingleMap for non-QueryContainer properties' , ( ) => {
780+ const doc = createDocument ( ) ;
781+ doc . components ! . schemas ! . SortOrder = {
782+ type : 'string' ,
783+ enum : [ 'asc' , 'desc' ]
784+ } ;
785+
786+ const modifier = new SchemaModifier ( doc ) ;
787+ const visit = new Set ( ) ;
788+
789+ const schema : any = {
790+ type : 'object' ,
791+ additionalProperties : {
792+ $ref : '#/components/schemas/SortOrder'
793+ } ,
794+ minProperties : 1 ,
795+ maxProperties : 1
796+ } ;
797+
798+ // Pass a different parent schema name (not QueryContainer)
799+ modifier . simplifySingleMapSchema ( schema , visit , 'AggregateOrder' ) ;
800+
801+ // Should use new SingleMap behavior
802+ expect ( schema . $ref ) . toBe ( '#/components/schemas/SortOrderSingleMap' ) ;
803+ expect ( doc . components ! . schemas ! . SortOrderSingleMap ) . toBeDefined ( ) ;
804+ } ) ;
740805 } ) ;
741806
742807 describe ( 'convertAdditionalPropertiesToProperty - edge cases' , ( ) => {
@@ -894,5 +959,208 @@ describe('SchemaModifier', () => {
894959 expect ( result ) . toHaveProperty ( 'properties' ) ;
895960 expect ( ( result as any ) . properties ) . toHaveProperty ( 'customValue' ) ;
896961 } ) ;
962+
963+ it ( 'should handle oneOf schemas recursively' , ( ) => {
964+ const doc = createDocument ( ) ;
965+ doc . components ! . schemas ! . OptionA = {
966+ type : 'object' ,
967+ properties : { a : { type : 'string' } }
968+ } ;
969+ doc . components ! . schemas ! . OptionB = {
970+ type : 'object' ,
971+ properties : { b : { type : 'number' } }
972+ } ;
973+ doc . components ! . schemas ! . UnionType = {
974+ oneOf : [
975+ { $ref : '#/components/schemas/OptionA' } ,
976+ { $ref : '#/components/schemas/OptionB' }
977+ ]
978+ } ;
979+
980+ const modifier = new SchemaModifier ( doc ) ;
981+ const visit = new Set ( ) ;
982+
983+ const schema = { $ref : '#/components/schemas/UnionType' } ;
984+ modifier . reconstructAdditionalPropertySchema ( schema , visit ) ;
985+
986+ const optionA = doc . components ! . schemas ! . OptionA as any ;
987+ const optionB = doc . components ! . schemas ! . OptionB as any ;
988+
989+ // Both options should have the field property added
990+ expect ( optionA . properties ) . toHaveProperty ( 'field' ) ;
991+ expect ( optionB . properties ) . toHaveProperty ( 'field' ) ;
992+ } ) ;
993+
994+ it ( 'should handle anyOf schemas recursively' , ( ) => {
995+ const doc = createDocument ( ) ;
996+ doc . components ! . schemas ! . OptionC = {
997+ type : 'object' ,
998+ properties : { c : { type : 'string' } }
999+ } ;
1000+ doc . components ! . schemas ! . OptionD = {
1001+ type : 'object' ,
1002+ properties : { d : { type : 'number' } }
1003+ } ;
1004+ doc . components ! . schemas ! . FlexibleType = {
1005+ anyOf : [
1006+ { $ref : '#/components/schemas/OptionC' } ,
1007+ { $ref : '#/components/schemas/OptionD' }
1008+ ]
1009+ } ;
1010+
1011+ const modifier = new SchemaModifier ( doc ) ;
1012+ const visit = new Set ( ) ;
1013+
1014+ const schema = { $ref : '#/components/schemas/FlexibleType' } ;
1015+ modifier . reconstructAdditionalPropertySchema ( schema , visit ) ;
1016+
1017+ const optionC = doc . components ! . schemas ! . OptionC as any ;
1018+ const optionD = doc . components ! . schemas ! . OptionD as any ;
1019+
1020+ // Both options should have the field property added
1021+ expect ( optionC . properties ) . toHaveProperty ( 'field' ) ;
1022+ expect ( optionD . properties ) . toHaveProperty ( 'field' ) ;
1023+ } ) ;
1024+
1025+ it ( 'should return original schema if already visited' , ( ) => {
1026+ const doc = createDocument ( ) ;
1027+ doc . components ! . schemas ! . TestSchema = {
1028+ type : 'object' ,
1029+ properties : { test : { type : 'string' } }
1030+ } ;
1031+
1032+ const modifier = new SchemaModifier ( doc ) ;
1033+ const visit = new Set ( ) ;
1034+
1035+ const schema = { $ref : '#/components/schemas/TestSchema' } ;
1036+ const resolvedSchema = doc . components ! . schemas ! . TestSchema ;
1037+
1038+ visit . add ( resolvedSchema ) ;
1039+
1040+ const result = modifier . reconstructAdditionalPropertySchema ( schema , visit ) ;
1041+
1042+ // Should return original schema without modification
1043+ expect ( result ) . toBe ( schema ) ;
1044+ expect ( ( resolvedSchema as any ) . properties ) . not . toHaveProperty ( 'field' ) ;
1045+ } ) ;
1046+
1047+ it ( 'should handle primitive types without title' , ( ) => {
1048+ const doc = createDocument ( ) ;
1049+ const modifier = new SchemaModifier ( doc ) ;
1050+ const visit = new Set ( ) ;
1051+
1052+ const schema : any = { type : 'number' } ;
1053+ const result = modifier . reconstructAdditionalPropertySchema ( schema , visit ) ;
1054+
1055+ expect ( result ) . toHaveProperty ( 'properties' ) ;
1056+ expect ( ( result as any ) . properties ) . toHaveProperty ( 'value' ) ;
1057+ } ) ;
1058+
1059+ it ( 'should log error when field property already exists' , ( ) => {
1060+ const doc = createDocument ( ) ;
1061+ doc . components ! . schemas ! . ConflictSchema = {
1062+ type : 'object' ,
1063+ properties : {
1064+ field : { type : 'string' } ,
1065+ existing : { type : 'number' }
1066+ }
1067+ } ;
1068+
1069+ const modifier = new SchemaModifier ( doc ) ;
1070+ const visit = new Set ( ) ;
1071+
1072+ const schema = { $ref : '#/components/schemas/ConflictSchema' } ;
1073+
1074+ const errorSpy = jest . spyOn ( console , 'error' ) . mockImplementation ( ) ;
1075+
1076+ modifier . reconstructAdditionalPropertySchema ( schema , visit ) ;
1077+
1078+ expect ( errorSpy ) . toHaveBeenCalled ( ) ;
1079+ errorSpy . mockRestore ( ) ;
1080+ } ) ;
1081+ } ) ;
1082+
1083+ describe ( 'getTypeName' , ( ) => {
1084+ it ( 'should extract name from $ref' , ( ) => {
1085+ const doc = createDocument ( ) ;
1086+ const modifier = new SchemaModifier ( doc ) as any ;
1087+
1088+ const schema = { $ref : '#/components/schemas/TestType' } ;
1089+ const result = modifier . getTypeName ( schema ) ;
1090+
1091+ expect ( result ) . toBe ( 'TestType' ) ;
1092+ } ) ;
1093+
1094+ it ( 'should extract name from title' , ( ) => {
1095+ const doc = createDocument ( ) ;
1096+ const modifier = new SchemaModifier ( doc ) as any ;
1097+
1098+ const schema : OpenAPIV3 . SchemaObject = { type : 'object' , title : 'CustomTitle' } ;
1099+ const result = modifier . getTypeName ( schema ) ;
1100+
1101+ expect ( result ) . toBe ( 'CustomTitle' ) ;
1102+ } ) ;
1103+
1104+ it ( 'should return null if no $ref or title' , ( ) => {
1105+ const doc = createDocument ( ) ;
1106+ const modifier = new SchemaModifier ( doc ) as any ;
1107+
1108+ const schema : OpenAPIV3 . SchemaObject = { type : 'string' } ;
1109+ const result = modifier . getTypeName ( schema ) ;
1110+
1111+ expect ( result ) . toBeNull ( ) ;
1112+ } ) ;
1113+ } ) ;
1114+
1115+ describe ( 'createAdditionalPropertySchema' , ( ) => {
1116+ it ( 'should create schema with field property' , ( ) => {
1117+ const doc = createDocument ( ) ;
1118+ const modifier = new SchemaModifier ( doc ) as any ;
1119+
1120+ const result = modifier . createAdditionalPropertySchema ( ) ;
1121+
1122+ expect ( result . type ) . toBe ( 'object' ) ;
1123+ expect ( result . properties ) . toHaveProperty ( 'field' ) ;
1124+ expect ( result . properties ! . field ) . toEqual ( { type : 'string' } ) ;
1125+ } ) ;
1126+ } ) ;
1127+
1128+ describe ( 'isArraySchemaObject' , ( ) => {
1129+ it ( 'should return true for array schema with items' , ( ) => {
1130+ const doc = createDocument ( ) ;
1131+ const modifier = new SchemaModifier ( doc ) as any ;
1132+
1133+ const schema : OpenAPIV3 . ArraySchemaObject = {
1134+ type : 'array' ,
1135+ items : { type : 'string' }
1136+ } ;
1137+
1138+ const result = modifier . isArraySchemaObject ( schema ) ;
1139+ expect ( result ) . toBe ( true ) ;
1140+ } ) ;
1141+
1142+ it ( 'should return false for non-array schema' , ( ) => {
1143+ const doc = createDocument ( ) ;
1144+ const modifier = new SchemaModifier ( doc ) as any ;
1145+
1146+ const schema : OpenAPIV3 . SchemaObject = {
1147+ type : 'object'
1148+ } ;
1149+
1150+ const result = modifier . isArraySchemaObject ( schema ) ;
1151+ expect ( result ) . toBe ( false ) ;
1152+ } ) ;
1153+
1154+ it ( 'should return false for array without items' , ( ) => {
1155+ const doc = createDocument ( ) ;
1156+ const modifier = new SchemaModifier ( doc ) as any ;
1157+
1158+ const schema : any = {
1159+ type : 'array'
1160+ } ;
1161+
1162+ const result = modifier . isArraySchemaObject ( schema ) ;
1163+ expect ( result ) . toBe ( false ) ;
1164+ } ) ;
8971165 } ) ;
8981166} ) ;
0 commit comments