@@ -135,3 +135,68 @@ export function deleteMatchingKeys(obj: any, condition: (item: any) => boolean):
135135 }
136136 }
137137}
138+
139+ /**
140+ * Find all $ref references in the spec, including nested references
141+ */
142+ export function find_refs (
143+ current : Record < string , any > ,
144+ root ?: Record < string , any > ,
145+ call_stack : string [ ] = [ ]
146+ ) : Set < string > {
147+ const results = new Set < string > ( ) ;
148+
149+ if ( root === undefined ) {
150+ root = current ;
151+ current = current . paths ;
152+ }
153+
154+ if ( current ?. $ref != null ) {
155+ const ref = current . $ref as string ;
156+ results . add ( ref ) ;
157+
158+ const ref_node = resolveRef ( ref , root as OpenAPIV3 . Document ) ;
159+ if ( ref_node !== undefined && ! call_stack . includes ( ref ) ) {
160+ call_stack . push ( ref ) ;
161+ find_refs ( ref_node as Record < string , any > , root , call_stack ) . forEach ( ( ref ) => results . add ( ref ) ) ;
162+ }
163+ }
164+
165+ if ( _ . isObject ( current ) ) {
166+ _ . forEach ( current , ( v ) => {
167+ find_refs ( v as Record < string , any > , root , call_stack ) . forEach ( ( ref ) => results . add ( ref ) ) ;
168+ } ) ;
169+ }
170+
171+ return results ;
172+ }
173+
174+ /**
175+ * Remove unused component definitions and broken $ref entries
176+ */
177+ export function remove_unused ( spec : OpenAPIV3 . Document ) : void {
178+ if ( spec === undefined ) return ;
179+
180+ const references = find_refs ( spec ) ;
181+
182+ const componentTypes = [ 'parameters' , 'requestBodies' , 'responses' , 'schemas' ] ;
183+ for ( const componentType of componentTypes ) {
184+ const components = spec . components ?. [ componentType as keyof OpenAPIV3 . ComponentsObject ] ;
185+ if ( ! components || ! _ . isObject ( components ) ) continue ;
186+
187+ for ( const key of Object . keys ( components ) ) {
188+ if ( ! references . has ( `#/components/${ componentType } /${ key } ` ) ) {
189+ delete components [ key ] ;
190+ }
191+ }
192+ }
193+
194+ const remaining = _ . flatMap (
195+ [ 'schemas' , 'parameters' , 'responses' , 'requestBodies' ] ,
196+ ( key ) => _ . keys ( ( spec ?. components as any ) ?. [ key ] ) . map ( ( ref ) => `#/components/${ key } /${ ref } ` )
197+ ) ;
198+
199+ deleteMatchingKeys ( spec , ( obj : any ) =>
200+ obj . $ref !== undefined && ! _ . includes ( remaining , obj . $ref )
201+ ) ;
202+ }
0 commit comments