Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit eafd062

Browse files
committed
fix(oas3): error out when parsing components using reserved elements
1 parent 96fbce7 commit eafd062

File tree

5 files changed

+62
-7
lines changed

5 files changed

+62
-7
lines changed

packages/openapi3-parser/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# API Elements: OpenAPI 3 Parser Changelog
22

3+
## 0.14.2 (2020-07-20)
4+
5+
### Bug Fixes
6+
7+
- Prevents the parser from throwing an unhandled error while parsing components
8+
which use keys which are the same as an [API Element type
9+
identifier](https://apielements.org/en/latest/element-definitions.html). The
10+
parser will now produce a handled error mentioning that these keys are
11+
reserved and currently unsupported in the parser.
12+
313
## 0.14.1 (2020-07-01)
414

515
### Enhancements

packages/openapi3-parser/lib/parser/oas/parseComponentsObject.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const R = require('ramda');
22
const {
3-
isObject, isAnnotation, hasKey, isExtension, getValue,
3+
isObject, isAnnotation, hasKey, isExtension, getKey, getValue,
44
} = require('../../predicates');
55
const {
6+
createError,
67
createWarning,
78
createUnsupportedMemberWarning,
89
createInvalidMemberWarning,
@@ -134,8 +135,21 @@ function parseComponentsObject(context, element) {
134135
const parseComponentObjectMember = R.curry((parser, member) => {
135136
const component = member.key.toValue();
136137

138+
const createKeyIsReservedError = key => createError(
139+
namespace,
140+
`'${name}' '${component}' contains a reserved key '${key.toValue()}' which is not currently supported by this parser`,
141+
key
142+
);
143+
const isReservedKey = key => namespace.elementMap[key.toValue()] !== undefined;
144+
const validateKeyIsNotReservedKey = R.when(
145+
R.compose(isReservedKey, getKey),
146+
R.compose(createKeyIsReservedError, getKey)
147+
);
148+
137149
const parseMember = parseComponentMember(context, parser);
138-
const parseMemberOrRef = m => parseReference(component, () => parseMember(m), context, m.value, false, true);
150+
const parseMemberOrRef = pipeParseResult(namespace,
151+
validateKeyIsNotReservedKey,
152+
m => parseReference(component, () => parseMember(m), context, m.value, false, true));
139153

140154
return pipeParseResult(context.namespace,
141155
validateIsObject,

packages/openapi3-parser/lib/parser/parseObject.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,29 @@ const pipeParseResult = require('../pipeParseResult');
1313
*/
1414
const isAnnotationOrMember = R.anyPass([isAnnotation, isMember]);
1515

16+
const parseResultHasErrors = parseResult => !parseResult.errors.isEmpty;
17+
18+
1619
/**
1720
* Transform every non-annotation element in the parse result and then flatten all of the results into a parse result
1821
* @param transform {function}
1922
* @param parseResult {ParseResult}
2023
* @private
2124
*/
2225
const chainParseResult = R.curry((transform, parseResult) => {
26+
if (parseResultHasErrors(parseResult)) {
27+
return parseResult;
28+
}
29+
2330
const result = R.chain(transform, parseResult);
2431

25-
if (!result.errors.isEmpty) {
32+
if (parseResultHasErrors(result)) {
2633
return new parseResult.constructor(result.errors);
2734
}
2835

2936
return result;
3037
});
3138

32-
const parseResultHasErrors = parseResult => !parseResult.errors.isEmpty;
33-
3439
// FIXME Can be simplified once https://github.com/refractproject/minim/issues/201 is completed
3540
const hasMember = R.curry((object, key) => {
3641
const findKey = R.allPass([isMember, member => member.key.toValue() === key]);
@@ -145,13 +150,25 @@ function parseObject(context, name, parseMember, requiredKeys = [], orderedKeys
145150
wrapObjectInParseResult,
146151
(value) => {
147152
// pre-parse the ordered keys in order
153+
let errors = null;
154+
148155
orderedKeys.forEach((key) => {
149156
const isOrderedKey = R.allPass([isMember, m => m.key.equals(key)]);
150157
const member = R.filter(isOrderedKey, value).get(0);
151158
if (member) {
152-
member.value = parseMember(member);
159+
const parseResult = parseMember(member);
160+
member.value = parseResult;
161+
162+
if (parseResultHasErrors(parseResult)) {
163+
({ errors } = parseResult);
164+
}
153165
}
154166
});
167+
168+
if (errors) {
169+
return new namespace.elements.ParseResult(errors.elements);
170+
}
171+
155172
return value;
156173
},
157174
chainParseResult(transformMember),

packages/openapi3-parser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@apielements/openapi3-parser",
3-
"version": "0.14.1",
3+
"version": "0.14.2",
44
"description": "Open API Specification 3 API Elements Parser",
55
"author": "Apiary.io <support@apiary.io>",
66
"license": "MIT",

packages/openapi3-parser/test/unit/parser/oas/parseComponentsObject-test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ describe('Components Object', () => {
2020
expect(parseResult).to.contain.warning("'Components Object' is not an object");
2121
});
2222

23+
it('provides an error when a reusable component is named after an element', () => {
24+
const components = new namespace.elements.Object({
25+
schemas: {
26+
member: {},
27+
},
28+
});
29+
30+
const parseResult = parse(context, components);
31+
32+
expect(parseResult).to.contain.error(
33+
"'Components Object' 'schemas' contains a reserved key 'member' which is not currently supported by this parser"
34+
);
35+
});
36+
2337
describe('#schemas', () => {
2438
it('provides a warning when schemas is non-object', () => {
2539
const components = new namespace.elements.Object({

0 commit comments

Comments
 (0)