UNPKG

ts-enum-tools

Version:

Tools for evaluating TypeScript enum types

206 lines (182 loc) 5.87 kB
/** Interface describing the tools for flag enums */ export interface EnumFlagsTool<E, e> { state: e, // Returns map of T/F values eql: (a: E) => boolean; has: (a: E) => boolean; any: (a: E) => boolean; toArray: () => string[]; toString: () => string; } /** Static properties on the function returned by EnumFlagsType<E,e> */ export interface EnumFlagsFunc<E, e> { (val?): EnumFlagsTool<E, e>, toArray: () => { key: string, val: number }[]; val: e, key: e, } /** Interface describing the tools for string enums */ export interface EnumStringsTool<E, e> { state: e, // Returns map of T/F values equals: (a: E) => boolean; toStringKey: () => string; toStringVal: () => string; } /** Static properties on the function returned by EnumStringsType<E,e> */ export interface EnumStringsFunc<E, e> { (str?): EnumStringsTool<E, e>, toArray: () => { key: string, val: string }[]; val: e, key: e, } /** * Fastest methods are these simple no frills comparison tests. */ export var EnumFlagsTest = { has: function(val, flags) { return ((+val & +flags) === +flags); }, any: function(val, flags) { return !!(+val & +flags); }, eql: function(val, flags) { return (+val === +flags); } } /** * This alternative using prototype method may be faster - WTH ? */ export var EnumFlagsTestAlt = function(val) { this.val = val; }; EnumFlagsTestAlt.prototype.has = function(flags) { return ((+this.val & +flags) === +flags) }; /** * Returns a tools assortment for flag enums, and optionally implements them as a property of * Number.prototype (named getter). The tools automatically bind to each unique Number. */ export function EnumFlagsType<E, e>(enumeration, prop?: string): EnumFlagsFunc<E, e> { var keys = {}; var hash = Object.keys(enumeration).reduce(function(obj, k) { // Excludes bi-directional numeric keys if (isNaN(<any>k)) { obj[k] = +enumeration[k]; } keys[k] = k; return obj; }, {}); // New instance created per each binding var State = function(methods) { this.methods = methods }; Object.keys(hash).forEach(function(k) { Object.defineProperty(State.prototype, k, { get: function() { return !!hash[k] ? ((this.methods.val & hash[k]) === hash[k]) : !this.methods.val; }}); }); // New instance created per each binding var Methods = function(val) { this.val = +val; this.state = new State(this); }; Methods.prototype.eql = function(flags) { return (this.val === +flags); }; Methods.prototype.has = function(flags) { return (+(this.val & +flags) === +flags); }; Methods.prototype.any = function(flags) { return !!(this.val & +flags); }; Methods.prototype.toArray = function() { return Object.keys(hash).filter(function(k) { return !!hash[k] && ((this.val & hash[k]) === hash[k]); // all bits weed out combos }.bind(this)); }; Methods.prototype.toString = function() { return Object.keys(hash).filter(function(k) { return !!hash[k] && ((this.val & hash[k]) === hash[k]); }.bind(this)).join(' | '); }; // This either runs in the context of a primitive or a value must be provided var BindValue: any = function BindValue(val?: number): EnumFlagsTool<E, e> { return new Methods((val === undefined) ? this : val); }; BindValue.val = hash; BindValue.key = keys; BindValue.toArray = function() { let arr = []; Object.keys(hash).map(function(k) { arr.push({ key: k, val: hash[k] }); }); }; // If property name is given, a number prototype is set if (prop) { Object.defineProperty(Number.prototype, prop, { get: BindValue }); } return BindValue; } /** * Returns a tools assortment for string enums, and optionally implements them as a property of * String.prototype (named getter). The tools automatically bind to each unique string. */ export function EnumStringsType<E, e>(enumeration, prop?: string, validKeysFilter?: Function): EnumStringsFunc<E, e> { var hash = {}; var keys = {}; if (validKeysFilter) { Object.keys(enumeration).forEach(function(k) { if (validKeysFilter(k)) { hash[k] = enumeration[k]; keys[k] = k; } }); } else { Object.keys(enumeration).forEach(function(k) { hash[k] = enumeration[k]; keys[k] = k; }); } // New instance created per each binding var State = function(methods) { this.methods = methods }; Object.keys(hash).forEach(function(k) { Object.defineProperty(State.prototype, k, { get: function() { return (this.methods.str === hash[k]); }}); }); // New instance created per each binding var Methods = function(str) { this.str = str.toString(); this.state = new State(this); }; Methods.prototype.equals = function(str) { return (this.str === str); }; Methods.prototype.toStringKey = function() { for(var k in hash) { if(hash[k] === this.str) { return k; } } }; Methods.prototype.toStringVal = function() { return this.str; }; // This either runs in the context of a primitive or a string must be provided var BindString: any = function (str?: string): EnumStringsTool<E, e> { return new Methods((str === undefined) ? this : str); }; BindString.val = hash; BindString.key = keys; BindString.toArray = function() { return Object.keys(hash).map(function(k) { return { key: k, val: hash[k] }; }); }; // If property name is given, a string prototype is set if (prop) { Object.defineProperty(String.prototype, prop, { get: BindString }); } return BindString; }