UNPKG

mongoose-to-swagger

Version:

Conversion library for transforming Mongoose schema objects into Swagger schema definitions.

201 lines 6.96 kB
"use strict"; const bson_1 = require("bson"); const isString = value => typeof value === 'string'; const mapMongooseTypeToSwaggerType = (type) => { if (!type) { return null; } if (type === Number || (isString(type) && type.toLowerCase() === 'number')) { return 'number'; } if (type === String || (isString(type) && type.toLowerCase() === 'string')) { return 'string'; } if (type.schemaName === 'Mixed') { return 'object'; } if (type === 'ObjectId' || type === 'ObjectID') { return 'string'; } if (type === bson_1.ObjectId) { return 'string'; } if (type === Boolean || (isString(type) && type.toLowerCase() === 'boolean')) { return 'boolean'; } if (type === Map) { return 'map'; } if (type instanceof Function) { if (type.name === 'ObjectId' || type.name === 'ObjectID') { return 'string'; } if (type.name === 'Date') { return 'string'; } if (type.name === 'Decimal128') { return 'number'; } return type.name.toLowerCase(); } if (type.type != null) { return mapMongooseTypeToSwaggerType(type.type); } if (type.instance) { switch (type.instance) { case 'Array': case 'DocumentArray': return 'array'; case 'ObjectId': case 'ObjectID': case 'SchemaDate': return 'string'; case 'Mixed': return 'object'; case 'String': case 'SchemaString': case 'SchemaBuffer': case 'SchemaObjectId': return 'string'; case 'SchemaArray': return 'array'; case 'Boolean': case 'SchemaBoolean': return 'boolean'; case 'Number': case 'Decimal128': case 'SchemaNumber': return 'number'; default: } } if (Array.isArray(type)) { return 'array'; } if (type.$schemaType) { return mapMongooseTypeToSwaggerType(type.$schemaType.tree); } if (type.getters && Array.isArray(type.getters) && type.path != null) { return null; } return 'object'; }; const defaultSupportedMetaProps = [ 'enum', 'required', 'description', ]; const mapSchemaTypeToFieldSchema = ({ key = null, value, props, omitFields, }) => { const swaggerType = mapMongooseTypeToSwaggerType(value); const meta = {}; for (const metaProp of props) { if (value && value[metaProp] != null) { meta[metaProp] = value[metaProp]; } } if (value === Date || value.type === Date) { meta.format = 'date-time'; } else if (swaggerType === 'array') { const arraySchema = Array.isArray(value) ? value[0] : value.type[0]; const items = mapSchemaTypeToFieldSchema({ value: arraySchema || {}, props, omitFields }); meta.items = items; } else if (swaggerType === 'object') { let fields = []; if (value && value.constructor && value.constructor.name === 'Schema') { fields = getFieldsFromMongooseSchema(value, { props, omitFields }); } else { const subSchema = value.type ? value.type : value; if (subSchema.obj && Object.keys(subSchema.obj).length > 0) { fields = getFieldsFromMongooseSchema({ tree: subSchema.tree ? subSchema.tree : subSchema }, { props, omitFields }); } else if (subSchema.schemaName !== 'Mixed') { fields = getFieldsFromMongooseSchema({ tree: subSchema.tree ? subSchema.tree : subSchema }, { props, omitFields }); } } const properties = {}; for (const field of fields.filter(f => f.type != null)) { properties[field.field] = field; delete field.field; } meta.properties = properties; } else if (swaggerType === 'map') { const subSchema = mapSchemaTypeToFieldSchema({ value: value.of || {}, props, omitFields }); meta.type = 'object'; meta.additionalProperties = subSchema; } const result = Object.assign({ type: swaggerType }, meta); if (key) { result.field = key; } return result; }; const getFieldsFromMongooseSchema = (schema, options) => { const { props, omitFields, omitMongooseInternals = true } = options; const omitted = new Set([...(omitMongooseInternals ? ['__v', 'id'] : []), ...omitFields || []]); const tree = schema.tree; const keys = Object.keys(schema.tree); const fields = []; for (const key of keys .filter(x => !omitted.has(x))) { const value = tree[key]; const field = mapSchemaTypeToFieldSchema({ key, value, props, omitFields }); const required = []; if (field.type === 'object') { const { field: propName } = field; const fieldProperties = field.properties || field.additionalProperties; for (const f of Object.values(fieldProperties)) { if (f.required && propName != null) { required.push(propName); delete f.required; } } } if (field.type === 'array' && field.items.type === 'object') { field.items.required = []; for (const key in field.items.properties) { const val = field.items.properties[key]; if (val.required) { field.items.required.push(key); delete val.required; } } } fields.push(field); } return fields; }; function documentModel(Model, options = {}) { let { props = [], omitFields = [], omitMongooseInternals = true, } = options; props = [...defaultSupportedMetaProps, ...props]; const removeVirtual = (swaggerFieldSchema) => { return swaggerFieldSchema.type != null; }; const schema = Model.schema; const fields = getFieldsFromMongooseSchema(schema, { props, omitFields, omitMongooseInternals }); const obj = { title: Model.modelName, required: [], properties: {}, }; for (const field of fields.filter(removeVirtual)) { const { field: fieldName } = field; delete field.field; obj.properties[fieldName] = field; if (field.required && fieldName != null) { obj.required.push(fieldName); delete field.required; } } if (!obj.required || !obj.required.length) { delete obj.required; } return obj; } documentModel.adjustType = mapMongooseTypeToSwaggerType; documentModel.getFieldsFromMongooseSchema = getFieldsFromMongooseSchema; module.exports = documentModel; //# sourceMappingURL=index.js.map