ts-enum-util
Advanced tools
Comparing version
@@ -29,3 +29,2 @@ "use strict"; | ||
function EnumWrapper(enumObj) { | ||
var _this = this; | ||
this.enumObj = enumObj; | ||
@@ -37,18 +36,16 @@ /** | ||
this.keysByValueMap = new Map(); | ||
this.keySet = new Set(Object.keys(enumObj) | ||
.filter( | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
function (key) { return key !== String(parseInt(key, 10)); }) | ||
.sort()); | ||
var index = 0; | ||
this.keySet.forEach(function (key) { | ||
this.keysList = Object.keys(enumObj) | ||
.filter(isNonIndexKey) | ||
.sort(); | ||
var length = this.keysList.length; | ||
this.valuesList = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var key = this.keysList[index]; | ||
var value = enumObj[key]; | ||
_this.keysByValueMap.set(value, key); | ||
this.valuesList[index] = value; | ||
this.keysByValueMap.set(value, key); | ||
// type casting necessary to bypass readonly index signature for initialization | ||
_this[index] = [key, value]; | ||
++index; | ||
}); | ||
this.size = this.length = this.keySet.size; | ||
this[index] = [key, value]; | ||
} | ||
this.size = this.length = length; | ||
} | ||
@@ -98,3 +95,22 @@ /** | ||
EnumWrapper.prototype.keys = function () { | ||
return this.keySet.values(); | ||
var _this = this; | ||
var index = 0; | ||
return _a = { | ||
next: function () { | ||
var isDone = index >= _this.length; | ||
var result = { | ||
done: isDone, | ||
// "as any" cast is necessary to work around this bug: | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined : _this.keysList[index] | ||
}; | ||
++index; | ||
return result; | ||
} | ||
}, | ||
_a[Symbol.iterator] = function () { | ||
return this; | ||
}, | ||
_a; | ||
var _a; | ||
}; | ||
@@ -119,3 +135,3 @@ /** | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined : _this[index][1] | ||
value: isDone ? undefined : _this.valuesList[index] | ||
}; | ||
@@ -178,8 +194,7 @@ ++index; | ||
EnumWrapper.prototype.forEach = function (iteratee, context) { | ||
var _this = this; | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
Array.prototype.forEach.call(this, function (entry, index) { | ||
iteratee.call(context, entry[1], entry[0], _this, index); | ||
}); | ||
var length = this.length; | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
}; | ||
@@ -198,8 +213,9 @@ /** | ||
EnumWrapper.prototype.map = function (iteratee, context) { | ||
var _this = this; | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry, index) { | ||
return iteratee.call(context, entry[1], entry[0], _this, index); | ||
}); | ||
var length = this.length; | ||
var result = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
result[index] = iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
return result; | ||
}; | ||
@@ -212,7 +228,4 @@ /** | ||
EnumWrapper.prototype.getKeys = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
return entry[0]; | ||
}); | ||
// return defensive copy | ||
return this.keysList.slice(); | ||
}; | ||
@@ -227,7 +240,4 @@ /** | ||
EnumWrapper.prototype.getValues = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
return entry[1]; | ||
}); | ||
// return defensive copy | ||
return this.valuesList.slice(); | ||
}; | ||
@@ -240,8 +250,10 @@ /** | ||
EnumWrapper.prototype.getEntries = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
var length = this.length; | ||
var result = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
// Create a defensive copy of the entry | ||
return [entry[0], entry[1]]; | ||
}); | ||
result[index] = [entry[0], entry[1]]; | ||
} | ||
return result; | ||
}; | ||
@@ -255,3 +267,3 @@ /** | ||
EnumWrapper.prototype.isKey = function (key) { | ||
return this.keySet.has(key); | ||
return key != null && isNonIndexKey(key) && this.enumObj.hasOwnProperty(key); | ||
}; | ||
@@ -415,2 +427,13 @@ /** | ||
exports.$enum = $enum; | ||
/** | ||
* Return true if the specified object key value is NOT an integer index key. | ||
* @param key - An object key. | ||
* @return true if the specified object key value is NOT an integer index key. | ||
*/ | ||
function isNonIndexKey(key) { | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
return key !== String(parseInt(key, 10)); | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -27,3 +27,2 @@ /** | ||
function EnumWrapper(enumObj) { | ||
var _this = this; | ||
this.enumObj = enumObj; | ||
@@ -35,18 +34,16 @@ /** | ||
this.keysByValueMap = new Map(); | ||
this.keySet = new Set(Object.keys(enumObj) | ||
.filter( | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
function (key) { return key !== String(parseInt(key, 10)); }) | ||
.sort()); | ||
var index = 0; | ||
this.keySet.forEach(function (key) { | ||
this.keysList = Object.keys(enumObj) | ||
.filter(isNonIndexKey) | ||
.sort(); | ||
var length = this.keysList.length; | ||
this.valuesList = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var key = this.keysList[index]; | ||
var value = enumObj[key]; | ||
_this.keysByValueMap.set(value, key); | ||
this.valuesList[index] = value; | ||
this.keysByValueMap.set(value, key); | ||
// type casting necessary to bypass readonly index signature for initialization | ||
_this[index] = [key, value]; | ||
++index; | ||
}); | ||
this.size = this.length = this.keySet.size; | ||
this[index] = [key, value]; | ||
} | ||
this.size = this.length = length; | ||
} | ||
@@ -96,3 +93,22 @@ /** | ||
EnumWrapper.prototype.keys = function () { | ||
return this.keySet.values(); | ||
var _this = this; | ||
var index = 0; | ||
return _a = { | ||
next: function () { | ||
var isDone = index >= _this.length; | ||
var result = { | ||
done: isDone, | ||
// "as any" cast is necessary to work around this bug: | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined : _this.keysList[index] | ||
}; | ||
++index; | ||
return result; | ||
} | ||
}, | ||
_a[Symbol.iterator] = function () { | ||
return this; | ||
}, | ||
_a; | ||
var _a; | ||
}; | ||
@@ -117,3 +133,3 @@ /** | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined : _this[index][1] | ||
value: isDone ? undefined : _this.valuesList[index] | ||
}; | ||
@@ -176,8 +192,7 @@ ++index; | ||
EnumWrapper.prototype.forEach = function (iteratee, context) { | ||
var _this = this; | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
Array.prototype.forEach.call(this, function (entry, index) { | ||
iteratee.call(context, entry[1], entry[0], _this, index); | ||
}); | ||
var length = this.length; | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
}; | ||
@@ -196,8 +211,9 @@ /** | ||
EnumWrapper.prototype.map = function (iteratee, context) { | ||
var _this = this; | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry, index) { | ||
return iteratee.call(context, entry[1], entry[0], _this, index); | ||
}); | ||
var length = this.length; | ||
var result = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
result[index] = iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
return result; | ||
}; | ||
@@ -210,7 +226,4 @@ /** | ||
EnumWrapper.prototype.getKeys = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
return entry[0]; | ||
}); | ||
// return defensive copy | ||
return this.keysList.slice(); | ||
}; | ||
@@ -225,7 +238,4 @@ /** | ||
EnumWrapper.prototype.getValues = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
return entry[1]; | ||
}); | ||
// return defensive copy | ||
return this.valuesList.slice(); | ||
}; | ||
@@ -238,8 +248,10 @@ /** | ||
EnumWrapper.prototype.getEntries = function () { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call(this, function (entry) { | ||
var length = this.length; | ||
var result = new Array(length); | ||
for (var index = 0; index < length; ++index) { | ||
var entry = this[index]; | ||
// Create a defensive copy of the entry | ||
return [entry[0], entry[1]]; | ||
}); | ||
result[index] = [entry[0], entry[1]]; | ||
} | ||
return result; | ||
}; | ||
@@ -253,3 +265,3 @@ /** | ||
EnumWrapper.prototype.isKey = function (key) { | ||
return this.keySet.has(key); | ||
return key != null && isNonIndexKey(key) && this.enumObj.hasOwnProperty(key); | ||
}; | ||
@@ -412,2 +424,13 @@ /** | ||
} | ||
/** | ||
* Return true if the specified object key value is NOT an integer index key. | ||
* @param key - An object key. | ||
* @return true if the specified object key value is NOT an integer index key. | ||
*/ | ||
function isNonIndexKey(key) { | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
return key !== String(parseInt(key, 10)); | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -32,6 +32,10 @@ /** | ||
/** | ||
* Set of all keys for this enum. | ||
* List of all keys for this enum, in sorted order. | ||
*/ | ||
private readonly keySet; | ||
private readonly keysList; | ||
/** | ||
* List of all values for this enum, in sorted key order. | ||
*/ | ||
private readonly valuesList; | ||
/** | ||
* Map of enum value -> enum key. | ||
@@ -38,0 +42,0 @@ * Used for reverse key lookups. |
{ | ||
"name": "ts-enum-util", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "TypeScript Enum Utilities", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -339,5 +339,3 @@ [](https://www.npmjs.com/package/ts-enum-util) | ||
## Requirements | ||
- *ES5/ES6 Features*: The following ES5/ES6 features are used by `ts-enum-util`, so they must exist (either natively or via polyfill) in the run-time environment: | ||
- `Array.prototype.forEach` | ||
- `Array.prototype.map` | ||
- *ES6 Features*: The following ES6 features are used by `ts-enum-util`, so they must exist (either natively or via polyfill) in the run-time environment: | ||
- `Map` | ||
@@ -344,0 +342,0 @@ - `Set` |
158
src/index.ts
@@ -36,7 +36,12 @@ /** | ||
/** | ||
* Set of all keys for this enum. | ||
* List of all keys for this enum, in sorted order. | ||
*/ | ||
private readonly keySet: Set<keyof T>; | ||
private readonly keysList: (keyof T)[]; | ||
/** | ||
* List of all values for this enum, in sorted key order. | ||
*/ | ||
private readonly valuesList: T[keyof T][]; | ||
/** | ||
* Map of enum value -> enum key. | ||
@@ -197,28 +202,25 @@ * Used for reverse key lookups. | ||
private constructor(private readonly enumObj: T) { | ||
this.keySet = new Set<keyof T>( | ||
Object.keys(enumObj) | ||
// Exclude integer indexes. | ||
// This is necessary to ignore the reverse-lookup entries that are automatically added | ||
// by TypeScript to numeric enums. | ||
.filter( | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
(key) => key !== String(parseInt(key, 10)) | ||
) | ||
// Order of Object.keys() is implementation-dependent, so sort the keys to guarantee | ||
// a consistent order for iteration. | ||
.sort() | ||
); | ||
this.keysList = Object.keys(enumObj) | ||
// Include only keys that are not index keys. | ||
// This is necessary to ignore the reverse-lookup entries that are automatically added | ||
// by TypeScript to numeric enums. | ||
.filter(isNonIndexKey) | ||
// Order of Object.keys() is implementation-dependent, so sort the keys to guarantee | ||
// a consistent order for iteration. | ||
.sort(); | ||
let index = 0; | ||
this.keySet.forEach((key) => { | ||
const length = this.keysList.length; | ||
this.valuesList = new Array<T[keyof T]>(length); | ||
for (let index = 0; index < length; ++index) { | ||
const key = this.keysList[index]; | ||
const value = enumObj[key]; | ||
this.valuesList[index] = value; | ||
this.keysByValueMap.set(value, key); | ||
// type casting necessary to bypass readonly index signature for initialization | ||
(this as any as EnumWrapper.Entry<V, T>[])[index] = [key, value]; | ||
++index; | ||
}); | ||
} | ||
this.size = this.length = this.keySet.size; | ||
this.size = this.length = length; | ||
} | ||
@@ -240,3 +242,23 @@ | ||
public keys(): IterableIterator<keyof T> { | ||
return this.keySet.values(); | ||
let index = 0; | ||
return { | ||
next: () => { | ||
const isDone = index >= this.length; | ||
const result: IteratorResult<keyof T> = { | ||
done: isDone, | ||
// "as any" cast is necessary to work around this bug: | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined as any : this.keysList[index] | ||
}; | ||
++index; | ||
return result; | ||
}, | ||
[Symbol.iterator](): IterableIterator<keyof T> { | ||
return this; | ||
} | ||
}; | ||
} | ||
@@ -256,9 +278,9 @@ | ||
return { | ||
next: (): IteratorResult<T[keyof T]> => { | ||
next: () => { | ||
const isDone = index >= this.length; | ||
const result = { | ||
const result: IteratorResult<T[keyof T]> = { | ||
done: isDone, | ||
// "as any" cast is necessary to work around this bug: | ||
// https://github.com/Microsoft/TypeScript/issues/11375 | ||
value: isDone ? undefined as any : this[index][1] | ||
value: isDone ? undefined as any : this.valuesList[index] | ||
}; | ||
@@ -326,10 +348,8 @@ | ||
public forEach(iteratee: EnumWrapper.Iteratee<void, V, T>, context?: any): void { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
Array.prototype.forEach.call( | ||
this, | ||
(entry: EnumWrapper.Entry<V, T>, index: number): void => { | ||
iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
); | ||
const length = this.length; | ||
for (let index = 0; index < length; ++index) { | ||
const entry = this[index]; | ||
iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
} | ||
@@ -349,10 +369,11 @@ | ||
public map<R>(iteratee: EnumWrapper.Iteratee<R, V, T>, context?: any): R[] { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call( | ||
this, | ||
(entry: EnumWrapper.Entry<V, T>, index: number): R => { | ||
return iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
); | ||
const length = this.length; | ||
const result = new Array<R>(length); | ||
for (let index = 0; index < length; ++index) { | ||
const entry = this[index]; | ||
result[index] = iteratee.call(context, entry[1], entry[0], this, index); | ||
} | ||
return result; | ||
} | ||
@@ -366,10 +387,4 @@ | ||
public getKeys(): (keyof T)[] { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call( | ||
this, | ||
(entry: EnumWrapper.Entry<V, T>): keyof T => { | ||
return entry[0]; | ||
} | ||
); | ||
// return defensive copy | ||
return this.keysList.slice(); | ||
} | ||
@@ -385,10 +400,4 @@ | ||
public getValues(): T[keyof T][] { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call( | ||
this, | ||
(entry: EnumWrapper.Entry<V, T>): T[keyof T] => { | ||
return entry[1]; | ||
} | ||
); | ||
// return defensive copy | ||
return this.valuesList.slice(); | ||
} | ||
@@ -402,11 +411,12 @@ | ||
public getEntries(): EnumWrapper.Entry<V, T>[] { | ||
// Taking advantage of "this" being ArrayLike<EnumWrapper.Entry>, so we can call | ||
// non-mutating Array.prototype methods on it. | ||
return Array.prototype.map.call( | ||
this, | ||
(entry: EnumWrapper.Entry<V, T>): EnumWrapper.Entry<V, T> => { | ||
// Create a defensive copy of the entry | ||
return [entry[0], entry[1]]; | ||
} | ||
); | ||
const length = this.length; | ||
const result = new Array<EnumWrapper.Entry<V, T>>(length); | ||
for (let index = 0; index < length; ++index) { | ||
const entry = this[index]; | ||
// Create a defensive copy of the entry | ||
result[index] = [entry[0], entry[1]]; | ||
} | ||
return result; | ||
} | ||
@@ -421,3 +431,3 @@ | ||
public isKey(key: string | null | undefined): key is keyof T { | ||
return this.keySet.has(key); | ||
return key != null && isNonIndexKey(key) && this.enumObj.hasOwnProperty(key); | ||
} | ||
@@ -892,1 +902,13 @@ | ||
} | ||
/** | ||
* Return true if the specified object key value is NOT an integer index key. | ||
* @param key - An object key. | ||
* @return true if the specified object key value is NOT an integer index key. | ||
*/ | ||
function isNonIndexKey(key: string): boolean { | ||
// If after converting the key to an integer, then back to a string, the result is different | ||
// than the original key, then the key is NOT an integer index. | ||
// See ECMAScript spec section 15.4: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4 | ||
return key !== String(parseInt(key, 10)); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
152385
1.91%2226
2.72%697
-0.29%