diff --git a/tools/spectral/ipa/__tests__/IPA112BooleanFieldNamesAvoidIsPrefix.test.js b/tools/spectral/ipa/__tests__/IPA112BooleanFieldNamesAvoidIsPrefix.test.js new file mode 100644 index 0000000000..fc1a654e48 --- /dev/null +++ b/tools/spectral/ipa/__tests__/IPA112BooleanFieldNamesAvoidIsPrefix.test.js @@ -0,0 +1,180 @@ +import testRule from './__helpers__/testRule'; +import { DiagnosticSeverity } from '@stoplight/types'; + +testRule('xgen-IPA-112-boolean-field-names-avoid-is-prefix', [ + { + name: 'valid schema - no "is" prefix in boolean fields', + document: { + components: { + schemas: { + SchemaName: { + properties: { + enabled: { type: 'boolean' }, + active: { type: 'boolean' }, + disabled: { type: 'boolean' }, + isString: { type: 'string' }, + visible: { type: 'boolean' }, + }, + }, + }, + }, + paths: { + '/users': { + post: { + requestBody: { + content: { + 'application/vnd.atlas.2024-01-01+json': { + schema: { + type: 'object', + properties: { + available: { type: 'boolean' }, + paused: { type: 'boolean' }, + }, + }, + }, + }, + }, + responses: { + 201: { + content: { + 'application/vnd.atlas.2024-01-01+json': { + schema: { + type: 'object', + properties: { + valid: { type: 'boolean' }, + hidden: { type: 'boolean' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, + { + name: 'invalid schema - with "is" prefix in boolean fields', + document: { + components: { + schemas: { + SchemaName: { + properties: { + isEnabled: { type: 'boolean' }, + isActive: { type: 'boolean' }, + isError: { type: 'boolean' }, + isString: { type: 'string' }, + }, + }, + }, + }, + paths: { + '/users': { + post: { + requestBody: { + content: { + 'application/vnd.atlas.2024-01-01+json': { + schema: { + type: 'object', + properties: { + isAvailable: { type: 'boolean' }, + }, + }, + }, + }, + }, + responses: { + 201: { + content: { + 'application/vnd.atlas.2024-01-01+json': { + schema: { + type: 'object', + properties: { + isValid: { type: 'boolean' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + errors: [ + { + code: 'xgen-IPA-112-boolean-field-names-avoid-is-prefix', + message: 'Boolean field "isEnabled" should not use the "is" prefix. Use "enabled" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'isEnabled'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-112-boolean-field-names-avoid-is-prefix', + message: 'Boolean field "isActive" should not use the "is" prefix. Use "active" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'isActive'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-112-boolean-field-names-avoid-is-prefix', + message: 'Boolean field "isError" should not use the "is" prefix. Use "error" instead.', + path: ['components', 'schemas', 'SchemaName', 'properties', 'isError'], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-112-boolean-field-names-avoid-is-prefix', + message: 'Boolean field "isAvailable" should not use the "is" prefix. Use "available" instead.', + path: [ + 'paths', + '/users', + 'post', + 'requestBody', + 'content', + 'application/vnd.atlas.2024-01-01+json', + 'schema', + 'properties', + 'isAvailable', + ], + severity: DiagnosticSeverity.Warning, + }, + { + code: 'xgen-IPA-112-boolean-field-names-avoid-is-prefix', + message: 'Boolean field "isValid" should not use the "is" prefix. Use "valid" instead.', + path: [ + 'paths', + '/users', + 'post', + 'responses', + '201', + 'content', + 'application/vnd.atlas.2024-01-01+json', + 'schema', + 'properties', + 'isValid', + ], + severity: DiagnosticSeverity.Warning, + }, + ], + }, + { + name: 'schema with exception - "is" prefix with exception', + document: { + components: { + schemas: { + SchemaName: { + properties: { + isEnabled: { + type: 'boolean', + 'x-xgen-IPA-exception': { + 'xgen-IPA-112-boolean-field-names-avoid-is-prefix': 'Reason', + }, + }, + }, + }, + }, + }, + }, + errors: [], + }, +]); diff --git a/tools/spectral/ipa/rulesets/IPA-112.yaml b/tools/spectral/ipa/rulesets/IPA-112.yaml index 05a647fb99..ca484fff11 100644 --- a/tools/spectral/ipa/rulesets/IPA-112.yaml +++ b/tools/spectral/ipa/rulesets/IPA-112.yaml @@ -4,6 +4,7 @@ functions: - IPA112AvoidProjectFieldNames - IPA112FieldNamesAreCamelCase + - IPA112BooleanFieldNamesAvoidIsPrefix rules: xgen-IPA-112-avoid-project-field-names: @@ -50,3 +51,20 @@ rules: - '$.paths..responses..content[?(@property.match(/json$/i))].schema..properties[*]~' then: function: 'IPA112FieldNamesAreCamelCase' + xgen-IPA-112-boolean-field-names-avoid-is-prefix: + description: | + Boolean field names should avoid the "is" prefix. + + ##### Implementation details + Rule checks for the following conditions: + - Applies only to properties with type 'boolean' + - Identifies property names that start with "is" followed by an uppercase letter + - Suggests using the direct adjective form instead (e.g., "disabled" instead of "isDisabled") + message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-112-boolean-field-names-avoid-is-prefix' + severity: warn + given: + - '$.components.schemas..properties[*]~' + - '$.paths..requestBody.content[?(@property.match(/json$/i))].schema..properties[*]~' + - '$.paths..responses..content[?(@property.match(/json$/i))].schema..properties[*]~' + then: + function: 'IPA112BooleanFieldNamesAvoidIsPrefix' diff --git a/tools/spectral/ipa/rulesets/README.md b/tools/spectral/ipa/rulesets/README.md index 3f0e20fb63..70fd87a42c 100644 --- a/tools/spectral/ipa/rulesets/README.md +++ b/tools/spectral/ipa/rulesets/README.md @@ -475,6 +475,17 @@ Rule checks for the following conditions: - Identifies property names that are not in camelCase format - Reports any instances where these field names are not in camelCase format +#### xgen-IPA-112-boolean-field-names-avoid-is-prefix + + ![warn](https://img.shields.io/badge/warning-yellow) +Boolean field names should avoid the "is" prefix. + +##### Implementation details +Rule checks for the following conditions: + - Applies only to properties with type 'boolean' + - Identifies property names that start with "is" followed by an uppercase letter + - Suggests using the direct adjective form instead (e.g., "disabled" instead of "isDisabled") + ### IPA-113 diff --git a/tools/spectral/ipa/rulesets/functions/IPA112BooleanFieldNamesAvoidIsPrefix.js b/tools/spectral/ipa/rulesets/functions/IPA112BooleanFieldNamesAvoidIsPrefix.js new file mode 100644 index 0000000000..25f8076f75 --- /dev/null +++ b/tools/spectral/ipa/rulesets/functions/IPA112BooleanFieldNamesAvoidIsPrefix.js @@ -0,0 +1,28 @@ +import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; +import { hasException } from './utils/exceptions.js'; +import { resolveObject } from './utils/componentUtils.js'; + +const RULE_NAME = 'xgen-IPA-112-boolean-field-names-avoid-is-prefix'; +const IS_PREFIX_REGEX = /^is[A-Z]/; + +export default (input, options, { path, documentInventory }) => { + const oas = documentInventory.resolved; + const property = resolveObject(oas, path); + + if (hasException(property, RULE_NAME)) { + collectException(property, RULE_NAME, path); + return; + } + + if (property.type !== 'boolean') { + return; + } + + if (IS_PREFIX_REGEX.test(input)) { + const suggestedName = input.charAt(2).toLowerCase() + input.slice(3); + const errorMessage = `Boolean field "${input}" should not use the "is" prefix. Use "${suggestedName}" instead.`; + return collectAndReturnViolation(path, RULE_NAME, errorMessage); + } + + collectAdoption(path, RULE_NAME); +};