diff --git a/packages/openapi-merge-cli/src/data.ts b/packages/openapi-merge-cli/src/data.ts index 27a557a..8b42070 100644 --- a/packages/openapi-merge-cli/src/data.ts +++ b/packages/openapi-merge-cli/src/data.ts @@ -1,3 +1,10 @@ +import { Swagger } from "atlassian-openapi"; + +export type PathConfig = { + path: string; + method: Swagger.Method; +} + export type OperationSelection = { /** * Only Operatinos that have these tags will be taken from this OpenAPI file. If a single Operation contains @@ -10,6 +17,10 @@ export type OperationSelection = { * an includeTag and an excludeTag then it will be excluded; exclusion takes precedence. */ excludeTags?: string[]; + + includePaths?: PathConfig[]; + + excludePaths?: PathConfig[]; } export type PathModification = { diff --git a/packages/openapi-merge/src/data.ts b/packages/openapi-merge/src/data.ts index a3c9e87..ac1eaed 100644 --- a/packages/openapi-merge/src/data.ts +++ b/packages/openapi-merge/src/data.ts @@ -1,5 +1,10 @@ import { Swagger } from 'atlassian-openapi'; +export type PathConfig = { + path: string; + method: Swagger.Method; +} + export type OperationSelection = { /** * Only Operatinos that have these tags will be taken from this OpenAPI file. If a single Operation contains @@ -12,6 +17,10 @@ export type OperationSelection = { * an includeTag and an excludeTag then it will be excluded; exclusion takes precedence. */ excludeTags?: string[]; + + includePaths?: PathConfig[]; + + excludePaths?: PathConfig[]; }; export interface DisputeBase { diff --git a/packages/openapi-merge/src/operation-selection.ts b/packages/openapi-merge/src/operation-selection.ts index 31b2c49..9fa1d98 100644 --- a/packages/openapi-merge/src/operation-selection.ts +++ b/packages/openapi-merge/src/operation-selection.ts @@ -1,15 +1,26 @@ import _ from 'lodash'; import { Swagger } from "atlassian-openapi"; -import { OperationSelection } from './data'; +import { OperationSelection, PathConfig } from './data'; const allMethods: Swagger.Method[] = [ - 'get' , 'put' , 'post' , 'delete' , 'options' , 'head' , 'patch' , 'trace' + 'get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace' ] function operationContainsAnyTag(operation: Swagger.Operation, tags: string[]): boolean { return operation.tags !== undefined && operation.tags.some(tag => tags.includes(tag)); } +function operationContainsAnyPath(currentPath: string, method: Swagger.Method, pathConfigs: PathConfig[]): boolean { + return currentPath !== undefined && pathConfigs.some(pathConfig => { + const regex = new RegExp(`^${pathConfig.path}`); + if (regex.test(currentPath) && method.toLowerCase() === pathConfig.method.toLowerCase()) { + return true; + } + return false; + }); +} + + function dropOperationsThatHaveTags(originalOas: Swagger.SwaggerV3, excludedTags: string[]): Swagger.SwaggerV3 { if (excludedTags.length === 0) { return originalOas; @@ -36,6 +47,32 @@ function dropOperationsThatHaveTags(originalOas: Swagger.SwaggerV3, excludedTags return oas; } +function dropOperationsThatHavePaths(originalOas: Swagger.SwaggerV3, excludedPaths: PathConfig[]): Swagger.SwaggerV3 { + if (excludedPaths.length === 0) { + return originalOas; + } + + const oas = _.cloneDeep(originalOas); + + for (const path in oas.paths) { + /* eslint-disable-next-line no-prototype-builtins */ + if (oas.paths.hasOwnProperty(path)) { + const pathItem = oas.paths[path]; + + for (let i = 0; i < allMethods.length; i++) { + const method = allMethods[i]; + const operation = pathItem[method]; + + if (operation !== undefined && operationContainsAnyPath(path, method, excludedPaths)) { + delete pathItem[method]; + } + } + } + } + + return oas; +} + function includeOperationsThatHaveTags(originalOas: Swagger.SwaggerV3, includeTags: string[]): Swagger.SwaggerV3 { if (includeTags.length === 0) { return originalOas; @@ -62,11 +99,49 @@ function includeOperationsThatHaveTags(originalOas: Swagger.SwaggerV3, includeTa return oas; } +function includeOperationsThatHavePaths(originalOas: Swagger.SwaggerV3, includedPaths: PathConfig[]): Swagger.SwaggerV3 { + if (includedPaths.length === 0) { + return originalOas; + } + + const oas = _.cloneDeep(originalOas); + + for (const path in oas.paths) { + /* eslint-disable-next-line no-prototype-builtins */ + if (oas.paths.hasOwnProperty(path)) { + const pathItem = oas.paths[path]; + + for (let i = 0; i < allMethods.length; i++) { + const method = allMethods[i]; + const operation = pathItem[method]; + + if (operation !== undefined && !operationContainsAnyPath(path,method, includedPaths)) { + delete pathItem[method]; + } + } + } + } + + return oas; +} + export function runOperationSelection(originalOas: Swagger.SwaggerV3, operationSelection: OperationSelection | undefined): Swagger.SwaggerV3 { if (operationSelection === undefined) { return originalOas; } - return dropOperationsThatHaveTags(includeOperationsThatHaveTags(originalOas, operationSelection.includeTags || []), operationSelection.excludeTags || []); + // dropOperationsThatHaveTags(includeOperationsThatHaveTags(originalOas, operationSelection.includeTags || []), operationSelection.excludeTags || []) + return dropOperationsThatHavePaths( + includeOperationsThatHavePaths( + dropOperationsThatHaveTags( + includeOperationsThatHaveTags( + originalOas, operationSelection.includeTags || [] + ), + operationSelection.excludeTags || [] + ), + operationSelection.includePaths || [] + ), + operationSelection.excludePaths || [] + ) } \ No newline at end of file