@@ -54,14 +54,7 @@ const toOpenAPIPath = (path: string) =>
5454const capitalize = ( word : string ) =>
5555 word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) ;
5656
57- const generateOperationIdCache = new Map < string , string > ( ) ;
5857const generateOperationId = ( route : RouterRoute ) => {
59- const operationIdKey = `${ route . method } :${ route . path } ` ;
60-
61- if ( generateOperationIdCache . has ( operationIdKey ) ) {
62- return generateOperationIdCache . get ( operationIdKey ) as string ;
63- }
64-
6558 let operationId = route . method ;
6659
6760 if ( route . path === "/" ) return `${ operationId } Index` ;
@@ -74,8 +67,6 @@ const generateOperationId = (route: RouterRoute) => {
7467 }
7568 }
7669
77- generateOperationIdCache . set ( operationIdKey , operationId ) ;
78-
7970 return operationId ;
8071} ;
8172
@@ -85,27 +76,16 @@ const paramKey = (param: Parameter) =>
8576 "$ref" in param ? param . $ref : `${ param . in } ${ param . name } ` ;
8677
8778function mergeParameters ( ...params : ( Parameter [ ] | undefined ) [ ] ) : Parameter [ ] {
88- const _params = params . flatMap ( ( x ) => x ?? [ ] ) ;
89-
90- const merged = _params . reduce ( ( acc , param ) => {
91- acc . set ( paramKey ( param ) , param ) ;
92- return acc ;
93- } , new Map < string , Parameter > ( ) ) ;
79+ const merged = params
80+ . flatMap ( ( x ) => x ?? [ ] )
81+ . reduce ( ( acc , param ) => {
82+ acc . set ( paramKey ( param ) , param ) ;
83+ return acc ;
84+ } , new Map < string , Parameter > ( ) ) ;
9485
9586 return Array . from ( merged . values ( ) ) ;
9687}
9788
98- function getProperty < T = unknown > (
99- obj : Record < string , unknown > | undefined ,
100- key : string ,
101- defaultValue ?: T ,
102- ) : T | undefined {
103- if ( obj != null && key in obj ) {
104- return obj [ key ] as T ;
105- }
106- return defaultValue ;
107- }
108-
10989const specsByPathContext = new Map <
11090 string ,
11191 RegisterSchemaPathOptions [ "specs" ]
@@ -125,32 +105,52 @@ function getPathContext(path: string) {
125105}
126106
127107function mergeSpecs (
128- ...specs : ( RegisterSchemaPathOptions [ "specs" ] | undefined ) [ ]
108+ route : RouterRoute ,
109+ ...specs : RegisterSchemaPathOptions [ "specs" ] [ ]
129110) {
130- return specs . reduce (
111+ return specs . reduce < OpenAPIV3_1 . OperationObject > (
131112 ( prev , spec ) => {
132- if ( ! spec ) return prev ;
133-
134- return {
135- ...prev ,
136- ...spec ,
137- tags : Array . from (
138- new Set ( [
139- ...( getProperty < string [ ] > ( prev , "tags" ) ?? [ ] ) ,
140- ...( getProperty < string [ ] > ( spec , "tags" ) ?? [ ] ) ,
141- ] ) ,
142- ) ,
143- parameters : mergeParameters (
144- getProperty ( prev , "parameters" ) ,
145- getProperty ( spec , "parameters" ) ,
146- ) ,
147- responses : {
148- ...getProperty ( prev , "responses" , { } ) ,
149- ...getProperty ( spec , "responses" , { } ) ,
150- } ,
151- } ;
113+ if ( ! spec || ! prev ) return prev ;
114+
115+ for ( const [ key , value ] of Object . entries ( spec ) ) {
116+ if ( value == null ) continue ;
117+
118+ if (
119+ key in prev &&
120+ ( typeof value === "object" ||
121+ ( typeof value === "function" && key === "operationId" ) )
122+ ) {
123+ if ( Array . isArray ( value ) ) {
124+ const values = [ ...( prev [ key ] ?? [ ] ) , ...value ] ;
125+
126+ if ( key === "tags" ) {
127+ prev [ key ] = Array . from ( new Set ( values ) ) ;
128+ } else {
129+ prev [ key ] = values ;
130+ }
131+ } else if ( typeof value === "function" ) {
132+ prev [ key ] = value ( route ) ;
133+ } else {
134+ if ( key === "parameters" ) {
135+ // @ts -expect-error
136+ prev [ key ] = mergeParameters ( prev [ key ] , value ) ;
137+ } else {
138+ prev [ key ] = {
139+ ...prev [ key ] ,
140+ ...value ,
141+ } ;
142+ }
143+ }
144+ } else {
145+ prev [ key ] = value ;
146+ }
147+ }
148+
149+ return prev ;
150+ } ,
151+ {
152+ operationId : generateOperationId ( route ) ,
152153 } ,
153- { } as NonNullable < RegisterSchemaPathOptions [ "specs" ] > ,
154154 ) ;
155155}
156156
@@ -171,21 +171,26 @@ export function registerSchemaPath({
171171 if ( specsByPathContext . has ( path ) ) {
172172 const prev = specsByPathContext . get ( path ) ?? { } ;
173173
174- specsByPathContext . set ( path , mergeSpecs ( prev , specs ) ) ;
174+ specsByPathContext . set ( path , mergeSpecs ( route , prev , specs ) ) ;
175175 } else {
176176 // If the specs are not present, we can just set it
177177 specsByPathContext . set ( path , specs ) ;
178178 }
179179 } else {
180180 const pathContext = getPathContext ( path ) ;
181181
182- paths [ path ] = {
183- ...( paths [ path ] ? paths [ path ] : { } ) ,
184- [ method ] : {
185- operationId : generateOperationId ( route ) ,
186- ...mergeSpecs ( ...pathContext , paths [ path ] ?. [ method ] , specs ) ,
187- } satisfies OpenAPIV3_1 . OperationObject ,
188- } ;
182+ if ( ! ( path in paths ) ) {
183+ paths [ path ] = { } ;
184+ }
185+
186+ if ( paths [ path ] ) {
187+ paths [ path ] [ method ] = mergeSpecs (
188+ route ,
189+ ...pathContext ,
190+ paths [ path ] ?. [ method ] ,
191+ specs ,
192+ ) ;
193+ }
189194 }
190195}
191196
0 commit comments