Skip to content

Commit f252064

Browse files
committed
refactor: move extractOperationBasePath and corresponding tests from api-processor to avoid code duplication
1 parent 76a3f5b commit f252064

File tree

4 files changed

+87
-22
lines changed

4 files changed

+87
-22
lines changed

src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export {
3434
isDiffReplace,
3535
} from './utils'
3636

37-
export { onlyExistedArrayIndexes } from './utils'
37+
export {
38+
aggregateDiffsWithRollup,
39+
extractOperationBasePath,
40+
onlyExistedArrayIndexes
41+
} from './utils'
3842

39-
export { aggregateDiffsWithRollup } from './utils'

src/openapi/openapi3.mapping.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { MapKeysResult, MappingResolver, NodeContext } from '../types'
22
import {
33
difference,
4+
extractOperationBasePath,
45
getStringValue,
56
intersection,
67
objectKeys,
@@ -194,26 +195,6 @@ function isWildcardCompatible(beforeType: string, afterType: string): boolean {
194195
return true
195196
}
196197

197-
// todo copy-paste from api-processor
198-
export const extractOperationBasePath = (servers?: OpenAPIV3.ServerObject[]): string => {
199-
if (!Array.isArray(servers) || !servers.length) { return '' }
200-
201-
try {
202-
const [firstServer] = servers
203-
let serverUrl = firstServer.url
204-
const { variables = {} } = firstServer
205-
206-
for (const param of Object.keys(variables)) {
207-
serverUrl = serverUrl.replace(new RegExp(`{${param}}`, 'g'), variables[param].default)
208-
}
209-
210-
const { pathname } = new URL(serverUrl, 'https://localhost')
211-
return pathname.slice(-1) === '/' ? pathname.slice(0, -1) : pathname
212-
} catch (error) {
213-
return ''
214-
}
215-
}
216-
217198
export function createPathUnifier(rootServers?: OpenAPIV3.ServerObject[]): (path: string, pathServers?: OpenAPIV3.ServerObject[]) => string {
218199
return (path, pathServers) => {
219200
// Prioritize path-level servers over root-level servers

src/utils.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
JSON_SCHEMA_NODE_TYPE_STRING,
2424
JsonSchemaNodesNormalizedType,
2525
} from '@netcracker/qubership-apihub-api-unifier'
26+
import { OpenAPIV3 } from 'openapi-types'
2627

2728
export const isObject = (value: unknown): value is Record<string | symbol, unknown> => {
2829
return typeof value === 'object' && value !== null
@@ -309,3 +310,29 @@ export function aggregateDiffsWithRollup(obj: any, diffProperty: any, aggregated
309310
return _aggregateDiffsWithRollup(obj)
310311
}
311312

313+
/**
314+
* Extracts the base path (path after the domain) from the first server URL in an array of OpenAPI ServerObjects.
315+
* It replaces any URL variable placeholders (e.g. {host}) with their default values from the 'variables' property.
316+
* The function will return the normalized pathname (without trailing slash) or an empty string on error or if the input is empty.
317+
*
318+
* @param {OpenAPIV3.ServerObject[]} [servers] - An array of OpenAPI ServerObject definitions.
319+
* @returns {string} The base path (pathname) part of the URL, without a trailing slash, or an empty string if unavailable.
320+
*/
321+
export const extractOperationBasePath = (servers?: OpenAPIV3.ServerObject[]): string => {
322+
if (!Array.isArray(servers) || !servers.length) { return '' }
323+
324+
try {
325+
const [firstServer] = servers
326+
let serverUrl = firstServer.url
327+
const { variables = {} } = firstServer
328+
329+
for (const param of Object.keys(variables)) {
330+
serverUrl = serverUrl.replace(new RegExp(`{${param}}`, 'g'), variables[param].default)
331+
}
332+
333+
const { pathname } = new URL(serverUrl, 'https://localhost')
334+
return pathname.slice(-1) === '/' ? pathname.slice(0, -1) : pathname
335+
} catch (error) {
336+
return ''
337+
}
338+
}

test/utils.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright 2024-2025 NetCracker Technology Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { extractOperationBasePath } from '../src/utils'
18+
19+
describe('Unit test for extractOperationBasePath', () => {
20+
test('Should handle Servers with parameters correctly', () => {
21+
const servers = [{
22+
url: '{protocol}://{host}/api',
23+
description: 'Remote server',
24+
variables: {
25+
protocol: {
26+
description: 'Request protocol.',
27+
enum: ['http', 'https'],
28+
default: 'https',
29+
},
30+
host: {
31+
description: 'Name of the server, for remote development.',
32+
enum: ['billing-ui-api.com'],
33+
default: 'billing-ui-api.com',
34+
},
35+
},
36+
}]
37+
38+
expect(extractOperationBasePath(servers)).toEqual('/api')
39+
})
40+
41+
test('Should handle Servers with absolute url correctly', () => {
42+
expect(extractOperationBasePath([{ url: 'https://example.com/v1' }])).toEqual('/v1')
43+
expect(extractOperationBasePath([{ url: 'https://example.com/v1/' }])).toEqual('/v1')
44+
})
45+
46+
test('Should handle Servers with relative url correctly', () => {
47+
expect(extractOperationBasePath([{ url: '/v1' }])).toEqual('/v1')
48+
expect(extractOperationBasePath([{ url: 'v1' }])).toEqual('/v1')
49+
expect(extractOperationBasePath([{ url: 'v1/' }])).toEqual('/v1')
50+
expect(extractOperationBasePath([{ url: '/v1/' }])).toEqual('/v1')
51+
expect(extractOperationBasePath([{ url: '/' }])).toEqual('')
52+
})
53+
})
54+

0 commit comments

Comments
 (0)