skema
Version:
Skema provides a handy & composable way to validate / transform / purify the input data.
205 lines (148 loc) • 5.57 kB
JavaScript
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;
;