From 0d7775dc435b2c2104cb7b4cb843f702dc0c88df Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Thu, 10 Jul 2025 15:47:42 +0100 Subject: [PATCH 01/22] Test extension detection --- .../ipa/rulesets/functions/utils/extensions.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tools/spectral/ipa/rulesets/functions/utils/extensions.js diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js new file mode 100644 index 0000000000..904eb083f4 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -0,0 +1,14 @@ +export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; + +/** + * Checks if the object has the extension "x-xgen-method-verb-override" + * + * @param object the object to evaluate + * @returns {boolean} true if the object has verb override extension, otherwise false + */ +export function hasVerbOverride(object) { + if (object[VERB_OVERRIDE_EXTENSION]) { + return true; + } + return false; +} \ No newline at end of file From c45f1696a0fadd77b7430b75e09e98e5a53b58c4 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Thu, 10 Jul 2025 18:12:03 +0100 Subject: [PATCH 02/22] CLOUDP-306294: Get/List extension implementation --- .../functions/IPA104ValidOperationID.js | 10 ++++- .../functions/IPA105ValidOperationID.js | 8 +++- .../functions/IPA109ValidOperationID.js | 19 ++++++-- .../rulesets/functions/utils/extensions.js | 44 +++++++++++++++---- .../rulesets/functions/utils/methodLogic.js | 9 ++++ 5 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 tools/spectral/ipa/rulesets/functions/utils/methodLogic.js diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index f2583bfbb4..b995a46269 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -8,6 +8,8 @@ import { getResourcePathItems, isCustomMethodIdentifier, } from './utils/resourceEvaluation.js'; +import { hasVerbOverride, isGetOverride, isLegacyCustomMethod, isListOverride } from './utils/extensions.js'; +import { invalidGetMethod } from './utils/methodLogic.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -18,9 +20,10 @@ export default (input, { methodName }, { path, documentInventory }) => { const resourcePaths = getResourcePathItems(resourcePath, oas.paths); if ( + isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath) || - (!isSingleResourceIdentifier(resourcePath) && - !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths))) + isListOverride(input) || + (invalidGetMethod(resourcePath, resourcePaths) && !isGetOverride(input)) ) { return; } @@ -32,6 +35,9 @@ export default (input, { methodName }, { path, documentInventory }) => { const expectedOperationId = generateOperationID(methodName, resourcePath); if (expectedOperationId !== input.operationId) { + if (isGetOverride(input)) { + console.log( `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${resourcePath, input['x-xgen-owner-team']}`); + } const errors = [ { path, diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index f35a694631..0bc649b18c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -7,6 +7,8 @@ import { isSingletonResource, } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; +import { invalidListMethod } from './utils/methodLogic.js'; +import { isLegacyCustomMethod, isGetOverride, isListOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -14,11 +16,13 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path, documentInventory }) => { const resourcePath = path[1]; const oas = documentInventory.resolved; + const resourcePaths = getResourcePathItems(resourcePath, oas.paths); if ( + isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath) || - !isResourceCollectionIdentifier(resourcePath) || - isSingletonResource(getResourcePathItems(resourcePath, oas.paths)) + isGetOverride(input) || + (invalidListMethod(resourcePath, resourcePaths) && !isListOverride(input)) ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js index ec3a15f47d..53ca5e656f 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js @@ -2,26 +2,38 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; +import { hasVerbOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-109-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, _, { path }) => { let resourcePath = path[1]; - const methodName = getCustomMethodName(resourcePath); - if (!isCustomMethodIdentifier(resourcePath)) { + if (!isCustomMethodIdentifier(resourcePath) && !hasMethodWithVerbOverride(input)) { return; } - // TODO detect custom method extension - CLOUDP-306294 + let expectedOperationID = ''; + if (isCustomMethodIdentifier(resourcePath)) { + expectedOperationID = generateOperationID(getCustomMethodName(resourcePath), stripCustomMethodName(resourcePath)); + } else if (hasVerbOverride(input)) { + + + //const ext = input['x-xgen-method-verb-override']; + //expectedOperationID = generateOperationID(ext.verb, resourcePath); + } let obj; if (input.post) { obj = input.post; } else if (input.get) { obj = input.get; + } else if (input.delete) { + obj = input.delete; + console.log("yes"); } else { + console.log('AHHHHH', input); return; } @@ -31,7 +43,6 @@ export default (input, _, { path }) => { } const operationId = obj.operationId; - const expectedOperationID = generateOperationID(methodName, stripCustomMethodName(resourcePath)); if (expectedOperationID !== operationId) { const errors = [ { diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index 904eb083f4..eca813b01c 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -1,14 +1,42 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; -/** - * Checks if the object has the extension "x-xgen-method-verb-override" - * - * @param object the object to evaluate - * @returns {boolean} true if the object has verb override extension, otherwise false - */ +// for endpoint +export function hasMethodWithVerbOverride(endpoint) { + const keys = Object.keys(endpoint); + for (let i=0; i< keys.length; i++) { + if (endpoint[keys[i]][VERB_OVERRIDE_EXTENSION]) { + return true + } + } + return false; +} + +// for method export function hasVerbOverride(object) { - if (object[VERB_OVERRIDE_EXTENSION]) { - return true; + if (!object[VERB_OVERRIDE_EXTENSION]) { + return false; + } + return true; +} + +// for method +export function isLegacyCustomMethod(object) { + if (hasVerbOverride(object)) { + return object[VERB_OVERRIDE_EXTENSION].customMethod; } return false; +} + +export function isGetOverride(object) { + if (hasVerbOverride(object)) { + return object[VERB_OVERRIDE_EXTENSION].verb === 'get'; + } + return false; +} + +export function isListOverride(object) { + if (hasVerbOverride(object)) { + return object[VERB_OVERRIDE_EXTENSION].verb === 'list'; + } + return false; } \ No newline at end of file diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js new file mode 100644 index 0000000000..ec7f737b7e --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -0,0 +1,9 @@ +import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource } from "./resourceEvaluation" + +export function invalidGetMethod(resourcePath, resourcePaths) { + return !isSingleResourceIdentifier(resourcePath) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) +} + +export function invalidListMethod(resourcePath, resourcePaths) { + return !isResourceCollectionIdentifier(resourcePath) || isSingletonResource(resourcePaths) +} \ No newline at end of file From 79da6ecbf948719810708a05798a93b2485f6086 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 11 Jul 2025 11:23:02 +0100 Subject: [PATCH 03/22] CLOUDP-306294: Final get/list logic --- .../rulesets/functions/IPA104ValidOperationID.js | 13 ++----------- .../rulesets/functions/IPA105ValidOperationID.js | 7 +------ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index b995a46269..918742ec0c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -1,14 +1,8 @@ import { generateOperationID } from './utils/operationIdGeneration.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; import { hasException } from './utils/exceptions.js'; -import { - isSingleResourceIdentifier, - isResourceCollectionIdentifier, - isSingletonResource, - getResourcePathItems, - isCustomMethodIdentifier, -} from './utils/resourceEvaluation.js'; -import { hasVerbOverride, isGetOverride, isLegacyCustomMethod, isListOverride } from './utils/extensions.js'; +import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; +import { isGetOverride, isLegacyCustomMethod, isListOverride } from './utils/extensions.js'; import { invalidGetMethod } from './utils/methodLogic.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; @@ -35,9 +29,6 @@ export default (input, { methodName }, { path, documentInventory }) => { const expectedOperationId = generateOperationID(methodName, resourcePath); if (expectedOperationId !== input.operationId) { - if (isGetOverride(input)) { - console.log( `${input.operationId}, ${expectedOperationId}, ${resourcePath}, ${input.deprecated ? 'TRUE' : 'FALSE'}, ${resourcePath, input['x-xgen-owner-team']}`); - } const errors = [ { path, diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index 0bc649b18c..c87e52ef6d 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -1,11 +1,6 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; -import { - getResourcePathItems, - isCustomMethodIdentifier, - isResourceCollectionIdentifier, - isSingletonResource, -} from './utils/resourceEvaluation.js'; +import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; import { invalidListMethod } from './utils/methodLogic.js'; import { isLegacyCustomMethod, isGetOverride, isListOverride } from './utils/extensions.js'; From 3f502eed95cd356b17a69ae21b0eb2111f63858c Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 11 Jul 2025 12:00:09 +0100 Subject: [PATCH 04/22] CLOUDP-306294: Final create, update, delete logic --- .../ipa/rulesets/functions/IPA106ValidOperationID.js | 3 ++- .../ipa/rulesets/functions/IPA107ValidOperationID.js | 2 ++ .../ipa/rulesets/functions/IPA108ValidOperationID.js | 7 ++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 0b4c5039ad..359458016e 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -7,6 +7,7 @@ import { getResourcePathItems, } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; +import { isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -17,7 +18,7 @@ export default (input, { methodName }, { path, documentInventory }) => { const resourcePaths = getResourcePathItems(resourcePath, oas.paths); const isResourceCollection = isResourceCollectionIdentifier(resourcePath) && !isSingletonResource(resourcePaths); - if (isCustomMethodIdentifier(resourcePath) || !isResourceCollection) { + if (isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath) || !isResourceCollection) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 5e95184694..b65d4691be 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -8,6 +8,7 @@ import { isCustomMethodIdentifier, } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; +import { isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -19,6 +20,7 @@ export default (input, { methodName }, { path, documentInventory }) => { if ( isCustomMethodIdentifier(resourcePath) || + isLegacyCustomMethod(input) || (!isSingleResourceIdentifier(resourcePath) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths))) ) { diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 3f4dfef420..ad60ab34d5 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -2,6 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; +import { isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -9,7 +10,11 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if (isCustomMethodIdentifier(resourcePath) || !isSingleResourceIdentifier(resourcePath)) { + if ( + isCustomMethodIdentifier(resourcePath) || + !isSingleResourceIdentifier(resourcePath) || + isLegacyCustomMethod(input) + ) { return; } From 875b8805c94722621ba04422a2f2d8529000cb6b Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 11 Jul 2025 14:03:22 +0100 Subject: [PATCH 05/22] CLOUDP-306294: Draft custom method extension handling --- .../functions/IPA109ValidOperationID.js | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js index 53ca5e656f..3793641591 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { hasVerbOverride } from './utils/extensions.js'; +import { hasMethodWithVerbOverride, isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-109-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -14,44 +14,54 @@ export default (input, _, { path }) => { return; } + let errors = []; let expectedOperationID = ''; if (isCustomMethodIdentifier(resourcePath)) { expectedOperationID = generateOperationID(getCustomMethodName(resourcePath), stripCustomMethodName(resourcePath)); - } else if (hasVerbOverride(input)) { + let obj; + if (input.post) { + obj = input.post; + } else if (input.get) { + obj = input.get; + } else { + return; + } - //const ext = input['x-xgen-method-verb-override']; - //expectedOperationID = generateOperationID(ext.verb, resourcePath); - } + if (hasException(obj, RULE_NAME)) { + collectException(obj, RULE_NAME, path); + return; + } - let obj; - if (input.post) { - obj = input.post; - } else if (input.get) { - obj = input.get; - } else if (input.delete) { - obj = input.delete; - console.log("yes"); + const operationId = obj.operationId; + errors.push(checkViolationAndReturnError(operationId, expectedOperationID, path)); + } else if (hasMethodWithVerbOverride(input)) { + const methods = Object.keys(input); + for (let i = 0; i < methods.length; i++) { + let obj = input[methods[i]]; + const operationId = obj.operationId; + if (isLegacyCustomMethod(obj)) { + expectedOperationID = generateOperationID(obj['x-xgen-method-verb-override'].verb, resourcePath); + errors.push(checkViolationAndReturnError(operationId, expectedOperationID, path)); + } + } } else { - console.log('AHHHHH', input); - return; - } - - if (hasException(obj, RULE_NAME)) { - collectException(obj, RULE_NAME, path); return; } - const operationId = obj.operationId; - if (expectedOperationID !== operationId) { - const errors = [ - { - path, - message: `${ERROR_MESSAGE} Found ${operationId}, expected ${expectedOperationID}.`, - }, - ]; + if (errors.length !== 0) { return collectAndReturnViolation(path, RULE_NAME, errors); } collectAdoption(path, RULE_NAME); }; + +function checkViolationAndReturnError(oldOperationID, newOperationID, path) { + if (oldOperationID !== newOperationID) { + return { + path, + message: `${ERROR_MESSAGE} Found ${oldOperationID}, expected ${newOperationID}.`, + }; + } + return; +} From e00ebcf2d7e23d7d55ac06d24ab0706f645b8f3f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 11 Jul 2025 14:03:41 +0100 Subject: [PATCH 06/22] CLOUDP-306294: Uncommented extension utilities --- .../ipa/rulesets/functions/utils/extensions.js | 10 +++++----- .../ipa/rulesets/functions/utils/methodLogic.js | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index eca813b01c..a0681adec2 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -3,9 +3,9 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; // for endpoint export function hasMethodWithVerbOverride(endpoint) { const keys = Object.keys(endpoint); - for (let i=0; i< keys.length; i++) { + for (let i = 0; i < keys.length; i++) { if (endpoint[keys[i]][VERB_OVERRIDE_EXTENSION]) { - return true + return true; } } return false; @@ -30,13 +30,13 @@ export function isLegacyCustomMethod(object) { export function isGetOverride(object) { if (hasVerbOverride(object)) { return object[VERB_OVERRIDE_EXTENSION].verb === 'get'; - } + } return false; } export function isListOverride(object) { if (hasVerbOverride(object)) { return object[VERB_OVERRIDE_EXTENSION].verb === 'list'; - } + } return false; -} \ No newline at end of file +} diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index ec7f737b7e..01157dae38 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -1,9 +1,12 @@ -import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource } from "./resourceEvaluation" +import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation'; export function invalidGetMethod(resourcePath, resourcePaths) { - return !isSingleResourceIdentifier(resourcePath) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) + return ( + !isSingleResourceIdentifier(resourcePath) && + !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) + ); } export function invalidListMethod(resourcePath, resourcePaths) { - return !isResourceCollectionIdentifier(resourcePath) || isSingletonResource(resourcePaths) -} \ No newline at end of file + return !isResourceCollectionIdentifier(resourcePath) || isSingletonResource(resourcePaths); +} From 794456ce6df0311ce51d9375515d0a528852d495 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Fri, 11 Jul 2025 16:08:32 +0100 Subject: [PATCH 07/22] CLOUDP-306294: updated utilities to handle get/list edge cases --- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 7 ++++--- .../ipa/rulesets/functions/utils/operationIdGeneration.js | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index 01157dae38..5820bc3766 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -1,12 +1,13 @@ -import { isSingleResourceIdentifier, isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation'; +import { isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation'; +import { isPathParam } from './resourceEvaluation'; export function invalidGetMethod(resourcePath, resourcePaths) { return ( - !isSingleResourceIdentifier(resourcePath) && + !isPathParam(resourcePath.split('/').pop()) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) ); } export function invalidListMethod(resourcePath, resourcePaths) { - return !isResourceCollectionIdentifier(resourcePath) || isSingletonResource(resourcePaths); + return isPathParam(resourcePath.split('/').pop()) || isSingletonResource(resourcePaths); } diff --git a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js index 12ee3cfe98..73c66336b0 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js +++ b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js @@ -11,6 +11,10 @@ const CAMEL_CASE = /[A-Z]?[a-z]+/g; */ export function generateOperationID(method, path) { let resourceIdentifier = removePrefix(path); + if (resourceIdentifier.includes('.')) { + resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.lastIndexOf('.')); + } + let nouns = resourceIdentifier.split('/').filter((section) => section.length > 0 && !isPathParam(section)); // legacy custom method - use end of path as custom method name From d3deaaeafad3b8ac616f1d1e90beadb452acadc9 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 10:01:11 +0100 Subject: [PATCH 08/22] Edit to logic to handle outliers --- .../functions/IPA106ValidOperationID.js | 14 +++------- .../functions/IPA107ValidOperationID.js | 19 +++---------- .../functions/IPA108ValidOperationID.js | 6 +---- .../functions/IPA109ValidOperationID.js | 27 ++++++++++--------- 4 files changed, 22 insertions(+), 44 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 359458016e..6fc6a37a61 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -1,24 +1,16 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { - isCustomMethodIdentifier, - isResourceCollectionIdentifier, - isSingletonResource, - getResourcePathItems, -} from './utils/resourceEvaluation.js'; +import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; import { isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; -export default (input, { methodName }, { path, documentInventory }) => { +export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - const oas = documentInventory.resolved; - const resourcePaths = getResourcePathItems(resourcePath, oas.paths); - const isResourceCollection = isResourceCollectionIdentifier(resourcePath) && !isSingletonResource(resourcePaths); - if (isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath) || !isResourceCollection) { + if (isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index b65d4691be..2cac263d8a 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -1,29 +1,16 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { - isSingleResourceIdentifier, - isResourceCollectionIdentifier, - isSingletonResource, - getResourcePathItems, - isCustomMethodIdentifier, -} from './utils/resourceEvaluation.js'; +import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; import { isLegacyCustomMethod } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; -export default (input, { methodName }, { path, documentInventory }) => { +export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - const oas = documentInventory.resolved; - const resourcePaths = getResourcePathItems(resourcePath, oas.paths); - if ( - isCustomMethodIdentifier(resourcePath) || - isLegacyCustomMethod(input) || - (!isSingleResourceIdentifier(resourcePath) && - !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths))) - ) { + if (isCustomMethodIdentifier(resourcePath) || isLegacyCustomMethod(input)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index ad60ab34d5..91fb768d3c 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -10,11 +10,7 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if ( - isCustomMethodIdentifier(resourcePath) || - !isSingleResourceIdentifier(resourcePath) || - isLegacyCustomMethod(input) - ) { + if (isCustomMethodIdentifier(resourcePath) || isLegacyCustomMethod(input)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js index 3793641591..70cbc2c677 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js @@ -34,7 +34,15 @@ export default (input, _, { path }) => { } const operationId = obj.operationId; - errors.push(checkViolationAndReturnError(operationId, expectedOperationID, path)); + if (operationId !== expectedOperationID) { + const errors = [ + { + path, + message: `${ERROR_MESSAGE} Found ${operationId}, expected ${expectedOperationID}.`, + }, + ]; + return collectAndReturnViolation(path, RULE_NAME, errors); + } } else if (hasMethodWithVerbOverride(input)) { const methods = Object.keys(input); for (let i = 0; i < methods.length; i++) { @@ -42,7 +50,12 @@ export default (input, _, { path }) => { const operationId = obj.operationId; if (isLegacyCustomMethod(obj)) { expectedOperationID = generateOperationID(obj['x-xgen-method-verb-override'].verb, resourcePath); - errors.push(checkViolationAndReturnError(operationId, expectedOperationID, path)); + if (operationId !== expectedOperationID) { + errors.push({ + path, + message: `${ERROR_MESSAGE} Found ${operationId}, expected ${expectedOperationID}.`, + }); + } } } } else { @@ -55,13 +68,3 @@ export default (input, _, { path }) => { collectAdoption(path, RULE_NAME); }; - -function checkViolationAndReturnError(oldOperationID, newOperationID, path) { - if (oldOperationID !== newOperationID) { - return { - path, - message: `${ERROR_MESSAGE} Found ${oldOperationID}, expected ${newOperationID}.`, - }; - } - return; -} From 9ae2c9349f4906e0f47bae9278efa141d051812f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 10:02:09 +0100 Subject: [PATCH 09/22] Edit logic to handle outliers --- .../rulesets/functions/utils/operationIdGeneration.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js index 73c66336b0..69921f42db 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js +++ b/tools/spectral/ipa/rulesets/functions/utils/operationIdGeneration.js @@ -10,6 +10,10 @@ const CAMEL_CASE = /[A-Z]?[a-z]+/g; * @param path the path for the endpoint */ export function generateOperationID(method, path) { + if (!path) { + return method; + } + let resourceIdentifier = removePrefix(path); if (resourceIdentifier.includes('.')) { resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.lastIndexOf('.')); @@ -37,7 +41,11 @@ export function generateOperationID(method, path) { } // singularize final noun, dependent on resource identifier - if (isSingleResourceIdentifier(resourceIdentifier) || verb === 'create') { + if ( + isPathParam(resourceIdentifier.split('/').pop()) || + isSingleResourceIdentifier(resourceIdentifier) || + verb === 'create' + ) { nouns[nouns.length - 1] = inflection.singularize(nouns[nouns.length - 1]); } From ea69c297cbc81e009d7ba082dfa75260bfc6d601 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 14:24:39 +0100 Subject: [PATCH 10/22] CLOUDP-306294: Refactored and commented opID related utilities --- .../functions/IPA104ValidOperationID.js | 8 +-- .../functions/IPA105ValidOperationID.js | 8 +-- .../functions/IPA106ValidOperationID.js | 4 +- .../functions/IPA107ValidOperationID.js | 4 +- .../functions/IPA108ValidOperationID.js | 4 +- .../functions/IPA109ValidOperationID.js | 4 +- .../rulesets/functions/utils/extensions.js | 53 ++++++++++++------- .../rulesets/functions/utils/methodLogic.js | 25 ++++++++- 8 files changed, 73 insertions(+), 37 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index 918742ec0c..c4e975d6d4 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -2,7 +2,7 @@ import { generateOperationID } from './utils/operationIdGeneration.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; import { hasException } from './utils/exceptions.js'; import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; -import { isGetOverride, isLegacyCustomMethod, isListOverride } from './utils/extensions.js'; +import { hasCustomMethodOverride, hasMethodVerbOverride } from './utils/extensions.js'; import { invalidGetMethod } from './utils/methodLogic.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; @@ -14,10 +14,10 @@ export default (input, { methodName }, { path, documentInventory }) => { const resourcePaths = getResourcePathItems(resourcePath, oas.paths); if ( - isLegacyCustomMethod(input) || + hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath) || - isListOverride(input) || - (invalidGetMethod(resourcePath, resourcePaths) && !isGetOverride(input)) + hasMethodVerbOverride(input, "list") || + (invalidGetMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index c87e52ef6d..f61742bf33 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -3,7 +3,7 @@ import { collectAdoption, collectAndReturnViolation, collectException } from './ import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; import { invalidListMethod } from './utils/methodLogic.js'; -import { isLegacyCustomMethod, isGetOverride, isListOverride } from './utils/extensions.js'; +import { hasCustomMethodOverride, hasMethodVerbOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -14,10 +14,10 @@ export default (input, { methodName }, { path, documentInventory }) => { const resourcePaths = getResourcePathItems(resourcePath, oas.paths); if ( - isLegacyCustomMethod(input) || + hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath) || - isGetOverride(input) || - (invalidListMethod(resourcePath, resourcePaths) && !isListOverride(input)) + hasMethodVerbOverride(input, 'get') || + (invalidListMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js index 6fc6a37a61..428fd33b20 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA106ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { isLegacyCustomMethod } from './utils/extensions.js'; +import { hasCustomMethodOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-106-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -10,7 +10,7 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if (isLegacyCustomMethod(input) || isCustomMethodIdentifier(resourcePath)) { + if (hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js index 2cac263d8a..1500354412 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA107ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { isLegacyCustomMethod } from './utils/extensions.js'; +import { hasCustomMethodOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-107-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -10,7 +10,7 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if (isCustomMethodIdentifier(resourcePath) || isLegacyCustomMethod(input)) { + if (isCustomMethodIdentifier(resourcePath) || hasCustomMethodOverride(input)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 91fb768d3c..37cb9c20e9 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { isLegacyCustomMethod } from './utils/extensions.js'; +import { hasCustomMethodOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-108-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -10,7 +10,7 @@ const ERROR_MESSAGE = 'Invalid OperationID.'; export default (input, { methodName }, { path }) => { const resourcePath = path[1]; - if (isCustomMethodIdentifier(resourcePath) || isLegacyCustomMethod(input)) { + if (isCustomMethodIdentifier(resourcePath) || hasCustomMethodOverride(input)) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js index 70cbc2c677..39058f5d8b 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { hasMethodWithVerbOverride, isLegacyCustomMethod } from './utils/extensions.js'; +import { hasMethodWithVerbOverride, hasCustomMethodOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-109-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -48,7 +48,7 @@ export default (input, _, { path }) => { for (let i = 0; i < methods.length; i++) { let obj = input[methods[i]]; const operationId = obj.operationId; - if (isLegacyCustomMethod(obj)) { + if (hasCustomMethodOverride(obj)) { expectedOperationID = generateOperationID(obj['x-xgen-method-verb-override'].verb, resourcePath); if (operationId !== expectedOperationID) { errors.push({ diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index a0681adec2..7a91b44c8b 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -1,42 +1,57 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; -// for endpoint +/** + * Checks if the endpoint has a method with an extension "x-xgen-method-verb-override" + * + * @param object the object to evaluate + * @returns {boolean} true if the object has the extension, otherwise false + */ export function hasMethodWithVerbOverride(endpoint) { const keys = Object.keys(endpoint); for (let i = 0; i < keys.length; i++) { - if (endpoint[keys[i]][VERB_OVERRIDE_EXTENSION]) { + if (hasVerbOverride(endpoint[keys[i]])) { return true; } } return false; } -// for method -export function hasVerbOverride(object) { - if (!object[VERB_OVERRIDE_EXTENSION]) { - return false; - } - return true; -} - -// for method -export function isLegacyCustomMethod(object) { +/** + * Checks if the object has an extension "x-xgen-method-verb-override" with the customMethod boolean set to true + * + * @param object the object to evaluate + * @returns {boolean} true if the object has an extension with customMethod=True, otherwise false + */ +export function hasCustomMethodOverride(object) { if (hasVerbOverride(object)) { return object[VERB_OVERRIDE_EXTENSION].customMethod; } return false; } -export function isGetOverride(object) { +/** + * Checks if the object has an extension "x-xgen-method-verb-override" with the verb set to a specific verb + * + * @param object the object to evaluate + * @param verb the verb to inspect the extension for + * @returns {boolean} true if the object has the extension with the given verb, otherwise false + */ +export function hasMethodVerbOverride(object, verb) { if (hasVerbOverride(object)) { - return object[VERB_OVERRIDE_EXTENSION].verb === 'get'; + return object[VERB_OVERRIDE_EXTENSION].verb === verb; } return false; } -export function isListOverride(object) { - if (hasVerbOverride(object)) { - return object[VERB_OVERRIDE_EXTENSION].verb === 'list'; +/** + * Checks if the object has an extension "x-xgen-method-verb-override" + * + * @param object the object to evaluate + * @returns {boolean} true if the object has the extension, otherwise false + */ +function hasVerbOverride(object) { + if (!object[VERB_OVERRIDE_EXTENSION]) { + return false; } - return false; -} + return true; +} \ No newline at end of file diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index 5820bc3766..b0cc6c6bf5 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -1,13 +1,34 @@ import { isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation'; import { isPathParam } from './resourceEvaluation'; +/** + * Checks whether the get method at a given path is valid + * + * @param resourcePath the resource path to inspect + * @param resourcePaths the resource paths generated by getResourcePathItems + * @returns true if the resourcePath has an invalid list method, false otherwise + */ export function invalidGetMethod(resourcePath, resourcePaths) { return ( - !isPathParam(resourcePath.split('/').pop()) && + !lastIdentifierIsPathParam(resourcePath) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) ); } +/** + * Checks whether the list method at a given path is valid + * + * @param resourcePath the resource path to inspect + * @param resourcePaths the resource paths generated by getResourcePathItems + * @returns true if the resourcePath has an invalid list method, false otherwise + */ export function invalidListMethod(resourcePath, resourcePaths) { - return isPathParam(resourcePath.split('/').pop()) || isSingletonResource(resourcePaths); + return lastIdentifierIsPathParam(resourcePath) || isSingletonResource(resourcePaths); } + +function lastIdentifierIsPathParam(resourceIdentifier) { + if (resourceIdentifier.includes('.')) { + resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.lastIndexOf('.')); + } + return isPathParam(resourceIdentifier.split('/').pop()); +} \ No newline at end of file From 00a2052c12baf9985f853ba5ba1c4d43fd3d8453 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 16:20:22 +0100 Subject: [PATCH 11/22] fixed flawed test --- .../spectral/ipa/__tests__/utils/operationIdGeneration.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/spectral/ipa/__tests__/utils/operationIdGeneration.test.js b/tools/spectral/ipa/__tests__/utils/operationIdGeneration.test.js index b39ac9cd98..185987d00f 100644 --- a/tools/spectral/ipa/__tests__/utils/operationIdGeneration.test.js +++ b/tools/spectral/ipa/__tests__/utils/operationIdGeneration.test.js @@ -28,7 +28,7 @@ describe('tools/spectral/ipa/utils/operationIdGeneration.js', () => { expect(generateOperationID('addNode', '/groups/{groupId}/clusters/{clusterName}')).toEqual('addGroupClusterNode'); expect(generateOperationID('get', '/api/atlas/v2/groups/byName/{groupName}')).toEqual('getGroupByName'); expect(generateOperationID('', '/api/atlas/v2/groups/{groupId}/backup/exportBuckets/{exportBucketId}')).toEqual( - 'exportGroupBackupBuckets' + 'exportGroupBackupBucket' ); }); From 1c864be99e3b3661291890aac714aefbbafa0c7f Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 16:35:46 +0100 Subject: [PATCH 12/22] Added tests for extension utilities --- .../ipa/__tests__/utils/extensions.test.js | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tools/spectral/ipa/__tests__/utils/extensions.test.js diff --git a/tools/spectral/ipa/__tests__/utils/extensions.test.js b/tools/spectral/ipa/__tests__/utils/extensions.test.js new file mode 100644 index 0000000000..c766deee70 --- /dev/null +++ b/tools/spectral/ipa/__tests__/utils/extensions.test.js @@ -0,0 +1,65 @@ +import { describe, it, expect, toBe } from '@jest/globals'; +import { hasMethodWithVerbOverride, hasCustomMethodOverride, hasMethodVerbOverride } from '../../rulesets/functions/utils/extensions'; + +const methodWithExtension = { + 'x-xgen-method-verb-override': { + verb: 'get', + customMethod: false, + }, +}; + +const customMethod = { + 'x-xgen-method-verb-override': { + verb: 'add', + customMethod: true, + }, +} + +const endpointWithMethodExtension = { + delete: { + 'x-xgen-method-verb-override': { verb: '‘remove’', customMethod: true } + } +}; + +const endpointWithNoMethodExtension = { + 'exception' : true +}; + +describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { + describe('hasMethodWithVerbOverride', () => { + it('returns true if endpoint has method with the extension', () => { + expect(hasMethodWithVerbOverride(endpointWithMethodExtension)).toBe(true); + }); + it('returns false if object does not a method with the extension', () => { + expect(hasMethodWithVerbOverride(endpointWithNoMethodExtension)).toBe(false); + }); + }); +}); + +describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { + describe('hasCustomMethodOverride', () => { + it('returns true if the method has the extension with the cusotmMethod boolean set to true', () => { + expect(hasCustomMethodOverride(customMethod)).toBe(true); + }); + it('returns false if the method does not have the extension', () => { + expect(hasCustomMethodOverride({})).toBe(false); + }); + it('returns false if the method has the extension but is not a custom method', () => { + expect(hasCustomMethodOverride(methodWithExtension)).toBe(false); + }); + }); +}); + +describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { + describe('hasMethodVerbOverride', () => { + it('returns true if the method has the extension with the expected verb', () => { + expect(hasMethodVerbOverride(methodWithExtension, "get")).toBe(true); + }); + it('returns false if the method does not have the extension', () => { + expect(hasMethodVerbOverride({}, "get")).toBe(false); + }); + it('returns false if the method has the extension but with an unexpected verb', () => { + expect(hasMethodVerbOverride(methodWithExtension, "put")).toBe(false); + }); + }); +}); From 6c2f9fcf30a7118d75d9e39375d2aae32f05cfab Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 16:36:49 +0100 Subject: [PATCH 13/22] CLOUDP-306294: silenced opIdgeneration tests + prettier --- package.json | 3 +- .../ipa/__tests__/utils/extensions.test.js | 36 ++++++++++--------- .../functions/IPA104ValidOperationID.js | 2 +- .../rulesets/functions/utils/extensions.js | 6 ++-- .../rulesets/functions/utils/methodLogic.js | 6 ++-- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 1b7d4e30e3..cc547efdfa 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "testPathIgnorePatterns": [ "__helpers__", "metrics/data", - "IPA\\d+ValidOperationID\\.test\\.js$" + "IPA\\d+ValidOperationID\\.test\\.js$", + "operationIdGeneration.test.js" ] }, "dependencies": { diff --git a/tools/spectral/ipa/__tests__/utils/extensions.test.js b/tools/spectral/ipa/__tests__/utils/extensions.test.js index c766deee70..6e3719d6ee 100644 --- a/tools/spectral/ipa/__tests__/utils/extensions.test.js +++ b/tools/spectral/ipa/__tests__/utils/extensions.test.js @@ -1,28 +1,32 @@ import { describe, it, expect, toBe } from '@jest/globals'; -import { hasMethodWithVerbOverride, hasCustomMethodOverride, hasMethodVerbOverride } from '../../rulesets/functions/utils/extensions'; +import { + hasMethodWithVerbOverride, + hasCustomMethodOverride, + hasMethodVerbOverride, +} from '../../rulesets/functions/utils/extensions'; const methodWithExtension = { - 'x-xgen-method-verb-override': { - verb: 'get', - customMethod: false, - }, + 'x-xgen-method-verb-override': { + verb: 'get', + customMethod: false, + }, }; const customMethod = { - 'x-xgen-method-verb-override': { - verb: 'add', - customMethod: true, - }, -} + 'x-xgen-method-verb-override': { + verb: 'add', + customMethod: true, + }, +}; const endpointWithMethodExtension = { delete: { - 'x-xgen-method-verb-override': { verb: '‘remove’', customMethod: true } - } + 'x-xgen-method-verb-override': { verb: '‘remove’', customMethod: true }, + }, }; const endpointWithNoMethodExtension = { - 'exception' : true + exception: true, }; describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { @@ -53,13 +57,13 @@ describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { describe('tools/spectral/ipa/rulesets/functions/utils/extensions.js', () => { describe('hasMethodVerbOverride', () => { it('returns true if the method has the extension with the expected verb', () => { - expect(hasMethodVerbOverride(methodWithExtension, "get")).toBe(true); + expect(hasMethodVerbOverride(methodWithExtension, 'get')).toBe(true); }); it('returns false if the method does not have the extension', () => { - expect(hasMethodVerbOverride({}, "get")).toBe(false); + expect(hasMethodVerbOverride({}, 'get')).toBe(false); }); it('returns false if the method has the extension but with an unexpected verb', () => { - expect(hasMethodVerbOverride(methodWithExtension, "put")).toBe(false); + expect(hasMethodVerbOverride(methodWithExtension, 'put')).toBe(false); }); }); }); diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index c4e975d6d4..06377196b6 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -16,7 +16,7 @@ export default (input, { methodName }, { path, documentInventory }) => { if ( hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath) || - hasMethodVerbOverride(input, "list") || + hasMethodVerbOverride(input, 'list') || (invalidGetMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) ) { return; diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index 7a91b44c8b..10ea48d651 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -3,8 +3,8 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; /** * Checks if the endpoint has a method with an extension "x-xgen-method-verb-override" * - * @param object the object to evaluate - * @returns {boolean} true if the object has the extension, otherwise false + * @param endpoint the endpoint to evaluate + * @returns {boolean} true if the endpoint has a nested method with the extension, otherwise false */ export function hasMethodWithVerbOverride(endpoint) { const keys = Object.keys(endpoint); @@ -54,4 +54,4 @@ function hasVerbOverride(object) { return false; } return true; -} \ No newline at end of file +} diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index b0cc6c6bf5..10eec98d4b 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -3,7 +3,7 @@ import { isPathParam } from './resourceEvaluation'; /** * Checks whether the get method at a given path is valid - * + * * @param resourcePath the resource path to inspect * @param resourcePaths the resource paths generated by getResourcePathItems * @returns true if the resourcePath has an invalid list method, false otherwise @@ -17,7 +17,7 @@ export function invalidGetMethod(resourcePath, resourcePaths) { /** * Checks whether the list method at a given path is valid - * + * * @param resourcePath the resource path to inspect * @param resourcePaths the resource paths generated by getResourcePathItems * @returns true if the resourcePath has an invalid list method, false otherwise @@ -31,4 +31,4 @@ function lastIdentifierIsPathParam(resourceIdentifier) { resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.lastIndexOf('.')); } return isPathParam(resourceIdentifier.split('/').pop()); -} \ No newline at end of file +} From 96802135a1402be0dac31f3345c6fcde60f7595d Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 16:50:28 +0100 Subject: [PATCH 14/22] fix lint errors --- .../spectral/ipa/rulesets/functions/IPA108ValidOperationID.js | 2 +- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js index 37cb9c20e9..7e049a815b 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA108ValidOperationID.js @@ -1,6 +1,6 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; -import { isCustomMethodIdentifier, isSingleResourceIdentifier } from './utils/resourceEvaluation.js'; +import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; import { hasCustomMethodOverride } from './utils/extensions.js'; diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index 10eec98d4b..e3274c7a19 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -1,5 +1,5 @@ -import { isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation'; -import { isPathParam } from './resourceEvaluation'; +import { isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation.js'; +import { isPathParam } from './resourceEvaluation.js'; /** * Checks whether the get method at a given path is valid From a15ca0ede77153642d7de7b472fff15ecaaed780 Mon Sep 17 00:00:00 2001 From: Sophia Terry <157913563+sphterry@users.noreply.github.com> Date: Mon, 14 Jul 2025 16:58:06 +0100 Subject: [PATCH 15/22] Update tools/spectral/ipa/rulesets/functions/utils/extensions.js Co-authored-by: Lovisa Berggren <59226031+lovisaberggren@users.noreply.github.com> --- tools/spectral/ipa/rulesets/functions/utils/extensions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index 10ea48d651..1b3bf920b8 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -8,11 +8,7 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; */ export function hasMethodWithVerbOverride(endpoint) { const keys = Object.keys(endpoint); - for (let i = 0; i < keys.length; i++) { - if (hasVerbOverride(endpoint[keys[i]])) { - return true; - } - } +return keys.contains(VERB_OVERRIDE_EXTENSION) return false; } From c95204cbe24d82b3bfab961d3132af34bbf2a369 Mon Sep 17 00:00:00 2001 From: Sophia Terry <157913563+sphterry@users.noreply.github.com> Date: Mon, 14 Jul 2025 16:59:58 +0100 Subject: [PATCH 16/22] Apply refactor suggestions from code review Co-authored-by: Lovisa Berggren <59226031+lovisaberggren@users.noreply.github.com> --- .../ipa/rulesets/functions/utils/extensions.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index 1b3bf920b8..9726fda2f2 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -19,10 +19,7 @@ return keys.contains(VERB_OVERRIDE_EXTENSION) * @returns {boolean} true if the object has an extension with customMethod=True, otherwise false */ export function hasCustomMethodOverride(object) { - if (hasVerbOverride(object)) { - return object[VERB_OVERRIDE_EXTENSION].customMethod; - } - return false; + return hasVerbOverride(object)) && object[VERB_OVERRIDE_EXTENSION].customMethod; } /** @@ -32,12 +29,7 @@ export function hasCustomMethodOverride(object) { * @param verb the verb to inspect the extension for * @returns {boolean} true if the object has the extension with the given verb, otherwise false */ -export function hasMethodVerbOverride(object, verb) { - if (hasVerbOverride(object)) { - return object[VERB_OVERRIDE_EXTENSION].verb === verb; - } - return false; -} +return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].verb === verb /** * Checks if the object has an extension "x-xgen-method-verb-override" From e5f2adca98c87fbc0965f2a4a77ec5fd5e56285c Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 17:14:29 +0100 Subject: [PATCH 17/22] cleaned up hasMethodWithVerbOverride logic --- .../ipa/rulesets/functions/utils/extensions.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index 9726fda2f2..debf881669 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -7,9 +7,7 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; * @returns {boolean} true if the endpoint has a nested method with the extension, otherwise false */ export function hasMethodWithVerbOverride(endpoint) { - const keys = Object.keys(endpoint); -return keys.contains(VERB_OVERRIDE_EXTENSION) - return false; + return Object.values(endpoint).some(hasVerbOverride); } /** @@ -19,7 +17,7 @@ return keys.contains(VERB_OVERRIDE_EXTENSION) * @returns {boolean} true if the object has an extension with customMethod=True, otherwise false */ export function hasCustomMethodOverride(object) { - return hasVerbOverride(object)) && object[VERB_OVERRIDE_EXTENSION].customMethod; + return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].customMethod; } /** @@ -29,7 +27,10 @@ export function hasCustomMethodOverride(object) { * @param verb the verb to inspect the extension for * @returns {boolean} true if the object has the extension with the given verb, otherwise false */ -return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].verb === verb +export function hasMethodVerbOverride(object, verb){ + return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].verb === verb +} + /** * Checks if the object has an extension "x-xgen-method-verb-override" From c1dff452548a6f9f0b940e421d270d4dce24cf59 Mon Sep 17 00:00:00 2001 From: Sophia Terry <157913563+sphterry@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:23:35 +0100 Subject: [PATCH 18/22] Apply suggestions from code review Co-authored-by: Lovisa Berggren <59226031+lovisaberggren@users.noreply.github.com> --- tools/spectral/ipa/__tests__/utils/extensions.test.js | 2 +- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/spectral/ipa/__tests__/utils/extensions.test.js b/tools/spectral/ipa/__tests__/utils/extensions.test.js index 6e3719d6ee..7a20020237 100644 --- a/tools/spectral/ipa/__tests__/utils/extensions.test.js +++ b/tools/spectral/ipa/__tests__/utils/extensions.test.js @@ -21,7 +21,7 @@ const customMethod = { const endpointWithMethodExtension = { delete: { - 'x-xgen-method-verb-override': { verb: '‘remove’', customMethod: true }, + 'x-xgen-method-verb-override': { verb: 'remove', customMethod: true }, }, }; diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index e3274c7a19..a05323a746 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -6,7 +6,7 @@ import { isPathParam } from './resourceEvaluation.js'; * * @param resourcePath the resource path to inspect * @param resourcePaths the resource paths generated by getResourcePathItems - * @returns true if the resourcePath has an invalid list method, false otherwise + * @returns true if the resourcePath has an invalid get method, false otherwise */ export function invalidGetMethod(resourcePath, resourcePaths) { return ( From eca80ae8b30f54da9c780ccfbd793d8d7332e3f0 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Mon, 14 Jul 2025 17:38:50 +0100 Subject: [PATCH 19/22] renamed utils and enabled opID unit tests --- package.json | 3 +-- .../spectral/ipa/rulesets/functions/IPA104ValidOperationID.js | 4 ++-- .../spectral/ipa/rulesets/functions/IPA105ValidOperationID.js | 4 ++-- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index cc547efdfa..8a28bf792b 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,7 @@ "testPathIgnorePatterns": [ "__helpers__", "metrics/data", - "IPA\\d+ValidOperationID\\.test\\.js$", - "operationIdGeneration.test.js" + "IPA\\d+ValidOperationID\\.test\\.js$" ] }, "dependencies": { diff --git a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js index 06377196b6..60dee4bdd3 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA104ValidOperationID.js @@ -3,7 +3,7 @@ import { collectAdoption, collectAndReturnViolation, collectException } from './ import { hasException } from './utils/exceptions.js'; import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { hasCustomMethodOverride, hasMethodVerbOverride } from './utils/extensions.js'; -import { invalidGetMethod } from './utils/methodLogic.js'; +import { isInvalidGetMethod } from './utils/methodLogic.js'; const RULE_NAME = 'xgen-IPA-104-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -17,7 +17,7 @@ export default (input, { methodName }, { path, documentInventory }) => { hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath) || hasMethodVerbOverride(input, 'list') || - (invalidGetMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) + (isInvalidGetMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js index f61742bf33..fef0997cca 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA105ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; import { getResourcePathItems, isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { invalidListMethod } from './utils/methodLogic.js'; +import { isInvalidListMethod } from './utils/methodLogic.js'; import { hasCustomMethodOverride, hasMethodVerbOverride } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-105-valid-operation-id'; @@ -17,7 +17,7 @@ export default (input, { methodName }, { path, documentInventory }) => { hasCustomMethodOverride(input) || isCustomMethodIdentifier(resourcePath) || hasMethodVerbOverride(input, 'get') || - (invalidListMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) + (isInvalidListMethod(resourcePath, resourcePaths) && !hasMethodVerbOverride(input, methodName)) ) { return; } diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index a05323a746..faeb357ad8 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -8,7 +8,7 @@ import { isPathParam } from './resourceEvaluation.js'; * @param resourcePaths the resource paths generated by getResourcePathItems * @returns true if the resourcePath has an invalid get method, false otherwise */ -export function invalidGetMethod(resourcePath, resourcePaths) { +export function isInvalidGetMethod(resourcePath, resourcePaths) { return ( !lastIdentifierIsPathParam(resourcePath) && !(isResourceCollectionIdentifier(resourcePath) && isSingletonResource(resourcePaths)) @@ -22,7 +22,7 @@ export function invalidGetMethod(resourcePath, resourcePaths) { * @param resourcePaths the resource paths generated by getResourcePathItems * @returns true if the resourcePath has an invalid list method, false otherwise */ -export function invalidListMethod(resourcePath, resourcePaths) { +export function isInvalidListMethod(resourcePath, resourcePaths) { return lastIdentifierIsPathParam(resourcePath) || isSingletonResource(resourcePaths); } From dc29321b277422c6beda04e03c7aaa6fdf492db7 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 15 Jul 2025 10:05:33 +0100 Subject: [PATCH 20/22] CLOUDP-306294: Refactored IPA109 Validation function + prettier --- .../functions/IPA109ValidOperationID.js | 40 +++++++++---------- .../rulesets/functions/utils/extensions.js | 7 ++-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js index 39058f5d8b..ba432acb4e 100644 --- a/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js +++ b/tools/spectral/ipa/rulesets/functions/IPA109ValidOperationID.js @@ -2,7 +2,7 @@ import { hasException } from './utils/exceptions.js'; import { collectAdoption, collectException, collectAndReturnViolation } from './utils/collectionUtils.js'; import { isCustomMethodIdentifier, getCustomMethodName, stripCustomMethodName } from './utils/resourceEvaluation.js'; import { generateOperationID } from './utils/operationIdGeneration.js'; -import { hasMethodWithVerbOverride, hasCustomMethodOverride } from './utils/extensions.js'; +import { hasMethodWithVerbOverride, hasCustomMethodOverride, VERB_OVERRIDE_EXTENSION } from './utils/extensions.js'; const RULE_NAME = 'xgen-IPA-109-valid-operation-id'; const ERROR_MESSAGE = 'Invalid OperationID.'; @@ -14,11 +14,12 @@ export default (input, _, { path }) => { return; } - let errors = []; - let expectedOperationID = ''; - if (isCustomMethodIdentifier(resourcePath)) { - expectedOperationID = generateOperationID(getCustomMethodName(resourcePath), stripCustomMethodName(resourcePath)); + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + if (isCustomMethodIdentifier(resourcePath)) { let obj; if (input.post) { obj = input.post; @@ -28,12 +29,11 @@ export default (input, _, { path }) => { return; } - if (hasException(obj, RULE_NAME)) { - collectException(obj, RULE_NAME, path); - return; - } - const operationId = obj.operationId; + const expectedOperationID = generateOperationID( + getCustomMethodName(resourcePath), + stripCustomMethodName(resourcePath) + ); if (operationId !== expectedOperationID) { const errors = [ { @@ -44,12 +44,12 @@ export default (input, _, { path }) => { return collectAndReturnViolation(path, RULE_NAME, errors); } } else if (hasMethodWithVerbOverride(input)) { - const methods = Object.keys(input); - for (let i = 0; i < methods.length; i++) { - let obj = input[methods[i]]; - const operationId = obj.operationId; - if (hasCustomMethodOverride(obj)) { - expectedOperationID = generateOperationID(obj['x-xgen-method-verb-override'].verb, resourcePath); + const methods = Object.values(input); + let errors = []; + methods.forEach((method) => { + if (hasCustomMethodOverride(method)) { + const operationId = method.operationId; + const expectedOperationID = generateOperationID(method[VERB_OVERRIDE_EXTENSION].verb, resourcePath); if (operationId !== expectedOperationID) { errors.push({ path, @@ -57,14 +57,14 @@ export default (input, _, { path }) => { }); } } + }); + + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); } } else { return; } - if (errors.length !== 0) { - return collectAndReturnViolation(path, RULE_NAME, errors); - } - collectAdoption(path, RULE_NAME); }; diff --git a/tools/spectral/ipa/rulesets/functions/utils/extensions.js b/tools/spectral/ipa/rulesets/functions/utils/extensions.js index debf881669..335d2be13c 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/extensions.js +++ b/tools/spectral/ipa/rulesets/functions/utils/extensions.js @@ -7,7 +7,7 @@ export const VERB_OVERRIDE_EXTENSION = 'x-xgen-method-verb-override'; * @returns {boolean} true if the endpoint has a nested method with the extension, otherwise false */ export function hasMethodWithVerbOverride(endpoint) { - return Object.values(endpoint).some(hasVerbOverride); + return Object.values(endpoint).some(hasVerbOverride); } /** @@ -27,11 +27,10 @@ export function hasCustomMethodOverride(object) { * @param verb the verb to inspect the extension for * @returns {boolean} true if the object has the extension with the given verb, otherwise false */ -export function hasMethodVerbOverride(object, verb){ - return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].verb === verb +export function hasMethodVerbOverride(object, verb) { + return hasVerbOverride(object) && object[VERB_OVERRIDE_EXTENSION].verb === verb; } - /** * Checks if the object has an extension "x-xgen-method-verb-override" * From 30fdbac66f690fd03cc52e07e3fbe5bd190a5fce Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 15 Jul 2025 10:35:38 +0100 Subject: [PATCH 21/22] Simplify utility logic --- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index faeb357ad8..9b788fd872 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -30,5 +30,5 @@ function lastIdentifierIsPathParam(resourceIdentifier) { if (resourceIdentifier.includes('.')) { resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.lastIndexOf('.')); } - return isPathParam(resourceIdentifier.split('/').pop()); + return resourceIdentifier.at(-1) === '}'; } From c5cb6aaa09a7afe74a29441ca874bf940222c269 Mon Sep 17 00:00:00 2001 From: Sophia Marie Terry Date: Tue, 15 Jul 2025 10:36:48 +0100 Subject: [PATCH 22/22] remove import --- tools/spectral/ipa/rulesets/functions/utils/methodLogic.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js index 9b788fd872..3677186895 100644 --- a/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js +++ b/tools/spectral/ipa/rulesets/functions/utils/methodLogic.js @@ -1,5 +1,4 @@ import { isResourceCollectionIdentifier, isSingletonResource } from './resourceEvaluation.js'; -import { isPathParam } from './resourceEvaluation.js'; /** * Checks whether the get method at a given path is valid