iface-js
Version:
458 lines (389 loc) • 15.9 kB
JavaScript
'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;