diff --git a/tools/spectral/ipa/__tests__/IPA117OperationSummaryGetStartsWith.test.js b/tools/spectral/ipa/__tests__/IPA117OperationSummaryGetStartsWith.test.js new file mode 100644 index 0000000000..ed7b1b358d --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA117OperationSummaryGetStartsWith.test.js @@ -0,0 +1,92 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-117-get-operation-summary-starts-with', [ + { + name: 'valid summary', + document: { + paths: { + '/resource/{id}': { + get: { + summary: 'Return One Resource by ID', + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid summaries', + document: { + paths: { + '/resource/{id}': { + get: { + summary: 'Returns One Resource', + }, + }, + '/resource': { + get: { + summary: 'Get One Resource', + }, + }, + '/resource/{id}/child': { + get: { + summary: 'One Resource Return', + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-117-get-operation-summary-starts-with', + message: 'Operation summary must start with the word "Return".', + path: ['paths', '/resource/{id}', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-117-get-operation-summary-starts-with', + message: 'Operation summary must start with the word "Return".', + path: ['paths', '/resource', 'get'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-117-get-operation-summary-starts-with', + message: 'Operation summary must start with the word "Return".', + path: ['paths', '/resource/{id}/child', 'get'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid summary with exceptions', + document: { + paths: { + '/resource/{id}': { + get: { + summary: 'Returns One Resource', + 'x-xgen-IPA-exception': { + 'xgen-IPA-117-get-operation-summary-starts-with': 'reason', + }, + }, + }, + '/resource': { + get: { + summary: 'Get One Resource', + 'x-xgen-IPA-exception': { + 'xgen-IPA-117-get-operation-summary-starts-with': 'reason', + }, + }, + }, + '/resource/{id}/child': { + get: { + summary: 'One Resource Return', + 'x-xgen-IPA-exception': { + 'xgen-IPA-117-get-operation-summary-starts-with': 'reason', + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-117.yaml b/tools/spectral/ipa/rulesets/IPA-117.yaml index 9973e60c99..cf3642c3ac 100644 --- a/tools/spectral/ipa/rulesets/IPA-117.yaml +++ b/tools/spectral/ipa/rulesets/IPA-117.yaml @@ -12,6 +12,7 @@ functions: - IPA117ObjectsMustBeWellDefined - IPA117ParameterHasExamplesOrSchema - IPA117OperationSummaryFormat + - IPA117OperationSummaryGetStartsWith aliases: OperationObject: @@ -282,3 +283,22 @@ rules: - 'into' - 'via' - 'on' + xgen-IPA-117-get-operation-summary-starts-with: + description: | + In operation summaries, use 'Return' instead of 'Get' or 'List'. For example "Return One Identity Provider". + + ##### Implementation details + - The rule checks that the `summary` property of get and list operations use the word 'Return' as the first word. + - The rule only applies to get and list methods and ignores custom methods + ##### Configuration + This rule includes a configuration option: + - `allowedStartVerbs`: Allow list of verb that the operation summary can start with, defaults to `['Return']` + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-117-get-operation-summary-starts-with' + severity: warn + given: + - '$.paths[*][get].summary' + then: + function: 'IPA117OperationSummaryGetStartsWith' + functionOptions: + allowedStartVerbs: + - Return diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index d97328faef..258cb75f49 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -864,6 +864,18 @@ This rule includes two configuration options: - `ignoreList`: Words that are allowed to maintain their specific casing (e.g., "API", "AWS", "DNS") - `grammaticalWords`: Common words that can remain lowercase in titles (e.g., "and", "or", "the") +#### xgen-IPA-117-get-operation-summary-starts-with + + ![warn](https://img.shields.io/badge/warning-yellow) +In operation summaries, use 'Return' instead of 'Get' or 'List'. For example "Return One Identity Provider". + +##### Implementation details +- The rule checks that the `summary` property of get and list operations use the word 'Return' as the first word. +- The rule only applies to get and list methods and ignores custom methods +##### Configuration +This rule includes a configuration option: + - `allowedStartVerbs`: Allow list of verb that the operation summary can start with, defaults to `['Return']` + ### IPA-118 diff --git a/tools/spectral/ipa/rulesets/functions/IPA117OperationSummaryGetStartsWith.js b/tools/spectral/ipa/rulesets/functions/IPA117OperationSummaryGetStartsWith.js new file mode 100644 index 0000000000..712ff0ba49 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA117OperationSummaryGetStartsWith.js @@ -0,0 +1,44 @@ +import { evaluateAndCollectAdoptionStatus, handleInternalError } from './utils/collectionUtils.js'; +import { resolveObject } from './utils/componentUtils.js'; +import { isCustomMethodIdentifier } from './utils/resourceEvaluation.js'; +import { hasCustomMethodOverride } from './utils/extensions.js'; + +export default (input, { allowedStartVerbs }, { path, rule, documentInventory }) => { + const resourcePath = path[1]; + const operationObjectPath = path.slice(0, -1); + const operationObject = resolveObject(documentInventory.resolved, operationObjectPath); + + if (isCustomMethodIdentifier(resourcePath) || hasCustomMethodOverride(operationObject)) { + return; + } + + const errors = checkViolationsAndReturnErrors(input, allowedStartVerbs, operationObjectPath, rule.name); + return evaluateAndCollectAdoptionStatus(errors, rule.name, operationObject, operationObjectPath); +}; + +function checkViolationsAndReturnErrors(summary, allowedStartVerbs, path, ruleName) { + try { + const firstWord = summary.split(' ')[0]; + + if (!allowedStartVerbs.includes(firstWord)) { + if (allowedStartVerbs.length === 1) { + return [ + { + path, + message: `Operation summary must start with the word "${allowedStartVerbs[0]}".`, + }, + ]; + } else { + return [ + { + path, + message: `Operation summary must start with one of the words [${allowedStartVerbs}].`, + }, + ]; + } + } + return []; + } catch (e) { + return handleInternalError(ruleName, path, e); + } +}