jaywalk
Version:
Runtime type validation
184 lines • 7.46 kB
JavaScript
;
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var extend = require('xtend');
var Promise = require('any-promise');
var any_1 = require('./any');
var intersection_1 = require('./intersection');
var promises_1 = require('../support/promises');
var utils_1 = require('../utils');
var Object = (function (_super) {
__extends(Object, _super);
function Object(options) {
_super.call(this, options);
this.type = 'Object';
this.properties = {};
this.propertyTypes = [];
if (options.minKeys != null) {
this.minKeys = options.minKeys;
}
if (options.maxKeys != null) {
this.maxKeys = options.maxKeys;
}
if (options.properties != null) {
this.properties = options.properties;
}
if (options.propertyTypes != null) {
this.propertyTypes = options.propertyTypes;
}
this._tests.push(isObject);
this._tests.push(toPropertiesTest(this.properties, this.propertyTypes));
this._tests.push(toMinKeysTest(this.minKeys));
this._tests.push(toMaxKeysTest(this.minKeys));
}
Object.prototype._isType = function (value, path, context) {
var _this = this;
return utils_1.wrapIsType(this, value, path, context, _super.prototype._isType, function (value) {
if (typeof value !== 'object') {
throw context.error(path, 'Object', 'type', 'Object', value);
}
var res = 1;
var keys = global.Object.keys(value);
for (var _i = 0, _a = global.Object.keys(_this.properties); _i < _a.length; _i++) {
var key = _a[_i];
res += _this.properties[key]._isType(value[key], path.concat(key), context);
}
for (var _b = 0, keys_1 = keys; _b < keys_1.length; _b++) {
var key = keys_1[_b];
var keyPath = path.concat(key);
for (var _c = 0, _d = _this.propertyTypes; _c < _d.length; _c++) {
var _e = _d[_c], keyType = _e[0], valueType = _e[1];
if (utils_1.isType(keyType, key, keyPath, context)) {
res += valueType._isType(value[key], keyPath, context);
}
}
}
return res;
});
};
Object.prototype._extend = function (options) {
var result = _super.prototype._extend.call(this, options);
if (options.properties) {
result.properties = extend(this.properties);
for (var _i = 0, _a = global.Object.keys(options.properties); _i < _a.length; _i++) {
var key = _a[_i];
result.properties[key] = intersection_1.Intersection.intersect(this.properties[key], options.properties[key]);
}
}
if (options.propertyTypes) {
result.propertyTypes = this.propertyTypes.concat(options.propertyTypes);
}
return result;
};
return Object;
}(any_1.Any));
exports.Object = Object;
function isObject(value, path, context, next) {
if (typeof value !== 'object') {
throw context.error(path, 'Object', 'type', 'Object', value);
}
return next(value);
}
function toPropertiesTest(properties, propertyTypes) {
var propertyTypeTests = propertyTypes
.map(function (pair) {
var keyType = pair[0], valueType = pair[1];
return [keyType, keyType._compile(), valueType._compile()];
});
var propertyTests = global.Object.keys(properties)
.map(function (key) {
return [key, properties[key]._compile()];
});
return function (object, path, context, next) {
var keys = global.Object.keys(object);
var testMap = {};
var _loop_1 = function(key, test) {
pushKey(testMap, key, function (path, _a) {
var key = _a[0], value = _a[1];
return test(value, path, context, utils_1.identity).then(function (value) { return [key, value]; });
});
};
for (var _i = 0, propertyTests_1 = propertyTests; _i < propertyTests_1.length; _i++) {
var _a = propertyTests_1[_i], key = _a[0], test = _a[1];
_loop_1(key, test);
}
var _loop_2 = function(key) {
var keyPath = path.concat(key);
var _loop_3 = function(keyType, keyTest, valueTest) {
if (utils_1.isType(keyType, key, keyPath, context)) {
pushKey(testMap, key, function (path, _a) {
var key = _a[0], value = _a[1];
return promises_1.promiseEvery([
function () { return keyTest(key, keyPath, context, utils_1.identity); },
function () { return valueTest(value, keyPath, context, utils_1.identity); }
]);
});
}
};
for (var _b = 0, propertyTypeTests_1 = propertyTypeTests; _b < propertyTypeTests_1.length; _b++) {
var _c = propertyTypeTests_1[_b], keyType = _c[0], keyTest = _c[1], valueTest = _c[2];
_loop_3(keyType, keyTest, valueTest);
}
};
for (var _d = 0, keys_2 = keys; _d < keys_2.length; _d++) {
var key = keys_2[_d];
_loop_2(key);
}
var exec = global.Object.keys(testMap).map(function (key) {
var tests = testMap[key];
var value = object[key];
var testPath = path.concat(key);
return function () {
return tests.reduce(function (res, test) {
return res.then(function (out) { return test(testPath, out); });
}, Promise.resolve([key, value]));
};
});
return promises_1.promiseEvery(exec).then(pairs).then(function (res) { return next(res); });
};
}
function pairs(pairs) {
var result = {};
for (var _i = 0, pairs_1 = pairs; _i < pairs_1.length; _i++) {
var _a = pairs_1[_i], key = _a[0], value = _a[1];
if (typeof value !== 'undefined') {
result[key] = value;
}
}
return result;
}
function pushKey(obj, key, value) {
obj[key] = obj[key] || [];
obj[key].push(value);
return obj;
}
function toMinKeysTest(minKeys) {
if (minKeys == null) {
return utils_1.toNext;
}
var minKeysValue = utils_1.toValue(minKeys);
return function (value, path, context, next) {
var minKeys = minKeysValue(path, context);
if (global.Object.keys(value).length < minKeys) {
throw context.error(path, 'Object', 'minKeys', minKeys, value);
}
return next(value);
};
}
function toMaxKeysTest(maxKeys) {
if (maxKeys == null) {
return utils_1.toNext;
}
var maxKeysValue = utils_1.toValue(maxKeys);
return function (value, path, context, next) {
var maxKeys = maxKeysValue(path, context);
if (global.Object.keys(value).length > maxKeys) {
throw context.error(path, 'Object', 'maxKeys', maxKeys, value);
}
return next(value);
};
}
//# sourceMappingURL=object.js.map