UNPKG

@microfleet/core

Version:
131 lines (109 loc) 3.84 kB
import MicrofleetValidator from '@microfleet/validation' import ajv from 'ajv' import callsite = require('callsite') import { NotPermittedError } from 'common-errors' import path = require('path') import { strictEqual } from 'assert' import { isString, isPlainObject, isFunction } from 'lodash' import { deprecate } from 'util' import { Microfleet } from '../' import { PluginTypes } from '../constants' const { isArray } = Array type Validator = MicrofleetValidator & { addLocation(location: string): void; } /** * Validator configuration, more details in * https://github.com/microfleet/validation */ export type ValidatorConfig = { schemas: string[]; filter: ((filename: string) => boolean) | null; serviceConfigSchemaIds: string[]; ajv: ajv.Options; } /** * Plugin name */ export const name = 'validator' /** * Defines service extension */ export interface ValidatorPlugin { validator: Validator & { addLocation(location: string): void; }; validate: Validator['validate']; validateSync: Validator['validateSync']; ifError: Validator['ifError']; } /** * Plugin Type */ export const type = PluginTypes.essential /** * Relative priority inside the same plugin group type */ export const priority = 0 function configError(property: string): NotPermittedError { return new NotPermittedError(`Invalid validator.${property} config`) } /** * Attaches initialized validator based on conf. * Provides `validate` and `validateSync` methods. * @param conf - Validator Configuration Object. * @param parentFile - From which file this plugin was invoked. */ export const attach = function attachValidator( this: Microfleet, config: ValidatorConfig, parentFile: string ): void { // for relative paths const stack = callsite() const { schemas, serviceConfigSchemaIds, filter, ajv: ajvConfig } = config strictEqual(isArray(schemas), true, configError('schemas')) strictEqual(isArray(serviceConfigSchemaIds), true, configError('serviceConfigSchemaIds')) strictEqual(filter === null || isFunction(filter), true, configError('filter')) strictEqual(isPlainObject(ajvConfig), true, configError('ajvConfig')) const validator = new MicrofleetValidator('../../schemas', filter, ajvConfig) const addLocation = (location: string): void => { strictEqual(isString(location) && location.length !== 0, true, configError('schemas')) let dir if (!path.isAbsolute(location)) { const { length } = stack // filter out the file itself let iterator = 0 let source = '' while (iterator < length && !source) { const call = stack[iterator] const filename = call.getFileName() if ([parentFile, __filename, 'native array.js', null].indexOf(filename) === -1) { source = path.dirname(filename) } iterator += 1 } dir = path.resolve(source, location) } else { dir = location } validator.init(dir) } // Note that schemas with same file name will be overwritten for (const location of schemas) { addLocation(location) } // built-in configuration schema for (const schema of serviceConfigSchemaIds) { strictEqual(isString(schema) && schema.length !== 0, true, configError('serviceConfigSchemaIds')) if (validator.ajv.getSchema(schema)) { this.config = validator.ifError(schema, this.config) } } // extend service this[name] = validator this[name].addLocation = addLocation this.validate = deprecate(validator.validate.bind(validator), 'validate() deprecated. User validator.validate()') this.validateSync = deprecate(validator.validateSync.bind(validator), 'validateSync() deprecated. User validator.validateSync()') this.ifError = deprecate(validator.ifError.bind(validator), 'ifError() deprecated. User validator.ifError()') }