Skip to content

Commit 80da1ee

Browse files
authored
Add Bitflag Packages (#254)
1 parent a0e56da commit 80da1ee

29 files changed

+925
-6
lines changed

.changeset/rare-masks-deny.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"bitflag-js": major
3+
---
4+
5+
Initial Release

.changeset/ten-worms-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"discord-bitflag": major
3+
---
4+
5+
Initial release

package-lock.json

Lines changed: 40 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bitflag-js/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023-present Ian Mitchell
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/bitflag-js/README.md

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# bitflag-js
2+
3+
This package provides a class for working with bitflag fields. These structures are very useful as a way to condense a list of boolean values into a single number. They are perfect matches for things like user flags, permissions, and more.
4+
5+
bitflag-js is written in TypeScript and uses [bigints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) instead of numbers.
6+
7+
## Usage
8+
9+
Install this package by running
10+
11+
```
12+
npm install bitflag-js
13+
```
14+
15+
Then import and use it in your code like this:
16+
17+
```ts
18+
import { BitField } from "bitflags-js";
19+
20+
const UserBadges = {
21+
VERIFIED: 1n << 0n,
22+
CONTRIBUTOR: 1n << 1n,
23+
SUPPORTER: 1n << 2n,
24+
VIP: 1n << 3n,
25+
};
26+
27+
const bitfield = new BitField();
28+
bitfield.add(UserBadges.VERIFIED);
29+
bitfield.add(UserBadges.CONTRIBUTOR);
30+
31+
if (bitfield.has(UserBadges.VERIFIED)) {
32+
console.log("This user is verified!");
33+
}
34+
35+
console.log(bitfield.value);
36+
```
37+
38+
## Types
39+
40+
This package is developed in TypeScript and exports two helper types.
41+
42+
### BitFlags
43+
44+
Use the `BitFlags` type when you are defining a list of bit flags.
45+
46+
```ts
47+
import type { BitFlags } from "bitflag-js";
48+
49+
const UserBadges: BitFlags = {
50+
VERIFIED: 1n << 0n,
51+
CONTRIBUTOR: 1n << 1n,
52+
SUPPORTER: 1n << 2n,
53+
VIP: 1n << 3n,
54+
};
55+
```
56+
57+
### BitFlagResolvable
58+
59+
Use the `BitFlagResolvable` type to define a list of accepted values the BitField class can resolve.
60+
61+
```ts
62+
import type { BitFlagResolvable } from "bitflag-js";
63+
64+
interface User {
65+
// ...
66+
flags: BitField;
67+
}
68+
69+
export function addFlagToUser(user: User, flag: BitFlagResolvable) {
70+
user.flags.add(flag);
71+
}
72+
```
73+
74+
For more information about the resolvable types, refer to the documentation for BitField#resolve.
75+
76+
## BitField Static APIs
77+
78+
The BitField class has static API methods available.
79+
80+
### static resolve(...values: BitFlagResolvable[]): bigint {
81+
82+
Resolves an array of `BitFlagResolvable` to a bitfield value. This method accepts the following types:
83+
84+
- `number`
85+
- `bigint`
86+
- `BitField` instance
87+
- An array of any of the above
88+
89+
```ts
90+
const first = 1n << 0n;
91+
const second = 1n << 1n;
92+
const value = BitField.resolve(first, second);
93+
```
94+
95+
All the instance methods call this method internally as a convenience.
96+
97+
## BitField Instance APIs
98+
99+
### constructor(...value: BitFlagResolvable[])
100+
101+
Creates a new BitField instance with an optional initial value.
102+
103+
```ts
104+
const bitfield = new BitField();
105+
const bitfield = new BitField(1n << 0n, 1n << 1n);
106+
```
107+
108+
### get value(): bigint
109+
110+
Returns the computed value of the bitfield.
111+
112+
### set(flag: BitFlagResolvable, value: boolean)
113+
114+
Sets or unsets a flag.
115+
116+
```ts
117+
const bitfield = new BitField();
118+
bitfield.set(1n << 0n, true);
119+
bitfield.set(1n << 1n, false);
120+
```
121+
122+
### add(...flags: BitFlagResolvable[])
123+
124+
Sets one or more flags.
125+
126+
```ts
127+
const bitfield = new BitField();
128+
bitfield.add(1n << 0n);
129+
bitfield.add(1n << 1n);
130+
```
131+
132+
### has(...flags: BitFlagResolvable[])
133+
134+
Checks if the bitfield has one or more flags.
135+
136+
```ts
137+
const bitfield = new BitField();
138+
bitfield.add(1n << 0n);
139+
140+
bitfield.has(1n << 0n); // true
141+
bitfield.has(1n << 1n); // false
142+
```
143+
144+
### remove(...flags: BitFlagResolvable[])
145+
146+
Removes one or more flags.
147+
148+
```ts
149+
const bitfield = new BitField(1n << 0n, 1n << 1n);
150+
bitfield.remove(1n << 0n);
151+
```
152+
153+
### mask(...flags: BitFlagResolvable[])
154+
155+
Returns the union of the bitfield and the given flags. This is useful when you have a single field for your flags that mixes public and private values.
156+
157+
```ts
158+
const flags = {
159+
PRIVATE: 1n << 0n,
160+
PUBLIC: 1n << 1n,
161+
PUBLIC_TWO: 1n << 2n,
162+
};
163+
164+
const PUBLIC_API_MASK = [flags.PUBLIC, flags.PUBLIC_TWO];
165+
166+
const bitfield = new BitField(Flags.PRIVATE, Flags.PUBLIC);
167+
168+
bitfield.mask(PUBLIC_API_MASK); // returns Flags.PUBLIC, because it's the only shared value between the bitfield value and the PUBLIC_API_MASK variable.
169+
```
170+
171+
This field does **not** modify the underlying value. To do that, use `BitField#set`.
172+
173+
### \\*\[Symbol.iterator]()
174+
175+
This is less intimidating than it looks! It lets you reference flags in a BitField using the `for...of` syntax.
176+
177+
```ts
178+
const bitfield = new BitField();
179+
bitfield.add(1n << 0n);
180+
bitfield.add(1n << 1n);
181+
182+
for (const flag of bitfield) {
183+
console.log(flag);
184+
}
185+
```
186+
187+
### toJSON()
188+
189+
Returns the value of the bitfield as a number if able, or a string if not.
190+
191+
```ts
192+
const bitfield = new BitField();
193+
bitfield.add(1n << 0n);
194+
bitfield.add(1n << 1n);
195+
196+
bitfield.toJSON(); // a number
197+
198+
bitfield.add(1n << 64n);
199+
bitfield.toJSON(); // a string (value > Number.MAX_SAFE_INTEGER)
200+
```
201+
202+
To force the return value to always be a string, use `BitField#toString`.
203+
204+
### toString()
205+
206+
Returns the value of the bitfield as a string.
207+
208+
```ts
209+
const bitfield = new BitField();
210+
bitfield.add(1n << 0n);
211+
bitfield.add(1n << 1n);
212+
213+
bitfield.toString(); // a string
214+
```

0 commit comments

Comments
 (0)