export type BitFieldResolvable = keyof T | number | bigint | (keyof T | number | bigint)[]; export class BitField { static None = 0n; Flags: Record = {}; protected bit: bigint = BitField.None; constructor(bitfields?: BitFieldResolvable) { if (bitfields) this.bit = this.resolve(bitfields); } set bits(bits: BitFieldResolvable) { this.bit = this.resolve(bits); } get bits(): bigint { return this.bit; } add(...bits: (BitFieldResolvable | undefined)[]): bigint { for (const bit of bits) { if (!bit) continue; this.bit |= this.resolve(bit); } return this.bit; } remove(...bits: BitFieldResolvable[]): bigint { for (const bit of bits) { this.bit &= ~this.resolve(bit); } return this.bit; } has(...bits: BitFieldResolvable[]) { const bitsResolved = bits.map(bit => this.resolve(bit)); return bitsResolved.every(bit => (this.bits & bit) === bit); } missings(...bits: BitFieldResolvable[]) { const bitsResolved = bits.map(bit => this.resolve(bit)); return bitsResolved.filter(bit => (this.bits & bit) !== bit); } equals(other: BitFieldResolvable) { return this.bits === this.resolve(other); } resolve(bits: BitFieldResolvable): bigint { switch (typeof bits) { case 'string': return BitField.resolve(this.Flags[bits]); default: return BitField.resolve(bits); } } keys(bits: BitFieldResolvable[] = [this.bits]) { const bitsResolved = bits.map(bit => this.resolve(bit)); return Object.entries(this.Flags).reduce((acc, value) => { if (bitsResolved.some(bit => (bit & value[1]) === value[1])) { acc.push(value[0]); return acc; } return acc; }, [] as string[]); } values(bits: BitFieldResolvable[] = [this.bits]) { const bitsResolved = bits.map(bit => this.resolve(bit)); return Object.entries(this.Flags).reduce((acc, value) => { if (bitsResolved.some(bit => (bit & value[1]) === value[1])) { acc.push(value[1]); return acc; } return acc; }, [] as bigint[]); } static add(base: BitFieldResolvable, ...bits: (BitFieldResolvable | undefined)[]) { base = BitField.resolve(base); for (const bit of bits) { if (!bit) continue; base |= BitField.resolve(bit); } return base; } static remove(base: BitFieldResolvable, ...bits: BitFieldResolvable[]): bigint { base = BitField.resolve(base); for (const bit of bits) { base &= ~BitField.resolve(bit); } return base; } static resolve(bits: BitFieldResolvable): bigint { switch (typeof bits) { case 'number': return BigInt(bits); case 'bigint': return bits; case 'object': { if (!Array.isArray(bits)) { throw new TypeError(`Cannot resolve permission: ${bits}`); } return bits.map(x => BitField.resolve(x)).reduce((acc, cur) => acc | cur, BitField.None); } default: throw new TypeError(`Cannot resolve permission: ${typeof bits === 'symbol' ? String(bits) : (bits as any)}`); } } }