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

Commit 615cb37

Browse files
kylefopichals
andauthored
feat(oas3): support null 3.1 type in Schema Object (#597)
Co-authored-by: Standa Opichal <stanislav.opichal@oracle.com>
1 parent 00d9daf commit 615cb37

File tree

2 files changed

+59
-16
lines changed

2 files changed

+59
-16
lines changed

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

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ const unsupportedKeys = [
3030
];
3131
const isUnsupportedKey = R.anyPass(R.map(hasKey, unsupportedKeys));
3232

33-
// purposely in the order defined in the JSON Schema spec, integer is an OAS 3 specific addition and thus is at the end
34-
const types = ['boolean', 'object', 'array', 'number', 'string', 'integer'];
35-
const isValidType = R.anyPass(R.map(hasValue, types));
3633

3734
function constructObjectStructure(namespace, schema) {
3835
const element = R.or(schema.get('properties'), new namespace.elements.Object());
@@ -69,6 +66,11 @@ function constructArrayStructure(namespace, schema) {
6966
return element;
7067
}
7168

69+
const openapi30Types = ['boolean', 'object', 'array', 'number', 'string', 'integer'];
70+
const openapi31Types = openapi30Types.concat(['null']);
71+
const isValidOpenAPI30Type = R.anyPass(R.map(hasValue, openapi30Types));
72+
const isValidOpenAPI31Type = R.anyPass(R.map(hasValue, openapi31Types));
73+
7274
const typeToElementNameMap = {
7375
array: 'array',
7476
boolean: 'boolean',
@@ -79,6 +81,31 @@ const typeToElementNameMap = {
7981
string: 'string',
8082
};
8183

84+
function parseType(context) {
85+
let types;
86+
let isValidType;
87+
88+
if (context.isOpenAPIVersionMoreThanOrEqual(3, 1)) {
89+
types = openapi31Types;
90+
isValidType = isValidOpenAPI31Type;
91+
} else {
92+
types = openapi30Types;
93+
isValidType = isValidOpenAPI30Type;
94+
}
95+
96+
const ensureValidType = R.unless(
97+
isValidType,
98+
R.compose(
99+
createWarning(context.namespace, `'${name}' 'type' must be either ${types.join(', ')}`),
100+
getValue
101+
)
102+
);
103+
104+
return pipeParseResult(context.namespace,
105+
parseString(context, name, false),
106+
ensureValidType);
107+
}
108+
82109
// Returns whether the given element value matches the provided schema type
83110
const valueMatchesType = (type, value) => {
84111
const expectedElementType = typeToElementNameMap[type];
@@ -172,18 +199,6 @@ function validateOneOfIsNotUsedWithUnsupportedConstraints(context) {
172199
function parseSchema(context) {
173200
const { namespace } = context;
174201

175-
const ensureValidType = R.unless(
176-
isValidType,
177-
R.compose(
178-
createWarning(namespace, `'Schema Object' 'type' must be either ${types.join(', ')}`),
179-
getValue
180-
)
181-
);
182-
183-
const parseType = pipeParseResult(namespace,
184-
parseString(context, name, false),
185-
ensureValidType);
186-
187202
const parseSubSchema = element => parseReference('schemas', R.uncurryN(2, parseSchema), context, element, true);
188203
const parseProperties = parseObject(context, `${name}' 'properties`, R.compose(parseSubSchema, getValue));
189204

@@ -200,7 +215,7 @@ function parseSchema(context) {
200215
});
201216

202217
const parseMember = R.cond([
203-
[hasKey('type'), parseType],
218+
[hasKey('type'), parseType(context)],
204219
[hasKey('enum'), R.compose(parseEnum(context, name), getValue)],
205220
[hasKey('properties'), R.compose(parseProperties, getValue)],
206221
[hasKey('items'), R.compose(parseSubSchema, getValue)],
@@ -243,6 +258,8 @@ function parseSchema(context) {
243258
element = new namespace.elements.Number();
244259
} else if (type === 'boolean') {
245260
element = new namespace.elements.Boolean();
261+
} else if (type === 'null') {
262+
element = new namespace.elements.Null();
246263
} else {
247264
element = new namespace.elements.Enum();
248265
element.enumerations = [

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,32 @@ describe('Schema Object', () => {
143143
const string = parseResult.get(0).content;
144144
expect(string).to.be.instanceof(namespace.elements.Number);
145145
});
146+
147+
it('returns a warning for null type on OpenAPI prior 3.1', () => {
148+
const schema = new namespace.elements.Object({
149+
type: 'null',
150+
});
151+
const parseResult = parse(context, schema);
152+
153+
expect(parseResult).to.contain.warning(
154+
"'Schema Object' 'type' must be either boolean, object, array, number, string, integer"
155+
);
156+
});
157+
158+
it('returns a null structure for null type on OpenAPI 3.1', () => {
159+
context.openapiVersion = { major: 3, minor: 1 };
160+
const schema = new namespace.elements.Object({
161+
type: 'null',
162+
});
163+
const parseResult = parse(context, schema);
164+
165+
expect(parseResult.length).to.equal(1);
166+
expect(parseResult.get(0)).to.be.instanceof(namespace.elements.DataStructure);
167+
expect(parseResult).to.not.contain.annotations;
168+
169+
const element = parseResult.get(0).content;
170+
expect(element).to.be.instanceof(namespace.elements.Null);
171+
});
146172
});
147173

148174
describe('#enum', () => {

0 commit comments

Comments
 (0)