discord.js-selfbot-v13/src/util/BitField.js
Elysia d1d842098a chore: Miscellaneous fixes
#9271 djs

> Backports the following pull requests to version 13:
>
> * docs: describe private properties #8879
> * fix(snowflake): snowflakes length #9144
> * fix(Message): `bulkDeletable` permissions should be retrieved later for DMs #9146
> * fix(Message#editable): update editable check in threads locked #9216
> * fix: add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` #9219
> * fix(AutocompleteInteraction): Send `name_localizations` correctly #9238
> * fix(ThreadManager): Respect `cache` and `force` in fetching #9239
> * docs(FetchArchivedThreadOptions): `before` respects `archive_timestamp`, not creation timestamp #9240
> * refactor(FetchThreadsOptions): Remove `active` #9241
> * docs: differ `User#send` #9251
> * docs: add more examples #9252
> * fix(ClientUser): No mutation on edit #9259
> * fix: resolving string bitfield #9262
> * refactor: call `GuildBanManager#create()` directly #9263
> * docs(Role): Fix example for `comparePositionTo()` #9270
> * docs: fix compare position example #9272
> * fix: Keep symbols in actions manager #9293
2023-04-02 12:46:18 +07:00

171 lines
4.7 KiB
JavaScript

'use strict';
const { RangeError } = require('../errors');
/**
* Data structure that makes it easy to interact with a bitfield.
*/
class BitField {
/**
* @param {BitFieldResolvable} [bits=this.constructor.defaultBit] Bit(s) to read from
*/
constructor(bits = this.constructor.defaultBit) {
/**
* Bitfield of the packed bits
* @type {number|bigint}
*/
this.bitfield = this.constructor.resolve(bits);
}
/**
* Checks whether the bitfield has a bit, or any of multiple bits.
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
any(bit) {
return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.defaultBit;
}
/**
* Checks if this bitfield equals another
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
equals(bit) {
return this.bitfield === this.constructor.resolve(bit);
}
/**
* Checks whether the bitfield has a bit, or multiple bits.
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
has(bit) {
bit = this.constructor.resolve(bit);
return (this.bitfield & bit) === bit;
}
/**
* Gets all given bits that are missing from the bitfield.
* @param {BitFieldResolvable} bits Bit(s) to check for
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {string[]}
*/
missing(bits, ...hasParams) {
return new this.constructor(bits).remove(this).toArray(...hasParams);
}
/**
* Freezes these bits, making them immutable.
* @returns {Readonly<BitField>}
*/
freeze() {
return Object.freeze(this);
}
/**
* Adds bits to these ones.
* @param {...BitFieldResolvable} [bits] Bits to add
* @returns {BitField} These bits or new BitField if the instance is frozen.
*/
add(...bits) {
let total = this.constructor.defaultBit;
for (const bit of bits) {
total |= this.constructor.resolve(bit);
}
if (Object.isFrozen(this)) return new this.constructor(this.bitfield | total);
this.bitfield |= total;
return this;
}
/**
* Removes bits from these.
* @param {...BitFieldResolvable} [bits] Bits to remove
* @returns {BitField} These bits or new BitField if the instance is frozen.
*/
remove(...bits) {
let total = this.constructor.defaultBit;
for (const bit of bits) {
total |= this.constructor.resolve(bit);
}
if (Object.isFrozen(this)) return new this.constructor(this.bitfield & ~total);
this.bitfield &= ~total;
return this;
}
/**
* Gets an object mapping field names to a {@link boolean} indicating whether the
* bit is available.
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {Object}
*/
serialize(...hasParams) {
const serialized = {};
for (const [flag, bit] of Object.entries(this.constructor.FLAGS)) serialized[flag] = this.has(bit, ...hasParams);
return serialized;
}
/**
* Gets an {@link Array} of bitfield names based on the bits available.
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {string[]}
*/
toArray(...hasParams) {
return Object.keys(this.constructor.FLAGS).filter(bit => this.has(bit, ...hasParams));
}
toJSON() {
return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString();
}
valueOf() {
return this.bitfield;
}
*[Symbol.iterator]() {
yield* this.toArray();
}
/**
* Data that can be resolved to give a bitfield. This can be:
* * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS})
* * A string bit number
* * An instance of BitField
* * An Array of BitFieldResolvable
* @typedef {number|string|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable
*/
/**
* Resolves bitfields to their numeric form.
* @param {BitFieldResolvable} [bit] bit(s) to resolve
* @returns {number|bigint}
*/
static resolve(bit) {
const { defaultBit } = this;
if (typeof defaultBit === typeof bit && bit >= defaultBit) return bit;
if (bit instanceof BitField) return bit.bitfield;
if (Array.isArray(bit)) return bit.map(p => this.resolve(p)).reduce((prev, p) => prev | p, defaultBit);
if (typeof bit === 'string') {
if (!isNaN(bit)) return typeof defaultBit === 'bigint' ? BigInt(bit) : Number(bit);
if (this.FLAGS[bit] !== undefined) return this.FLAGS[bit];
}
throw new RangeError('BITFIELD_INVALID', bit);
}
}
/**
* Numeric bitfield flags.
* <info>Defined in extension classes</info>
* @type {Object}
* @abstract
*/
BitField.FLAGS = {};
/**
* @type {number|bigint}
* @private
*/
BitField.defaultBit = 0;
module.exports = BitField;