@@ -29,6 +29,7 @@ import {
2929 EXPORT_FORMAT_TO_FILE_FORMAT ,
3030 fromBase64 ,
3131 removeFirstSlash ,
32+ setValueByPath ,
3233 slugify ,
3334 takeIfDefined ,
3435 toVersionDocument ,
@@ -37,25 +38,19 @@ import { OpenAPIV3 } from 'openapi-types'
3738import { getOperationBasePath } from '../apitypes/rest/rest.utils'
3839import { VersionRestDocument } from '../apitypes/rest/rest.types'
3940import { FILE_FORMAT_JSON , INLINE_REFS_FLAG , NORMALIZE_OPTIONS } from '../consts'
40- import { normalize } from '@netcracker/qubership-apihub-api-unifier'
41+ import { normalize , parseRef } from '@netcracker/qubership-apihub-api-unifier'
4142import { calculateSpecRefs , extractCommonPathItemProperties } from '../apitypes/rest/rest.operation'
43+ import { getValueByPath } from '../utils/path'
4244
4345function getTransformedDocument ( document : ResolvedGroupDocument , format : FileFormat , packages : ResolvedReferenceMap ) : VersionRestDocument {
4446 const versionDocument = toVersionDocument ( document , format )
4547
46- const source = extractDocumentData ( versionDocument )
48+ const sourceDocument = extractDocumentData ( versionDocument )
4749 versionDocument . data = transformDocumentData ( versionDocument )
48- const normalizedDocument = normalize (
49- versionDocument . data ,
50- {
51- ...NORMALIZE_OPTIONS ,
52- inlineRefsFlag : INLINE_REFS_FLAG ,
53- source,
54- } ,
55- ) as OpenAPIV3 . Document
50+ const normalizedDocument = normalizeOpenApi ( versionDocument . data , sourceDocument )
5651 versionDocument . publish = true
5752
58- calculateSpecRefs ( source , normalizedDocument , versionDocument . data )
53+ calculateSpecRefs ( sourceDocument , normalizedDocument , versionDocument . data )
5954
6055 // dashboard case
6156 if ( document . packageRef ) {
@@ -116,48 +111,119 @@ function extractDocumentData(versionDocument: VersionDocument): OpenAPIV3.Docume
116111}
117112
118113function transformDocumentData ( versionDocument : VersionDocument ) : OpenAPIV3 . Document {
114+ const sourceDocument = extractDocumentData ( versionDocument )
115+ const normalizedDocument = normalizeOpenApi ( sourceDocument )
119116
120- const documentData = extractDocumentData ( versionDocument )
121- const { paths, components, ...rest } = documentData
122- const result : OpenAPIV3 . Document = {
123- ...rest ,
117+ const { paths : sourcePaths , components : sourceComponents , ...restOfSource } = sourceDocument
118+ const { paths : normalizedPaths } = normalizedDocument
119+
120+ const resultDocument : OpenAPIV3 . Document = {
121+ ...restOfSource ,
124122 paths : { } ,
125123 }
126124
127- for ( const path of Object . keys ( paths ) ) {
128- const pathData = paths [ path ]
129- if ( typeof pathData !== 'object' || ! pathData ) {
125+ for ( const path of Object . keys ( normalizedPaths ) ) {
126+ const sourcePathItem = sourcePaths [ path ]
127+ const normalizedPathItem = normalizedPaths [ path ]
128+
129+ if ( ! isNonNullObject ( sourcePathItem ) || ! isNonNullObject ( normalizedPathItem ) ) {
130130 continue
131131 }
132- const commonPathItemProperties = extractCommonPathItemProperties ( pathData )
133132
134- for ( const method of Object . keys ( pathData ) ) {
135- const inferredMethod = method as OpenAPIV3 . HttpMethods
133+ const commonPathProps = extractCommonPathItemProperties ( sourcePathItem )
134+ const pathItemRef = '$ref' in sourcePathItem ? sourcePathItem . $ref : undefined
136135
137- // check if field is a valid openapi http method defined in OpenAPIV3.HttpMethods
138- if ( ! Object . values ( OpenAPIV3 . HttpMethods ) . includes ( inferredMethod ) ) {
136+ for ( const method of Object . keys ( normalizedPathItem ) ) {
137+ const inferredMethod = method as OpenAPIV3 . HttpMethods
138+ if ( ! isValidHttpMethod ( inferredMethod ) ) {
139139 continue
140140 }
141141
142- const methodData = pathData [ inferredMethod ]
143- const basePath = getOperationBasePath ( methodData ?. servers || pathData ?. servers || documentData ?. servers || [ ] )
142+ const methodData = normalizedPathItem [ inferredMethod ]
143+ const basePath = getOperationBasePath ( methodData ?. servers || sourcePathItem ?. servers || sourcePathItem ?. servers || [ ] )
144144 const operationPath = basePath + path
145145
146146 const operationId = slugify ( `${ removeFirstSlash ( operationPath ) } -${ method } ` )
147147
148- if ( versionDocument . operationIds . includes ( operationId ) ) {
149- const pathData = documentData . paths [ path ] !
150- result . paths [ path ] = {
151- ...result . paths [ path ] ,
152- ...commonPathItemProperties ,
153- [ inferredMethod ] : { ...pathData [ inferredMethod ] } ,
154- }
155- result . components = {
156- ...takeIfDefined ( { securitySchemes : components ?. securitySchemes } ) ,
157- }
148+ if ( ! versionDocument . operationIds . includes ( operationId ) ) {
149+ continue
150+ }
151+
152+ const { updatedPathItem, extraComponents } = buildPathAndComponents (
153+ sourceDocument ,
154+ path ,
155+ inferredMethod ,
156+ commonPathProps ,
157+ pathItemRef ,
158+ )
159+
160+ resultDocument . paths [ path ] = {
161+ ...( resultDocument . paths [ path ] || { } ) ,
162+ ...updatedPathItem ,
163+ }
164+ resultDocument . components = {
165+ ...takeIfDefined ( { securitySchemes : sourceComponents ?. securitySchemes } ) ,
166+ ...extraComponents ,
158167 }
159168 }
160169 }
161170
162- return result
171+ return resultDocument
172+ }
173+
174+ function normalizeOpenApi ( document : OpenAPIV3 . Document , source ?: OpenAPIV3 . Document ) : OpenAPIV3 . Document {
175+ return normalize (
176+ document ,
177+ {
178+ ...NORMALIZE_OPTIONS ,
179+ inlineRefsFlag : INLINE_REFS_FLAG ,
180+ ...( source ? { source } : { } ) ,
181+ } ,
182+ ) as OpenAPIV3 . Document
183+ }
184+
185+ function isValidHttpMethod ( method : string ) : method is OpenAPIV3 . HttpMethods {
186+ return ( Object . values ( OpenAPIV3 . HttpMethods ) as string [ ] ) . includes ( method )
187+ }
188+
189+ function isNonNullObject ( value : unknown ) : value is Record < string , unknown > {
190+ return typeof value === 'object' && value !== null
191+ }
192+
193+ function buildPathAndComponents (
194+ sourceDocument : OpenAPIV3 . Document ,
195+ path : string ,
196+ method : OpenAPIV3 . HttpMethods ,
197+ commonPathProps : Partial < OpenAPIV3 . PathItemObject > ,
198+ pathItemRef ?: string ,
199+ ) : { updatedPathItem : OpenAPIV3 . PathItemObject ; extraComponents ?: OpenAPIV3 . ComponentsObject } {
200+ if ( ! pathItemRef ) {
201+ const originalPathItem = sourceDocument . paths [ path ] !
202+ return {
203+ updatedPathItem : {
204+ ...commonPathProps ,
205+ [ method ] : { ...originalPathItem [ method ] } ,
206+ } as OpenAPIV3 . PathItemObject ,
207+ }
208+ }
209+
210+ const { jsonPath } = parseRef ( pathItemRef )
211+ const targetPathItem = getValueByPath ( sourceDocument , jsonPath ) as OpenAPIV3 . PathItemObject
212+ const resolvedPathItem = {
213+ ...extractCommonPathItemProperties ( targetPathItem ) ,
214+ [ method ] : { ...targetPathItem [ method ] } ,
215+ }
216+ const componentsContainer : any = { }
217+ setValueByPath ( componentsContainer , jsonPath , resolvedPathItem )
218+
219+ const originalPathItem = sourceDocument . paths [ path ] !
220+ const mergedPathItem : OpenAPIV3 . PathItemObject = {
221+ ...( originalPathItem ) ,
222+ ...commonPathProps ,
223+ }
224+
225+ return {
226+ updatedPathItem : mergedPathItem ,
227+ extraComponents : componentsContainer . components ,
228+ }
163229}
0 commit comments