diff --git a/tools/spectral/ipa/__tests__/IPA117DescriptionEndsWithPeriod.test.js b/tools/spectral/ipa/__tests__/IPA117DescriptionEndsWithPeriod.test.js new file mode 100644 index 0000000000..877bbab06d --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA117DescriptionEndsWithPeriod.test.js @@ -0,0 +1,83 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-117-description-ends-with-period', [ + { + name: 'valid description', + document: { + components: { + schemas: { + Schema: { + properties: { + id: { + description: 'Description.', + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid descriptions', + document: { + components: { + schemas: { + Schema: { + properties: { + noPeriod: { + description: 'Description', + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-117-description-ends-with-period', + message: 'Descriptions must end with a full stop(.).', + path: ['components', 'schemas', 'Schema', 'properties', 'noPeriod'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'ignores descriptions ending with table', + document: { + components: { + schemas: { + Schema: { + properties: { + noPeriod: { + description: 'Description\n| Table |', + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid components with exceptions', + document: { + components: { + schemas: { + Schema: { + properties: { + noPeriod: { + description: 'Description', + 'x-xgen-IPA-exception': { + 'xgen-IPA-117-description-ends-with-period': 'reason', + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/__tests__/IPA117DescriptionStartsWithUpperCase.test.js b/tools/spectral/ipa/__tests__/IPA117DescriptionStartsWithUpperCase.test.js new file mode 100644 index 0000000000..e72777c061 --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA117DescriptionStartsWithUpperCase.test.js @@ -0,0 +1,66 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-117-description-starts-with-uppercase', [ + { + name: 'valid description', + document: { + components: { + schemas: { + Schema: { + properties: { + id: { + description: 'Description', + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid descriptions', + document: { + components: { + schemas: { + Schema: { + properties: { + noUpperCase: { + description: 'description', + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-117-description-starts-with-uppercase', + message: 'Descriptions must start with Uppercase.', + path: ['components', 'schemas', 'Schema', 'properties', 'noUpperCase'], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'invalid components with exceptions', + document: { + components: { + schemas: { + Schema: { + properties: { + noUpperCase: { + description: 'description', + 'x-xgen-IPA-exception': { + 'xgen-IPA-117-description-starts-with-uppercase': 'reason', + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-117.yaml b/tools/spectral/ipa/rulesets/IPA-117.yaml index cab084d98a..e2750ff485 100644 --- a/tools/spectral/ipa/rulesets/IPA-117.yaml +++ b/tools/spectral/ipa/rulesets/IPA-117.yaml @@ -3,6 +3,8 @@ functions: - IPA117HasDescription + - IPA117DescriptionStartsWithUpperCase + - IPA117DescriptionEndsWithPeriod rules: xgen-IPA-117-description: @@ -30,3 +32,52 @@ rules: - '$.components.parameters[*]' then: function: 'IPA117HasDescription' + xgen-IPA-117-description-starts-with-uppercase: + description: | + Descriptions must start with Uppercase. + + ##### Implementation details + Rule checks the format of the description property in the following components: + - Info object + - Tags + - Operation objects + - Inline schema properties for operation object requests and responses + - Parameter objects (in operations and components) + - Schema properties + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-117-description-starts-with-uppercase' + severity: warn + given: + - '$.info' + - '$.tags[*]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace].parameters[*]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace]..content..properties[*]' + - '$.components.schemas..properties[*]' + - '$.components.parameters[*]' + then: + function: 'IPA117DescriptionStartsWithUpperCase' + xgen-IPA-117-description-ends-with-period: + description: | + Descriptions must end with a full stop(.). + + ##### Implementation details + Rule checks the format of the description property in the following components: + - Info object + - Tags + - Operation objects + - Inline schema properties for operation object requests and responses + - Parameter objects (in operations and components) + - Schema properties + The rule ignores descriptions that end with `|`, i.e. inline markdown tables + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-117-description-ends-with-period' + severity: warn + given: + - '$.info' + - '$.tags[*]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace].parameters[*]' + - '$.paths[*][get,put,post,delete,options,head,patch,trace]..content..properties[*]' + - '$.components.schemas..properties[*]' + - '$.components.parameters[*]' + then: + function: 'IPA117DescriptionEndsWithPeriod' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 3f0e20fb63..d7f37a128a 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -535,6 +535,35 @@ Rule checks for description property in the following components: - Schema properties The rule also fails if the description is an empty string. +#### xgen-IPA-117-description-starts-with-uppercase + + ![warn](https://img.shields.io/badge/warning-yellow) +Descriptions must start with Uppercase. + +##### Implementation details +Rule checks the format of the description property in the following components: + - Info object + - Tags + - Operation objects + - Inline schema properties for operation object requests and responses + - Parameter objects (in operations and components) + - Schema properties + +#### xgen-IPA-117-description-ends-with-period + + ![warn](https://img.shields.io/badge/warning-yellow) +Descriptions must end with a full stop(.). + +##### Implementation details +Rule checks the format of the description property in the following components: + - Info object + - Tags + - Operation objects + - Inline schema properties for operation object requests and responses + - Parameter objects (in operations and components) + - Schema properties +The rule ignores descriptions that end with `|`, i.e. inline markdown tables + ### IPA-123 diff --git a/tools/spectral/ipa/rulesets/functions/IPA117DescriptionEndsWithPeriod.js b/tools/spectral/ipa/rulesets/functions/IPA117DescriptionEndsWithPeriod.js new file mode 100644 index 0000000000..2ac45dc343 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA117DescriptionEndsWithPeriod.js @@ -0,0 +1,41 @@ +import { hasException } from './utils/exceptions.js'; +import { + collectAdoption, + collectAndReturnViolation, + collectException, + handleInternalError, +} from './utils/collectionUtils.js'; + +const RULE_NAME = 'xgen-IPA-117-description-ends-with-period'; +const ERROR_MESSAGE_PERIOD = 'Descriptions must end with a full stop(.).'; + +export default (input, opts, { path }) => { + // Ignore missing descriptions or descriptions that ends with an inline table + if (!input['description'] || input['description'].endsWith('|') || input['description'].endsWith('|\n')) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input['description'], path); + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(description, path) { + const periodEnd = new RegExp(`[.]$`); + + try { + if (!periodEnd.test(description)) { + return [{ path, message: ERROR_MESSAGE_PERIOD }]; + } + return []; + } catch (e) { + handleInternalError(RULE_NAME, path, e); + } +} diff --git a/tools/spectral/ipa/rulesets/functions/IPA117DescriptionStartsWithUpperCase.js b/tools/spectral/ipa/rulesets/functions/IPA117DescriptionStartsWithUpperCase.js new file mode 100644 index 0000000000..61b964c660 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA117DescriptionStartsWithUpperCase.js @@ -0,0 +1,40 @@ +import { hasException } from './utils/exceptions.js'; +import { + collectAdoption, + collectAndReturnViolation, + collectException, + handleInternalError, +} from './utils/collectionUtils.js'; + +const RULE_NAME = 'xgen-IPA-117-description-starts-with-uppercase'; +const ERROR_MESSAGE_UPPER_CASE = 'Descriptions must start with Uppercase.'; + +export default (input, opts, { path }) => { + if (!input['description']) { + return; + } + + if (hasException(input, RULE_NAME)) { + collectException(input, RULE_NAME, path); + return; + } + + const errors = checkViolationsAndReturnErrors(input['description'], path); + if (errors.length !== 0) { + return collectAndReturnViolation(path, RULE_NAME, errors); + } + collectAdoption(path, RULE_NAME); +}; + +function checkViolationsAndReturnErrors(description, path) { + const upperCaseStart = new RegExp(`^[A-Z]`); + + try { + if (!upperCaseStart.test(description)) { + return [{ path, message: ERROR_MESSAGE_UPPER_CASE }]; + } + return []; + } catch (e) { + handleInternalError(RULE_NAME, path, e); + } +}