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
						
					
					
				'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
 | 
						|
}
 |