UNPKG

iface-js

Version:
458 lines (389 loc) 15.9 kB
'use strict'; var _bind = Function.prototype.bind; var _get = function get(_x4, _x5, _x6) { var _again = true; _function: while (_again) { var object = _x4, property = _x5, receiver = _x6; desc = parent = getter = undefined; _again = false; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x4 = parent; _x5 = property; _x6 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var Iface = (function () { function Iface() { _classCallCheck(this, Iface); } _createClass(Iface, null, [{ key: 'register', value: function register(Sig, args) { var key = args[0]; if (!key) throw new Error('Missing iface key'); if (!(Sig.prototype instanceof Iface)) throw new Error('Expected Iface subclass'); if (Iface.registered[key]) throw new Error('Another iface is already registered with key ' + key); Iface.registered[key] = [Sig, args]; } }]); return Iface; })(); Iface.registered = {}; var LiteralIface = (function (_Iface) { function LiteralIface(val, eq) { _classCallCheck(this, LiteralIface); _get(Object.getPrototypeOf(LiteralIface.prototype), 'constructor', this).call(this); this.depth = 1; this.val = val; if (eq instanceof Function) { this.eq = eq; this.match = this.matchCustom; } } _inherits(LiteralIface, _Iface); _createClass(LiteralIface, [{ key: 'match', value: function match(val) { return this.val === val; } }, { key: 'matchCustom', value: function matchCustom(val) { return this.eq(this.val, val); } }, { key: 'toString', value: function toString() { return '(LiteralIface: ' + this.val + ')'; } }]); return LiteralIface; })(Iface); var ConstructorIface = (function (_Iface2) { function ConstructorIface(constr) { _classCallCheck(this, ConstructorIface); if (!(constr instanceof Function)) throw new Error('Function expected for ConstructorIface'); _get(Object.getPrototypeOf(ConstructorIface.prototype), 'constructor', this).call(this); this.constr = constr; this.depth = 1; if (constr === Number) this.match = this.matchNumber; if (constr === String) this.match = this.matchString; } _inherits(ConstructorIface, _Iface2); _createClass(ConstructorIface, [{ key: 'match', value: function match(val) { return val instanceof this.constr; } }, { key: 'matchNumber', value: function matchNumber(val) { return typeof val === 'number'; } }, { key: 'matchString', value: function matchString(val) { return typeof val === 'string'; } }, { key: 'toString', value: function toString() { return '(ConstructorIface: ' + (this.constr.name || 'Unnamed') + ')'; } }]); return ConstructorIface; })(Iface); var PrototypeIface = (function (_Iface3) { function PrototypeIface(proto) { _classCallCheck(this, PrototypeIface); if (proto == null || typeof proto !== 'object') throw new Error('Object expected for PrototypeIface'); _get(Object.getPrototypeOf(PrototypeIface.prototype), 'constructor', this).call(this); this.proto = proto; this.depth = 1; if (proto === Number.prototype) this.match = this.matchNumber; if (proto === String.prototype) this.match = this.matchString; } _inherits(PrototypeIface, _Iface3); _createClass(PrototypeIface, [{ key: 'match', value: function match(val) { return this.proto.isPrototypeOf(val); } }, { key: 'matchNumber', value: function matchNumber(val) { return typeof val === 'number'; } }, { key: 'matchString', value: function matchString(val) { return typeof val === 'string'; } }, { key: 'toString', value: function toString() { var contents = Object.keys(this.proto).join(', '); return '(PrototypeIface: {' + contents + '})'; } }]); return PrototypeIface; })(Iface); var RecordIface = (function (_Iface4) { function RecordIface(spec, strict) { var _this = this; _classCallCheck(this, RecordIface); if (spec == null || typeof spec !== 'object') throw new Error('Expected object as RecordIface struct'); _get(Object.getPrototypeOf(RecordIface.prototype), 'constructor', this).call(this); this.struct = {}; this.keys = []; this.strict = strict; for (var key in spec) { this.struct[key] = iface(spec[key]); this.keys.push(key); } this.depth = 1 + this.keys.reduce(function (max, key) { return Math.max(max, _this.struct[key].depth); }, 0); } _inherits(RecordIface, _Iface4); _createClass(RecordIface, [{ key: 'match', value: function match(val) { if (val == null) return false; if (this.strict && Object.keys(val).length !== this.keys.length) return false; for (var i = 0; i < this.keys.length; i++) { var key = this.keys[i]; if (!this.struct[key].match(val[key])) return false; } return true; } }, { key: 'toString', value: function toString() { var _this2 = this; var contents = this.keys.map(function (key) { return '' + key + ': ' + _this2.struct[key]; }).join(', '); return '(RecordIface: {' + contents + '})'; } }]); return RecordIface; })(Iface); var MapIface = (function (_Iface5) { function MapIface(spec) { _classCallCheck(this, MapIface); _get(Object.getPrototypeOf(MapIface.prototype), 'constructor', this).call(this); this.prop = iface(spec); this.depth = this.prop.depth + 1; } _inherits(MapIface, _Iface5); _createClass(MapIface, [{ key: 'match', value: function match(val) { if (val == null) return false; for (var key in val) { if (!this.prop.match(val[key])) return false; } return true; } }, { key: 'toString', value: function toString() { return '(MapIface: ' + this.prop + ')'; } }]); return MapIface; })(Iface); var ArrayIface = (function (_Iface6) { function ArrayIface(spec) { _classCallCheck(this, ArrayIface); _get(Object.getPrototypeOf(ArrayIface.prototype), 'constructor', this).call(this); this.elem = iface(spec); this.depth = this.elem.depth + 1; } _inherits(ArrayIface, _Iface6); _createClass(ArrayIface, [{ key: 'match', value: function match(val) { if (!(val instanceof Array)) return false; for (var i = 0; i < val.length; i++) { if (!this.elem.match(val[i])) return false; } return true; } }, { key: 'toString', value: function toString() { return '(ArrayIface: ' + this.elem + ')'; } }]); return ArrayIface; })(Iface); var TupleIface = (function (_Iface7) { function TupleIface(spec) { var strict = arguments[1] === undefined ? false : arguments[1]; _classCallCheck(this, TupleIface); _get(Object.getPrototypeOf(TupleIface.prototype), 'constructor', this).call(this); if (!(spec instanceof Array)) throw new Error('Array of ifaces expected for TupleIface'); this.struct = spec.map(function (subSpec) { return iface(subSpec); }); this.length = this.struct.length; this.strict = strict; this.depth = 1 + this.struct.reduce(function (max, i) { return Math.max(max, i.depth); }, 0); } _inherits(TupleIface, _Iface7); _createClass(TupleIface, [{ key: 'match', value: function match(val) { if (!(val instanceof Array)) return false; if (val.length < this.length) return false; if (this.strict && val.length > this.length) return false; for (var i = 0; i < this.length; i++) { if (!this.struct[i].match(val[i])) return false; } return true; } }, { key: 'toString', value: function toString() { var contents = this.struct.join(', '); return '(TupleIface: [' + contents + '])'; } }]); return TupleIface; })(Iface); var AnyIface = (function (_Iface8) { function AnyIface() { var spec = arguments[0] === undefined ? [] : arguments[0]; _classCallCheck(this, AnyIface); if (!(spec instanceof Array)) throw new Error('Array of ifaces expected for AnyIface'); if (spec instanceof Array && !spec.length && AnyIface.never) return AnyIface.never; _get(Object.getPrototypeOf(AnyIface.prototype), 'constructor', this).call(this); this.struct = spec.map(function (subSpec) { return iface(subSpec); }); this.depth = 1 + this.struct.reduce(function (max, i) { return Math.max(max, i.depth); }, 0); if (!spec.length && !AnyIface.never) AnyIface.never = this; } _inherits(AnyIface, _Iface8); _createClass(AnyIface, [{ key: 'match', value: function match(val) { for (var i = 0; i < this.struct.length; i++) { if (this.struct[i].match(val)) return true; } return false; } }, { key: 'toString', value: function toString() { var contents = this.struct.join(', '); return '(AnyIface: [' + contents + '])'; } }]); return AnyIface; })(Iface); var AllIface = (function (_Iface9) { function AllIface() { var spec = arguments[0] === undefined ? [] : arguments[0]; _classCallCheck(this, AllIface); if (!(spec instanceof Array)) throw new Error('Array of ifaces expected for AllIface'); if (spec instanceof Array && !spec.length && AllIface.always) return AllIface.always; _get(Object.getPrototypeOf(AllIface.prototype), 'constructor', this).call(this); this.struct = spec.map(function (subSpec) { return iface(subSpec); }); this.depth = 1 + this.struct.reduce(function (max, i) { return Math.max(max, i.depth); }, 0); if (!spec.length && !AllIface.always) AllIface.always = this; } _inherits(AllIface, _Iface9); _createClass(AllIface, [{ key: 'match', value: function match(val) { // console.log(`match: ${val} ${this.toString()}`) for (var i = 0; i < this.struct.length; i++) { if (!this.struct[i].match(val)) return false; } return true; } }, { key: 'toString', value: function toString() { var contents = this.struct.join(', '); return '(AllIface: [' + contents + '])'; } }]); return AllIface; })(Iface); function iface(spec) { var t = typeof spec; switch (true) { case spec instanceof Iface: return spec; case t === 'function': return new ConstructorIface(spec); case !spec || t !== 'object': return new LiteralIface(spec); case spec instanceof Array: return new ArrayIface(spec[0]); } for (var key in spec) { if (Iface.registered[key]) { var _Iface$registered$key = _slicedToArray(Iface.registered[key], 2); var Sig = _Iface$registered$key[0]; var args = _Iface$registered$key[1]; return new (_bind.apply(Sig, [null].concat(_toConsumableArray(args.map(function (arg) { return spec[arg]; })))))(); } } return new RecordIface(spec); } Iface.register(LiteralIface, ['$literal', 'eq']); Iface.register(TupleIface, ['$tuple', 'strict']); Iface.register(RecordIface, ['$record', 'strict']); Iface.register(ConstructorIface, ['$constr']); Iface.register(PrototypeIface, ['$proto']); Iface.register(MapIface, ['$map']); Iface.register(ArrayIface, ['$array']); Iface.register(AnyIface, ['$any']); Iface.register(AllIface, ['$all']); iface.Iface = Iface; iface.LiteralIface = LiteralIface; iface.ConstructorIface = ConstructorIface; iface.RecordIface = RecordIface; iface.MapIface = MapIface; iface.ArrayIface = ArrayIface; iface.TupleIface = TupleIface; iface.AnyIface = AnyIface; iface.AllIface = AllIface; iface.literal = function literal(spec, eq) { return new LiteralIface(spec, eq); }; iface.record = function record(spec, strict) { return new RecordIface(spec, strict); }; iface.tuple = function tuple(spec, strict) { return new TupleIface(spec, strict); }; iface.constr = function constr(spec) { return new ConstructorIface(spec); }; iface.proto = function proto(spec) { return new PrototypeIface(spec); }; iface.map = function map(spec) { return new MapIface(spec); }; iface.array = function array(spec) { return new ArrayIface(spec); }; iface.any = function any(spec) { return new AnyIface(spec); }; iface.all = function all(spec) { return new AllIface(spec); }; iface.iface = iface; module.exports = iface;