aesy/easy-bits

View on GitHub
src/Enum.js

Summary

Maintainability
A
0 mins
Test Coverage
import EnumConstant from './EnumConstant';
import EnumLike from './EnumLike';

/**
 * An Enum consists of a set of predefined constants. These constants are accessible directly on the instance.
 *
 * @public
 * @class
 * @implements {EnumLike}
 */
class Enum {
    /**
     * The amount of values/constants in this instance.
     *
     * @public
     * @readonly
     * @member {Number}
     */
    length;

    /**
     * @public
     * @constructor
     * @param {...String} constants
     */
    constructor(...constants) {
        const flags = {};
        let bitValue = 0;
        let length = 0;

        for (const flag of constants) {
            flags[flag] = new EnumConstant(flag, bitValue);

            Object.defineProperty(this, flag, {
                enumerable: true,
                get() {
                    return flags[flag];
                },
            });

            bitValue++;
            length++;
        }

        Object.defineProperty(this, 'length', {
            value: length,
            writable: false,
            enumerable: false,
        });

        Object.freeze(this);
    }

    /**
     * Produces a new instance from an array.
     *
     * @public
     * @static
     * @param {Array<String>} array
     * @returns {Enum} A new instance.
     */
    static fromArray(array) {
        return new this(...array);
    }

    /**
     * Deserializes a string and returns a new instance.
     *
     * @public
     * @static
     * @param {String} input
     * @throws {Error} In case input could not be parsed.
     * @returns {Enum} A new instance.
     */
    static deserialize(input) {
        if (typeof input !== 'string') {
            throw new Error('Failed to deserialize input');
        }

        const values = input.split(',').map(value => value.trim());

        if (values.includes('')) {
            throw new Error('Failed to deserialize input - invalid enum <<empty>> found');
        }

        return new Enum(...values);
    }

    forEach(callback) {
        this.values().forEach(value => {
            callback(value, value.name, this);
        });
    }

    values() {
        return Object.values(this)
            .sort((a, b) => a.ordinal - b.ordinal);
    }

    has(value) {
        return this.values().includes(value);
    }

    serialize() {
        return this.values()
            .map(constant => constant.name)
            .toString();
    }

    [Symbol.iterator]() {
        const arr = this.values();
        let index = 0;

        return {
            next() {
                const value = arr[index];
                index++;

                return {
                    value,
                    done: index > arr.length,
                };
            },
        };
    }

    toString() {
        return `Enum(length:${this.length})`;
    }
}

export default Enum;