@@ -88,11 +88,29 @@ function stripDeprecatedParametersFromOperation(op: any, counters: { removedPara
8888 * - Remove deprecated parameters from operations and from components.parameters
8989 * - Optionally remove deprecated operations (if removeDeprecatedOperations = true)
9090 */
91- export function sanitizeOpenAPI ( spec : any , opts : { removeDeprecatedOperations ?: boolean , removeDeprecatedParameters ?: boolean , operationIdsToSkip ?: string [ ] } = { } ) {
92- const counters = { removedProperties : 0 , removedParameters : 0 , removedOperations : 0 } ;
93- let { removeDeprecatedOperations = true , removeDeprecatedParameters = true , operationIdsToSkip = [ ] } = opts ;
94-
95- console . log ( `sanitize OpenAPI spec with params:\n\tremoveDeprecatedOperations: ${ removeDeprecatedOperations } \n\tremoveDeprecatedParameters: ${ removeDeprecatedParameters } \n\toperationIdsToSkip: ${ operationIdsToSkip } ` )
91+ export function sanitizeOpenAPI (
92+ spec : any ,
93+ opts : {
94+ removeDeprecatedOperations ?: boolean ,
95+ removeDeprecatedParameters ?: boolean ,
96+ operationIdsToSkip ?: string [ ] ,
97+ tagsToSkip ?: string [ ]
98+ } = { }
99+ ) {
100+ const counters = { removedProperties : 0 , removedParameters : 0 , removedOperations : 0 , removedSchemas : 0 } ;
101+ let {
102+ removeDeprecatedOperations = true ,
103+ removeDeprecatedParameters = true ,
104+ operationIdsToSkip = [ ] ,
105+ tagsToSkip = [ ]
106+ } = opts ;
107+
108+ console . log (
109+ `sanitize OpenAPI spec with params:\n\tremoveDeprecatedOperations: ${ removeDeprecatedOperations } ` +
110+ `\n\tremoveDeprecatedParameters: ${ removeDeprecatedParameters } ` +
111+ `\n\toperationIdsToSkip: ${ operationIdsToSkip } ` +
112+ `\n\ttagsToSkip: ${ tagsToSkip } `
113+ )
96114
97115 if ( ! spec || typeof spec !== "object" ) return counters ;
98116
@@ -136,6 +154,15 @@ export function sanitizeOpenAPI(spec: any, opts: { removeDeprecatedOperations?:
136154 continue ;
137155 }
138156
157+ // Optionally delete whole operation if its tag is skipped
158+ if ( tagsToSkip && Array . isArray ( op . tags ) && op . tags . some ( ( tag : string ) => tagsToSkip . includes ( tag ) ) ) {
159+ const removedOperation = pathItem [ method ] ;
160+ delete pathItem [ method ] ;
161+ counters . removedOperations += 1 ;
162+ console . debug ( `remove skipped tag operation: ${ method } ${ removedOperation . operationId } ${ op . tags } ` )
163+ continue ;
164+ }
165+
139166 // Optionally delete whole operation if it's marked deprecated
140167 if ( removeDeprecatedOperations && op . deprecated === true ) {
141168 const removedOperation = pathItem [ method ] ;
@@ -178,15 +205,93 @@ export function sanitizeOpenAPI(spec: any, opts: { removeDeprecatedOperations?:
178205 }
179206 }
180207
181- // 4) Remove get from method name, temporary while its done on core side
208+ // 4) Remove unreferenced component schemas after operation filtering
209+ counters . removedSchemas += removeUnreferencedSchemas ( spec ) ;
210+
211+ // 5) Remove get from method name, temporary while its done on core side
182212 normalizeGetOperationIds ( spec )
183213
184- // 5 ) Replace Flow.labels property schema
214+ // 6 ) Replace Flow.labels property schema
185215 replaceFlowLabelsSpec ( spec )
186216
187217 return counters ;
188218}
189219
220+ function removeUnreferencedSchemas ( spec : any ) : number {
221+ if ( ! spec ?. components ?. schemas || ! spec ?. paths || typeof spec . paths !== "object" ) return 0 ;
222+
223+ const components = spec . components || { } ;
224+ const schemas = components . schemas || { } ;
225+ const referencedSchemas = new Set < string > ( ) ;
226+ const visitedComponents = new Set < string > ( ) ;
227+
228+ const parseComponentRef = ( ref : string ) => {
229+ if ( typeof ref !== "string" || ! ref . startsWith ( "#/components/" ) ) return null ;
230+ const rest = ref . slice ( "#/components/" . length ) ;
231+ const parts = rest . split ( "/" ) ;
232+ const type = parts . shift ( ) ;
233+ const name = parts . join ( "/" ) ;
234+ if ( ! type || ! name ) return null ;
235+ return { type, name } ;
236+ } ;
237+
238+ const traverseNode = ( node : any ) => {
239+ if ( ! node || typeof node !== "object" ) return ;
240+ if ( Array . isArray ( node ) ) {
241+ for ( const item of node ) traverseNode ( item ) ;
242+ return ;
243+ }
244+
245+ const ref = node . $ref ;
246+ if ( typeof ref === "string" ) {
247+ const parsed = parseComponentRef ( ref ) ;
248+ if ( parsed ) {
249+ const { type, name } = parsed ;
250+ const key = `${ type } /${ name } ` ;
251+ if ( ! visitedComponents . has ( key ) ) {
252+ visitedComponents . add ( key ) ;
253+ if ( type === "schemas" ) {
254+ referencedSchemas . add ( name ) ;
255+ if ( schemas [ name ] ) traverseNode ( schemas [ name ] ) ;
256+ } else if ( components [ type ] && components [ type ] [ name ] ) {
257+ traverseNode ( components [ type ] [ name ] ) ;
258+ }
259+ }
260+ }
261+ }
262+
263+ for ( const value of Object . values ( node ) ) {
264+ traverseNode ( value ) ;
265+ }
266+ } ;
267+
268+ const httpMethods = [ "get" , "put" , "post" , "delete" , "options" , "head" , "patch" , "trace" ] as const ;
269+ for ( const p of Object . keys ( spec . paths ) ) {
270+ const pathItem = spec . paths [ p ] ;
271+ if ( ! pathItem || typeof pathItem !== "object" ) continue ;
272+
273+ if ( Array . isArray ( pathItem . parameters ) ) {
274+ traverseNode ( pathItem . parameters ) ;
275+ }
276+
277+ for ( const method of httpMethods ) {
278+ const op = pathItem [ method ] ;
279+ if ( ! op || typeof op !== "object" ) continue ;
280+ traverseNode ( op ) ;
281+ }
282+ }
283+
284+ let removed = 0 ;
285+ for ( const name of Object . keys ( schemas ) ) {
286+ if ( ! referencedSchemas . has ( name ) ) {
287+ delete schemas [ name ] ;
288+ removed += 1 ;
289+ }
290+ }
291+
292+ return removed ;
293+ }
294+
190295export function normalizeGetOperationIds ( spec : any ) : number {
191296 if ( ! spec || typeof spec !== "object" || ! spec . paths || typeof spec . paths !== "object" ) return 0 ;
192297 let renamed = 0 ;
@@ -245,5 +350,3 @@ export function replaceFlowLabelsSpec(spec: any) {
245350 }
246351 }
247352}
248-
249-
0 commit comments