UNPKG

skema

Version:

Skema provides a handy & composable way to validate / transform / purify the input data.

205 lines (148 loc) 5.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.factory = void 0; var _skema = require("./skema"); var _future = require("./future"); var _options = require("./options"); var _makeArray = _interopRequireDefault(require("make-array")); var _error = require("./error"); var _util = require("./util"); var _type = require("./type"); var _shape = require("./shape"); var _class; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; } const METHODS = ['type', 'shape', 'objectOf', 'arrayOf', 'any', 'declare']; const REGEX_ENDS_QUESTION_MARK = /\?$/; // Trim and validate type name const parseTypeName = name => { if (!(0, _util.isString)(name) || REGEX_ENDS_QUESTION_MARK.test(name = name.trim())) { throw (0, _error.error)('INVALID_TYPE_NAME', name); } return name; }; const validateTypeName = name => (0, _util.isObject)(name) ? name : parseTypeName(name); // @decorator const memoize = (target, key, descriptor) => { const original = descriptor.value; descriptor.value = function (arg) { const value = this._types.get(arg); if ((0, _util.isDefined)(value)) { return value; } if (Object.keys(arg).length === 0) { throw (0, _error.error)('EMPTY_TYPE'); } const created = original.call(this, arg); this._types.set(arg, created); return created; }; return descriptor; }; let SkemaFactory = (_class = class SkemaFactory { constructor(options) { METHODS.forEach(method => { this[method] = this[method].bind(this); }); const { types = [], ...others } = options; this._options = new _options.Options(others); this._types = new _future.Types(); if (!(0, _util.isArray)(types)) { throw (0, _error.error)('NON_ARRAY_TYPES'); } types.forEach(({ name, definition }) => { this.declare(name, definition); }); } set(...args) { return (0, _shape.set)(...args); } // IPTypeDefinition: {set () {}, type: Skema | StringType} -> Skema // SkemaAlias: string | object // TypeDef: SkemaAlias | IPTypeDefinition | Skema // ShapeDef: {[string]: TypeDef} -> Skema // - ArrayShape: TypeDef[TypeDef] -> Skema // - special: objectOf(TypeDef) -> Skema // - special: arrayOf(TypeDef) -> Skema // Create a single type type(def) { if ((0, _future.isSkema)(def)) { return def; } if ((0, _util.isString)(def)) { return this._stringType(def); } if ((0, _util.isObject)(def)) { return this._type(def); } throw (0, _error.error)('INVALID_TYPE'); } _type(def) { const definition = new _type.TypeDefinition(def); if (definition._type) { definition._type = this.type(definition._type); } return this._create(definition); } shape(shape, clean) { return this._create({ _shape: (0, _util.isArray)(shape) ? new _shape.ArrayShape(this._arrayShape(shape), clean) : new _shape.ObjectShape(this._objectShape(shape), clean) }); } // `objectOf` and `arrayOf` are two special kinds of shapes. // An object with property values of a certain type objectOf(type) { return this._create({ _shape: new _shape.ObjectOfShape(this.type(type)) }); } // An array of a certain type arrayOf(type) { return this._create({ _shape: new _shape.ArrayOfShape(this.type(type)) }); } // Anything that is ok any() { return this._create({ _any: true }); } // Declare a basic type declare(name, definition) { const names = (0, _makeArray.default)(name).map(validateTypeName); const skema = this.type(definition); names.forEach(name => this._types.set(name, skema)); } // 'number' -> Skema _stringType(string) { string = string.trim(); const hasOptionalMark = REGEX_ENDS_QUESTION_MARK.test(string); if (hasOptionalMark) { // 'number?' -> 'number' // 'number ?' -> 'number' string = string.slice(0, string.length - 1).trimRight(); } const skema = this._types.get(string, true); return hasOptionalMark ? skema.isOptional() ? skema : this.type({ type: skema, optional: true }) : skema; } _arrayShape(array) { return array.map(type => this.type(type)); } _objectShape(shape) { const skemaMap = {}; Object.keys(shape).forEach(key => { skemaMap[key] = this.type(shape[key]); }); return skemaMap; } _create(definition) { definition._options = this._options; return new _skema.Skema(definition); } }, (_applyDecoratedDescriptor(_class.prototype, "_type", [memoize], Object.getOwnPropertyDescriptor(_class.prototype, "_type"), _class.prototype)), _class); const factory = (options = {}) => new SkemaFactory(options); exports.factory = factory;