Primitive-enum is a a lightweight generator of immutable enums that aims to optimize convenience and utility without resorting to enumerated keys, values, or pairs wrapped in objects. This enum facility may be the best fit if you:
- want convenient lookup for both properties and values
- need full control over how values are generated for enumerated properties
- want to maximize interoperability by keeping values primitive (string, int, float)
- want the reliability of immutable enums
- or just want to keep enum usage terse
Create a new enum. Enjoy.
const Enum = require('primitive-enum');
const myEnum = Enum({a: 'x', c: 'z', b: 'y'});
// myEnum is identifiable
myEnum instanceof Enum; // => true
myEnum.name; // => 'PrimitiveEnum'
// myEnum provides immutable metadata
myEnum.keys; // => ['a', 'c', 'b'];
myEnum.values; // => ['x', 'z', 'y'];
myEnum.map; // => {a: 'x', c: 'z', b: 'y'}
myEnum.reverseMap; // => {x: 'a', z: 'c', y: 'b'}
myEnum.defaultKey; // => 'a'
myEnum.defaultValue; // => 'x'
myEnum.count; // => 3
// myEnum supports multiple forms of expression and lookup
myEnum.a; // => 'x'
myEnum['a']; // => 'x'
myEnum('a'); // => 'x'
myEnum.value('a') // => 'x'
myEnum.value('x') // => undefined
myEnum.x; // => 'a'
myEnum['x']; // => 'a'
myEnum('x'); // => 'a'
myEnum.key('x') // => 'a'
myEnum.key('a') // => undefined
// myEnum is iterable
var keys = [];
for(var key in myEnum) {
keys.push(key);
}
keys; // => ['a', 'c', 'b']
Coming soon.
const myEnum = Enum(mapping, options);
mapping
is either an object defining key => value enum pairs, or an array listing only keys.options
is either a configuration object or one of the properties accepted in one:options.defaultKey
is a string identifying the default key (and by extension default value). If unspecified, it will be the first key defined.options.transform
is a function of the formfn(value, key|idx) => enum-value
used to transform or generate the enum values to pair with keys. Several built-in transform options are available, along with configurable default behavior. See Value Transforms.
Access enum keys and values, in original order.
myEnum.keys; // => ['a', 'c', 'b']
myEnum.values; // => ['x', 'z', 'y']
Access forward and reverse mappings as immutable objects.
myEnum.map; // => {a: 'x', c: 'z', b: 'y'}
myEnum.reverseMap; // => {x: 'a', z: 'c', y: 'b'}
Find any value or key by its corresponding property-like pair.
myEnum.a; // => 'x'
myEnum.x; // => 'a'
For non-strings and strings that cannot be used as property names, use array or function access.
const uglyEnum = {'string with spaces': 12}
uglyEnum['string with spaces']; // => 12
uglyEnum[''+12]; // => 'string with spaces'
Note that array lookup must be by string keys or values cast to strings. The returned value for any key will however be in its original primitive form. Lookups by non-string primitive types can be performed using the following function-based lookup options.
Primitive-enum is not intended to support non-primitive keys or values.
uglyEnum('string with spaces'); // => 12
uglyEnum(12); // => 'string with spaces'
For explicit lookup among only keys or values, use one-way lookup methods.
myEnum.key('x'); // => 'a'
myEnum.key('a'); // => undefined
myEnum.value('a'); // => 'x'
myEnum.value('x'); // => undefined
PrimitiveEnums also specify a default key/value, which is initially the first pair defined.
myEnum.defaultKey; // => 'a'
myEnum.defaultKey = 'b'; // throws Error
myEnum.defaultValue; // => 'x'
myEnum.defaultValue = 'y'; // throws Error
PrimitiveEnum instances are string-comparable - so long as their enumerated values are comparable primitives - and serializable. The constructed results are preserved, but details of construction are discarded.
const
enum1 = Enum(['a', 'b', 'c'], Enum.bitwise),
enum2 = Enum({a: 1, b: 2, c: 4});
enum1.toString(); // => '[Function: PrimitiveEnum] a,b,c|1,2,4|0
''+enum1 == enum2; // => true
const jsonStr = JSON.stringify(myEnum);
const copiedEnum = Enum.fromJSON(jsonStr);
''+copiedEnum == myEnum; // => true
When constructing an enum from an array, the array values are treated as enum keys. When constructing an enum from an object, the property names are treated as enum keys. In either case, the object/array keys/indices and values are passed through a transform function to determine the paired enum values. Several standard options are made available through the enum constructor, and as well as configuration properties to alter the default choices.
Enum.defaultArrayTransform
Default transform to use on arrays. Initially Enum.sequenceEnum.defaultObjectTransform
Default transform to use on objects. Initially unset (Enum.defaultTransform
is used instead).Enum.defaultTransform
Default transform to use for arrays or objects if no input-type-specific transform is provided. Initially Enum.identity. Changing is supported but not advised.
const identEnum = Enum(['a', 'b', 'c'], Enum.identity);
identEnum.map; // => {'a': 'a', 'b': 'b', 'c': 'c'}
const normalEnum = Enum({a: 'x', b: 'y', c: 'z'}, Enum.identity);
normalEnum.map; // => {a: 'x', b: 'y', c: 'z'}
Straightforward identity mapping: key === value. Final default option, supports objects and arrays.
const seqEnum = Enum(['a', 'b', 'c'], Enum.sequence);
seqEnum.map; // => {'a': 1, 'b': 2, 'c': 3};
Basic incrementing integer values for array inputs. Starts at 1 so that the enumeration contains no falsey values. For arrays only. Default option for arrays.
const bitEnum = Enum(['a', 'b', 'c'], Enum.bitwise);
bitEnum.map; // => {'a': 1, 'b': 2, 'c': 4}
Sequence of incrementing powers of 2. While primitive-enum provides no support for bitwise comparisons or combinations (yet), this will play nicely with other tools that do. For arrays only.
const colorEnum = Enum(['RED', 'BLUE', 'COUNTRY_ROSE'], Enum.idString);
colorEnum.map; // => {RED: 'red', BLUE: 'blue', COUNTRY_ROSE: 'country-rose'}
Provides conversion from SCREAMING_SNAKE
to winding-river
format, as
an option for working with classic c-style constant naming conventions, where
string values are also needed. For arrays only.
Arrays send value
, idx
as arguments.
Objects send propvalue
, propname
as arguments.
// Generate values based on enum keys (from array or object)
const ucKeys = (propvalue, propname) => propname.toUpperCase();
const ucKeysEnum = Enum({a: 1, b: 2}, ucKeys);
ucKeysEnum.map; // => {a: 'A', b: 'B'}
const ucArr = (value, idx) => value.toUpperCase();
const ucArrEnum = Enum(['a', 'b'], ucArr);
ucArrEnum.map; // => {a: 'A', b: 'B'}
// Generate values based on array indices
const even = (value, idx) => (idx+1) * 2;
const evenEnum = Enum(['a', 'b'], even);
evenEnum.map; // => {a: 2, b: 4}
By design, primitive-enum does not allow the same value to be used as two different keys nor as two different values. Additionally, no same value may be used as both enum key and enum value, except in the case of matching key-value pairs where key == value. This is partly to enforce good enum-defining conventions, but primarily to minimize limitations of using the most concise means of performing enum lookups - which map keys and values interchangeably.
Lastly, all enum keys and values are expected to be simple primitives, castable to strings. Instead supplying custom objects which cast to (unique) strings may also work, but is not explicitly supported.
The following features are planned for the 1.0 release:
- Package for client-side use (include es5-compatible
dist/primitive-enum.js
with browser test coverage).
And for subsequent 1.x releases:
- Add minified source
dist/primitive-enum.min.js
. - Add support for aliases (
options.aliases
probably as map of key => [alternate keys]).