Skip to content

Commit 3ab9c3a

Browse files
authored
feat: flag properties with the same name but different type (#140)
This is to catch properties used inconsistently throughout an API Definition
1 parent edd3000 commit 3ab9c3a

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ The supported rules are described below:
262262
| no_property_description | Flag any schema that contains a 'property' without a `description` field. | shared |
263263
| description_mentions_json | Flag any schema with a 'property' description that mentions the word 'JSON'. | shared |
264264
| array_of_arrays | Flag any schema with a 'property' of type `array` with items of type `array`. | shared |
265+
| inconsistent_property_type | Flag any properties that have the same name but an inconsistent type. | shared |
265266
| property_case_convention | Flag any property with a `name` that does not follow a given case convention. snake_case_only must be 'off' to use. | shared |
266267
| enum_case_convention | Flag any enum with a `value` that does not follow a given case convention. snake_case_only must be 'off' to use. | shared |
267268
| json_or_param_binary_string | Flag parameters or application/json request/response bodies with schema type: string, format: binary. | oas3 |
@@ -440,6 +441,7 @@ The default values for each rule are described below.
440441
| no_property_description | warning |
441442
| description_mentions_json | warning |
442443
| array_of_arrays | warning |
444+
| inconsistent_property_type | warning |
443445
| property_case_convention | error, lower_snake_case |
444446
| enum_case_convention | error, lower_snake_case |
445447

src/.defaultsForValidator.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const defaults = {
6464
'no_property_description': 'warning',
6565
'description_mentions_json': 'warning',
6666
'array_of_arrays': 'warning',
67+
'inconsistent_property_type': 'warning',
6768
'property_case_convention': [ 'error', 'lower_snake_case'],
6869
'enum_case_convention': [ 'error', 'lower_snake_case']
6970
},

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) {
100100
}
101101
});
102102

103+
// Collect the properties info. Pass it to checkProperties to catch
104+
// properties that have the same name but an inconsistent type.
105+
const propertiesToCompare = {};
106+
103107
schemas.forEach(({ schema, path }) => {
104108
generateFormatErrors(schema, path, config, isOAS3, messages);
105109

@@ -137,6 +141,15 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) {
137141
}
138142
}
139143
}
144+
if (config.inconsistent_property_type !== 'off') {
145+
checkProperties(
146+
schema,
147+
propertiesToCompare,
148+
path,
149+
config.inconsistent_property_type,
150+
messages
151+
);
152+
}
140153
});
141154

142155
return messages;
@@ -511,3 +524,44 @@ function isRootSchema(path) {
511524
current === 'schema' || (parent === 'definitions' && path.length === 2)
512525
);
513526
}
527+
528+
// Flag any properties that have the same name but an inconsistent type.
529+
function checkProperties(
530+
schema,
531+
propertiesToCompare,
532+
contextPath,
533+
configOption,
534+
messages
535+
) {
536+
if (!schema.properties) return;
537+
538+
for (const [key, value] of Object.entries(schema.properties)) {
539+
// skips properties that use $ref
540+
if (value.type) {
541+
if (propertiesToCompare[key]) {
542+
if (propertiesToCompare[key].type !== value.type) {
543+
// First property that appeared in API def, should only print once.
544+
if (!propertiesToCompare[key].printed) {
545+
propertiesToCompare[key].printed = true;
546+
messages.addMessage(
547+
propertiesToCompare[key].path,
548+
`Property has inconsistent type: ${key}.`,
549+
configOption
550+
);
551+
}
552+
messages.addMessage(
553+
contextPath.concat(['properties', key]).join('.'),
554+
`Property has inconsistent type: ${key}.`,
555+
configOption
556+
);
557+
}
558+
} else {
559+
propertiesToCompare[key] = {
560+
type: value.type,
561+
path: contextPath.concat(['properties', key]).join('.'),
562+
printed: false
563+
};
564+
}
565+
}
566+
}
567+
}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,4 +1660,59 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => {
16601660
expect(res.errors.length).toEqual(0);
16611661
expect(res.warnings.length).toEqual(0);
16621662
});
1663+
1664+
it('should produce a warning for properties that have the same name but an inconsistent type', () => {
1665+
const spec = {
1666+
components: {
1667+
schemas: {
1668+
person: {
1669+
description: 'Produce warnings',
1670+
properties: {
1671+
name: {
1672+
description: 'type integer',
1673+
type: 'integer'
1674+
}
1675+
}
1676+
},
1677+
adult: {
1678+
description: 'Causes first warnings',
1679+
properties: {
1680+
name: {
1681+
description: 'different type',
1682+
type: 'number'
1683+
}
1684+
}
1685+
},
1686+
kid: {
1687+
description: 'Causes second warning',
1688+
properties: {
1689+
name: {
1690+
type: 'string',
1691+
description: 'differnt type'
1692+
}
1693+
}
1694+
}
1695+
}
1696+
}
1697+
};
1698+
1699+
const message = 'Property has inconsistent type: name.';
1700+
const res = validate({ jsSpec: spec }, config);
1701+
1702+
expect(res.warnings.length).toEqual(3);
1703+
expect(res.errors.length).toEqual(0);
1704+
1705+
expect(res.warnings[0].message).toEqual(message);
1706+
expect(res.warnings[0].path).toEqual(
1707+
'components.schemas.person.properties.name'
1708+
);
1709+
expect(res.warnings[1].message).toEqual(message);
1710+
expect(res.warnings[1].path).toEqual(
1711+
'components.schemas.adult.properties.name'
1712+
);
1713+
expect(res.warnings[2].message).toEqual(message);
1714+
expect(res.warnings[2].path).toEqual(
1715+
'components.schemas.kid.properties.name'
1716+
);
1717+
});
16631718
});

0 commit comments

Comments
 (0)