-
Notifications
You must be signed in to change notification settings - Fork 14
CLOUDP-306582: IPA-126: Top-Level API Names #668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
0e70c41
fc990a0
1217f4e
73f0be7
df4381c
c896471
bee67d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| import testRule from './__helpers__/testRule.js'; | ||
| import { DiagnosticSeverity } from '@stoplight/types'; | ||
|
|
||
| testRule('xgen-IPA-126-tag-names-should-use-title-case', [ | ||
| { | ||
| name: 'valid Title Case tag names', | ||
| document: { | ||
| tags: [ | ||
| { name: 'User Management' }, | ||
| { name: 'Resource Groups' }, | ||
| { name: 'Atlas' }, | ||
| { name: 'User Profiles' }, | ||
| { name: 'Api' }, | ||
| { name: 'Users' }, | ||
| { name: 'Resources' }, | ||
| { name: 'Projects' }, | ||
| ], | ||
| }, | ||
| errors: [], | ||
| }, | ||
| { | ||
| name: 'invalid camelCase instead of Title Case', | ||
| document: { | ||
| tags: [{ name: 'userManagement' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "userManagement".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'invalid kebab-case instead of Title Case', | ||
| document: { | ||
| tags: [{ name: 'user-management' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "user-management".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'invalid snake_case instead of Title Case', | ||
| document: { | ||
| tags: [{ name: 'user_management' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "user_management".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'invalid all lowercase instead of Title Case', | ||
| document: { | ||
| tags: [{ name: 'user management' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "user management".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'invalid ALL UPPERCASE instead of Title Case', | ||
| document: { | ||
| tags: [{ name: 'USER MANAGEMENT' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "USER MANAGEMENT".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'mixed cases in multiple tags', | ||
| document: { | ||
| tags: [{ name: 'User Management' }, { name: 'resourceGroups' }, { name: 'API ENDPOINTS' }], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "resourceGroups".', | ||
| path: ['tags', '1'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "API ENDPOINTS".', | ||
| path: ['tags', '2'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| name: 'valid with exception', | ||
| document: { | ||
| tags: [ | ||
| { | ||
| name: 'legacy_tag', | ||
| 'x-xgen-IPA-exception': { | ||
| 'xgen-IPA-126-tag-names-should-use-title-case': 'Legacy tag that cannot be changed', | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| errors: [], | ||
| }, | ||
| { | ||
| name: 'invalid tag names', | ||
| document: { | ||
| tags: [ | ||
| { name: 'Api V1' }, | ||
| { name: 'Version 2 Resources' }, | ||
| { name: 'Push-Based Log Export' }, //valid | ||
| { name: 'AWS Clusters DNS' }, // valid | ||
| { name: 'Encryption at Rest using Customer Key Management' }, | ||
| { name: '-Test Tag' }, | ||
| { name: 'Test Tag-' }, | ||
| { name: 'Test Tag -Name' }, | ||
| ], | ||
| }, | ||
| errors: [ | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "Api V1".', | ||
| path: ['tags', '0'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "Version 2 Resources".', | ||
| path: ['tags', '1'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "Encryption at Rest using Customer Key Management".', | ||
| path: ['tags', '4'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "-Test Tag".', | ||
| path: ['tags', '5'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "Test Tag-".', | ||
| path: ['tags', '6'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| { | ||
| code: 'xgen-IPA-126-tag-names-should-use-title-case', | ||
| message: 'Tag name should use Title Case, found: "Test Tag -Name".', | ||
| path: ['tags', '7'], | ||
| severity: DiagnosticSeverity.Warning, | ||
| }, | ||
| ], | ||
| }, | ||
| ]); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # IPA-126: Top-Level API Names | ||
| # http://go/ipa/126 | ||
|
|
||
| functions: | ||
| - IPA126TagNamesShouldUseTitleCase | ||
| rules: | ||
| xgen-IPA-126-tag-names-should-use-title-case: | ||
| description: | | ||
| Tag names in the OpenAPI specification should use Title Case. | ||
|
|
||
| ##### Implementation details | ||
| Rule checks for the following conditions: | ||
| - All tag names defined in the OpenAPI tags object should use Title Case | ||
| - Title Case means each word starts with an uppercase letter, and the rest are lowercase | ||
| - Certain abbreviations (like "API", "AWS", etc.) in the ignoreList are allowed to maintain their casing | ||
| - Grammatical words (like "and", "or", "the", etc.) are allowed to be all lowercase | ||
|
|
||
| ##### Configuration | ||
| 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") | ||
| message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-126-tag-names-should-use-title-case' | ||
| severity: warn | ||
| given: $.tags[?(@.name && @.name.length > 0)] | ||
| then: | ||
| function: 'IPA126TagNamesShouldUseTitleCase' | ||
| functionOptions: | ||
| ignoreList: | ||
| - 'AWS' | ||
| - 'DNS' | ||
| - 'API' | ||
| - 'IP' | ||
| - 'MongoDB' | ||
| - 'LDAP' | ||
| - 'GCP' | ||
| grammaticalWords: | ||
| - 'and' | ||
| - 'or' | ||
| - 'to' | ||
| - 'in' | ||
| - 'as' | ||
| - 'for' | ||
| - 'of' | ||
| - 'with' | ||
| - 'by' | ||
| - 'but' | ||
| - 'the' | ||
| - 'a' | ||
| - 'an' |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||
| import { hasException } from './utils/exceptions.js'; | ||||||
| import { collectAdoption, collectAndReturnViolation, collectException } from './utils/collectionUtils.js'; | ||||||
|
|
||||||
| const RULE_NAME = 'xgen-IPA-126-tag-names-should-use-title-case'; | ||||||
|
|
||||||
| export default (input, { ignoreList, grammaticalWords }, { path }) => { | ||||||
| const tagName = input.name; | ||||||
| if (hasException(input, RULE_NAME)) { | ||||||
| collectException(input, RULE_NAME, path); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| // Check if the tag name uses Title Case | ||||||
| if (!isTitleCase(tagName, ignoreList, grammaticalWords)) { | ||||||
| return collectAndReturnViolation(path, RULE_NAME, [ | ||||||
| { | ||||||
| path, | ||||||
| message: `Tag name should use Title Case, found: "${tagName}".`, | ||||||
| }, | ||||||
| ]); | ||||||
| } | ||||||
|
|
||||||
| // Tag name uses Title Case | ||||||
| collectAdoption(path, RULE_NAME); | ||||||
| }; | ||||||
|
|
||||||
| function isTitleCase(str, ignoreList, grammaticalWords) { | ||||||
| // Split by spaces to check each word/word-group | ||||||
| const words = str.split(' '); | ||||||
|
|
||||||
| return words.every((wordGroup) => { | ||||||
| // For hyphenated words, check each part | ||||||
| if (wordGroup.includes('-')) { | ||||||
| const hyphenatedParts = wordGroup.split('-'); | ||||||
| return hyphenatedParts.every((part) => { | ||||||
| if (ignoreList.includes(part)) return true; | ||||||
| if (grammaticalWords.includes(part)) return true; | ||||||
| // First character should be uppercase, rest lowercase, all alphabetical | ||||||
| return /^[A-Z][a-z]*$/.test(part); | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| // For regular words | ||||||
| if (ignoreList.includes(wordGroup)) return true; | ||||||
| if (grammaticalWords.includes(wordGroup)) return true; | ||||||
|
||||||
| if (grammaticalWords.includes(wordGroup)) return true; | |
| if (index !== 0 && grammaticalWords.includes(wordGroup)) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! Applied the suggestion, and added a unit test for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] There are probably no compound words (I think that's what it's called 😋 ) using dashes with words like "the" or "a"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good catch! Applied the suggestion, thanks!