UNPKG

ottoman

Version:
253 lines 8.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mergeHooks = exports.addValidators = exports.registerType = exports.applyDefaultValue = exports.validate = exports.buildFields = void 0; const utils_1 = require("../../utils"); const errors_1 = require("../errors"); const schema_1 = require("../schema"); const types_1 = require("../types"); const cast_strategy_1 = require("../../utils/cast-strategy"); /** * Build the fields using the given definition. * If the [[obj]] is a schema instance, the data will be taken from the fields provided. * @function * @public * * @param {Schema|Object} obj the definition or schema instance * @param strict will drop all properties not defined in the schema * @returns {FieldMap} * @throws {Error} * * @example * ```ts * const fields = buildFields({ name: String, hasChild: { type: Boolean, default: true } }); * ``` */ const buildFields = (obj, strict = true) => { if (obj instanceof schema_1.Schema) { return obj.fields; } const fields = {}; const keys = Object.keys(obj); for (const _key of keys) { const opts = obj[_key] !== undefined && obj[_key] !== null ? _parseType(obj[_key], strict) : { type: false }; if (!opts.type) { throw new errors_1.BuildSchemaError(`Property '${_key}' is a required type`); } fields[_key] = _makeField(_key, opts, obj[_key]); } return fields; }; exports.buildFields = buildFields; /** * Parse the definition of a field in the schema to identify its type. * @function * @private * @param value that is going to parsed * @param strict Schema Validation Strategy Strict * @throws BuildSchemaError */ const _parseType = (value, strict = true) => { if (value instanceof schema_1.Schema) { return _makeParseResult('Embed', value); } else if ((0, utils_1.is)(value, Array)) { return _makeParseResult(Array.name, _makeField('', _parseType(value[0], strict))); } else if (value instanceof types_1.CoreType || (0, utils_1.isSchemaFactoryType)(value, schema_1.Schema.FactoryTypes)) { return _makeParseResult(_getFieldType(value), {}); } else if ((0, utils_1.is)(value, Object)) { if (Object.keys(value).length === 0) { return _makeParseResult('Mixed', value); } else if (value.ref) { const options = { schema: new schema_1.Schema(value.type, { strict }), refModel: value.ref, }; return _makeParseResult('Reference', options); } else if (typeof value.type !== 'undefined') { if ((0, utils_1.is)(value.type, Array)) { return _makeParseResult(Array.name, _makeField('', _parseType(value.type[0], strict))); } return Object.assign(Object.assign({}, _parseType(value.type, strict)), { options: value }); } else { return _makeParseResult('Embed', new schema_1.Schema(value, { strict })); } } else { return _makeParseResult('Unknown', value); } }; /** * Create the structure of schema object. * @private * @param type of the field * @param options of the schema * */ const _makeParseResult = (type, options) => { return { type, options }; }; /** * Get the String type of a field. * @private * @param type of the field * */ const _getFieldType = (type) => { return type ? type.name || type.constructor['sName'] || undefined : undefined; }; /** * Make a field using its definition, throw a [[BuildSchemaError]] if the type is not supported. * @private * @param name of the field * @param def result of parsing the field schema * @throws BuildSchemaError */ const _makeField = (name, def, arrayOptions) => { const typeFactory = schema_1.Schema.FactoryTypes[String(def.type)]; if (typeFactory === undefined) { throw new errors_1.BuildSchemaError(`Unsupported type specified in the property '${name}'`); } if (arrayOptions !== undefined) { return typeFactory(name, def.options, arrayOptions); } return typeFactory(name, def.options); }; /** * Validate data using the schema definition. * @param data that is going to be validated * @param schema that will be used to validate * @param options * @throws BuildSchemaError, ValidationError * @example * ```ts * const data = { * name: "John", * age: "50" * }; * const schema = new Schema({ * name: String, * age: {type: Number, intVal: true} * }); * const strictSchema = new Schema({ * name: String, * age: {type: Number, intVal: true} * }, * { * validationStrategy: VALIDATION_STRATEGY.STRICT * }); * console.log(castSchema(data, schema)); // Print { name: "John", age: 50 } * console.log(castSchema(data, strictSchema)); // Throw "Property age must be of type Number" * ``` */ const validate = (data, schema, options = { strategy: cast_strategy_1.CAST_STRATEGY.THROW, strict: true, skip: [], }) => { const _schema = schema instanceof schema_1.Schema ? schema : new schema_1.Schema(schema); const _data = (0, cast_strategy_1.cast)(data, _schema, options); const skip = options.skip || []; const errors = []; for (const key in _schema.fields) { const type = _schema.fields[key]; if (!skip.includes(type.name)) { try { const value = _data[type.name]; type.validate(value, options.strict); } catch (e) { errors.push(e.message); } } } if (errors.length > 0) { throw new errors_1.ValidationError(errors.join(', ')); } return _data; }; exports.validate = validate; /** * Apply default values defined on schema to an object instance. * @param obj reference to object instance * @param schema definition will be used to determine default definitions * * @example * ```ts * const schema = { name: { type: String, default: 'John' }, hasChild: { type: Boolean, default: true } }; * const obj: any = applyDefaultValue(obj, schema) * * console.log(obj); * ``` */ const applyDefaultValue = (obj, schema) => { const _schema = schema instanceof schema_1.Schema ? schema : new schema_1.Schema(schema); return _schema.applyDefaultsToObject(obj); }; exports.applyDefaultValue = applyDefaultValue; /** * Register a custom type to Schema supported types. * @function * @param name * @param factory * @throws Error * @example * ```ts * registerType(Int8.name, (fieldName, opts) => new Int8(fieldName, opts.required)); * ``` */ const registerType = (name, factory) => { if (schema_1.Schema.FactoryTypes[name] !== undefined) { throw new errors_1.ValidationError(`A type with name '${name}' has already been registered`); } schema_1.Schema.FactoryTypes[name] = factory; }; exports.registerType = registerType; /** * Register custom validators to Schema validators register. * @function * @param validators * @throws Error * @example * ```ts * addValidators({ * email: (value) => { * regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/); * if (!regexp.test(value)) { * throw new Error('Email address is invalid.') * } * } * }); * * const ContactSchema = new Schema({ * name: String, * contact: { type: String, validator: 'email' } * }); * ``` */ const addValidators = (validators) => { if (!(0, utils_1.is)(validators, Object)) { throw new errors_1.BuildSchemaError('Validators must be an object.'); } for (const prop in validators) { const validator = validators[prop]; if (typeof validator !== 'function') { throw new errors_1.BuildSchemaError('Validator object properties must be functions.'); } schema_1.Schema.validators[prop] = validator; } }; exports.addValidators = addValidators; const mergeHooks = (hook, other) => { const _hook = Object.assign({}, hook); Object.keys(_hook).forEach((value) => { if (other.hasOwnProperty(value)) { _hook[value] = [..._hook[value], ...other[value]]; } }); return _hook; }; exports.mergeHooks = mergeHooks; //# sourceMappingURL=fn-schema.js.map