"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.strEnum = strEnum;
function lessThan(a, b) {
    return a == null || b == null ? false : a < b;
}
function strEnum(...o) {
    const values = Object.freeze([...new Set(o)]);
    // toLowerCase() is safe because we know all strEnum values are latin ASCII:
    const lcToValue = new Map(values.map((ea) => [ea.toLowerCase(), ea]));
    const valueToIndex = Object.fromEntries(values.map((ea, idx) => [ea, idx]));
    const dict = {};
    for (const ea of values) {
        dict[ea] = ea;
    }
    // toLowerCase() is safe because we know all strEnum values are latin ASCII:
    const getCI = (s) => s == null ? undefined : lcToValue.get(s?.toLowerCase());
    const indexOf = (s) => s != null ? valueToIndex[s] : undefined;
    const ordinal = (s) => indexOf(s) ?? values.length;
    const includes = (s) => indexOf(s) != null;
    const pick = (...t) => values.filter((ea) => t.includes(ea));
    const omit = (...t) => values.filter((ea) => !t.includes(ea));
    const toValid = (s) => s == null ? undefined : includes(s) ? s : getCI(s);
    const firstValid = (...s) => {
        for (const ea of s) {
            const v = toValid(ea);
            if (v != null)
                return v;
        }
        return;
    };
    const mapValid = (s, f) => includes(s) ? f(s) : undefined;
    const cmp = (a, b) => {
        const a_ = indexOf(a);
        const b_ = indexOf(b);
        return a_ == null || b_ == null
            ? undefined
            : a_ > b_
                ? 1
                : a_ < b_
                    ? -1
                    : 0;
    };
    const lt = (a, b) => lessThan(indexOf(a), indexOf(b));
    const next = (s) => {
        const i = indexOf(s);
        return i == null ? undefined : values[i];
    };
    const toReversed = () => strEnum(...[...values].reverse());
    return {
        ...dict,
        values,
        length: values.length,
        has: includes, // alias for includes
        includes,
        getCI,
        pick,
        omit,
        indexOf,
        ordinal,
        toValid,
        firstValid,
        mapValid,
        cmp,
        lt,
        next,
        toReversed,
        [Symbol.iterator]: () => values[Symbol.iterator](),
        [Symbol.toStringTag]: "StrEnum",
    };
}
// Example usage:
// export const Directions = strEnum("North", "South", "East", "West");
// export type Direction = StrEnumKeys<typeof Directions>;
// assert the strEnum exactly matches the field names of an interface:
// declare const _: Expect<Equal<Direction, keyof DirectionInterface>>
//# sourceMappingURL=StrEnum.js.map