@@ -19,29 +19,35 @@ import { OpenAPIV3 } from 'openapi-types'
1919import { REST_API_TYPE , REST_KIND_KEY } from './rest.consts'
2020import { operationRules } from './rest.rules'
2121import type * as TYPE from './rest.types'
22- import type {
22+ import { RestOperationData } from './rest.types'
23+ import {
2324 BuildConfig ,
2425 CrawlRule ,
2526 DeprecateItem ,
2627 NotificationMessage ,
2728 OperationCrawlState ,
29+ OperationId ,
2830 SearchScopes ,
2931} from '../../types'
3032import {
3133 buildSearchScope ,
34+ calculateOperationId ,
3235 capitalize ,
36+ extractSymbolProperty ,
3337 getKeyValue ,
3438 getSplittedVersionKey ,
39+ getSymbolValueIfDefined ,
3540 isDeprecatedOperationItem ,
3641 isOperationDeprecated ,
42+ isValidHttpMethod ,
3743 normalizePath ,
3844 rawToApiKind ,
3945 setValueByPath ,
4046 takeIf ,
4147 takeIfDefined ,
4248} from '../../utils'
4349import { API_KIND , INLINE_REFS_FLAG , ORIGINS_SYMBOL , VERSION_STATUS } from '../../consts'
44- import { getCustomTags , resolveApiAudience } from './rest.utils'
50+ import { getCustomTags , getOperationBasePath , resolveApiAudience } from './rest.utils'
4551import { DebugPerformanceContext , syncDebugPerformance } from '../../utils/logs'
4652import {
4753 calculateDeprecatedItems ,
@@ -59,6 +65,7 @@ import {
5965} from '@netcracker/qubership-apihub-api-unifier'
6066import { calculateObjectHash } from '../../utils/hashes'
6167import { calculateTolerantHash } from '../../components/deprecated'
68+ import { getValueByPath } from '../../utils/path'
6269
6370export const buildRestOperation = (
6471 operationId : string ,
@@ -143,7 +150,7 @@ export const buildRestOperation = (
143150 security ,
144151 components ?. securitySchemes ,
145152 )
146- calculateSpecRefs ( document . data , refsOnlySingleOperationSpec , specWithSingleOperation , models , componentsHashMap )
153+ calculateSpecRefs ( document . data , refsOnlySingleOperationSpec , specWithSingleOperation , [ operationId ] , models , componentsHashMap )
147154 const dataHash = calculateObjectHash ( specWithSingleOperation )
148155 return [ specWithSingleOperation , dataHash ]
149156 } , debugCtx )
@@ -180,7 +187,14 @@ export const buildRestOperation = (
180187 }
181188}
182189
183- export const calculateSpecRefs = ( sourceDocument : unknown , normalizedSpec : unknown , resultSpec : unknown , models ?: Record < string , string > , componentsHashMap ?: Map < string , string > ) : void => {
190+ export const calculateSpecRefs = (
191+ sourceDocument : TYPE . RestOperationData ,
192+ normalizedSpec : TYPE . RestOperationData ,
193+ resultSpec : TYPE . RestOperationData ,
194+ operations : OperationId [ ] ,
195+ models ?: Record < string , string > ,
196+ componentsHashMap ?: Map < string , string > ,
197+ ) : void => {
184198 const handledObjects = new Set < unknown > ( )
185199 const inlineRefs = new Set < string > ( )
186200 syncCrawl (
@@ -212,10 +226,11 @@ export const calculateSpecRefs = (sourceDocument: unknown, normalizedSpec: unkno
212226 return
213227 }
214228 const componentName = matchResult . grepValues [ grepKey ] . toString ( )
215- const component = getKeyValue ( sourceDocument , ...matchResult . path )
229+ const component = getKeyValue ( sourceDocument , ...matchResult . path ) as Record < string , unknown >
216230 if ( ! component ) {
217231 return
218232 }
233+
219234 if ( models && ! models [ componentName ] && isComponentsSchemaRef ( matchResult . path ) ) {
220235 let componentHash = componentsHashMap ?. get ( componentName )
221236 if ( componentHash ) {
@@ -226,8 +241,68 @@ export const calculateSpecRefs = (sourceDocument: unknown, normalizedSpec: unkno
226241 models [ componentName ] = componentHash
227242 }
228243 }
244+
229245 setValueByPath ( resultSpec , matchResult . path , component )
230246 } )
247+
248+ if ( operations ?. length ) {
249+ reduceComponentPathItemsToOperations ( resultSpec , normalizedSpec , operations )
250+ }
251+ }
252+
253+ function reduceComponentPathItemsToOperations (
254+ resultSpec : RestOperationData ,
255+ normalizedDocument : RestOperationData ,
256+ operations : OperationId [ ] ,
257+ ) : void {
258+ const { paths } = normalizedDocument
259+
260+ for ( const path of Object . keys ( paths ) ) {
261+ const sourcePathItem = paths [ path ] as OpenAPIV3 . PathItemObject
262+ const pathItemComponentJsonPath = getPathItemComponentJsonPath ( sourcePathItem )
263+ if ( ! pathItemComponentJsonPath ) {
264+ continue
265+ }
266+
267+ const pathItemComponent = getValueByPath ( resultSpec , pathItemComponentJsonPath ) as OpenAPIV3 . PathItemObject
268+
269+ const operationIds : OpenAPIV3 . HttpMethods [ ] = ( Object . keys ( pathItemComponent ) as OpenAPIV3 . HttpMethods [ ] )
270+ . filter ( ( httpMethod ) => isValidHttpMethod ( httpMethod ) )
271+ . filter ( httpMethod => {
272+ const methodData = sourcePathItem [ httpMethod as OpenAPIV3 . HttpMethods ]
273+ if ( ! methodData ) return false
274+ const basePath = getOperationBasePath (
275+ methodData ?. servers ||
276+ sourcePathItem ?. servers ||
277+ [ ] ,
278+ )
279+ const operationId = calculateOperationId ( basePath , httpMethod , path )
280+ return operations . includes ( operationId )
281+ } )
282+
283+ if ( operationIds ?. length ) {
284+ const pathItemObject = {
285+ ...extractCommonPathItemProperties ( pathItemComponent ) ,
286+ ...operationIds . reduce < OpenAPIV3 . PathItemObject > ( ( pathItemObject : OpenAPIV3 . PathItemObject , operationId : OpenAPIV3 . HttpMethods ) => {
287+ const operationData = pathItemComponent [ operationId ]
288+ if ( operationData ) {
289+ pathItemObject [ operationId ] = { ...operationData }
290+ }
291+ return pathItemObject
292+ } , { } ) ,
293+ }
294+ setValueByPath ( resultSpec , pathItemComponentJsonPath , pathItemObject )
295+ }
296+ }
297+ }
298+
299+ const getPathItemComponentJsonPath = ( sourcePathItem : OpenAPIV3 . PathItemObject ) : JsonPath | undefined => {
300+ const refs = getSymbolValueIfDefined ( sourcePathItem , INLINE_REFS_FLAG ) as string [ ] | undefined
301+ if ( ! refs || refs . length === 0 ) {
302+ return undefined
303+ }
304+
305+ return parseRef ( refs [ 0 ] ) ?. jsonPath
231306}
232307
233308export const isComponentsSchemaRef = ( path : JsonPath ) : boolean => {
@@ -236,6 +311,7 @@ export const isComponentsSchemaRef = (path: JsonPath): boolean => {
236311 [ [ OPEN_API_PROPERTY_COMPONENTS , OPEN_API_PROPERTY_SCHEMAS , PREDICATE_UNCLOSED_END ] ] ,
237312 )
238313}
314+
239315const isOperationPaths = ( paths : JsonPath [ ] ) : boolean => {
240316 return ! ! matchPaths (
241317 paths ,
@@ -257,15 +333,19 @@ const createSingleOperationSpec = (
257333) : TYPE . RestOperationData => {
258334 const pathData = document . paths [ path ] as OpenAPIV3 . PathItemObject
259335
336+ const isRefPathData = ! ! pathData . $ref
260337 return {
261338 openapi : openapi ?? '3.0.0' ,
262339 ...takeIfDefined ( { servers } ) ,
263340 ...takeIfDefined ( { security } ) , // TODO: remove duplicates in security
264341 paths : {
265- [ path ] : {
266- ...extractCommonPathItemProperties ( pathData ) ,
267- [ method ] : { ...pathData [ method ] } ,
268- } ,
342+ [ path ] : isRefPathData
343+ ? pathData
344+ : {
345+ ...extractCommonPathItemProperties ( pathData ) ,
346+ [ method ] : { ...pathData [ method ] } ,
347+ ...extractSymbolProperty ( pathData , INLINE_REFS_FLAG ) ,
348+ } ,
269349 } ,
270350 components : {
271351 ...takeIfDefined ( { securitySchemes } ) ,
0 commit comments