You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					128 lines
				
				3.5 KiB
			
		
		
			
		
	
	
					128 lines
				
				3.5 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fastClone = require('rfdc')({ circles: false, proto: true })
							 | 
						||
| 
								 | 
							
								const { kSchemaVisited } = require('./symbols')
							 | 
						||
| 
								 | 
							
								const kFluentSchema = Symbol.for('fluent-schema-object')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  FST_ERR_SCH_MISSING_ID,
							 | 
						||
| 
								 | 
							
								  FST_ERR_SCH_ALREADY_PRESENT,
							 | 
						||
| 
								 | 
							
								  FST_ERR_SCH_DUPLICATE
							 | 
						||
| 
								 | 
							
								} = require('./errors')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const SCHEMAS_SOURCE = ['params', 'body', 'querystring', 'query', 'headers']
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function Schemas (initStore) {
							 | 
						||
| 
								 | 
							
								  this.store = initStore || {}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Schemas.prototype.add = function (inputSchema) {
							 | 
						||
| 
								 | 
							
								  const schema = fastClone((inputSchema.isFluentSchema || inputSchema.isFluentJSONSchema || inputSchema[kFluentSchema])
							 | 
						||
| 
								 | 
							
								    ? inputSchema.valueOf()
							 | 
						||
| 
								 | 
							
								    : inputSchema
							 | 
						||
| 
								 | 
							
								  )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // devs can add schemas without $id, but with $def instead
							 | 
						||
| 
								 | 
							
								  const id = schema.$id
							 | 
						||
| 
								 | 
							
								  if (!id) {
							 | 
						||
| 
								 | 
							
								    throw new FST_ERR_SCH_MISSING_ID()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.store[id]) {
							 | 
						||
| 
								 | 
							
								    throw new FST_ERR_SCH_ALREADY_PRESENT(id)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.store[id] = schema
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Schemas.prototype.getSchemas = function () {
							 | 
						||
| 
								 | 
							
								  return Object.assign({}, this.store)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Schemas.prototype.getSchema = function (schemaId) {
							 | 
						||
| 
								 | 
							
								  return this.store[schemaId]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function normalizeSchema (routeSchemas, serverOptions) {
							 | 
						||
| 
								 | 
							
								  if (routeSchemas[kSchemaVisited]) {
							 | 
						||
| 
								 | 
							
								    return routeSchemas
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // alias query to querystring schema
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.query) {
							 | 
						||
| 
								 | 
							
								    // check if our schema has both querystring and query
							 | 
						||
| 
								 | 
							
								    if (routeSchemas.querystring) {
							 | 
						||
| 
								 | 
							
								      throw new FST_ERR_SCH_DUPLICATE('querystring')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    routeSchemas.querystring = routeSchemas.query
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  generateFluentSchema(routeSchemas)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // let's check if our schemas have a custom prototype
							 | 
						||
| 
								 | 
							
								  for (const key of ['headers', 'querystring', 'params', 'body']) {
							 | 
						||
| 
								 | 
							
								    if (typeof routeSchemas[key] === 'object' && Object.getPrototypeOf(routeSchemas[key]) !== Object.prototype) {
							 | 
						||
| 
								 | 
							
								      return routeSchemas
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.body) {
							 | 
						||
| 
								 | 
							
								    routeSchemas.body = getSchemaAnyway(routeSchemas.body, serverOptions.jsonShorthand)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.headers) {
							 | 
						||
| 
								 | 
							
								    routeSchemas.headers = getSchemaAnyway(routeSchemas.headers, serverOptions.jsonShorthand)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.querystring) {
							 | 
						||
| 
								 | 
							
								    routeSchemas.querystring = getSchemaAnyway(routeSchemas.querystring, serverOptions.jsonShorthand)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.params) {
							 | 
						||
| 
								 | 
							
								    routeSchemas.params = getSchemaAnyway(routeSchemas.params, serverOptions.jsonShorthand)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (routeSchemas.response) {
							 | 
						||
| 
								 | 
							
								    const httpCodes = Object.keys(routeSchemas.response)
							 | 
						||
| 
								 | 
							
								    for (const code of httpCodes) {
							 | 
						||
| 
								 | 
							
								      routeSchemas.response[code] = getSchemaAnyway(routeSchemas.response[code], serverOptions.jsonShorthand)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  routeSchemas[kSchemaVisited] = true
							 | 
						||
| 
								 | 
							
								  return routeSchemas
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function generateFluentSchema (schema) {
							 | 
						||
| 
								 | 
							
								  for (const key of SCHEMAS_SOURCE) {
							 | 
						||
| 
								 | 
							
								    if (schema[key] && (schema[key].isFluentSchema || schema[key][kFluentSchema])) {
							 | 
						||
| 
								 | 
							
								      schema[key] = schema[key].valueOf()
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (schema.response) {
							 | 
						||
| 
								 | 
							
								    const httpCodes = Object.keys(schema.response)
							 | 
						||
| 
								 | 
							
								    for (const code of httpCodes) {
							 | 
						||
| 
								 | 
							
								      if (schema.response[code].isFluentSchema || schema.response[code][kFluentSchema]) {
							 | 
						||
| 
								 | 
							
								        schema.response[code] = schema.response[code].valueOf()
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getSchemaAnyway (schema, jsonShorthand) {
							 | 
						||
| 
								 | 
							
								  if (!jsonShorthand || schema.$ref || schema.oneOf || schema.allOf || schema.anyOf || schema.$merge || schema.$patch) return schema
							 | 
						||
| 
								 | 
							
								  if (!schema.type && !schema.properties) {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      type: 'object',
							 | 
						||
| 
								 | 
							
								      properties: schema
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return schema
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
								  buildSchemas (initStore) { return new Schemas(initStore) },
							 | 
						||
| 
								 | 
							
								  normalizeSchema
							 | 
						||
| 
								 | 
							
								}
							 |