Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: edge case where component would sometimes be marked a string #174

Merged
merged 1 commit into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 63 additions & 21 deletions packages/tooling/__tests__/lib/parameters-to-json-schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -834,35 +834,77 @@ describe('type', () => {
});
});

it('should repair an invalid schema that has no `type` as just a simple string', () => {
const schema = parametersToJsonSchema(
{
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
host: {
description: 'Host name to check validity of.',
describe('repair invalid schema that has no `type`', () => {
it('should repair an invalid schema that has no `type` as just a simple string', () => {
const schema = parametersToJsonSchema(
{
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
host: {
description: 'Host name to check validity of.',
},
},
},
},
},
},
},
},
{}
);
{}
);

expect(schema[0].schema).toStrictEqual({
properties: {
host: {
description: 'Host name to check validity of.',
type: 'string',
expect(schema[0].schema).toStrictEqual({
properties: {
host: {
description: 'Host name to check validity of.',
type: 'string',
},
},
},
type: 'object',
type: 'object',
});
});

it('should not add a string type on a ref and component schema that are clearly objects', () => {
const schema = parametersToJsonSchema(
{
requestBody: {
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/NewUser',
},
},
},
},
},
{
components: {
schemas: {
ErrorResponse: {
properties: {
message: {
type: 'string',
},
},
},
NewUser: {
required: ['user_id'],
properties: {
user_id: {
type: 'integer',
},
},
},
},
},
}
);

expect(schema[0].schema.components.schemas.ErrorResponse.type).toBe('object');
expect(schema[0].schema.components.schemas.NewUser.type).toBe('object');
});
});
});
Expand Down
40 changes: 25 additions & 15 deletions packages/tooling/src/lib/parameters-to-json-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ function getBodyParam(pathOperation, oas) {

const cleanupSchemaDefaults = (obj, prevProp = false, prevProps = []) => {
Object.keys(obj).forEach(prop => {
// Since this method is recursive, let's reset our states when we're first processing a new property tree.
if (!prevProp) {
prevProps = [];
}

if (obj[prop] === null) {
// If the item is null, just carry on. Why do this in addition to `typeof obj[prop] == object`? Because
// `typeof null` equates to `object` for "legacy reasons" apparently.
Expand Down Expand Up @@ -77,15 +82,10 @@ function getBodyParam(pathOperation, oas) {
if (!prevProp) {
// If we have no previous prop, then we're processing a top-level title and description on a requestBody.
delete obj[prop];
} else if (
prevProp !== false &&
prevProps.includes('schemas') &&
'components' in oas &&
'schemas' in oas.components &&
prevProp in oas.components.schemas
) {
// If we have a previous prop, but we're parsing the immediate schemas tree in the components object,
// then we're processing a title and description on a component schema.
} else if (prevProp !== false && prevProps.length === 1) {
// If we have a previous prop, but we're parsing the immediate schemas tree (we know this if prevProps

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this stuff is crazy

Copy link
Member Author

@erunion erunion Apr 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this just to remove this kind of stuff because RJSF renders it as an orphan block of text:

// only has a single entry as that entry will be the name of the schema!) in the components object, then
// we're processing a title and description on a component schema.
delete obj[prop];
}
break;
Expand Down Expand Up @@ -128,13 +128,23 @@ function getBodyParam(pathOperation, oas) {
};

const type = schema.type === 'application/x-www-form-urlencoded' ? 'formData' : 'body';
let cleanedSchema;

const cleanedSchema = oas.components
? {
components: cleanupSchemaDefaults(oas.components),
...cleanupSchemaDefaults(schema.schema),
}
: cleanupSchemaDefaults(schema.schema);
if (oas.components) {
cleanedSchema = {
components: {},
...cleanupSchemaDefaults(schema.schema),
};

// Since cleanupSchemaDefaults is a recursive method, it's best if we start it at the `components.schemas` level
// so we have immediate knowledge of when we're first processing a component schema, and can reset our internal
// prop states that keep track of how we should treat certain prop edge cases.
Object.keys(oas.components).forEach(componentType => {
cleanedSchema.components[componentType] = cleanupSchemaDefaults(oas.components[componentType]);
});
} else {
cleanedSchema = cleanupSchemaDefaults(schema.schema);
}

// If there's not actually any data within this schema, don't bother returning it.
if (Object.keys(cleanedSchema).length === 0) {
Expand Down