Skip to content

Commit 4d93d66

Browse files
authored
Merge pull request #107 from DjDeveloperr/permissions
fix: use bigint for bitfield (permissions)
2 parents b222d91 + 84baae2 commit 4d93d66

File tree

3 files changed

+75
-70
lines changed

3 files changed

+75
-70
lines changed

src/types/permissionFlags.ts

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
// https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags
22

3-
export const PermissionFlags: { [key: string]: number } = {
4-
CREATE_INSTANT_INVITE: 1 << 0,
5-
KICK_MEMBERS: 1 << 1,
6-
BAN_MEMBERS: 1 << 2,
7-
ADMINISTRATOR: 1 << 3,
8-
MANAGE_CHANNELS: 1 << 4,
9-
MANAGE_GUILD: 1 << 5,
10-
ADD_REACTIONS: 1 << 6,
11-
VIEW_AUDIT_LOG: 1 << 7,
12-
PRIORITY_SPEAKER: 1 << 8,
13-
STREAM: 1 << 9,
14-
VIEW_CHANNEL: 1 << 10,
15-
SEND_MESSAGES: 1 << 11,
16-
SEND_TTS_MESSAGES: 1 << 12,
17-
MANAGE_MESSAGES: 1 << 13,
18-
EMBED_LINKS: 1 << 14,
19-
ATTACH_FILES: 1 << 15,
20-
READ_MESSAGE_HISTORY: 1 << 16,
21-
MENTION_EVERYONE: 1 << 17,
22-
USE_EXTERNAL_EMOJIS: 1 << 18,
23-
VIEW_GUILD_INSIGHTS: 1 << 19,
24-
CONNECT: 1 << 20,
25-
SPEAK: 1 << 21,
26-
MUTE_MEMBERS: 1 << 22,
27-
DEAFEN_MEMBERS: 1 << 23,
28-
MOVE_MEMBERS: 1 << 24,
29-
USE_VAD: 1 << 25,
30-
CHANGE_NICKNAME: 1 << 26,
31-
MANAGE_NICKNAMES: 1 << 27,
32-
MANAGE_ROLES: 1 << 28,
33-
MANAGE_WEBHOOKS: 1 << 29,
34-
MANAGE_EMOJIS: 1 << 30
3+
export const PermissionFlags: { [key: string]: bigint } = {
4+
CREATE_INSTANT_INVITE: 1n << 0n,
5+
KICK_MEMBERS: 1n << 1n,
6+
BAN_MEMBERS: 1n << 2n,
7+
ADMINISTRATOR: 1n << 3n,
8+
MANAGE_CHANNELS: 1n << 4n,
9+
MANAGE_GUILD: 1n << 5n,
10+
ADD_REACTIONS: 1n << 6n,
11+
VIEW_AUDIT_LOG: 1n << 7n,
12+
PRIORITY_SPEAKER: 1n << 8n,
13+
STREAM: 1n << 9n,
14+
VIEW_CHANNEL: 1n << 10n,
15+
SEND_MESSAGES: 1n << 11n,
16+
SEND_TTS_MESSAGES: 1n << 12n,
17+
MANAGE_MESSAGES: 1n << 13n,
18+
EMBED_LINKS: 1n << 14n,
19+
ATTACH_FILES: 1n << 15n,
20+
READ_MESSAGE_HISTORY: 1n << 16n,
21+
MENTION_EVERYONE: 1n << 17n,
22+
USE_EXTERNAL_EMOJIS: 1n << 18n,
23+
VIEW_GUILD_INSIGHTS: 1n << 19n,
24+
CONNECT: 1n << 20n,
25+
SPEAK: 1n << 21n,
26+
MUTE_MEMBERS: 1n << 22n,
27+
DEAFEN_MEMBERS: 1n << 23n,
28+
MOVE_MEMBERS: 1n << 24n,
29+
USE_VAD: 1n << 25n,
30+
CHANGE_NICKNAME: 1n << 26n,
31+
MANAGE_NICKNAMES: 1n << 27n,
32+
MANAGE_ROLES: 1n << 28n,
33+
MANAGE_WEBHOOKS: 1n << 29n,
34+
MANAGE_EMOJIS: 1n << 30n,
35+
USE_SLASH_COMMANDS: 1n << 31n
3536
}

src/utils/bitfield.ts

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,36 @@ export type BitFieldResolvable =
66
| string
77
| string[]
88
| BitField[]
9+
| bigint
10+
| Array<bigint>
911

1012
/** Bit Field utility to work with Bits and Flags */
1113
export class BitField {
12-
flags: { [name: string]: number } = {}
13-
bitfield: number
14+
#flags: { [name: string]: number | bigint } = {}
15+
bitfield: bigint
1416

15-
constructor(flags: { [name: string]: number }, bits: any) {
16-
this.flags = flags
17-
this.bitfield = BitField.resolve(this.flags, bits)
17+
constructor(flags: { [name: string]: number | bigint }, bits: any) {
18+
this.#flags = flags
19+
this.bitfield = BitField.resolve(this.#flags, bits)
1820
}
1921

2022
any(bit: BitFieldResolvable): boolean {
21-
return (this.bitfield & BitField.resolve(this.flags, bit)) !== 0
23+
return (this.bitfield & BitField.resolve(this.#flags, bit)) !== 0n
2224
}
2325

2426
equals(bit: BitFieldResolvable): boolean {
25-
return this.bitfield === BitField.resolve(this.flags, bit)
27+
return this.bitfield === BitField.resolve(this.#flags, bit)
2628
}
2729

2830
has(bit: BitFieldResolvable, ...args: any[]): boolean {
2931
if (Array.isArray(bit)) return (bit.every as any)((p: any) => this.has(p))
30-
bit = BitField.resolve(this.flags, bit)
32+
bit = BitField.resolve(this.#flags, bit)
3133
return (this.bitfield & bit) === bit
3234
}
3335

3436
missing(bits: any, ...hasParams: any[]): string[] {
3537
if (!Array.isArray(bits))
36-
bits = new BitField(this.flags, bits).toArray(false)
38+
bits = new BitField(this.#flags, bits).toArray(false)
3739
return bits.filter((p: any) => !this.has(p, ...hasParams))
3840
}
3941

@@ -42,58 +44,63 @@ export class BitField {
4244
}
4345

4446
add(...bits: BitFieldResolvable[]): BitField {
45-
let total = 0
47+
let total = 0n
4648
for (const bit of bits) {
47-
total |= BitField.resolve(this.flags, bit)
49+
total |= BitField.resolve(this.#flags, bit)
4850
}
4951
if (Object.isFrozen(this))
50-
return new BitField(this.flags, this.bitfield | total)
52+
return new BitField(this.#flags, this.bitfield | total)
5153
this.bitfield |= total
5254
return this
5355
}
5456

5557
remove(...bits: BitFieldResolvable[]): BitField {
56-
let total = 0
58+
let total = 0n
5759
for (const bit of bits) {
58-
total |= BitField.resolve(this.flags, bit)
60+
total |= BitField.resolve(this.#flags, bit)
5961
}
6062
if (Object.isFrozen(this))
61-
return new BitField(this.flags, this.bitfield & ~total)
63+
return new BitField(this.#flags, this.bitfield & ~total)
6264
this.bitfield &= ~total
6365
return this
6466
}
6567

66-
serialize(...hasParams: any[]): { [key: string]: any } {
67-
const serialized: { [key: string]: any } = {}
68-
for (const [flag, bit] of Object.entries(this.flags))
68+
flags(): { [name: string]: bigint | number } {
69+
return this.#flags
70+
}
71+
72+
serialize(...hasParams: any[]): { [key: string]: boolean } {
73+
const serialized: { [key: string]: boolean } = {}
74+
for (const [flag, bit] of Object.entries(this.#flags))
6975
serialized[flag] = this.has(
70-
BitField.resolve(this.flags, bit),
76+
BitField.resolve(this.#flags, bit),
7177
...hasParams
7278
)
7379
return serialized
7480
}
7581

7682
toArray(...hasParams: any[]): string[] {
77-
return Object.keys(this.flags).filter((bit) =>
78-
this.has(BitField.resolve(this.flags, bit), ...hasParams)
83+
return Object.keys(this.#flags).filter((bit) =>
84+
this.has(BitField.resolve(this.#flags, bit), ...hasParams)
7985
)
8086
}
8187

82-
toJSON(): number {
83-
return this.bitfield
88+
toJSON(): string {
89+
return this.bitfield.toString()
8490
}
8591

86-
valueOf(): number {
92+
valueOf(): bigint {
8793
return this.bitfield
8894
}
8995

9096
*[Symbol.iterator](): Iterator<string> {
9197
yield* this.toArray()
9298
}
9399

94-
static resolve(flags: any, bit: BitFieldResolvable = 0): number {
95-
if (typeof bit === 'string' && !isNaN(parseInt(bit))) return parseInt(bit)
96-
if (typeof bit === 'number' && bit >= 0) return bit
100+
static resolve(flags: any, bit: BitFieldResolvable = 0n): bigint {
101+
if (typeof bit === 'bigint') return bit
102+
if (typeof bit === 'string' && !isNaN(parseInt(bit))) return BigInt(bit)
103+
if (typeof bit === 'number' && bit >= 0) return BigInt(bit)
97104
if (bit instanceof BitField) return this.resolve(flags, bit.bitfield)
98105
if (Array.isArray(bit))
99106
return (bit.map as any)((p: any) => this.resolve(flags, p)).reduce(

src/utils/permissions.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,30 @@
22
import { PermissionFlags } from '../types/permissionFlags.ts'
33
import { BitField, BitFieldResolvable } from './bitfield.ts'
44

5-
export type PermissionResolvable =
6-
| string
7-
| string[]
8-
| number
9-
| number[]
10-
| Permissions
11-
| PermissionResolvable[]
5+
export type PermissionResolvable = BitFieldResolvable
126

137
/** Manages Discord's Bit-based Permissions */
148
export class Permissions extends BitField {
15-
static DEFAULT = 104324673
16-
static ALL = Object.values(PermissionFlags).reduce((all, p) => all | p, 0)
9+
static DEFAULT = 104324673n
10+
static ALL = Object.values(PermissionFlags).reduce(
11+
(all, p) => BigInt(all) | BigInt(p),
12+
0n
13+
)
1714

1815
constructor(bits: BitFieldResolvable) {
1916
super(PermissionFlags, bits)
2017
}
2118

2219
any(permission: PermissionResolvable, checkAdmin = true): boolean {
2320
return (
24-
(checkAdmin && super.has(this.flags.ADMINISTRATOR)) ||
21+
(checkAdmin && super.has(this.flags().ADMINISTRATOR)) ||
2522
super.any(permission as any)
2623
)
2724
}
2825

2926
has(permission: PermissionResolvable, checkAdmin = true): boolean {
3027
return (
31-
(checkAdmin && super.has(this.flags.ADMINISTRATOR)) ||
28+
(checkAdmin && super.has(this.flags().ADMINISTRATOR)) ||
3229
super.has(permission as any)
3330
)
3431
}

0 commit comments

Comments
 (0)