api-quality-spectral-ruleset 1.4.1-beta.4 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/apq-spectral.yaml CHANGED
@@ -338,7 +338,7 @@ rules:
338
338
  field: "$[?(@.name == '$start' && @.in == 'query')]"
339
339
  function: truthy
340
340
  apiq:OAR025:
341
- description: "$limit must be defined as a query parameter in the collection GET operations selected by the configured paths."
341
+ description: "$limit must be defined as an integer query parameter in the collection GET operations selected by the configured paths."
342
342
  message: "{{error}}"
343
343
  documentationUrl: "https://github.com/apiaddicts/apquality-spectral/blob/main/docs/resources/OAR025.md"
344
344
  severity: error
@@ -22,12 +22,32 @@ const shouldIncludePath = (path, patterns, strategy) => {
22
22
  return strategy === STRATEGY_INCLUDE ? matchesList : !matchesList;
23
23
  };
24
24
 
25
- const hasQueryParameter = (parameters, parameterName) => Array.isArray(parameters)
26
- && parameters.some((p) => p && !p.$ref && p.name === parameterName && p.in === 'query');
25
+ const resolveRef = (ref, context) => {
26
+ const root = context && context.document && context.document.resolved;
27
+ if (!root || typeof ref !== 'string' || !ref.startsWith('#/')) return undefined;
28
+ return ref.replace(/^#\//, '').split('/')
29
+ .reduce((node, part) => (node == null ? undefined : node[part]), root);
30
+ };
31
+
32
+ const resolveParam = (p, context) => (p && p.$ref ? resolveRef(p.$ref, context) : p);
33
+
34
+ const findQueryParameter = (parameters, parameterName, context) => (Array.isArray(parameters)
35
+ ? parameters
36
+ .map((p) => resolveParam(p, context))
37
+ .find((p) => p && p.name === parameterName && p.in === 'query')
38
+ : undefined);
39
+
40
+ const getParameterType = (param) => {
41
+ if (!param) return undefined;
42
+ if (param.schema && typeof param.schema === 'object') return param.schema.type;
43
+ return param.type;
44
+ };
27
45
 
28
46
  const PAGINATED_RESPONSE_CODE = '206';
29
47
  const PAGINATED_RULE_CODES = ['OAR022', 'OAR025'];
30
48
 
49
+ const REQUIRED_PARAM_TYPES = { OAR025: 'integer' };
50
+
31
51
  const hasResponseCode = (operation, code) => {
32
52
  const responses = operation && operation.responses;
33
53
  return !!responses && typeof responses === 'object'
@@ -71,11 +91,21 @@ module.exports = (given, options = {}, context) => {
71
91
  if (!shouldIncludePath(path, patterns, strategy)) return;
72
92
  if (requiresPaginated && !hasResponseCode(getOperation, PAGINATED_RESPONSE_CODE)) return;
73
93
 
74
- if (!hasQueryParameter(getOperation.parameters, parameterName)) {
94
+ const param = findQueryParameter(getOperation.parameters, parameterName, context);
95
+ if (!param) {
75
96
  results.push({
76
97
  message: `${ruleCode}: ${parameterName} must be defined as a query parameter in this operation.`,
77
98
  path: [...context.path, path, 'get'],
78
99
  });
100
+ return;
101
+ }
102
+
103
+ const expectedType = REQUIRED_PARAM_TYPES[ruleCode];
104
+ if (expectedType && getParameterType(param) !== expectedType) {
105
+ results.push({
106
+ message: `${ruleCode}: ${parameterName} must be defined as a query parameter of type ${expectedType} in this operation.`,
107
+ path: [...context.path, path, 'get'],
108
+ });
79
109
  }
80
110
  });
81
111
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-quality-spectral-ruleset",
3
- "version": "1.4.1-beta.4",
3
+ "version": "1.4.1",
4
4
  "description": "Spectral ruleset by API Quality",
5
5
  "main": "apq-spectral.yaml",
6
6
  "files": [