diff --git a/packages/core/src/structures/special/permissions.ts b/packages/core/src/structures/special/permissions.ts index 274ebee..717c18b 100644 --- a/packages/core/src/structures/special/permissions.ts +++ b/packages/core/src/structures/special/permissions.ts @@ -1,5 +1,13 @@ import { BitwisePermissionFlags } from '@biscuitland/api-types'; +export interface BitField { + add(...bits: T[]): this; + remove(...bits: T[]): this; + has(bit: T): boolean; + any(bit: T): boolean; + equals(bit: T): boolean; +} + export type PermissionString = keyof typeof BitwisePermissionFlags; export type PermissionResolvable = | bigint @@ -7,22 +15,84 @@ export type PermissionResolvable = | PermissionString[] | BitwisePermissionFlags; -export class Permissions { +export class Permissions implements BitField { + /** Stores a reference to BitwisePermissionFlags */ static Flags = BitwisePermissionFlags; + + /** Falsy; Stores the lack of permissions*/ + static None = 0n; + + /** Stores all entity permissions */ bitfield: bigint; + /** Wheter to grant all other permissions to the administrator */ + __admin__: boolean = true; + constructor(bitfield: PermissionResolvable) { this.bitfield = Permissions.resolve(bitfield); } + get array(): PermissionString[] { + // unsafe cast, do not edit + const permissions = Object.keys(Permissions.Flags) as PermissionString[]; + return permissions.filter(bit => typeof bit === 'number' && this.has(bit)); + } + + add(...bits: PermissionResolvable[]): this { + let reduced: bigint = 0n; + for (const bit of bits) { + reduced |= Permissions.resolve(bit); + } + this.bitfield |= reduced; + return this; + } + + remove(...bits: PermissionResolvable[]): this { + let reduced: bigint = 0n; + for (const bit of bits) { + reduced |= Permissions.resolve(bit); + } + this.bitfield &= ~reduced; + return this; + } + has(bit: PermissionResolvable): boolean { - if (this.bitfield & BigInt(Permissions.Flags.ADMINISTRATOR)) { + const bbit = Permissions.resolve(bit); + + if (this.__admin__ && this.bitfield & BigInt(Permissions.Flags.ADMINISTRATOR)) { return true; } - return !!(this.bitfield & Permissions.resolve(bit)); + return (this.bitfield & bbit) === bbit; } + any(bit: PermissionResolvable): boolean { + const bbit = Permissions.resolve(bit); + + if (this.__admin__ && this.bitfield & BigInt(Permissions.Flags.ADMINISTRATOR)) { + return true; + } + + return (this.bitfield & bbit) === 0n; + } + + equals(bit: PermissionResolvable): boolean { + return !!(this.bitfield & Permissions.resolve(bit)); + } + + /** Gets all permissions */ + static get All(): bigint { + let reduced = 0n; + for (const key in BitwisePermissionFlags) { + const perm = BitwisePermissionFlags[key]; + + if (typeof perm === 'number') { + reduced += perm; + } + } + return reduced; + } + static resolve(bit: PermissionResolvable): bigint { switch (typeof bit) { case 'bigint': @@ -42,8 +112,16 @@ export class Permissions { } } + *[Symbol.iterator]() { + yield* this.array; + } + + valueOf() { + return this.bitfield; + } + toJSON(): { fields: string[] } { - const fields = Object.keys(Permissions.Flags).filter((bit) => typeof bit !== 'string' && this.has(bit)); + const fields = Object.keys(Permissions.Flags).filter((bit) => typeof bit === 'number' && this.has(bit)); return { fields }; }