Skip to content

Commit 91178cf

Browse files
author
Dustin Popp
committed
feat(new-validation): flag descriptions sibling to $ref if identical to referenced description
1 parent b81c4ee commit 91178cf

File tree

4 files changed

+98
-19
lines changed

4 files changed

+98
-19
lines changed

README.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,12 @@ The supported rules are described below:
235235
| invalid_non_empty_security_array | Flag any non-empty security array this is not of type OAuth2 | shared |
236236

237237
##### walker
238-
| Rule | Description | Spec |
239-
| --------------------------- | ---------------------------------------------------------------------------- | ------ |
240-
| no_empty_descriptions | Flag any `description` field in the spec with an empty or whitespace string. | shared |
241-
| has_circular_references | Flag any circular references found in the Swagger spec. | shared |
242-
| $ref_siblings | Flag any properties that are siblings of a `$ref` property. | shared |
238+
| Rule | Description | Spec |
239+
| ----------------------------- | ---------------------------------------------------------------------------- | ------ |
240+
| no_empty_descriptions | Flag any `description` field in the spec with an empty or whitespace string. | shared |
241+
| has_circular_references | Flag any circular references found in the Swagger spec. | shared |
242+
| $ref_siblings | Flag any properties that are siblings of a `$ref` property. | shared |
243+
| duplicate_sibling_description | Flag descriptions sibling to `$ref` if identical to referenced description. | shared |
243244

244245
[1]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#dataTypeFormat
245246
[2]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameter-object
@@ -296,7 +297,7 @@ The default values for each rule are described below.
296297

297298
###### operations
298299
| Rule | Default |
299-
| --------------------------- | --------|
300+
| --------------------------- | ------- |
300301
| no_consumes_for_put_or_post | error |
301302
| get_op_has_consumes | warning |
302303
| no_produces | error |
@@ -306,13 +307,13 @@ The default values for each rule are described below.
306307

307308
###### operations
308309
| Rule | Default |
309-
| --------------------------- | --------|
310+
| --------------------------- | ------- |
310311
| no_request_body_content | error |
311312
| no_request_body_name | warning |
312313

313314
###### parameters
314315
| Rule | Default |
315-
| --------------------------- | --------|
316+
| --------------------------- | ------- |
316317
| no_in_property | error |
317318
| invalid_in_property | error |
318319
| missing_schema_or_content | error |
@@ -349,7 +350,7 @@ The default values for each rule are described below.
349350

350351
###### paths
351352
| Rule | Default |
352-
| --------------------------- | --------|
353+
| --------------------------- | ------- |
353354
| missing_path_parameter | error |
354355
| snake_case_only | warning |
355356

@@ -360,7 +361,7 @@ The default values for each rule are described below.
360361

361362
###### security_definitions
362363
| Rule | Default |
363-
| --------------------------- | --------|
364+
| --------------------------- | ------- |
364365
| unused_security_schemes | warning |
365366
| unused_security_scopes | warning |
366367

@@ -371,7 +372,7 @@ The default values for each rule are described below.
371372

372373
###### schemas
373374
| Rule | Default |
374-
| --------------------------- | --------|
375+
| --------------------------- | ------- |
375376
| invalid_type_format_pair | error |
376377
| snake_case_only | warning |
377378
| no_schema_description | warning |
@@ -380,11 +381,12 @@ The default values for each rule are described below.
380381
| array_of_arrays | warning |
381382

382383
###### walker
383-
| Rule | Default |
384-
| --------------------------- | --------|
385-
| no_empty_descriptions | error |
386-
| has_circular_references | warning |
387-
| $ref_siblings | off |
384+
| Rule | Default |
385+
| ----------------------------- | ------- |
386+
| no_empty_descriptions | error |
387+
| has_circular_references | warning |
388+
| $ref_siblings | off |
389+
| duplicate_sibling_description | warning |
388390

389391

390392
## Turning off `update-notifier`

src/.defaultsForValidator.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ const defaults = {
6161
'walker': {
6262
'no_empty_descriptions': 'error',
6363
'has_circular_references': 'warning',
64-
'$ref_siblings': 'off'
64+
'$ref_siblings': 'off',
65+
'duplicate_sibling_description': 'warning'
6566
}
6667
},
6768
'swagger2': {

src/plugins/validation/2and3/semantic-validators/walker-ibm.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Assertation 1:
22
// The description, when present, should not be empty or contain empty space
33

4+
// Assertation 2:
5+
// Description siblings to $refs should not exist if identical to referenced description
6+
7+
const at = require('lodash/at');
48
const walk = require('../../../utils/walk');
59

610
// Walks an entire spec.
7-
module.exports.validate = function({ jsSpec }, config) {
11+
module.exports.validate = function({ jsSpec, resolvedSpec }, config) {
812
const result = {};
913
result.error = [];
1014
result.warning = [];
@@ -15,6 +19,8 @@ module.exports.validate = function({ jsSpec }, config) {
1519
// check for empty descriptions
1620
if (obj.description !== undefined && obj.description !== null) {
1721
const description = obj.description.toString();
22+
23+
// verify description is not empty
1824
if (description.length === 0 || !description.trim()) {
1925
const checkStatus = config.no_empty_descriptions;
2026
if (checkStatus !== 'off') {
@@ -24,6 +30,27 @@ module.exports.validate = function({ jsSpec }, config) {
2430
});
2531
}
2632
}
33+
34+
// check description siblings to $refs
35+
// note: in general, siblings to $refs are discouraged and validated elsewhere.
36+
// this is a more specific check to flag duplicated descriptions for referenced schemas
37+
// (probably most useful when users turn of the $ref sibling validation)
38+
if (obj.$ref) {
39+
const referencedSchema = at(resolvedSpec, [path])[0];
40+
if (
41+
referencedSchema.description &&
42+
referencedSchema.description === description
43+
) {
44+
const checkStatus = config.duplicate_sibling_description;
45+
if (checkStatus !== 'off') {
46+
result[checkStatus].push({
47+
path: [...path, 'description'],
48+
message:
49+
'Description sibling to $ref matches that of the referenced schema. This is redundant and should be removed.'
50+
});
51+
}
52+
}
53+
}
2754
}
2855

2956
// check for and flag null values - they are not allowed by the spec and are likely mistakes

test/plugins/validation/2and3/walker-ibm.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
const expect = require('expect');
2+
const resolver = require('json-schema-ref-parser');
23
const {
34
validate
45
} = require('../../../../src/plugins/validation/2and3/semantic-validators/walker-ibm');
5-
66
const config = require('../../../../src/.defaultsForValidator').defaults.shared;
77

88
describe('validation plugin - semantic - walker-ibm', () => {
@@ -130,4 +130,53 @@ describe('validation plugin - semantic - walker-ibm', () => {
130130
);
131131
expect(res.warnings.length).toEqual(0);
132132
});
133+
134+
it('should complain if a description sibling to a $ref matches the referenced schema description', async () => {
135+
const spec = {
136+
paths: {
137+
'/stuff': {
138+
get: {
139+
summary: 'list stuff',
140+
operationId: 'listStuff',
141+
produces: ['application/json'],
142+
responses: {
143+
200: {
144+
description: 'successful operation',
145+
schema: {
146+
$ref: '#/responses/Success',
147+
description: 'simple success response'
148+
}
149+
}
150+
}
151+
}
152+
}
153+
},
154+
responses: {
155+
Success: {
156+
type: 'string',
157+
description: 'simple success response'
158+
}
159+
}
160+
};
161+
162+
// clone spec, otherwise 'dereference' will change the spec by reference
163+
const specCopy = JSON.parse(JSON.stringify(spec));
164+
const resolvedSpec = await resolver.dereference(specCopy);
165+
166+
const res = validate({ jsSpec: spec, resolvedSpec }, config);
167+
expect(res.errors.length).toEqual(0);
168+
expect(res.warnings.length).toEqual(1);
169+
expect(res.warnings[0].path).toEqual([
170+
'paths',
171+
'/stuff',
172+
'get',
173+
'responses',
174+
'200',
175+
'schema',
176+
'description'
177+
]);
178+
expect(res.warnings[0].message).toEqual(
179+
'Description sibling to $ref matches that of the referenced schema. This is redundant and should be removed.'
180+
);
181+
});
133182
});

0 commit comments

Comments
 (0)