Skip to content

Commit

Permalink
feat: add an ability to parse json encoded options (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulish committed Oct 11, 2021
1 parent 678c566 commit f8a39e7
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 10 deletions.
42 changes: 42 additions & 0 deletions test/transforms/components/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,48 @@ describe('parseComponents method', () => {
expect(result).toEqual(expected);
});

it('Should parse jsdoc component spec with json options', () => {
const jsodInput = [`
/**
* A song
* @typedef {object} Song
* @property {string} title - The title
* @property {string} artist - The artist - json:{"maxLength": 300}
* @property {number} year - The year - int64 - json:{"minimum": 2000}
*/
`];
const expected = {
components: {
schemas: {
Song: {
type: 'object',
description: 'A song',
properties: {
title: {
type: 'string',
description: 'The title',
},
artist: {
type: 'string',
description: 'The artist',
maxLength: 300,
},
year: {
type: 'number',
description: 'The year',
format: 'int64',
minimum: 2000,
},
},
},
},
},
};
const parsedJSDocs = jsdocInfo()(jsodInput);
const result = parseComponents({}, parsedJSDocs);
expect(result).toEqual(expected);
});

it('Should parse jsdoc component spec with require and format properties', () => {
const jsodInput = [`
/**
Expand Down
53 changes: 53 additions & 0 deletions test/transforms/paths/parameters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,56 @@ describe('params tests', () => {
expect(result).toEqual(expected);
});
});

it('should parse jsdoc path params with json options', () => {
const jsodInput = [`
/**
* GET /api/v1
* @param {string} name.query.required - name param description - enum:value1,value2 - json:{"minLength": 6}
* @param {integer} age.query - age param description - json:{"minimum": 0, "maximum": 130}
*/
`];
const expected = {
paths: {
'/api/v1': {
get: {
deprecated: false,
description: undefined,
summary: '',
responses: {},
security: [],
tags: [],
parameters: [{
deprecated: false,
description: 'name param description',
in: 'query',
name: 'name',
required: true,
schema: {
type: 'string',
enum: [
'value1',
'value2',
],
minLength: 6,
},
}, {
deprecated: false,
description: 'age param description',
in: 'query',
name: 'age',
required: false,
schema: {
type: 'integer',
minimum: 0,
maximum: 130,
},
}],
},
},
},
};
const parsedJSDocs = jsdocInfo()(jsodInput);
const result = setPaths({}, parsedJSDocs);
expect(result).toEqual(expected);
});
3 changes: 2 additions & 1 deletion transforms/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const formatProperties = (properties, options = {}) => {
const {
name: typeName, applications, expression, elements,
} = property.type;
const [descriptionValue, enumValues] = formatDescription(property.description);
const [descriptionValue, enumValues, jsonOptions] = formatDescription(property.description);
const [description, format] = mapDescription(descriptionValue);
return {
...acum,
Expand All @@ -52,6 +52,7 @@ const formatProperties = (properties, options = {}) => {
...(options.notRequiredAsNullable && !isRequired ? {
nullable: true,
} : {}),
...(jsonOptions || {}),
},
};
}, {});
Expand Down
4 changes: 2 additions & 2 deletions transforms/paths/parameters.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ const parseParameter = param => {
}
const isRequired = extraOptions.includes(REQUIRED);
const isDeprecated = extraOptions.includes(DEPRECATED);
const [description, enumValues] = formatDescription(param.description);
const [description, enumValues, jsonOptions] = formatDescription(param.description);
const options = {
name,
in: inOption,
required: isRequired,
deprecated: isDeprecated,
description,
};
const schema = getSchema('@param', param.name)(param.type, enumValues);
const schema = getSchema('@param', param.name)(param.type, enumValues, jsonOptions);
return parameterPayload(options, schema);
};

Expand Down
3 changes: 2 additions & 1 deletion transforms/paths/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const combineSchema = require('../utils/combineSchema');
const addEnumValues = require('../utils/enumValues');
const { refSchema, formatRefSchema } = require('../utils/refSchema');

const getSchema = (entity, message) => (type, enumValues = []) => {
const getSchema = (entity, message) => (type, enumValues = [], jsonOptions = {}) => {
if (!type) {
return errorMessage(`Entity: ${entity} could not be parsed. Value: "${message}" is wrong`);
}
Expand All @@ -16,6 +16,7 @@ const getSchema = (entity, message) => (type, enumValues = []) => {
...schema,
...combineSchema(type.elements),
...addEnumValues(enumValues),
...jsonOptions,
};
const notPrimitiveType = !nameType;
if (notPrimitiveType && !type.elements) {
Expand Down
27 changes: 21 additions & 6 deletions transforms/utils/formatDescription.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
const mapDescription = require('./mapDescription');
const errorMessage = require('./errorMessage');

const ENUM_IDENTIFIER = 'enum:';
const JSON_IDENTIFIER = 'json:';
const DESCRIPTION_DIVIDER = ' - ';

const formatDescription = description => {
const descriptionTypes = mapDescription(description);
const descriptionValue = descriptionTypes.filter(value => (
!value.includes(ENUM_IDENTIFIER)
!value.includes(ENUM_IDENTIFIER) && !value.includes(JSON_IDENTIFIER)
)).join(DESCRIPTION_DIVIDER);
const enumOption = descriptionTypes.find(value => value.includes(ENUM_IDENTIFIER));
if (!enumOption) {
return [descriptionValue];
const jsonOption = descriptionTypes.find(value => value.includes(JSON_IDENTIFIER));
const res = [descriptionValue];
if (enumOption) {
const [, enumOptions] = enumOption.split('enum:');
const enumValues = enumOptions.split(',');
res.push(enumValues);
} else {
res.push(undefined);
}
const [, enumOptions] = enumOption.split('enum:');
const enumValues = enumOptions.split(',');
return [descriptionValue, enumValues];
if (jsonOption) {
try {
const jsonOptions = JSON.parse(jsonOption.slice(JSON_IDENTIFIER.length));
if (typeof jsonOptions !== 'object') { throw new Error('options must be object'); }
res.push(jsonOptions);
} catch (err) {
errorMessage(`json options are malformed: ${err.message}`);
}
}
return res;
};

module.exports = formatDescription;

0 comments on commit f8a39e7

Please sign in to comment.