Skip to content

Commit 48b0633

Browse files
CLOUDP-287247: IPA-109: Validate custom method must use colon (:) followed by the custom verb
1 parent 636a4e7 commit 48b0633

File tree

8 files changed

+148
-0
lines changed

8 files changed

+148
-0
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"dependencies": {
2020
"@stoplight/spectral-cli": "^6.14.2",
2121
"@stoplight/spectral-core": "^1.19.4",
22+
"@stoplight/spectral-functions": "^1.9.3",
2223
"@stoplight/spectral-ref-resolver": "^1.0.5",
2324
"@stoplight/spectral-ruleset-bundler": "^1.6.1",
2425
"eslint-plugin-jest": "^28.9.0",

tools/spectral/ipa/__tests__/eachCustomMethodMustBeGetOrPost.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ testRule('xgen-IPA-109-custom-method-must-be-GET-or-POST', [
3030
},
3131
errors: [],
3232
},
33+
{
34+
name: 'invalid methods with exception',
35+
document: {
36+
paths: {
37+
'/d/{exampleId}:method': {
38+
get: {},
39+
post: {},
40+
'x-xgen-IPA-exception': {
41+
'xgen-IPA-109-custom-method-must-be-GET-or-POST' : {}
42+
},
43+
},
44+
'/d:method': {
45+
get: {},
46+
post: {},
47+
'x-xgen-IPA-exception': {
48+
'xgen-IPA-109-custom-method-must-be-GET-or-POST' : {}
49+
},
50+
},
51+
},
52+
},
53+
errors: [],
54+
},
3355
{
3456
name: 'invalid methods',
3557
document: {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import testRule from './__helpers__/testRule';
2+
import { DiagnosticSeverity } from '@stoplight/types';
3+
4+
testRule('xgen-IPA-109-custom-method-must-use-camel-case', [
5+
{
6+
name: 'valid methods',
7+
document: {
8+
paths: {
9+
'/a/{exampleId}:methodName': {},
10+
'/a:methodName': {},
11+
},
12+
},
13+
errors: [],
14+
},
15+
{
16+
name: 'invalid methods with exception',
17+
document: {
18+
paths: {
19+
'/b/{exampleId}:MethodName': {
20+
'x-xgen-IPA-exception': {
21+
'xgen-IPA-109-custom-method-must-use-camel-case' : {}
22+
},
23+
},
24+
'/b:MethodName': {
25+
'x-xgen-IPA-exception': {
26+
'xgen-IPA-109-custom-method-must-use-camel-case' : {}
27+
},
28+
},
29+
},
30+
},
31+
errors: [],
32+
},
33+
{
34+
name: 'invalid methods',
35+
document: {
36+
paths: {
37+
'/a/{exampleId}:MethodName': {},
38+
'/a:MethodName': {},
39+
'/a/{exampleId}:method_name': {},
40+
'/a:method_name': {},
41+
},
42+
},
43+
errors: [
44+
{
45+
code: 'xgen-IPA-109-custom-method-must-use-camel-case',
46+
message: 'The custom method must use camelCase format. http://go/ipa/109',
47+
path: ['paths', '/a/{exampleId}:MethodName'],
48+
severity: DiagnosticSeverity.Warning,
49+
},
50+
{
51+
code: 'xgen-IPA-109-custom-method-must-use-camel-case',
52+
message: 'The custom method must use camelCase format. http://go/ipa/109',
53+
path: ['paths', '/a:MethodName'],
54+
severity: DiagnosticSeverity.Warning,
55+
},
56+
{
57+
code: 'xgen-IPA-109-custom-method-must-use-camel-case',
58+
message: 'The custom method must use camelCase format. http://go/ipa/109',
59+
path: ['paths', '/a/{exampleId}:method_name'],
60+
severity: DiagnosticSeverity.Warning,
61+
},
62+
{
63+
code: 'xgen-IPA-109-custom-method-must-use-camel-case',
64+
message: 'The custom method must use camelCase format. http://go/ipa/109',
65+
path: ['paths', '/a:method_name'],
66+
severity: DiagnosticSeverity.Warning,
67+
}
68+
],
69+
},
70+
]);

tools/spectral/ipa/rulesets/IPA-109.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
functions:
55
- eachCustomMethodMustBeGetOrPost
6+
- eachCustomMethodMustUseCamelCase
67

78
rules:
89
xgen-IPA-109-custom-method-must-be-GET-or-POST:
@@ -12,3 +13,11 @@ rules:
1213
given: '$.paths[*]'
1314
then:
1415
function: 'eachCustomMethodMustBeGetOrPost'
16+
17+
xgen-IPA-109-custom-method-must-use-camel-case:
18+
description: 'The custom method must use camelCase format. http://go/ipa/109'
19+
message: '{{error}} http://go/ipa/109'
20+
severity: warn
21+
given: '$.paths[*]'
22+
then:
23+
function: 'eachCustomMethodMustUseCamelCase'

tools/spectral/ipa/rulesets/functions/eachCustomMethodMustBeGetOrPost.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { isCustomMethod } from './utils/resourceEvaluation.js';
2+
import { hasException } from './utils/exceptions.js';
23

4+
const RULE_NAME = 'xgen-IPA-109-custom-method-must-be-GET-or-POST';
35
const ERROR_MESSAGE = 'The HTTP method for custom methods must be GET or POST.';
46
const ERROR_RESULT = [{ message: ERROR_MESSAGE }];
57
const VALID_METHODS = ['get', 'post'];
@@ -11,6 +13,10 @@ export default (input, opts, { path }) => {
1113

1214
if (!isCustomMethod(pathKey)) return;
1315

16+
if (hasException(input, RULE_NAME)) {
17+
return;
18+
}
19+
1420
//Extract the keys which are equivalent of the http methods
1521
let keys = Object.keys(input);
1622
const httpMethods = keys.filter((key) => HTTP_METHODS.includes(key));
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { getCustomMethod, isCustomMethod } from './utils/resourceEvaluation.js';
2+
import { hasException } from './utils/exceptions.js';
3+
import { casing } from '@stoplight/spectral-functions';
4+
5+
const RULE_NAME = 'xgen-IPA-109-custom-method-must-use-camel-case';
6+
const ERROR_MESSAGE = 'The custom method must use camelCase format.';
7+
const ERROR_RESULT = [{ message: ERROR_MESSAGE }];
8+
9+
export default (input, opts, { path }) => {
10+
// Extract the path key (e.g., '/a/{exampleId}:method') from the JSONPath.
11+
let pathKey = path[1];
12+
13+
if (!isCustomMethod(pathKey)) return;
14+
15+
if (hasException(input, RULE_NAME)) {
16+
return;
17+
}
18+
19+
let methodName = getCustomMethod(pathKey);
20+
if (!methodName) {
21+
return;
22+
}
23+
24+
const isCamelCase = casing('fooBar' , { type: 'camel', disallowDigits: true });
25+
console.log(isCamelCase);
26+
if (!isCamelCase) {
27+
return ERROR_RESULT;
28+
}
29+
30+
/*const camelCaseRegex = /^[a-z]+(?:[A-Z](?:[a-z]+|$))*$/;
31+
if (!camelCaseRegex.test(methodName)) {
32+
return ERROR_RESULT;
33+
}*/
34+
};

tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export function isCustomMethod(path) {
66
return path.includes(':');
77
}
88

9+
export function getCustomMethod(path) {
10+
const [, methodName] = path.split(':');
11+
return methodName;
12+
}
13+
914
/**
1015
* Checks if a resource is a singleton resource ({@link https://docs.devprod.prod.corp.mongodb.com/ipa/113 IPA-113}) based on the paths for the
1116
* resource. The resource may have custom methods. Use {@link getResourcePaths} to get all paths of a resource.

0 commit comments

Comments
 (0)