Skip to content

Commit

Permalink
fix(ibm-schema-casing-convention): allow capitalized acronyms (#638)
Browse files Browse the repository at this point in the history
It is a common convention to allow capitalized acronyms in schema names,
like `IAMCredentialsSecret`. Spectral's `casing` function does not provide
us with the flexibility to support this outright, so this PR adjusts the
schema casing convention check to use a regular expression instead (the one
used in the old, pre-Spectral validator).

Signed-off-by: Dustin Popp <[email protected]>
  • Loading branch information
dpopp07 authored Oct 4, 2023
1 parent 58dbab6 commit 96f1bd3
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 19 deletions.
16 changes: 8 additions & 8 deletions docs/ibm-cloud-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -5432,7 +5432,7 @@ paths:
<td valign=top><b>Description:</b></td>
<td>
Schema names (the keys in `components -> schemas`) should follow the "upper camel case" convention
as required by the <a href="https://cloud.ibm.com/docs/api-handbook?topic=api-handbook-schemas#naming">IBM Cloud API Handbook</a>.
as required by the <a href="https://cloud.ibm.com/docs/api-handbook?topic=api-handbook-schemas#naming">IBM Cloud API Handbook</a>. Note that acronyms are allowed to be capitalized.
</td>
</tr>
<tr>
Expand All @@ -5445,25 +5445,25 @@ as required by the <a href="https://cloud.ibm.com/docs/api-handbook?topic=api-ha
</tr>
<tr>
<td valign=top><b>Configuration:</b></td>
<td>This rule can be configured to enforce a specific case convention for schema name values.
<td>This rule can be configured to define the specific regular expression used to enforce a case convention for schema name values.
To configure the rule, set the <code>functionOptions</code> field within the rule definition to be an object
that is the appropriate configuration to be used by Spectral's <code>casing()</code> function
[<a href="https://meta.stoplight.io/docs/spectral/ZG9jOjExNg-core-functions#casing">1</a>]
that is the appropriate configuration to be used by Spectral's <code>pattern()</code> function
[<a href="https://meta.stoplight.io/docs/spectral/ZG9jOjExNg-core-functions#pattern">1</a>]
to enforce the desired case convention for schema name values.
<p>The default configuration object provided in the rule definition is:
<pre>
{
type: 'pascal'
match: '/^[A-Z]+[a-z0-9]+([A-Z]+[a-z0-9]*)*$/'
}
</pre>
<p>To enforce a different case convention for schema name values, you'll need to
<a href="#replace-a-rule-from-ibm-cloudopenapi-ruleset">replace this rule with a new rule within your
custom ruleset</a> and modify the configuration such that the value of the <code>type</code> field
custom ruleset</a> and modify the configuration such that the value of the <code>match</code> field
specifies the desired case convention.
For example, to enforce snake case for schema names, the configuration object would look like this:
For example, to disallow capitalized acronymns for schema names, the configuration object would look like this:
<pre>
{
type: 'snake'
match: '/^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$/'
}
</pre>
</td>
Expand Down
19 changes: 9 additions & 10 deletions packages/ruleset/src/functions/schema-casing-convention.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
*/

const { isObject } = require('@ibm-cloud/openapi-ruleset-utilities');
const { casing } = require('@stoplight/spectral-functions');
const { pattern } = require('@stoplight/spectral-functions');
const { LoggerFactory } = require('../utils');

let casingConfig;
let patternConfig;
let ruleId;
let logger;

Expand All @@ -20,8 +20,8 @@ let logger;

module.exports = function (components, options, context) {
// Save this rule's "functionOptions" value since we need
// to pass it on to Spectral's "casing" function.
casingConfig = options;
// to pass it on to Spectral's "pattern" function.
patternConfig = options;

if (!logger) {
ruleId = context.rule.name;
Expand All @@ -40,14 +40,13 @@ function schemaCaseConvention(components, path) {
const errors = [];

Object.keys(components.schemas).forEach(schemaName => {
const result = casing(schemaName, casingConfig);
const result = pattern(schemaName, patternConfig);
if (result) {
logger.debug(`${ruleId}: failed casing check: ${JSON.stringify(result)}`);
logger.debug(
`${ruleId}: failed pattern check: ${JSON.stringify(result)}`
);
errors.push({
message: `Schema names ${result[0].message.replace(
'pascal',
'upper camel'
)}`,
message: 'Schema names must be upper camel case',
path: [...path, 'schemas', schemaName],
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ruleset/src/rules/schema-casing-convention.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
then: {
function: schemaCasingConvention,
functionOptions: {
type: 'pascal',
match: '/^[A-Z]+[a-z0-9]+([A-Z]+[a-z0-9]*)*$/',
},
},
};
8 changes: 8 additions & 0 deletions packages/ruleset/test/schema-casing-convention.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ describe(`Spectral rule: ${ruleId}`, () => {
const results = await testRule(ruleId, rule, testDocument);
expect(results).toHaveLength(0);
});

it('Upper camel case schema name with capitalized acronym', async () => {
const testDocument = makeCopy(rootDocument);
testDocument.components.schemas.IAMCredentialsSecret = {};

const results = await testRule(ruleId, rule, testDocument);
expect(results).toHaveLength(0);
});
});

describe('Should yield errors', () => {
Expand Down

0 comments on commit 96f1bd3

Please sign in to comment.