UNPKG

validate-rc

Version:

Validate config files following user-defined rules.

234 lines (233 loc) 7.82 kB
"use strict"; 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 });