functions/schema-type-and-format.js (75 lines of code) (raw):

// Check that format is valid for a schema type. // Valid formats are those defined in the OpenAPI spec and extensions in autorest. // - https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#data-types // - https://github.com/Azure/autorest/blob/main/packages/libs/openapi/src/v3/formats.ts // `input` is the schema of a request or response body module.exports = function checkTypeAndFormat(schema, options, { path }) { if (schema === null || typeof schema !== 'object') { return []; } const errors = []; const stringFormats = [ // OAS-defined formats 'byte', 'binary', 'date', 'date-time', 'password', // Additional formats recognized by autorest 'char', 'time', 'date-time-rfc1123', 'duration', 'uuid', 'base64url', 'url', 'uri', 'odata-query', 'certificate', ]; if (schema.type === 'string') { if (schema.format) { if (!stringFormats.includes(schema.format)) { errors.push({ message: `Schema with type: string has unrecognized format: ${schema.format}`, path: [...path, 'format'], }); } } } else if (schema.type === 'integer') { if (schema.format) { if (!['int32', 'int64', 'unixtime'].includes(schema.format)) { errors.push({ message: `Schema with type: integer has unrecognized format: ${schema.format}`, path: [...path, 'format'], }); } } else { errors.push({ message: 'Schema with type: integer should specify format', path, }); } } else if (schema.type === 'number') { if (schema.format) { if (!['float', 'double', 'decimal'].includes(schema.format)) { errors.push({ message: `Schema with type: number has unrecognized format: ${schema.format}`, path: [...path, 'format'], }); } } else { errors.push({ message: 'Schema with type: number should specify format', path, }); } } else if (schema.type === 'boolean') { if (schema.format) { errors.push({ message: 'Schema with type: boolean should not specify format', path: [...path, 'format'], }); } } else if (schema.properties && typeof schema.properties === 'object') { // eslint-disable-next-line no-restricted-syntax for (const [key, value] of Object.entries(schema.properties)) { errors.push( ...checkTypeAndFormat(value, options, { path: [...path, 'properties', key] }), ); } } if (schema.type === 'array') { errors.push( ...checkTypeAndFormat(schema.items, options, { path: [...path, 'items'] }), ); } if (schema.allOf && Array.isArray(schema.allOf)) { // eslint-disable-next-line no-restricted-syntax for (const [index, value] of schema.allOf.entries()) { errors.push( ...checkTypeAndFormat(value, options, { path: [...path, 'allOf', index] }), ); } } return errors; };