validate-rc
Version:
Validate config files following user-defined rules.
234 lines (233 loc) • 7.82 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var _a;
exports.__esModule = true;
exports.Any = exports.Choice = exports.Optional = exports.ValidationError = void 0;
// custom constructor overrides
var overrides = (_a = {},
// @ts-ignore
_a[Number] = /** @class */ (function () {
function class_1(num) {
this.num = num;
if (isNaN(this.num) || (this.num === true || this.num === false)) {
// is not a number so we throw
// it doesn't matter wht we write inside the error
throw new ValidationError('Number', this.num.constructor.name);
}
}
return class_1;
}()),
// @ts-ignore
_a[String] = /** @class */ (function () {
function class_2(str) {
this.str = str;
if (typeof this.str !== 'string') {
throw new ValidationError('String', this.str.constructor.name);
}
}
return class_2;
}()),
// @ts-ignore
_a[Boolean] = /** @class */ (function () {
function class_3(bool) {
this.bool = bool;
if (this.bool !== true && this.bool !== false) {
throw new ValidationError('Boolean', this.bool.constructor.name);
}
}
return class_3;
}()),
// @ts-ignore
_a[Array] = /** @class */ (function () {
function class_4(arr) {
this.arr = arr;
if (!Array.isArray(this.arr)) {
throw new ValidationError('Array', this.arr.constructor.name);
}
}
return class_4;
}()),
// @ts-ignore
_a[Object] = /** @class */ (function () {
function class_5(obj) {
this.obj = obj;
if (!isObject(this.obj)) {
throw new ValidationError('Object', this.obj.constructor.name);
}
}
return class_5;
}()),
// @ts-ignore
_a[Function] = /** @class */ (function () {
function class_6(fn) {
this.fn = fn;
if (typeof this.fn !== 'function') {
throw new ValidationError('Function', this.fn.constructor.name);
}
}
return class_6;
}()),
_a);
/**
* Checks if something is an object
* @param obj The object to check
*/
function isObject(obj) {
return !!obj && obj.constructor === Object;
}
var ValidationError = /** @class */ (function (_super) {
__extends(ValidationError, _super);
function ValidationError(expects, got) {
var _this = _super.call(this, 'Please handle this error, for more information: https://github.com/noname890/validate-rc') || this;
_this.expects = expects;
_this.got = got;
_this.name = 'ValidationError';
_this.VALIDATION_ERROR = true;
return _this;
}
return ValidationError;
}(Error));
exports.ValidationError = ValidationError;
/**
* Creates an entirely optional branch in the RC
* @param rules The Rules of the config
* @example
* const rules = {
* address: Optional(String)
* }
*
* validateRc(rules, {}) // => true
* validateRc(rules, { address: 'Foo Bar street' }) // => true
* validateRc(rules, { address: 1 }) // => throws, because `address` is specified, but it is not a `String`
*/
function Optional(rules) {
return /** @class */ (function () {
function class_7(rc) {
this.rc = rc;
try {
if (typeof rules !== 'object') {
// rules is not an object, so to pass it to validateRc
// we have to create a fake object
var fakeRule = { RULE: rules };
var fakeRc = { RULE: this.rc };
if (this.rc) {
validateRc(fakeRule, fakeRc);
}
}
else {
if (this.rc) {
validateRc(rules, this.rc);
}
}
}
catch (e) {
if (e.VALIDATION_ERROR) {
throw new ValidationError(rules ? rules.constructor.name : 'undefined', e.got);
}
throw e;
}
}
return class_7;
}());
}
exports.Optional = Optional;
/**
* Expects a value that is in choices, otherwise throws
* @param choiches The avaliable choices
* @example
* const rules = {
* os: Choice('linux', 'macos', 'windows')
* }
*
* validateRc(rules, { os: 'linux' }) // => true
* validateRc(rules, { os: 'macos' }) // => true
* validateRc(rules, { os: 'windows' }) // => true
* validateRc(rules, { os: 'freebsd' }) // => throws, because `freebsd` isn't in `Choice`
*/
function Choice() {
var choiches = [];
for (var _i = 0; _i < arguments.length; _i++) {
choiches[_i] = arguments[_i];
}
return /** @class */ (function () {
function class_8(rc) {
this.rc = rc;
if (!choiches.includes(this.rc)) {
throw new ValidationError(choiches.map(function (val) { return "'" + val + "'"; }).join(', '), "'" + this.rc + "'");
}
}
return class_8;
}());
}
exports.Choice = Choice;
/**
* Class that doesn't throw, so it matches everything
* @example
* const rules = {
* custom: Any
* }
* validateRc(rules, {}) // => true
* validateRc(rules, { custom: 42 }) // => true
* validateRc(rules, { custom: 'string' }) // => true
* validateRc(rules, { custom: [ 'array', 'of', 'strings' ] }) // => true
* validateRc(rules, { custom: { objects: true } }) // => true
* validateRc(rules, { custom: _ => _ }) // => true
*/
var Any = /** @class */ (function () {
function Any() {
}
return Any;
}());
exports.Any = Any;
/**
* Validates a config file, returns true if it follows `rules`
* @param rules The rules of the config file
* @param rc The config file
* @example
* import validateRc, { Optional } from 'validateRc'
*
* // the rules that the config should follow
* const rules = {
* name: String,
* age: Number,
* // Optional() will not throw if it is `undefined` in the config,
* // but it will throw if it is present in the config and doesn't follow
* // the rules
* hobbies: Optional(Array)
* }
*
* // pass the rules and the rc
* validateRc(rules, { name: 'Michael', age: 27 }) // => true
* validateRc(rules, { name: 'Michael', age: 27, hobbies: [ 'Sport', 'Climbing' ] }) // => true
* validateRc(rules, { name: 'Michael', age: NaN, hobbies: [ 'Sport', 'Climbing' ] }) // => throws, because age is NaN
* validateRc(rules, { name: 'Michael', age: 27, hobbies: 'Sport' }) // => throws, because `hobbies` is present and isn't an `Array`
*/
function validateRc(rules, rc) {
for (var i in rules) {
if (overrides[rules[i]]) {
// validate, `rules[i]` can be any constructor, even a user-defined one
new overrides[rules[i]](rc[i]);
}
else if (typeof rules[i] === 'object' && !Array.isArray(rules[i])) {
validateRc(rules[i], rc[i]);
}
else {
new rules[i](rc[i]);
}
}
return true;
}
exports["default"] = validateRc;
validateRc({ bruh: String }, { bruh: 42 });