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

Commit 11d8b9f

Browse files
committed
fix(oas3): gracefully handle non-string path keys
1 parent e05d2f9 commit 11d8b9f

File tree

4 files changed

+36
-7
lines changed

4 files changed

+36
-7
lines changed

packages/openapi3-parser/CHANGELOG.md

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

3+
## TBD
4+
5+
### Bug Fixes
6+
7+
- Return a parsing warning when Paths Object contains keys which are not
8+
strings. Previously the parser would throw an error.
9+
310
## 0.15.0 (2020-08-06)
411

512
### Enhancements

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
const R = require('ramda');
2-
const { isObject, isExtension } = require('../../predicates');
3-
const { createError, createInvalidMemberWarning } = require('../annotations');
2+
const {
3+
isObject, isString, isExtension, getKey,
4+
} = require('../../predicates');
5+
const { createError, createWarning } = require('../annotations');
46
const pipeParseResult = require('../../pipeParseResult');
57
const parsePathItemObject = require('./parsePathItemObject');
68

79
const name = 'Paths Object';
810

9-
// Returns true if the member's key starts with a slash
10-
const isPathField = member => member.key.toValue().startsWith('/');
11+
// Returns true if the member's key is a string, and starts with a slash
12+
const isPathField = R.compose(R.both(isString, key => key.toValue().startsWith('/')), getKey);
13+
const isKeyString = R.compose(isString, getKey);
1114

1215
/**
1316
* Parse Paths Object
@@ -19,6 +22,12 @@ function parsePaths(context, paths) {
1922
const { namespace } = context;
2023

2124
const createParseResult = annotation => new namespace.elements.ParseResult([annotation]);
25+
const createPathNotStringWarning = member => createWarning(namespace,
26+
`'${name}' path must be a string, found ${member.key.element}`,
27+
member.value);
28+
const createKeyNotPathOrExtensionWarning = member => createWarning(namespace,
29+
`'${name}' contains invalid key '${member.key.toValue()}', key must be a path starting with a leading forward slash '/', or an extension starting with 'x-'`,
30+
member.value);
2231

2332
const parseMember = R.cond([
2433
[isPathField, parsePathItemObject(context)],
@@ -27,7 +36,8 @@ function parsePaths(context, paths) {
2736
[isExtension, () => new namespace.elements.ParseResult()],
2837

2938
// Return a warning for additional properties
30-
[R.T, R.compose(createParseResult, createInvalidMemberWarning(namespace, name))],
39+
[isKeyString, R.compose(createParseResult, createKeyNotPathOrExtensionWarning)],
40+
[R.T, R.compose(createParseResult, createPathNotStringWarning)],
3141
]);
3242

3343
const parseMembers = object => R.chain(parseMember, new namespace.elements.ParseResult(object.content));

packages/openapi3-parser/test/integration/parser/oas/parseOpenAPI-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('#parseOpenAPIObject', () => {
3535
expect(result.annotations.toValue()).to.deep.equal([
3636
"Version '3.1337.0' is not fully supported",
3737
"'Info Object' contains invalid key 'invalid'",
38-
"'Paths Object' contains invalid key 'invalid'",
38+
"'Paths Object' contains invalid key 'invalid', key must be a path starting with a leading forward slash '/', or an extension starting with 'x-'",
3939
"'Components Object' contains invalid key 'invalid'",
4040
"'OpenAPI Object' contains invalid key 'invalid'",
4141
]);

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ describe('#parsePathsObject', () => {
2828
expect(parseResult.isEmpty).to.be.true;
2929
});
3030

31+
it('provides a warning when paths contains non-string field', () => {
32+
const paths = new namespace.elements.Object();
33+
paths.push(new namespace.elements.Member(true, {}));
34+
35+
const parseResult = parse(context, paths);
36+
37+
expect(parseResult.length).to.equal(1);
38+
expect(parseResult).to.contain.warning("'Paths Object' path must be a string, found boolean");
39+
});
40+
3141
it('provides a warning when paths contains non-path field pattern', () => {
3242
const paths = new namespace.elements.Object({
3343
test: {},
@@ -36,7 +46,9 @@ describe('#parsePathsObject', () => {
3646
const parseResult = parse(context, paths);
3747

3848
expect(parseResult.length).to.equal(1);
39-
expect(parseResult).to.contain.warning("'Paths Object' contains invalid key 'test'");
49+
expect(parseResult).to.contain.warning(
50+
"'Paths Object' contains invalid key 'test', key must be a path starting with a leading forward slash '/', or an extension starting with 'x-'"
51+
);
4052
});
4153

4254
it('ignores extension objects', () => {

0 commit comments

Comments
 (0)