Skip to content

Commit 3221e49

Browse files
author
Phil Sturgeon
authored
Merge pull request #1 from stoplightio/graceful-handling
Handle malformed schemas more gracefully
2 parents 10273ce + 4219c2d commit 3221e49

File tree

6 files changed

+247
-5
lines changed

6 files changed

+247
-5
lines changed

lib/converters/schema.js

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
var isObject = require('../utils/isObject').isObject;
12
var InvalidTypeError = require('../errors/invalid-type-error');
23

34
module.exports = convertFromSchema;
@@ -24,14 +25,22 @@ function convertSchema(schema, options) {
2425

2526
if (Array.isArray(schema[struct])) {
2627
for (j; j < schema[struct].length; j++) {
28+
if (!isObject(schema[struct][j])) {
29+
schema[struct].splice(j, 1);
30+
j--;
31+
continue;
32+
}
33+
2734
schema[struct][j] = convertSchema(schema[struct][j], options);
2835
}
36+
} else if (schema[struct] === null) {
37+
delete schema[struct];
2938
} else if (typeof schema[struct] === 'object') {
3039
schema[struct] = convertSchema(schema[struct], options);
3140
}
3241
}
3342

34-
if (typeof schema.properties === 'object') {
43+
if ('properties' in schema) {
3544
schema.properties = convertProperties(schema.properties, options);
3645

3746
if (Array.isArray(schema.required)) {
@@ -44,15 +53,13 @@ function convertSchema(schema, options) {
4453
if (Object.keys(schema.properties).length === 0) {
4554
delete schema.properties;
4655
}
47-
4856
}
4957

5058
validateType(schema.type);
5159
schema = convertTypes(schema);
5260
schema = convertFormat(schema, options);
5361

54-
if (typeof schema['x-patternProperties'] === 'object'
55-
&& options.supportPatternProperties) {
62+
if ('x-patternProperties' in schema && options.supportPatternProperties) {
5663
schema = convertPatternProperties(schema, options.patternPropertiesHandler);
5764
}
5865

@@ -78,10 +85,18 @@ function convertProperties(properties, options) {
7885
, removeProp
7986
;
8087

88+
if (!isObject(properties)) {
89+
return props;
90+
}
91+
8192
for (key in properties) {
8293
removeProp = false;
8394
property = properties[key];
8495

96+
if (!isObject(property)) {
97+
continue;
98+
}
99+
85100
options._removeProps.forEach(function(prop) {
86101
if (property[prop] === true) {
87102
removeProp = true;
@@ -189,7 +204,10 @@ function convertFormatByte (schema, settings) {
189204
}
190205

191206
function convertPatternProperties(schema, handler) {
192-
schema.patternProperties = schema['x-patternProperties'];
207+
if (isObject(schema['x-patternProperties'])) {
208+
schema.patternProperties = schema['x-patternProperties'];
209+
}
210+
193211
delete schema['x-patternProperties'];
194212

195213
return handler(schema);

lib/utils/isObject.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exports.isObject = function (maybeObj) {
2+
return maybeObj !== null && typeof maybeObj === 'object';
3+
};

test/combiners.test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
var test = require('tape')
2+
, convert = require('../')
3+
;
4+
5+
test('allOf is null', function(assert) {
6+
var schema
7+
, result
8+
, expected
9+
;
10+
11+
assert.plan(1);
12+
13+
schema = {
14+
allOf: null,
15+
};
16+
17+
result = convert(schema);
18+
19+
expected = {
20+
$schema: 'http://json-schema.org/draft-04/schema#',
21+
};
22+
23+
assert.deepEqual(result, expected, 'allOf is removed');
24+
});
25+
26+
test('anyOf is null', function(assert) {
27+
var schema
28+
, result
29+
, expected
30+
;
31+
32+
assert.plan(1);
33+
34+
schema = {
35+
anyOf: null,
36+
};
37+
38+
result = convert(schema);
39+
40+
expected = {
41+
$schema: 'http://json-schema.org/draft-04/schema#',
42+
};
43+
44+
assert.deepEqual(result, expected, 'anyOf is removed');
45+
});
46+
47+
48+
test('oneOf is null', function(assert) {
49+
var schema
50+
, result
51+
, expected
52+
;
53+
54+
assert.plan(1);
55+
56+
schema = {
57+
oneOf: null,
58+
};
59+
60+
result = convert(schema);
61+
62+
expected = {
63+
$schema: 'http://json-schema.org/draft-04/schema#',
64+
};
65+
66+
assert.deepEqual(result, expected, 'oneOf is removed');
67+
});

test/items.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,50 @@ test('items', function(assert) {
3030

3131
assert.deepEqual(result, expected, 'converted');
3232
});
33+
34+
test('handles items with invalid values', function(assert) {
35+
var schema
36+
, result
37+
, expected
38+
;
39+
40+
assert.plan(1);
41+
42+
schema = {
43+
type: 'array',
44+
items: [
45+
{
46+
type: 'string'
47+
},
48+
2,
49+
null,
50+
{
51+
type: 'number'
52+
},
53+
'foo',
54+
{
55+
type: 'array'
56+
},
57+
]
58+
};
59+
60+
result = convert(schema);
61+
62+
expected = {
63+
$schema: 'http://json-schema.org/draft-04/schema#',
64+
type: 'array',
65+
items: [
66+
{
67+
type: 'string'
68+
},
69+
{
70+
type: 'number'
71+
},
72+
{
73+
type: 'array'
74+
},
75+
]
76+
};
77+
78+
assert.deepEqual(result, expected, 'converted');
79+
});

test/pattern_properties.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,46 @@ test('handling additionalProperties with matching objects', function(assert) {
173173
assert.deepEqual(result, expected, 'additionalProperties set to false');
174174
});
175175

176+
test('handling null x-patternProperties', function(assert) {
177+
var schema
178+
, result
179+
, expected
180+
;
181+
182+
assert.plan(2);
183+
184+
schema = {
185+
type: 'object',
186+
additionalProperties: {
187+
type: 'object',
188+
properties: {
189+
test: {
190+
type: 'string'
191+
}
192+
}
193+
},
194+
'x-patternProperties': null,
195+
};
196+
197+
result = convert(schema, {supportPatternProperties: true});
198+
199+
expected = {
200+
$schema: 'http://json-schema.org/draft-04/schema#',
201+
type: 'object',
202+
additionalProperties: {
203+
type: 'object',
204+
properties: {
205+
test: {
206+
type: 'string'
207+
}
208+
}
209+
},
210+
};
211+
212+
assert.deepEqual(result['x-patternProperties'], void 0, 'x-patternProperties to be gone');
213+
assert.deepEqual(result, expected, 'additionalProperties to be preserved');
214+
});
215+
176216
test('handling additionalProperties with non-matching objects', function(assert) {
177217
var schema
178218
, result

test/properties.test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,73 @@ test('properties', function(assert) {
4444
assert.deepEqual(result, expected, 'converted');
4545
});
4646

47+
test('properties value is null', function(assert) {
48+
var schema
49+
, result
50+
, expected
51+
;
52+
53+
assert.plan(1);
54+
55+
schema = {
56+
type: 'object',
57+
properties: null,
58+
};
59+
60+
result = convert(schema);
61+
62+
expected = {
63+
$schema: 'http://json-schema.org/draft-04/schema#',
64+
type: 'object',
65+
};
66+
67+
assert.deepEqual(result, expected, 'successfully converted');
68+
});
69+
70+
test('strips malformed properties children', function(assert) {
71+
var schema
72+
, result
73+
, expected
74+
;
75+
76+
assert.plan(1);
77+
78+
schema = {
79+
type: 'object',
80+
required: ['bar'],
81+
properties: {
82+
foo: {
83+
type: 'string',
84+
example: '2017-01-01T12:34:56Z'
85+
},
86+
foobar: 2,
87+
bar: {
88+
type: 'string',
89+
nullable: true
90+
},
91+
baz: null,
92+
}
93+
};
94+
95+
result = convert(schema);
96+
97+
expected = {
98+
$schema: 'http://json-schema.org/draft-04/schema#',
99+
type: 'object',
100+
required: ['bar'],
101+
properties: {
102+
foo: {
103+
type: 'string',
104+
},
105+
bar: {
106+
type: ['string', 'null']
107+
}
108+
}
109+
};
110+
111+
assert.deepEqual(result, expected, 'successfully converted');
112+
});
113+
47114
test('additionalProperties is false', function(assert) {
48115
var schema
49116
, result

0 commit comments

Comments
 (0)