@sapphire/bitfield 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +306 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.global.js +127 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +118 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +68 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
# [@sapphire/bitfield@1.0.0](https://github.com/sapphiredev/utilities/tree/@sapphire/bitfield@1.0.0) - (2022-10-16)
|
|
6
|
+
|
|
7
|
+
## ๐ Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **deps:** Update all non-major dependencies (#505) ([6178296](https://github.com/sapphiredev/utilities/commit/617829649e1e4deeee02b14533b5377cd5bc1fb3))
|
|
10
|
+
|
|
11
|
+
## ๐ Features
|
|
12
|
+
|
|
13
|
+
- Add `@sapphire/bitfield` package (#502) ([64a9c50](https://github.com/sapphiredev/utilities/commit/64a9c5031509c7fc8f1b0ceffb2020635dbb3e5a))
|
|
14
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
# @sapphire/bitfield
|
|
6
|
+
|
|
7
|
+
**BitField utilities for JavaScript.**
|
|
8
|
+
|
|
9
|
+
[](https://github.com/sapphiredev/utilities/blob/main/LICENSE.md)
|
|
10
|
+
[](https://codecov.io/gh/sapphiredev/utilities)
|
|
11
|
+
[](https://bundlephobia.com/result?p=@sapphire/bitfield)
|
|
12
|
+
[](https://www.npmjs.com/package/@sapphire/bitfield)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
**Table of Contents**
|
|
17
|
+
|
|
18
|
+
- [Features](#features)
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Usage](#usage)
|
|
21
|
+
- [Resolving](#resolving)
|
|
22
|
+
- [Checking for the existence of any bit](#checking-for-the-existence-of-any-bit)
|
|
23
|
+
- [Checking for the existence of one or multiple bits](#checking-for-the-existence-of-one-or-multiple-bits)
|
|
24
|
+
- [Getting the field's complement](#getting-the-fields-complement)
|
|
25
|
+
- [Getting the union of different fields](#getting-the-union-of-different-fields)
|
|
26
|
+
- [Getting the intersection between different fields](#getting-the-intersection-between-different-fields)
|
|
27
|
+
- [Getting the symmetric difference between different fields](#getting-the-symmetric-difference-between-different-fields)
|
|
28
|
+
- [Formatting a field](#formatting-a-field)
|
|
29
|
+
- [Buy us some doughnuts](#buy-us-some-doughnuts)
|
|
30
|
+
- [Contributors โจ](#contributors-)
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- Written in TypeScript
|
|
35
|
+
- Bundled with esbuild so it can be used in NodeJS and browsers
|
|
36
|
+
- Offers CommonJS, ESM and UMD bundles
|
|
37
|
+
- Fully tested
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
You can use the following command to install this package, or replace `npm install` with your package manager of choice.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npm install @sapphire/bitfield
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
**Note:** While this section uses `require`, the imports match 1:1 with ESM imports. For example `const { BitField } = require('@sapphire/bitfield')` equals `import { BitField } from '@sapphire/bitfield'`.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Require the BitField class
|
|
53
|
+
const { BitField } = require('@sapphire/bitfield');
|
|
54
|
+
|
|
55
|
+
const PermissionFlags = {
|
|
56
|
+
Read: 1 << 0,
|
|
57
|
+
Write: 1 << 1,
|
|
58
|
+
Edit: 1 << 2,
|
|
59
|
+
Delete: 1 << 3
|
|
60
|
+
};
|
|
61
|
+
const PermissionsBitField = new BitField(PermissionFlags);
|
|
62
|
+
|
|
63
|
+
const DetailedPermissionsFlags = {
|
|
64
|
+
ReadMessages: 1n << 0n,
|
|
65
|
+
ReadChannels: 1n << 1n,
|
|
66
|
+
CreateMessages: 1n << 2n,
|
|
67
|
+
CreateChannels: 1n << 3n
|
|
68
|
+
// ...
|
|
69
|
+
};
|
|
70
|
+
const DetailedPermissionsBitField = new BitField(DetailedPermissionsFlags);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> **Note**: An exception will be thrown in the constructor if a non-object, null, empty object, or objects with values that aren't all numbers or all bigints.
|
|
74
|
+
|
|
75
|
+
### Resolving
|
|
76
|
+
|
|
77
|
+
You can resolve bitfields from raw numbers, strings, or arrays of them. All of `BitField`'s methods call `resolve` internally, making the usage a lot easier.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
PermissionsBitField.resolve(PermissionFlags.Read);
|
|
81
|
+
PermissionsBitField.resolve(1);
|
|
82
|
+
PermissionsBitField.resolve('Read');
|
|
83
|
+
PermissionsBitField.resolve([1]);
|
|
84
|
+
PermissionsBitField.resolve(['Read']);
|
|
85
|
+
// 1 [Read]
|
|
86
|
+
|
|
87
|
+
PermissionsBitField.resolve(PermissionFlags.Read | PermissionFlags.Write);
|
|
88
|
+
PermissionsBitField.resolve([PermissionFlags.Read, PermissionFlags.Write]);
|
|
89
|
+
PermissionsBitField.resolve(['Read', 'Write']);
|
|
90
|
+
// 3 [Read + Write]
|
|
91
|
+
|
|
92
|
+
PermissionsBitField.resolve([]);
|
|
93
|
+
PermissionsBitField.zero;
|
|
94
|
+
// 0 [โ
]
|
|
95
|
+
|
|
96
|
+
// Out-of-bounds fields are masked by `PermissionsBitField.mask`:
|
|
97
|
+
PermissionsBitField.resolve(17);
|
|
98
|
+
// 0b10001 (17) -> ~~0b10000 (16, invalid)~~ | 0b0001 (1, Read)
|
|
99
|
+
// 1 [Read]
|
|
100
|
+
|
|
101
|
+
// Invalid names will cause a `RangeError` to be thrown:
|
|
102
|
+
PermissionsBitField.resolve(['Execute']);
|
|
103
|
+
// thrown RangeError('Received a name that could not be resolved to a property of flags')
|
|
104
|
+
|
|
105
|
+
// Invalid types, or non-array objects will cause a `TypeError` to be thrown:
|
|
106
|
+
PermissionsBitField.resolve(true);
|
|
107
|
+
PermissionsBitField.resolve(null);
|
|
108
|
+
PermissionsBitField.resolve({});
|
|
109
|
+
|
|
110
|
+
// Number BitFields do not accept bigints:
|
|
111
|
+
PermissionsBitField.resolve(1n);
|
|
112
|
+
// BigInt BitFields do not accept numbers:
|
|
113
|
+
DetailedPermissionsBitField.resolve(1);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For simplicity, we will be using arrays of strings for the rest of the README, but any of the above alternatives are available.
|
|
117
|
+
|
|
118
|
+
### Checking for the existence of any bit
|
|
119
|
+
|
|
120
|
+
Useful for checking if at least one of B's bits are included in A.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
PermissionsBitField.any(['Read', 'Write'], ['Read']);
|
|
124
|
+
PermissionsBitField.any(['Read', 'Write'], ['Write']);
|
|
125
|
+
PermissionsBitField.any(['Read', 'Write'], ['Write', 'Edit']);
|
|
126
|
+
// true
|
|
127
|
+
|
|
128
|
+
PermissionsBitField.any(['Read', 'Write'], ['Edit']);
|
|
129
|
+
PermissionsBitField.any(['Read', 'Write'], ['Delete']);
|
|
130
|
+
PermissionsBitField.any(['Read', 'Write'], ['Edit', 'Delete']);
|
|
131
|
+
// false
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Checking for the existence of one or multiple bits
|
|
135
|
+
|
|
136
|
+
Useful for checking if all of B's bits are included in A, or in other words, A is a superset of B.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
PermissionsBitField.any(['Read', 'Write'], ['Read']);
|
|
140
|
+
PermissionsBitField.any(['Read', 'Write'], ['Write']);
|
|
141
|
+
// true
|
|
142
|
+
|
|
143
|
+
PermissionsBitField.any(['Read', 'Write'], ['Write', 'Edit']);
|
|
144
|
+
PermissionsBitField.any(['Read', 'Write'], ['Edit']);
|
|
145
|
+
PermissionsBitField.any(['Read', 'Write'], ['Delete']);
|
|
146
|
+
PermissionsBitField.any(['Read', 'Write'], ['Edit', 'Delete']);
|
|
147
|
+
// false
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Getting the field's complement
|
|
151
|
+
|
|
152
|
+
Gets the complement of a field, or the result of excluding A from all of the BitField's mask.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
PermissionsBitField.complement(['Read']);
|
|
156
|
+
// 14 [Write + Edit + Delete]
|
|
157
|
+
|
|
158
|
+
PermissionsBitField.complement(['Read', 'Write']);
|
|
159
|
+
// 12 [Edit + Delete]
|
|
160
|
+
|
|
161
|
+
PermissionsBitField.complement(['Read', 'Write', 'Edit', 'Delete']);
|
|
162
|
+
// 0 [โ
]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Getting the union of different fields
|
|
166
|
+
|
|
167
|
+
Useful for adding multiple fields into one.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
PermissionsBitField.union(['Read'], ['Write'], ['Edit']);
|
|
171
|
+
// 7 [Read + Write + Edit]
|
|
172
|
+
|
|
173
|
+
PermissionsBitField.union();
|
|
174
|
+
// 0 [โ
]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Getting the intersection between different fields
|
|
178
|
+
|
|
179
|
+
Gets the intersection of all the fields.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
PermissionsBitField.intersection(['Read', 'Write'], ['Write']);
|
|
183
|
+
// 2 [Write]
|
|
184
|
+
|
|
185
|
+
PermissionsBitField.intersection(['Read'], ['Write']);
|
|
186
|
+
// 0 [โ
]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Getting the symmetric difference between different fields
|
|
190
|
+
|
|
191
|
+
The summetric difference is basically the union of the difference between A and B and vice versa (bits from A that aren't in B, and bits from B that aren't in A), or XOR, useful for retrieving the bit difference between two fields.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
PermissionsBitField.intersection(['Read', 'Write'], ['Write', 'Edit']);
|
|
195
|
+
// 5 [Read + Edit]
|
|
196
|
+
|
|
197
|
+
PermissionsBitField.intersection(['Write'], ['Write']);
|
|
198
|
+
// 0 [โ
]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Formatting a field
|
|
202
|
+
|
|
203
|
+
We can format fields in two ways, one is with arrays:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
PermissionsBitField.toArray(PermissionFlags.Read | PermissionFlags.Write);
|
|
207
|
+
PermissionsBitField.toArray([PermissionFlags.Read, PermissionFlags.Write]);
|
|
208
|
+
PermissionsBitField.toArray(['Read', 'Write']);
|
|
209
|
+
// ['Read', 'Write']
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
And another is with objects:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
PermissionsBitField.toObject(PermissionFlags.Read | PermissionFlags.Write);
|
|
216
|
+
PermissionsBitField.toObject([PermissionFlags.Read, PermissionFlags.Write]);
|
|
217
|
+
PermissionsBitField.toObject(['Read', 'Write']);
|
|
218
|
+
// {
|
|
219
|
+
// Read: true,
|
|
220
|
+
// Write: true,
|
|
221
|
+
// Edit: false,
|
|
222
|
+
// Delete: false
|
|
223
|
+
// }
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Buy us some doughnuts
|
|
227
|
+
|
|
228
|
+
Sapphire Community is and always will be open source, even if we don't get donations. That being said, we know there are amazing people who may still want to donate just to show their appreciation. Thank you very much in advance!
|
|
229
|
+
|
|
230
|
+
We accept donations through Open Collective, Ko-fi, PayPal, Patreon and GitHub Sponsorships. You can use the buttons below to donate through your method of choice.
|
|
231
|
+
|
|
232
|
+
| Donate With | Address |
|
|
233
|
+
| :-------------: | :-------------------------------------------------: |
|
|
234
|
+
| Open Collective | [Click Here](https://sapphirejs.dev/opencollective) |
|
|
235
|
+
| Ko-fi | [Click Here](https://sapphirejs.dev/kofi) |
|
|
236
|
+
| Patreon | [Click Here](https://sapphirejs.dev/patreon) |
|
|
237
|
+
| PayPal | [Click Here](https://sapphirejs.dev/paypal) |
|
|
238
|
+
|
|
239
|
+
## Contributors โจ
|
|
240
|
+
|
|
241
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
242
|
+
|
|
243
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
244
|
+
<!-- prettier-ignore-start -->
|
|
245
|
+
<!-- markdownlint-disable -->
|
|
246
|
+
<table>
|
|
247
|
+
<tr>
|
|
248
|
+
<td align="center"><a href="https://favware.tech/"><img src="https://avatars3.githubusercontent.com/u/4019718?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeroen Claassens</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=favna" title="Code">๐ป</a> <a href="#infra-favna" title="Infrastructure (Hosting, Build-Tools, etc)">๐</a> <a href="#projectManagement-favna" title="Project Management">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=favna" title="Documentation">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=favna" title="Tests">โ ๏ธ</a></td>
|
|
249
|
+
<td align="center"><a href="https://github.com/kyranet"><img src="https://avatars0.githubusercontent.com/u/24852502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aura Romรกn</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=kyranet" title="Code">๐ป</a> <a href="#projectManagement-kyranet" title="Project Management">๐</a> <a href="https://github.com/sapphiredev/utilities/pulls?q=is%3Apr+reviewed-by%3Akyranet" title="Reviewed Pull Requests">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=kyranet" title="Tests">โ ๏ธ</a></td>
|
|
250
|
+
<td align="center"><a href="https://github.com/PyroTechniac"><img src="https://avatars2.githubusercontent.com/u/39341355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gryffon Bellish</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=PyroTechniac" title="Code">๐ป</a> <a href="https://github.com/sapphiredev/utilities/pulls?q=is%3Apr+reviewed-by%3APyroTechniac" title="Reviewed Pull Requests">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=PyroTechniac" title="Tests">โ ๏ธ</a></td>
|
|
251
|
+
<td align="center"><a href="https://github.com/vladfrangu"><img src="https://avatars3.githubusercontent.com/u/17960496?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vlad Frangu</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=vladfrangu" title="Code">๐ป</a> <a href="https://github.com/sapphiredev/utilities/issues?q=author%3Avladfrangu" title="Bug reports">๐</a> <a href="https://github.com/sapphiredev/utilities/pulls?q=is%3Apr+reviewed-by%3Avladfrangu" title="Reviewed Pull Requests">๐</a> <a href="#userTesting-vladfrangu" title="User Testing">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=vladfrangu" title="Tests">โ ๏ธ</a></td>
|
|
252
|
+
<td align="center"><a href="https://github.com/Stitch07"><img src="https://avatars0.githubusercontent.com/u/29275227?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stitch07</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Stitch07" title="Code">๐ป</a> <a href="#projectManagement-Stitch07" title="Project Management">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=Stitch07" title="Tests">โ ๏ธ</a></td>
|
|
253
|
+
<td align="center"><a href="https://github.com/apps/depfu"><img src="https://avatars3.githubusercontent.com/in/715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>depfu[bot]</b></sub></a><br /><a href="#maintenance-depfu[bot]" title="Maintenance">๐ง</a></td>
|
|
254
|
+
<td align="center"><a href="https://github.com/apps/allcontributors"><img src="https://avatars0.githubusercontent.com/in/23186?v=4?s=100" width="100px;" alt=""/><br /><sub><b>allcontributors[bot]</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=allcontributors[bot]" title="Documentation">๐</a></td>
|
|
255
|
+
</tr>
|
|
256
|
+
<tr>
|
|
257
|
+
<td align="center"><a href="https://github.com/Nytelife26"><img src="https://avatars1.githubusercontent.com/u/22531310?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tyler J Russell</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Nytelife26" title="Documentation">๐</a></td>
|
|
258
|
+
<td align="center"><a href="https://github.com/Alcremie"><img src="https://avatars0.githubusercontent.com/u/54785334?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Lieder</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Alcremie" title="Code">๐ป</a> <a href="https://github.com/sapphiredev/utilities/issues?q=author%3AAlcremie" title="Bug reports">๐</a></td>
|
|
259
|
+
<td align="center"><a href="https://github.com/RealShadowNova"><img src="https://avatars3.githubusercontent.com/u/46537907?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hezekiah Hendry</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=RealShadowNova" title="Code">๐ป</a> <a href="#tool-RealShadowNova" title="Tools">๐ง</a></td>
|
|
260
|
+
<td align="center"><a href="https://github.com/Vetlix"><img src="https://avatars.githubusercontent.com/u/31412314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vetlix</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Vetlix" title="Code">๐ป</a></td>
|
|
261
|
+
<td align="center"><a href="https://github.com/ethamitc"><img src="https://avatars.githubusercontent.com/u/27776796?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ethan Mitchell</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=ethamitc" title="Documentation">๐</a></td>
|
|
262
|
+
<td align="center"><a href="https://github.com/noftaly"><img src="https://avatars.githubusercontent.com/u/34779161?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Elliot</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=noftaly" title="Code">๐ป</a></td>
|
|
263
|
+
<td align="center"><a href="https://jurien.dev"><img src="https://avatars.githubusercontent.com/u/5418114?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jurien Hamaker</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=jurienhamaker" title="Code">๐ป</a></td>
|
|
264
|
+
</tr>
|
|
265
|
+
<tr>
|
|
266
|
+
<td align="center"><a href="https://fanoulis.dev/"><img src="https://avatars.githubusercontent.com/u/38255093?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Charalampos Fanoulis</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=cfanoulis" title="Documentation">๐</a></td>
|
|
267
|
+
<td align="center"><a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="#maintenance-dependabot[bot]" title="Maintenance">๐ง</a></td>
|
|
268
|
+
<td align="center"><a href="https://kaname.netlify.app/"><img src="https://avatars.githubusercontent.com/u/56084970?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kaname</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=kaname-png" title="Code">๐ป</a></td>
|
|
269
|
+
<td align="center"><a href="https://github.com/nandhagk"><img src="https://avatars.githubusercontent.com/u/62976649?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nandhagk</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/issues?q=author%3Anandhagk" title="Bug reports">๐</a></td>
|
|
270
|
+
<td align="center"><a href="https://megatank58.me/"><img src="https://avatars.githubusercontent.com/u/51410502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>megatank58</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=megatank58" title="Code">๐ป</a></td>
|
|
271
|
+
<td align="center"><a href="https://github.com/UndiedGamer"><img src="https://avatars.githubusercontent.com/u/84702365?v=4?s=100" width="100px;" alt=""/><br /><sub><b>UndiedGamer</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=UndiedGamer" title="Code">๐ป</a></td>
|
|
272
|
+
<td align="center"><a href="https://github.com/Lioness100"><img src="https://avatars.githubusercontent.com/u/65814829?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lioness100</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Lioness100" title="Documentation">๐</a> <a href="https://github.com/sapphiredev/utilities/commits?author=Lioness100" title="Code">๐ป</a></td>
|
|
273
|
+
</tr>
|
|
274
|
+
<tr>
|
|
275
|
+
<td align="center"><a href="https://gitlab.com/DavidPH/"><img src="https://avatars.githubusercontent.com/u/44669930?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=DavidPHH" title="Code">๐ป</a></td>
|
|
276
|
+
<td align="center"><a href="https://github.com/apps/renovate"><img src="https://avatars.githubusercontent.com/in/2740?v=4?s=100" width="100px;" alt=""/><br /><sub><b>renovate[bot]</b></sub></a><br /><a href="#maintenance-renovate[bot]" title="Maintenance">๐ง</a></td>
|
|
277
|
+
<td align="center"><a href="https://renovate.whitesourcesoftware.com/"><img src="https://avatars.githubusercontent.com/u/25180681?v=4?s=100" width="100px;" alt=""/><br /><sub><b>WhiteSource Renovate</b></sub></a><br /><a href="#maintenance-renovate-bot" title="Maintenance">๐ง</a></td>
|
|
278
|
+
<td align="center"><a href="https://fc5570.me/"><img src="https://avatars.githubusercontent.com/u/68158483?v=4?s=100" width="100px;" alt=""/><br /><sub><b>FC</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=FC5570" title="Code">๐ป</a></td>
|
|
279
|
+
<td align="center"><a href="https://github.com/Tokipudi"><img src="https://avatars.githubusercontent.com/u/29551076?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jรฉrรฉmy de Saint Denis</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Tokipudi" title="Code">๐ป</a></td>
|
|
280
|
+
<td align="center"><a href="https://github.com/ItsMrCube"><img src="https://avatars.githubusercontent.com/u/25201357?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MrCube</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=ItsMrCube" title="Code">๐ป</a></td>
|
|
281
|
+
<td align="center"><a href="https://github.com/bitomic"><img src="https://avatars.githubusercontent.com/u/35199700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bitomic</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=bitomic" title="Code">๐ป</a></td>
|
|
282
|
+
</tr>
|
|
283
|
+
<tr>
|
|
284
|
+
<td align="center"><a href="https://c43721.dev/"><img src="https://avatars.githubusercontent.com/u/55610086?v=4?s=100" width="100px;" alt=""/><br /><sub><b>c43721</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=c43721" title="Code">๐ป</a></td>
|
|
285
|
+
<td align="center"><a href="https://commandtechno.com/"><img src="https://avatars.githubusercontent.com/u/68407783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Commandtechno</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Commandtechno" title="Code">๐ป</a></td>
|
|
286
|
+
<td align="center"><a href="https://github.com/dhruv-kaushikk"><img src="https://avatars.githubusercontent.com/u/73697546?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aura</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=dhruv-kaushikk" title="Code">๐ป</a></td>
|
|
287
|
+
<td align="center"><a href="https://axis.moe/"><img src="https://avatars.githubusercontent.com/u/54381371?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=axisiscool" title="Code">๐ป</a></td>
|
|
288
|
+
<td align="center"><a href="https://github.com/imranbarbhuiya"><img src="https://avatars.githubusercontent.com/u/74945038?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Parbez</b></sub></a><br /><a href="#maintenance-imranbarbhuiya" title="Maintenance">๐ง</a></td>
|
|
289
|
+
<td align="center"><a href="https://github.com/NotKaskus"><img src="https://avatars.githubusercontent.com/u/75168528?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Andrew</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=NotKaskus" title="Documentation">๐</a></td>
|
|
290
|
+
<td align="center"><a href="https://linktr.ee/mzato0001"><img src="https://avatars.githubusercontent.com/u/62367547?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mzato</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=Mzato0001" title="Code">๐ป</a> <a href="https://github.com/sapphiredev/utilities/issues?q=author%3AMzato0001" title="Bug reports">๐</a></td>
|
|
291
|
+
</tr>
|
|
292
|
+
<tr>
|
|
293
|
+
<td align="center"><a href="https://github.com/MajesticString"><img src="https://avatars.githubusercontent.com/u/66224939?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harry Allen</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=MajesticString" title="Documentation">๐</a></td>
|
|
294
|
+
<td align="center"><a href="https://github.com/EvolutionX-10"><img src="https://avatars.githubusercontent.com/u/85353424?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evo</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=EvolutionX-10" title="Code">๐ป</a></td>
|
|
295
|
+
<td align="center"><a href="https://enes.ovh/"><img src="https://avatars.githubusercontent.com/u/61084101?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Enes Genรง</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=enxg" title="Code">๐ป</a></td>
|
|
296
|
+
<td align="center"><a href="https://github.com/muchnameless"><img src="https://avatars.githubusercontent.com/u/12682826?v=4?s=100" width="100px;" alt=""/><br /><sub><b>muchnameless</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=muchnameless" title="Code">๐ป</a></td>
|
|
297
|
+
<td align="center"><a href="https://github.com/r-priyam"><img src="https://avatars.githubusercontent.com/u/50884372?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Priyam</b></sub></a><br /><a href="https://github.com/sapphiredev/utilities/commits?author=r-priyam" title="Code">๐ป</a></td>
|
|
298
|
+
</tr>
|
|
299
|
+
</table>
|
|
300
|
+
|
|
301
|
+
<!-- markdownlint-restore -->
|
|
302
|
+
<!-- prettier-ignore-end -->
|
|
303
|
+
|
|
304
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
305
|
+
|
|
306
|
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
declare class BitField<Flags extends Record<string, number> | Record<string, bigint>> {
|
|
2
|
+
readonly type: Flags[keyof Flags] extends number ? 'number' : 'bigint';
|
|
3
|
+
readonly zero: Flags[keyof Flags] extends number ? 0 : 0n;
|
|
4
|
+
readonly mask: ValueType<this>;
|
|
5
|
+
readonly flags: Flags;
|
|
6
|
+
constructor(flags: Readonly<Flags>);
|
|
7
|
+
/**
|
|
8
|
+
* Resolves a:
|
|
9
|
+
* - `string`: If it's a property of {@link Flags}.
|
|
10
|
+
* - `number`: If the BitField processes `number` primitives.
|
|
11
|
+
* - `bigint`: If the BitField processes `bigint` primitives.
|
|
12
|
+
* - `Array`: Resolves recursively.
|
|
13
|
+
* @param resolvable The value to resolve.
|
|
14
|
+
* @returns The resolved value.
|
|
15
|
+
*/
|
|
16
|
+
resolve(resolvable: ValueResolvable<this>): ValueType<this>;
|
|
17
|
+
/**
|
|
18
|
+
* Checks whether or not `field` contains any of the bits from `bits`.
|
|
19
|
+
* @param field The bits to compare the bits from.
|
|
20
|
+
* @param bits The bits to compare with.
|
|
21
|
+
* @returns Whether or not `field` has any of `bits`'s bits, also denoted as `A โฉ B โ โ
`.
|
|
22
|
+
*/
|
|
23
|
+
any(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether or not `field` is a superset of or equal to `bits`.
|
|
26
|
+
* @param field The bits to compare the bits from.
|
|
27
|
+
* @param bits The bits to compare with.
|
|
28
|
+
* @returns Whether or not `field` is a superset of or equal to `bits`, also denoted as `A โ B`.
|
|
29
|
+
*/
|
|
30
|
+
has(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Makes the complement of `field`, which is a field of all bits (of `U` or the union of all {@link Flags} bits)
|
|
33
|
+
* that do not belong to `A`. It is the result of `U โ A`, or `difference(U, field)`.
|
|
34
|
+
* @param field The bits to get the complement of.
|
|
35
|
+
* @returns The complement of `field`, also denoted `Aแถ` or `A'`.
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const bitfield = new BitField({
|
|
39
|
+
* Read: 0b0001,
|
|
40
|
+
* Write: 0b0010,
|
|
41
|
+
* Edit: 0b0100,
|
|
42
|
+
* Delete: 0b1000
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* bitfield.complement(0b0100);
|
|
46
|
+
* // 0b1011
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
complement(field: ValueResolvable<this>): ValueType<this>;
|
|
50
|
+
/**
|
|
51
|
+
* Makes a union of all the bits.
|
|
52
|
+
* @param fields The bits to create a union of.
|
|
53
|
+
* @returns The result of combining all bits together, also denoted as `โ
โ fields`.
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* bitfield.union(0b0001, 0b0100);
|
|
57
|
+
* // 0b0101
|
|
58
|
+
*
|
|
59
|
+
* bitfield.union(0b1100, 0b0001, 0b0010);
|
|
60
|
+
* // 0b1111
|
|
61
|
+
* ```
|
|
62
|
+
* @seealso {@link https://en.wikipedia.org/wiki/Union_(set_theory)}
|
|
63
|
+
*/
|
|
64
|
+
union(...fields: readonly ValueResolvable<this>[]): ValueType<this>;
|
|
65
|
+
/**
|
|
66
|
+
* Makes an intersection of all the bits.
|
|
67
|
+
* @param bitfield The first field.
|
|
68
|
+
* @param fields The bits to intersect with `bitfield`.
|
|
69
|
+
* @returns The result of intersecting `bitfield` with all of the `fields`, also denoted as `A โ fields`.
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* bitfield.intersection(0b0001, 0b0100);
|
|
73
|
+
* // 0b0000
|
|
74
|
+
*
|
|
75
|
+
* bitfield.intersection(0b1100, 0b0100);
|
|
76
|
+
* // 0b0100
|
|
77
|
+
*
|
|
78
|
+
* bitfield.intersection(0b1101, 0b0101, 0b1100);
|
|
79
|
+
* // 0b0100
|
|
80
|
+
* ```
|
|
81
|
+
* @seealso {@link https://en.wikipedia.org/wiki/Intersection_(set_theory)}
|
|
82
|
+
*/
|
|
83
|
+
intersection(bitfield: ValueResolvable<this>, ...fields: readonly ValueResolvable<this>[]): ValueType<this>;
|
|
84
|
+
/**
|
|
85
|
+
* Removes from `a` the bits that exist in `b`.
|
|
86
|
+
* @param a The first field.
|
|
87
|
+
* @param b The bits to remove from `a`.
|
|
88
|
+
* @returns The result of `a โ b`.
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* bitfield.difference(0b1100, 0b0100);
|
|
92
|
+
* // 0b1000
|
|
93
|
+
*
|
|
94
|
+
* bitfield.difference(0b1111, 0b0110);
|
|
95
|
+
* // 0b1001
|
|
96
|
+
* ```
|
|
97
|
+
* @seealso {@link https://en.wikipedia.org/wiki/Difference_(set_theory)}
|
|
98
|
+
*/
|
|
99
|
+
difference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this>;
|
|
100
|
+
/**
|
|
101
|
+
* Computes the symmetric difference, denoted as `A โ B` or `A ฮ B`, which is the disjunctive union, or the set of
|
|
102
|
+
* elements which are in either of the sets, but not in their intersection. As such, this is the result of
|
|
103
|
+
* `(A โ B) โช (B โ A)`, `union(difference(a, b), difference(b, a))`, or `a โ b`.
|
|
104
|
+
* @remarks The empty set (`โ
`) is neutral, as such, `A ฮ โ
= A` and `A ฮ A = โ
`
|
|
105
|
+
* @param a The first field.
|
|
106
|
+
* @param b The second field.
|
|
107
|
+
* @returns The result of computing `a ฮ b`.
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* bitfield.symmetricDifference(0b1100, 0b0011);
|
|
111
|
+
* // 0b1111
|
|
112
|
+
*
|
|
113
|
+
* bitfield.symmetricDifference(0b1101, 0b1011);
|
|
114
|
+
* // 0b0110
|
|
115
|
+
* ```
|
|
116
|
+
* @seealso {@link https://en.wikipedia.org/wiki/Symmetric_difference}
|
|
117
|
+
*/
|
|
118
|
+
symmetricDifference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this>;
|
|
119
|
+
/**
|
|
120
|
+
* Retrieves an array of the properties from {@link Flags} whose values are contained in `field`.
|
|
121
|
+
* @param field The field to convert to an array.
|
|
122
|
+
* @returns The names of the {@link BitField}'s flag properties whose value are contained in `field`.
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const bitfield = new BitField({
|
|
126
|
+
* Read: 0b0001,
|
|
127
|
+
* Write: 0b0010,
|
|
128
|
+
* Edit: 0b0100,
|
|
129
|
+
* Delete: 0b1000
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* bitfield.toArray(0b0101);
|
|
133
|
+
* // ['Read', 'Edit']
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
toArray(field: ValueResolvable<this>): (keyof Flags)[];
|
|
137
|
+
/**
|
|
138
|
+
* Retrieves an object with the properties from {@link Flags} whose values are boolean denoting whether or not the
|
|
139
|
+
* flag's bit is contained in `field`.
|
|
140
|
+
* @param field The field to convert to an object.
|
|
141
|
+
* @returns An object with the properties of {@link Flags} which values are boolean.
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const bitfield = new BitField({
|
|
145
|
+
* Read: 0b0001,
|
|
146
|
+
* Write: 0b0010,
|
|
147
|
+
* Edit: 0b0100,
|
|
148
|
+
* Delete: 0b1000
|
|
149
|
+
* });
|
|
150
|
+
*
|
|
151
|
+
* bitfield.toObject(0b0101);
|
|
152
|
+
* // {
|
|
153
|
+
* // Read: true,
|
|
154
|
+
* // Write: false,
|
|
155
|
+
* // Edit: true,
|
|
156
|
+
* // Delete: false
|
|
157
|
+
* // }
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
toObject(field: ValueResolvable<this>): Record<keyof Flags, boolean>;
|
|
161
|
+
}
|
|
162
|
+
declare type PrimitiveType<T> = T extends number ? number : bigint;
|
|
163
|
+
declare type MaybeArray<T> = T | readonly T[];
|
|
164
|
+
/**
|
|
165
|
+
* Resolves the type of the values the specified {@link BitField} takes.
|
|
166
|
+
* @typeparam A {@link BitField} instance type.
|
|
167
|
+
*/
|
|
168
|
+
declare type ValueType<T> = T extends BitField<infer Flags> ? PrimitiveType<Flags[keyof Flags]> : never;
|
|
169
|
+
/**
|
|
170
|
+
* Resolves the possible types accepted by the specified {@link BitField}.
|
|
171
|
+
* @typeparam A {@link BitField} instance type.
|
|
172
|
+
*/
|
|
173
|
+
declare type ValueResolvable<T> = T extends BitField<infer Flags> ? MaybeArray<keyof Flags | PrimitiveType<Flags[keyof Flags]>> : never;
|
|
174
|
+
|
|
175
|
+
export { BitField, ValueResolvable, ValueType };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
var SapphireBitField = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __publicField = (obj, key, value) => {
|
|
8
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/lib/BitField.ts
|
|
13
|
+
var BitField = class {
|
|
14
|
+
constructor(flags) {
|
|
15
|
+
__publicField(this, "type");
|
|
16
|
+
__publicField(this, "zero");
|
|
17
|
+
__publicField(this, "mask");
|
|
18
|
+
__publicField(this, "flags");
|
|
19
|
+
if (typeof flags !== "object" || flags === null) {
|
|
20
|
+
throw new TypeError("flags must be a non-null object");
|
|
21
|
+
}
|
|
22
|
+
const entries = Object.entries(flags);
|
|
23
|
+
if (entries.length === 0) {
|
|
24
|
+
throw new TypeError("flags must be a non-empty object");
|
|
25
|
+
}
|
|
26
|
+
const type = typeof entries[0][1];
|
|
27
|
+
if (type !== "number" && type !== "bigint") {
|
|
28
|
+
throw new TypeError("A bitfield can only use numbers or bigints for its values");
|
|
29
|
+
}
|
|
30
|
+
this.type = type;
|
|
31
|
+
this.flags = flags;
|
|
32
|
+
if (type === "number") {
|
|
33
|
+
this.zero = 0;
|
|
34
|
+
let mask = 0;
|
|
35
|
+
for (const [key, value] of entries) {
|
|
36
|
+
if (typeof value !== "number")
|
|
37
|
+
throw new TypeError(`The property "${key}" does not resolve to a number`);
|
|
38
|
+
if (value !== (value | 0))
|
|
39
|
+
throw new RangeError(`The property "${key}" does not resolve to a safe bitfield value`);
|
|
40
|
+
if (value <= 0)
|
|
41
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
42
|
+
mask |= value;
|
|
43
|
+
}
|
|
44
|
+
this.mask = mask;
|
|
45
|
+
} else {
|
|
46
|
+
this.zero = 0n;
|
|
47
|
+
let mask = 0n;
|
|
48
|
+
for (const [key, value] of entries) {
|
|
49
|
+
if (typeof value !== "bigint")
|
|
50
|
+
throw new TypeError(`The property "${key}" does not resolve to a bigint`);
|
|
51
|
+
if (value <= 0n)
|
|
52
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
53
|
+
mask |= value;
|
|
54
|
+
}
|
|
55
|
+
this.mask = mask;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
resolve(resolvable) {
|
|
59
|
+
switch (typeof resolvable) {
|
|
60
|
+
case "string":
|
|
61
|
+
if (resolvable in this.flags)
|
|
62
|
+
return this.flags[resolvable];
|
|
63
|
+
throw new RangeError("Received a name that could not be resolved to a property of flags");
|
|
64
|
+
case this.type:
|
|
65
|
+
return resolvable & this.mask;
|
|
66
|
+
case "object":
|
|
67
|
+
if (Array.isArray(resolvable))
|
|
68
|
+
return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);
|
|
69
|
+
throw new TypeError("Received an object value that is not an Array");
|
|
70
|
+
default:
|
|
71
|
+
throw new TypeError(`Received a value that is not either type "string", type "${this.type}", or an Array`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
any(field, bits) {
|
|
75
|
+
return (this.resolve(field) & this.resolve(bits)) !== this.zero;
|
|
76
|
+
}
|
|
77
|
+
has(field, bits) {
|
|
78
|
+
const resolved = this.resolve(bits);
|
|
79
|
+
return (this.resolve(field) & resolved) === resolved;
|
|
80
|
+
}
|
|
81
|
+
complement(field) {
|
|
82
|
+
return this.difference(this.mask, field);
|
|
83
|
+
}
|
|
84
|
+
union(...fields) {
|
|
85
|
+
let field = this.zero;
|
|
86
|
+
for (const resolvable of fields) {
|
|
87
|
+
field = field | this.resolve(resolvable);
|
|
88
|
+
}
|
|
89
|
+
return field;
|
|
90
|
+
}
|
|
91
|
+
intersection(bitfield, ...fields) {
|
|
92
|
+
let field = this.resolve(bitfield);
|
|
93
|
+
for (const resolvable of fields) {
|
|
94
|
+
field = field & this.resolve(resolvable);
|
|
95
|
+
}
|
|
96
|
+
return field;
|
|
97
|
+
}
|
|
98
|
+
difference(a, b) {
|
|
99
|
+
return this.resolve(a) & ~this.resolve(b);
|
|
100
|
+
}
|
|
101
|
+
symmetricDifference(a, b) {
|
|
102
|
+
return this.resolve(a) ^ this.resolve(b);
|
|
103
|
+
}
|
|
104
|
+
toArray(field) {
|
|
105
|
+
const bits = this.resolve(field);
|
|
106
|
+
const keys = [];
|
|
107
|
+
for (const [key, bit] of Object.entries(this.flags)) {
|
|
108
|
+
if ((bits & bit) === bit)
|
|
109
|
+
keys.push(key);
|
|
110
|
+
}
|
|
111
|
+
return keys;
|
|
112
|
+
}
|
|
113
|
+
toObject(field) {
|
|
114
|
+
const bits = this.resolve(field);
|
|
115
|
+
return Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit]));
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
__name(BitField, "BitField");
|
|
119
|
+
|
|
120
|
+
exports.BitField = BitField;
|
|
121
|
+
|
|
122
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
123
|
+
|
|
124
|
+
return exports;
|
|
125
|
+
|
|
126
|
+
})({});
|
|
127
|
+
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/BitField.ts"],"names":[],"mappings":"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","sourcesContent":["export class BitField<Flags extends Record<string, number> | Record<string, bigint>> {\n\tpublic readonly type: Flags[keyof Flags] extends number ? 'number' : 'bigint';\n\tpublic readonly zero: Flags[keyof Flags] extends number ? 0 : 0n;\n\tpublic readonly mask: ValueType<this>;\n\tpublic readonly flags: Flags;\n\n\tpublic constructor(flags: Readonly<Flags>) {\n\t\tif (typeof flags !== 'object' || flags === null) {\n\t\t\tthrow new TypeError('flags must be a non-null object');\n\t\t}\n\n\t\tconst entries = Object.entries(flags) as [string, Flags[keyof Flags]][];\n\t\tif (entries.length === 0) {\n\t\t\tthrow new TypeError('flags must be a non-empty object');\n\t\t}\n\n\t\tconst type = typeof entries[0][1];\n\t\tif (type !== 'number' && type !== 'bigint') {\n\t\t\tthrow new TypeError('A bitfield can only use numbers or bigints for its values');\n\t\t}\n\n\t\tthis.type = type as any;\n\t\tthis.flags = flags;\n\n\t\tif (type === 'number') {\n\t\t\tthis.zero = 0 as any;\n\n\t\t\tlet mask = 0;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'number') throw new TypeError(`The property \"${key}\" does not resolve to a number`);\n\t\t\t\tif (value !== (value | 0)) throw new RangeError(`The property \"${key}\" does not resolve to a safe bitfield value`);\n\t\t\t\tif (value <= 0) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t} else {\n\t\t\tthis.zero = 0n as any;\n\n\t\t\tlet mask = 0n;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'bigint') throw new TypeError(`The property \"${key}\" does not resolve to a bigint`);\n\t\t\t\tif (value <= 0n) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a:\n\t * - `string`: If it's a property of {@link Flags}.\n\t * - `number`: If the BitField processes `number` primitives.\n\t * - `bigint`: If the BitField processes `bigint` primitives.\n\t * - `Array`: Resolves recursively.\n\t * @param resolvable The value to resolve.\n\t * @returns The resolved value.\n\t */\n\tpublic resolve(resolvable: ValueResolvable<this>): ValueType<this> {\n\t\tswitch (typeof resolvable) {\n\t\t\tcase 'string':\n\t\t\t\tif ((resolvable as string) in this.flags) return this.flags[resolvable as keyof Flags] as any;\n\t\t\t\tthrow new RangeError('Received a name that could not be resolved to a property of flags');\n\t\t\tcase this.type:\n\t\t\t\treturn ((resolvable as ValueType<this>) & this.mask) as any;\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(resolvable)) return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);\n\t\t\t\tthrow new TypeError('Received an object value that is not an Array');\n\t\t\tdefault:\n\t\t\t\tthrow new TypeError(`Received a value that is not either type \"string\", type \"${this.type}\", or an Array`);\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether or not `field` contains any of the bits from `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` has any of `bits`'s bits, also denoted as `A โฉ B โ โ
`.\n\t */\n\tpublic any(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\treturn (this.resolve(field) & this.resolve(bits)) !== this.zero;\n\t}\n\n\t/**\n\t * Checks whether or not `field` is a superset of or equal to `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` is a superset of or equal to `bits`, also denoted as `A โ B`.\n\t */\n\tpublic has(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\tconst resolved = this.resolve(bits);\n\t\treturn (this.resolve(field) & resolved) === resolved;\n\t}\n\n\t/**\n\t * Makes the complement of `field`, which is a field of all bits (of `U` or the union of all {@link Flags} bits)\n\t * that do not belong to `A`. It is the result of `U โ A`, or `difference(U, field)`.\n\t * @param field The bits to get the complement of.\n\t * @returns The complement of `field`, also denoted `Aแถ` or `A'`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.complement(0b0100);\n\t * // 0b1011\n\t * ```\n\t */\n\tpublic complement(field: ValueResolvable<this>): ValueType<this> {\n\t\treturn this.difference(this.mask, field);\n\t}\n\n\t/**\n\t * Makes a union of all the bits.\n\t * @param fields The bits to create a union of.\n\t * @returns The result of combining all bits together, also denoted as `โ
โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.union(0b0001, 0b0100);\n\t * // 0b0101\n\t *\n\t * bitfield.union(0b1100, 0b0001, 0b0010);\n\t * // 0b1111\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Union_(set_theory)}\n\t */\n\tpublic union(...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.zero as ValueType<this>;\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field | this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Makes an intersection of all the bits.\n\t * @param bitfield The first field.\n\t * @param fields The bits to intersect with `bitfield`.\n\t * @returns The result of intersecting `bitfield` with all of the `fields`, also denoted as `A โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.intersection(0b0001, 0b0100);\n\t * // 0b0000\n\t *\n\t * bitfield.intersection(0b1100, 0b0100);\n\t * // 0b0100\n\t *\n\t * bitfield.intersection(0b1101, 0b0101, 0b1100);\n\t * // 0b0100\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Intersection_(set_theory)}\n\t */\n\tpublic intersection(bitfield: ValueResolvable<this>, ...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.resolve(bitfield);\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field & this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Removes from `a` the bits that exist in `b`.\n\t * @param a The first field.\n\t * @param b The bits to remove from `a`.\n\t * @returns The result of `a โ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.difference(0b1100, 0b0100);\n\t * // 0b1000\n\t *\n\t * bitfield.difference(0b1111, 0b0110);\n\t * // 0b1001\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Difference_(set_theory)}\n\t */\n\tpublic difference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) & ~this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Computes the symmetric difference, denoted as `A โ B` or `A ฮ B`, which is the disjunctive union, or the set of\n\t * elements which are in either of the sets, but not in their intersection. As such, this is the result of\n\t * `(A โ B) โช (B โ A)`, `union(difference(a, b), difference(b, a))`, or `a โ b`.\n\t * @remarks The empty set (`โ
`) is neutral, as such, `A ฮ โ
= A` and `A ฮ A = โ
`\n\t * @param a The first field.\n\t * @param b The second field.\n\t * @returns The result of computing `a ฮ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.symmetricDifference(0b1100, 0b0011);\n\t * // 0b1111\n\t *\n\t * bitfield.symmetricDifference(0b1101, 0b1011);\n\t * // 0b0110\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Symmetric_difference}\n\t */\n\tpublic symmetricDifference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) ^ this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Retrieves an array of the properties from {@link Flags} whose values are contained in `field`.\n\t * @param field The field to convert to an array.\n\t * @returns The names of the {@link BitField}'s flag properties whose value are contained in `field`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toArray(0b0101);\n\t * // ['Read', 'Edit']\n\t * ```\n\t */\n\tpublic toArray(field: ValueResolvable<this>): (keyof Flags)[] {\n\t\tconst bits = this.resolve(field);\n\t\tconst keys: (keyof Flags)[] = [];\n\t\tfor (const [key, bit] of Object.entries(this.flags)) {\n\t\t\t// Inline `.has` code for lower overhead:\n\t\t\tif ((bits & bit) === bit) keys.push(key);\n\t\t}\n\n\t\treturn keys;\n\t}\n\n\t/**\n\t * Retrieves an object with the properties from {@link Flags} whose values are boolean denoting whether or not the\n\t * flag's bit is contained in `field`.\n\t * @param field The field to convert to an object.\n\t * @returns An object with the properties of {@link Flags} which values are boolean.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toObject(0b0101);\n\t * // {\n\t * // \tRead: true,\n\t * // \tWrite: false,\n\t * // \tEdit: true,\n\t * // \tDelete: false\n\t * // }\n\t * ```\n\t */\n\tpublic toObject(field: ValueResolvable<this>): Record<keyof Flags, boolean> {\n\t\tconst bits = this.resolve(field);\n\t\treturn Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit])) as Record<keyof Flags, boolean>;\n\t}\n}\n\ntype PrimitiveType<T> = T extends number ? number : bigint;\ntype MaybeArray<T> = T | readonly T[];\n\n/**\n * Resolves the type of the values the specified {@link BitField} takes.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueType<T> = T extends BitField<infer Flags> ? PrimitiveType<Flags[keyof Flags]> : never;\n\n/**\n * Resolves the possible types accepted by the specified {@link BitField}.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueResolvable<T> = T extends BitField<infer Flags> ? MaybeArray<keyof Flags | PrimitiveType<Flags[keyof Flags]>> : never;\n"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
+
var __publicField = (obj, key, value) => {
|
|
9
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/lib/BitField.ts
|
|
14
|
+
var BitField = class {
|
|
15
|
+
constructor(flags) {
|
|
16
|
+
__publicField(this, "type");
|
|
17
|
+
__publicField(this, "zero");
|
|
18
|
+
__publicField(this, "mask");
|
|
19
|
+
__publicField(this, "flags");
|
|
20
|
+
if (typeof flags !== "object" || flags === null) {
|
|
21
|
+
throw new TypeError("flags must be a non-null object");
|
|
22
|
+
}
|
|
23
|
+
const entries = Object.entries(flags);
|
|
24
|
+
if (entries.length === 0) {
|
|
25
|
+
throw new TypeError("flags must be a non-empty object");
|
|
26
|
+
}
|
|
27
|
+
const type = typeof entries[0][1];
|
|
28
|
+
if (type !== "number" && type !== "bigint") {
|
|
29
|
+
throw new TypeError("A bitfield can only use numbers or bigints for its values");
|
|
30
|
+
}
|
|
31
|
+
this.type = type;
|
|
32
|
+
this.flags = flags;
|
|
33
|
+
if (type === "number") {
|
|
34
|
+
this.zero = 0;
|
|
35
|
+
let mask = 0;
|
|
36
|
+
for (const [key, value] of entries) {
|
|
37
|
+
if (typeof value !== "number")
|
|
38
|
+
throw new TypeError(`The property "${key}" does not resolve to a number`);
|
|
39
|
+
if (value !== (value | 0))
|
|
40
|
+
throw new RangeError(`The property "${key}" does not resolve to a safe bitfield value`);
|
|
41
|
+
if (value <= 0)
|
|
42
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
43
|
+
mask |= value;
|
|
44
|
+
}
|
|
45
|
+
this.mask = mask;
|
|
46
|
+
} else {
|
|
47
|
+
this.zero = 0n;
|
|
48
|
+
let mask = 0n;
|
|
49
|
+
for (const [key, value] of entries) {
|
|
50
|
+
if (typeof value !== "bigint")
|
|
51
|
+
throw new TypeError(`The property "${key}" does not resolve to a bigint`);
|
|
52
|
+
if (value <= 0n)
|
|
53
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
54
|
+
mask |= value;
|
|
55
|
+
}
|
|
56
|
+
this.mask = mask;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
resolve(resolvable) {
|
|
60
|
+
switch (typeof resolvable) {
|
|
61
|
+
case "string":
|
|
62
|
+
if (resolvable in this.flags)
|
|
63
|
+
return this.flags[resolvable];
|
|
64
|
+
throw new RangeError("Received a name that could not be resolved to a property of flags");
|
|
65
|
+
case this.type:
|
|
66
|
+
return resolvable & this.mask;
|
|
67
|
+
case "object":
|
|
68
|
+
if (Array.isArray(resolvable))
|
|
69
|
+
return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);
|
|
70
|
+
throw new TypeError("Received an object value that is not an Array");
|
|
71
|
+
default:
|
|
72
|
+
throw new TypeError(`Received a value that is not either type "string", type "${this.type}", or an Array`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
any(field, bits) {
|
|
76
|
+
return (this.resolve(field) & this.resolve(bits)) !== this.zero;
|
|
77
|
+
}
|
|
78
|
+
has(field, bits) {
|
|
79
|
+
const resolved = this.resolve(bits);
|
|
80
|
+
return (this.resolve(field) & resolved) === resolved;
|
|
81
|
+
}
|
|
82
|
+
complement(field) {
|
|
83
|
+
return this.difference(this.mask, field);
|
|
84
|
+
}
|
|
85
|
+
union(...fields) {
|
|
86
|
+
let field = this.zero;
|
|
87
|
+
for (const resolvable of fields) {
|
|
88
|
+
field = field | this.resolve(resolvable);
|
|
89
|
+
}
|
|
90
|
+
return field;
|
|
91
|
+
}
|
|
92
|
+
intersection(bitfield, ...fields) {
|
|
93
|
+
let field = this.resolve(bitfield);
|
|
94
|
+
for (const resolvable of fields) {
|
|
95
|
+
field = field & this.resolve(resolvable);
|
|
96
|
+
}
|
|
97
|
+
return field;
|
|
98
|
+
}
|
|
99
|
+
difference(a, b) {
|
|
100
|
+
return this.resolve(a) & ~this.resolve(b);
|
|
101
|
+
}
|
|
102
|
+
symmetricDifference(a, b) {
|
|
103
|
+
return this.resolve(a) ^ this.resolve(b);
|
|
104
|
+
}
|
|
105
|
+
toArray(field) {
|
|
106
|
+
const bits = this.resolve(field);
|
|
107
|
+
const keys = [];
|
|
108
|
+
for (const [key, bit] of Object.entries(this.flags)) {
|
|
109
|
+
if ((bits & bit) === bit)
|
|
110
|
+
keys.push(key);
|
|
111
|
+
}
|
|
112
|
+
return keys;
|
|
113
|
+
}
|
|
114
|
+
toObject(field) {
|
|
115
|
+
const bits = this.resolve(field);
|
|
116
|
+
return Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit]));
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
__name(BitField, "BitField");
|
|
120
|
+
|
|
121
|
+
exports.BitField = BitField;
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/BitField.ts"],"names":[],"mappings":"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","sourcesContent":["export class BitField<Flags extends Record<string, number> | Record<string, bigint>> {\n\tpublic readonly type: Flags[keyof Flags] extends number ? 'number' : 'bigint';\n\tpublic readonly zero: Flags[keyof Flags] extends number ? 0 : 0n;\n\tpublic readonly mask: ValueType<this>;\n\tpublic readonly flags: Flags;\n\n\tpublic constructor(flags: Readonly<Flags>) {\n\t\tif (typeof flags !== 'object' || flags === null) {\n\t\t\tthrow new TypeError('flags must be a non-null object');\n\t\t}\n\n\t\tconst entries = Object.entries(flags) as [string, Flags[keyof Flags]][];\n\t\tif (entries.length === 0) {\n\t\t\tthrow new TypeError('flags must be a non-empty object');\n\t\t}\n\n\t\tconst type = typeof entries[0][1];\n\t\tif (type !== 'number' && type !== 'bigint') {\n\t\t\tthrow new TypeError('A bitfield can only use numbers or bigints for its values');\n\t\t}\n\n\t\tthis.type = type as any;\n\t\tthis.flags = flags;\n\n\t\tif (type === 'number') {\n\t\t\tthis.zero = 0 as any;\n\n\t\t\tlet mask = 0;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'number') throw new TypeError(`The property \"${key}\" does not resolve to a number`);\n\t\t\t\tif (value !== (value | 0)) throw new RangeError(`The property \"${key}\" does not resolve to a safe bitfield value`);\n\t\t\t\tif (value <= 0) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t} else {\n\t\t\tthis.zero = 0n as any;\n\n\t\t\tlet mask = 0n;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'bigint') throw new TypeError(`The property \"${key}\" does not resolve to a bigint`);\n\t\t\t\tif (value <= 0n) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a:\n\t * - `string`: If it's a property of {@link Flags}.\n\t * - `number`: If the BitField processes `number` primitives.\n\t * - `bigint`: If the BitField processes `bigint` primitives.\n\t * - `Array`: Resolves recursively.\n\t * @param resolvable The value to resolve.\n\t * @returns The resolved value.\n\t */\n\tpublic resolve(resolvable: ValueResolvable<this>): ValueType<this> {\n\t\tswitch (typeof resolvable) {\n\t\t\tcase 'string':\n\t\t\t\tif ((resolvable as string) in this.flags) return this.flags[resolvable as keyof Flags] as any;\n\t\t\t\tthrow new RangeError('Received a name that could not be resolved to a property of flags');\n\t\t\tcase this.type:\n\t\t\t\treturn ((resolvable as ValueType<this>) & this.mask) as any;\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(resolvable)) return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);\n\t\t\t\tthrow new TypeError('Received an object value that is not an Array');\n\t\t\tdefault:\n\t\t\t\tthrow new TypeError(`Received a value that is not either type \"string\", type \"${this.type}\", or an Array`);\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether or not `field` contains any of the bits from `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` has any of `bits`'s bits, also denoted as `A โฉ B โ โ
`.\n\t */\n\tpublic any(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\treturn (this.resolve(field) & this.resolve(bits)) !== this.zero;\n\t}\n\n\t/**\n\t * Checks whether or not `field` is a superset of or equal to `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` is a superset of or equal to `bits`, also denoted as `A โ B`.\n\t */\n\tpublic has(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\tconst resolved = this.resolve(bits);\n\t\treturn (this.resolve(field) & resolved) === resolved;\n\t}\n\n\t/**\n\t * Makes the complement of `field`, which is a field of all bits (of `U` or the union of all {@link Flags} bits)\n\t * that do not belong to `A`. It is the result of `U โ A`, or `difference(U, field)`.\n\t * @param field The bits to get the complement of.\n\t * @returns The complement of `field`, also denoted `Aแถ` or `A'`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.complement(0b0100);\n\t * // 0b1011\n\t * ```\n\t */\n\tpublic complement(field: ValueResolvable<this>): ValueType<this> {\n\t\treturn this.difference(this.mask, field);\n\t}\n\n\t/**\n\t * Makes a union of all the bits.\n\t * @param fields The bits to create a union of.\n\t * @returns The result of combining all bits together, also denoted as `โ
โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.union(0b0001, 0b0100);\n\t * // 0b0101\n\t *\n\t * bitfield.union(0b1100, 0b0001, 0b0010);\n\t * // 0b1111\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Union_(set_theory)}\n\t */\n\tpublic union(...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.zero as ValueType<this>;\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field | this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Makes an intersection of all the bits.\n\t * @param bitfield The first field.\n\t * @param fields The bits to intersect with `bitfield`.\n\t * @returns The result of intersecting `bitfield` with all of the `fields`, also denoted as `A โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.intersection(0b0001, 0b0100);\n\t * // 0b0000\n\t *\n\t * bitfield.intersection(0b1100, 0b0100);\n\t * // 0b0100\n\t *\n\t * bitfield.intersection(0b1101, 0b0101, 0b1100);\n\t * // 0b0100\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Intersection_(set_theory)}\n\t */\n\tpublic intersection(bitfield: ValueResolvable<this>, ...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.resolve(bitfield);\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field & this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Removes from `a` the bits that exist in `b`.\n\t * @param a The first field.\n\t * @param b The bits to remove from `a`.\n\t * @returns The result of `a โ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.difference(0b1100, 0b0100);\n\t * // 0b1000\n\t *\n\t * bitfield.difference(0b1111, 0b0110);\n\t * // 0b1001\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Difference_(set_theory)}\n\t */\n\tpublic difference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) & ~this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Computes the symmetric difference, denoted as `A โ B` or `A ฮ B`, which is the disjunctive union, or the set of\n\t * elements which are in either of the sets, but not in their intersection. As such, this is the result of\n\t * `(A โ B) โช (B โ A)`, `union(difference(a, b), difference(b, a))`, or `a โ b`.\n\t * @remarks The empty set (`โ
`) is neutral, as such, `A ฮ โ
= A` and `A ฮ A = โ
`\n\t * @param a The first field.\n\t * @param b The second field.\n\t * @returns The result of computing `a ฮ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.symmetricDifference(0b1100, 0b0011);\n\t * // 0b1111\n\t *\n\t * bitfield.symmetricDifference(0b1101, 0b1011);\n\t * // 0b0110\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Symmetric_difference}\n\t */\n\tpublic symmetricDifference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) ^ this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Retrieves an array of the properties from {@link Flags} whose values are contained in `field`.\n\t * @param field The field to convert to an array.\n\t * @returns The names of the {@link BitField}'s flag properties whose value are contained in `field`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toArray(0b0101);\n\t * // ['Read', 'Edit']\n\t * ```\n\t */\n\tpublic toArray(field: ValueResolvable<this>): (keyof Flags)[] {\n\t\tconst bits = this.resolve(field);\n\t\tconst keys: (keyof Flags)[] = [];\n\t\tfor (const [key, bit] of Object.entries(this.flags)) {\n\t\t\t// Inline `.has` code for lower overhead:\n\t\t\tif ((bits & bit) === bit) keys.push(key);\n\t\t}\n\n\t\treturn keys;\n\t}\n\n\t/**\n\t * Retrieves an object with the properties from {@link Flags} whose values are boolean denoting whether or not the\n\t * flag's bit is contained in `field`.\n\t * @param field The field to convert to an object.\n\t * @returns An object with the properties of {@link Flags} which values are boolean.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toObject(0b0101);\n\t * // {\n\t * // \tRead: true,\n\t * // \tWrite: false,\n\t * // \tEdit: true,\n\t * // \tDelete: false\n\t * // }\n\t * ```\n\t */\n\tpublic toObject(field: ValueResolvable<this>): Record<keyof Flags, boolean> {\n\t\tconst bits = this.resolve(field);\n\t\treturn Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit])) as Record<keyof Flags, boolean>;\n\t}\n}\n\ntype PrimitiveType<T> = T extends number ? number : bigint;\ntype MaybeArray<T> = T | readonly T[];\n\n/**\n * Resolves the type of the values the specified {@link BitField} takes.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueType<T> = T extends BitField<infer Flags> ? PrimitiveType<Flags[keyof Flags]> : never;\n\n/**\n * Resolves the possible types accepted by the specified {@link BitField}.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueResolvable<T> = T extends BitField<infer Flags> ? MaybeArray<keyof Flags | PrimitiveType<Flags[keyof Flags]>> : never;\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
+
var __publicField = (obj, key, value) => {
|
|
5
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// src/lib/BitField.ts
|
|
10
|
+
var BitField = class {
|
|
11
|
+
constructor(flags) {
|
|
12
|
+
__publicField(this, "type");
|
|
13
|
+
__publicField(this, "zero");
|
|
14
|
+
__publicField(this, "mask");
|
|
15
|
+
__publicField(this, "flags");
|
|
16
|
+
if (typeof flags !== "object" || flags === null) {
|
|
17
|
+
throw new TypeError("flags must be a non-null object");
|
|
18
|
+
}
|
|
19
|
+
const entries = Object.entries(flags);
|
|
20
|
+
if (entries.length === 0) {
|
|
21
|
+
throw new TypeError("flags must be a non-empty object");
|
|
22
|
+
}
|
|
23
|
+
const type = typeof entries[0][1];
|
|
24
|
+
if (type !== "number" && type !== "bigint") {
|
|
25
|
+
throw new TypeError("A bitfield can only use numbers or bigints for its values");
|
|
26
|
+
}
|
|
27
|
+
this.type = type;
|
|
28
|
+
this.flags = flags;
|
|
29
|
+
if (type === "number") {
|
|
30
|
+
this.zero = 0;
|
|
31
|
+
let mask = 0;
|
|
32
|
+
for (const [key, value] of entries) {
|
|
33
|
+
if (typeof value !== "number")
|
|
34
|
+
throw new TypeError(`The property "${key}" does not resolve to a number`);
|
|
35
|
+
if (value !== (value | 0))
|
|
36
|
+
throw new RangeError(`The property "${key}" does not resolve to a safe bitfield value`);
|
|
37
|
+
if (value <= 0)
|
|
38
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
39
|
+
mask |= value;
|
|
40
|
+
}
|
|
41
|
+
this.mask = mask;
|
|
42
|
+
} else {
|
|
43
|
+
this.zero = 0n;
|
|
44
|
+
let mask = 0n;
|
|
45
|
+
for (const [key, value] of entries) {
|
|
46
|
+
if (typeof value !== "bigint")
|
|
47
|
+
throw new TypeError(`The property "${key}" does not resolve to a bigint`);
|
|
48
|
+
if (value <= 0n)
|
|
49
|
+
throw new RangeError(`The property "${key}" resolves to a non-positive value`);
|
|
50
|
+
mask |= value;
|
|
51
|
+
}
|
|
52
|
+
this.mask = mask;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
resolve(resolvable) {
|
|
56
|
+
switch (typeof resolvable) {
|
|
57
|
+
case "string":
|
|
58
|
+
if (resolvable in this.flags)
|
|
59
|
+
return this.flags[resolvable];
|
|
60
|
+
throw new RangeError("Received a name that could not be resolved to a property of flags");
|
|
61
|
+
case this.type:
|
|
62
|
+
return resolvable & this.mask;
|
|
63
|
+
case "object":
|
|
64
|
+
if (Array.isArray(resolvable))
|
|
65
|
+
return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);
|
|
66
|
+
throw new TypeError("Received an object value that is not an Array");
|
|
67
|
+
default:
|
|
68
|
+
throw new TypeError(`Received a value that is not either type "string", type "${this.type}", or an Array`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
any(field, bits) {
|
|
72
|
+
return (this.resolve(field) & this.resolve(bits)) !== this.zero;
|
|
73
|
+
}
|
|
74
|
+
has(field, bits) {
|
|
75
|
+
const resolved = this.resolve(bits);
|
|
76
|
+
return (this.resolve(field) & resolved) === resolved;
|
|
77
|
+
}
|
|
78
|
+
complement(field) {
|
|
79
|
+
return this.difference(this.mask, field);
|
|
80
|
+
}
|
|
81
|
+
union(...fields) {
|
|
82
|
+
let field = this.zero;
|
|
83
|
+
for (const resolvable of fields) {
|
|
84
|
+
field = field | this.resolve(resolvable);
|
|
85
|
+
}
|
|
86
|
+
return field;
|
|
87
|
+
}
|
|
88
|
+
intersection(bitfield, ...fields) {
|
|
89
|
+
let field = this.resolve(bitfield);
|
|
90
|
+
for (const resolvable of fields) {
|
|
91
|
+
field = field & this.resolve(resolvable);
|
|
92
|
+
}
|
|
93
|
+
return field;
|
|
94
|
+
}
|
|
95
|
+
difference(a, b) {
|
|
96
|
+
return this.resolve(a) & ~this.resolve(b);
|
|
97
|
+
}
|
|
98
|
+
symmetricDifference(a, b) {
|
|
99
|
+
return this.resolve(a) ^ this.resolve(b);
|
|
100
|
+
}
|
|
101
|
+
toArray(field) {
|
|
102
|
+
const bits = this.resolve(field);
|
|
103
|
+
const keys = [];
|
|
104
|
+
for (const [key, bit] of Object.entries(this.flags)) {
|
|
105
|
+
if ((bits & bit) === bit)
|
|
106
|
+
keys.push(key);
|
|
107
|
+
}
|
|
108
|
+
return keys;
|
|
109
|
+
}
|
|
110
|
+
toObject(field) {
|
|
111
|
+
const bits = this.resolve(field);
|
|
112
|
+
return Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit]));
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
__name(BitField, "BitField");
|
|
116
|
+
|
|
117
|
+
export { BitField };
|
|
118
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/BitField.ts"],"names":[],"mappings":"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","sourcesContent":["export class BitField<Flags extends Record<string, number> | Record<string, bigint>> {\n\tpublic readonly type: Flags[keyof Flags] extends number ? 'number' : 'bigint';\n\tpublic readonly zero: Flags[keyof Flags] extends number ? 0 : 0n;\n\tpublic readonly mask: ValueType<this>;\n\tpublic readonly flags: Flags;\n\n\tpublic constructor(flags: Readonly<Flags>) {\n\t\tif (typeof flags !== 'object' || flags === null) {\n\t\t\tthrow new TypeError('flags must be a non-null object');\n\t\t}\n\n\t\tconst entries = Object.entries(flags) as [string, Flags[keyof Flags]][];\n\t\tif (entries.length === 0) {\n\t\t\tthrow new TypeError('flags must be a non-empty object');\n\t\t}\n\n\t\tconst type = typeof entries[0][1];\n\t\tif (type !== 'number' && type !== 'bigint') {\n\t\t\tthrow new TypeError('A bitfield can only use numbers or bigints for its values');\n\t\t}\n\n\t\tthis.type = type as any;\n\t\tthis.flags = flags;\n\n\t\tif (type === 'number') {\n\t\t\tthis.zero = 0 as any;\n\n\t\t\tlet mask = 0;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'number') throw new TypeError(`The property \"${key}\" does not resolve to a number`);\n\t\t\t\tif (value !== (value | 0)) throw new RangeError(`The property \"${key}\" does not resolve to a safe bitfield value`);\n\t\t\t\tif (value <= 0) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t} else {\n\t\t\tthis.zero = 0n as any;\n\n\t\t\tlet mask = 0n;\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tif (typeof value !== 'bigint') throw new TypeError(`The property \"${key}\" does not resolve to a bigint`);\n\t\t\t\tif (value <= 0n) throw new RangeError(`The property \"${key}\" resolves to a non-positive value`);\n\t\t\t\tmask |= value;\n\t\t\t}\n\n\t\t\tthis.mask = mask as any;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a:\n\t * - `string`: If it's a property of {@link Flags}.\n\t * - `number`: If the BitField processes `number` primitives.\n\t * - `bigint`: If the BitField processes `bigint` primitives.\n\t * - `Array`: Resolves recursively.\n\t * @param resolvable The value to resolve.\n\t * @returns The resolved value.\n\t */\n\tpublic resolve(resolvable: ValueResolvable<this>): ValueType<this> {\n\t\tswitch (typeof resolvable) {\n\t\t\tcase 'string':\n\t\t\t\tif ((resolvable as string) in this.flags) return this.flags[resolvable as keyof Flags] as any;\n\t\t\t\tthrow new RangeError('Received a name that could not be resolved to a property of flags');\n\t\t\tcase this.type:\n\t\t\t\treturn ((resolvable as ValueType<this>) & this.mask) as any;\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(resolvable)) return resolvable.reduce((acc, value) => this.resolve(value) | acc, this.zero);\n\t\t\t\tthrow new TypeError('Received an object value that is not an Array');\n\t\t\tdefault:\n\t\t\t\tthrow new TypeError(`Received a value that is not either type \"string\", type \"${this.type}\", or an Array`);\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether or not `field` contains any of the bits from `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` has any of `bits`'s bits, also denoted as `A โฉ B โ โ
`.\n\t */\n\tpublic any(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\treturn (this.resolve(field) & this.resolve(bits)) !== this.zero;\n\t}\n\n\t/**\n\t * Checks whether or not `field` is a superset of or equal to `bits`.\n\t * @param field The bits to compare the bits from.\n\t * @param bits The bits to compare with.\n\t * @returns Whether or not `field` is a superset of or equal to `bits`, also denoted as `A โ B`.\n\t */\n\tpublic has(field: ValueResolvable<this>, bits: ValueResolvable<this>): boolean {\n\t\tconst resolved = this.resolve(bits);\n\t\treturn (this.resolve(field) & resolved) === resolved;\n\t}\n\n\t/**\n\t * Makes the complement of `field`, which is a field of all bits (of `U` or the union of all {@link Flags} bits)\n\t * that do not belong to `A`. It is the result of `U โ A`, or `difference(U, field)`.\n\t * @param field The bits to get the complement of.\n\t * @returns The complement of `field`, also denoted `Aแถ` or `A'`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.complement(0b0100);\n\t * // 0b1011\n\t * ```\n\t */\n\tpublic complement(field: ValueResolvable<this>): ValueType<this> {\n\t\treturn this.difference(this.mask, field);\n\t}\n\n\t/**\n\t * Makes a union of all the bits.\n\t * @param fields The bits to create a union of.\n\t * @returns The result of combining all bits together, also denoted as `โ
โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.union(0b0001, 0b0100);\n\t * // 0b0101\n\t *\n\t * bitfield.union(0b1100, 0b0001, 0b0010);\n\t * // 0b1111\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Union_(set_theory)}\n\t */\n\tpublic union(...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.zero as ValueType<this>;\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field | this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Makes an intersection of all the bits.\n\t * @param bitfield The first field.\n\t * @param fields The bits to intersect with `bitfield`.\n\t * @returns The result of intersecting `bitfield` with all of the `fields`, also denoted as `A โ fields`.\n\t * @example\n\t * ```typescript\n\t * bitfield.intersection(0b0001, 0b0100);\n\t * // 0b0000\n\t *\n\t * bitfield.intersection(0b1100, 0b0100);\n\t * // 0b0100\n\t *\n\t * bitfield.intersection(0b1101, 0b0101, 0b1100);\n\t * // 0b0100\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Intersection_(set_theory)}\n\t */\n\tpublic intersection(bitfield: ValueResolvable<this>, ...fields: readonly ValueResolvable<this>[]): ValueType<this> {\n\t\tlet field = this.resolve(bitfield);\n\t\tfor (const resolvable of fields) {\n\t\t\tfield = (field & this.resolve(resolvable)) as ValueType<this>;\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Removes from `a` the bits that exist in `b`.\n\t * @param a The first field.\n\t * @param b The bits to remove from `a`.\n\t * @returns The result of `a โ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.difference(0b1100, 0b0100);\n\t * // 0b1000\n\t *\n\t * bitfield.difference(0b1111, 0b0110);\n\t * // 0b1001\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Difference_(set_theory)}\n\t */\n\tpublic difference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) & ~this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Computes the symmetric difference, denoted as `A โ B` or `A ฮ B`, which is the disjunctive union, or the set of\n\t * elements which are in either of the sets, but not in their intersection. As such, this is the result of\n\t * `(A โ B) โช (B โ A)`, `union(difference(a, b), difference(b, a))`, or `a โ b`.\n\t * @remarks The empty set (`โ
`) is neutral, as such, `A ฮ โ
= A` and `A ฮ A = โ
`\n\t * @param a The first field.\n\t * @param b The second field.\n\t * @returns The result of computing `a ฮ b`.\n\t * @example\n\t * ```typescript\n\t * bitfield.symmetricDifference(0b1100, 0b0011);\n\t * // 0b1111\n\t *\n\t * bitfield.symmetricDifference(0b1101, 0b1011);\n\t * // 0b0110\n\t * ```\n\t * @seealso {@link https://en.wikipedia.org/wiki/Symmetric_difference}\n\t */\n\tpublic symmetricDifference(a: ValueResolvable<this>, b: ValueResolvable<this>): ValueType<this> {\n\t\treturn (this.resolve(a) ^ this.resolve(b)) as ValueType<this>;\n\t}\n\n\t/**\n\t * Retrieves an array of the properties from {@link Flags} whose values are contained in `field`.\n\t * @param field The field to convert to an array.\n\t * @returns The names of the {@link BitField}'s flag properties whose value are contained in `field`.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toArray(0b0101);\n\t * // ['Read', 'Edit']\n\t * ```\n\t */\n\tpublic toArray(field: ValueResolvable<this>): (keyof Flags)[] {\n\t\tconst bits = this.resolve(field);\n\t\tconst keys: (keyof Flags)[] = [];\n\t\tfor (const [key, bit] of Object.entries(this.flags)) {\n\t\t\t// Inline `.has` code for lower overhead:\n\t\t\tif ((bits & bit) === bit) keys.push(key);\n\t\t}\n\n\t\treturn keys;\n\t}\n\n\t/**\n\t * Retrieves an object with the properties from {@link Flags} whose values are boolean denoting whether or not the\n\t * flag's bit is contained in `field`.\n\t * @param field The field to convert to an object.\n\t * @returns An object with the properties of {@link Flags} which values are boolean.\n\t * @example\n\t * ```typescript\n\t * const bitfield = new BitField({\n\t * \tRead: 0b0001,\n\t * \tWrite: 0b0010,\n\t * \tEdit: 0b0100,\n\t * \tDelete: 0b1000\n\t * });\n\t *\n\t * bitfield.toObject(0b0101);\n\t * // {\n\t * // \tRead: true,\n\t * // \tWrite: false,\n\t * // \tEdit: true,\n\t * // \tDelete: false\n\t * // }\n\t * ```\n\t */\n\tpublic toObject(field: ValueResolvable<this>): Record<keyof Flags, boolean> {\n\t\tconst bits = this.resolve(field);\n\t\treturn Object.fromEntries(Object.entries(this.flags).map(([key, bit]) => [key, (bits & bit) === bit])) as Record<keyof Flags, boolean>;\n\t}\n}\n\ntype PrimitiveType<T> = T extends number ? number : bigint;\ntype MaybeArray<T> = T | readonly T[];\n\n/**\n * Resolves the type of the values the specified {@link BitField} takes.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueType<T> = T extends BitField<infer Flags> ? PrimitiveType<Flags[keyof Flags]> : never;\n\n/**\n * Resolves the possible types accepted by the specified {@link BitField}.\n * @typeparam A {@link BitField} instance type.\n */\nexport type ValueResolvable<T> = T extends BitField<infer Flags> ? MaybeArray<keyof Flags | PrimitiveType<Flags[keyof Flags]>> : never;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sapphire/bitfield",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A bitfield utility library for JavaScript.",
|
|
5
|
+
"author": "@sapphire",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"browser": "dist/index.global.js",
|
|
10
|
+
"unpkg": "dist/index.global.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"homepage": "https://github.com/sapphiredev/utilities/tree/main/packages/bitfield",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"lint": "eslint src tests --ext ts --fix -c ../../.eslintrc",
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"docs": "typedoc-json-parser",
|
|
24
|
+
"prepack": "yarn build",
|
|
25
|
+
"bump": "cliff-jumper",
|
|
26
|
+
"check-update": "cliff-jumper --dry-run"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/sapphiredev/utilities.git",
|
|
31
|
+
"directory": "packages/bitfield"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*.js*",
|
|
35
|
+
"dist/**/*.mjs*",
|
|
36
|
+
"dist/**/*.d*"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=v14.0.0",
|
|
40
|
+
"npm": ">=7.0.0"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"@sapphire/bitfield",
|
|
44
|
+
"bitfield",
|
|
45
|
+
"bot",
|
|
46
|
+
"typescript",
|
|
47
|
+
"ts",
|
|
48
|
+
"yarn",
|
|
49
|
+
"discord",
|
|
50
|
+
"sapphire",
|
|
51
|
+
"standalone"
|
|
52
|
+
],
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/sapphiredev/utilities/issues"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@favware/cliff-jumper": "^1.8.8",
|
|
61
|
+
"@vitest/coverage-c8": "^0.24.3",
|
|
62
|
+
"tsup": "^6.2.3",
|
|
63
|
+
"typedoc": "^0.23.16",
|
|
64
|
+
"typedoc-json-parser": "^6.0.0",
|
|
65
|
+
"typescript": "^4.8.4",
|
|
66
|
+
"vitest": "^0.24.3"
|
|
67
|
+
}
|
|
68
|
+
}
|