mirror of
https://github.com/discordjs/discord.js.git
synced 2026-06-01 16:40:07 +00:00
* chore: init /structures * feat: base structure * feat: initial structures design attempt * refactor(Structure): use unknown to store in kData * feat(Structure): add Invite refactor(Structure): patch to _patch * refactor: symbol names and override location * fix: don't possibly return 0 if discord borks Co-authored-by: Synbulat Biishev <signin@syjalo.dev> * refactor: use getter value instead of api Co-authored-by: Synbulat Biishev <signin@syjalo.dev> * refactor: cache createdTimestamp value Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> * docs: better docs for what's done so far * feat: add Mixin * refactor(User): remove bitfield getters and add displayName * feat(structures): add Connection * feat(structures): add Channel base * refactor(Mixin): trace prototype chain, allow construction * fix(structures): fix mixin behavior * fix(structures): data optimization call behavior from perf testing * feat: channel mixins * chore: update deps * feat: channels and mixins * chore: more typeguard tests * fix: tests and some other issues * feat: add ChannelWebhookMixin * fix: more tests * chore: tests and docs * chore: docs * fix: remove unneccessary omitted * chore: apply code suggestions * refactor: change how extended invite works * fix: type imports * Apply suggestions from code review Co-authored-by: Almeida <github@almeidx.dev> * fix: tests * chore: add jsdoc * refactor: apply code suggestions * fix: don't instantiate sub-structures * fix: don't do null default twice * chore: use formatters, add _cache * chore: lockfile * chore: move MixinTypes to declaratiion file * fix: tests * fix: don't include source d.ts files for docs * feat: bitfields * feat: more bitfields * refactor: remove DirectoryChannel structure * chore: apply suggestions from code review * chore: remove unused import * refactor: use symbol for mixin toJSON, remove _ prefix * chore: apply suggestions from code review * refactor: remove bitfield casts * refactor: remove special case for threadchannel types * fix: apply code review suggestions * refactor: bitfields always store bigint * fix: tests * chore: apply suggestions from code review * fix: lint * refactor: conditional structuredClone * Apply suggestions from code review Co-authored-by: ckohen <chaikohen@gmail.com> * fix: code review errors * fix: lint * chore: bump dtypes * Update packages/structures/cliff.toml Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * docs: link to VideoQualityMode * chore: typo in comment * chore: small nits in docs links * chore: small nits * docs: forgot one * chore: update template * chore: typos and things * chore: apply suggestions from code review * fix: tests and typeguards * chore: don't clone appliedTags * refactor: use a symbol for patch method * fix: add missing readonly * chore: remove todo comment * refactor: use symbol for clone * fix: add constraint to DataType * chore: apply suggestions * fix: dtypes bump * chore: fix comment * chore: add todo comment * chore: mark bitfield as todo chore: mark bit field as todo and edit readme --------- Co-authored-by: ckohen <chaikohen@gmail.com> Co-authored-by: Synbulat Biishev <signin@syjalo.dev> Co-authored-by: Almeida <github@almeidx.dev> Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
204 lines
6.0 KiB
TypeScript
204 lines
6.0 KiB
TypeScript
import type { EnumLike, NonAbstract, RecursiveReadonlyArray } from '../utils/types.js';
|
|
|
|
// TODO: this currently is mostly copied from mainlib discord.js v14 and definitely needs a refactor in a later iteration
|
|
|
|
/**
|
|
* Data that can be resolved to give a bit field. This can be:
|
|
* A bit number (this can be a number literal or a value taken from {@link (BitField:class).Flags})
|
|
* A string bit number
|
|
* An instance of BitField
|
|
* An Array of BitFieldResolvable
|
|
*/
|
|
export type BitFieldResolvable<Flags extends string> =
|
|
| Flags
|
|
| Readonly<BitField<Flags>>
|
|
| RecursiveReadonlyArray<Flags | Readonly<BitField<Flags>> | bigint | number | `${bigint}`>
|
|
| bigint
|
|
| number
|
|
| `${bigint}`;
|
|
|
|
/**
|
|
* Data structure that makes it easy to interact with a bit field.
|
|
*/
|
|
export abstract class BitField<Flags extends string> {
|
|
/**
|
|
* Numeric bit field flags.
|
|
*
|
|
* @remarks Defined in extension classes
|
|
*/
|
|
public static readonly Flags: EnumLike<unknown, bigint | number> = {};
|
|
|
|
public static readonly DefaultBit: bigint = 0n;
|
|
|
|
/**
|
|
* Bitfield of the packed bits
|
|
*/
|
|
public bitField: bigint;
|
|
|
|
declare public ['constructor']: NonAbstract<typeof BitField<Flags>>;
|
|
|
|
/**
|
|
* @param bits - Bit(s) to read from
|
|
*/
|
|
public constructor(bits: BitFieldResolvable<Flags> = this.constructor.DefaultBit) {
|
|
this.bitField = this.constructor.resolve(bits);
|
|
}
|
|
|
|
/**
|
|
* Checks whether the bit field has a bit, or any of multiple bits.
|
|
*
|
|
* @param bit - Bit(s) to check for
|
|
* @returns Whether the bit field has the bit(s)
|
|
*/
|
|
public any(bit: BitFieldResolvable<Flags>) {
|
|
return (this.bitField & this.constructor.resolve(bit)) !== this.constructor.DefaultBit;
|
|
}
|
|
|
|
/**
|
|
* Checks if this bit field equals another
|
|
*
|
|
* @param bit - Bit(s) to check for
|
|
* @returns Whether this bit field equals the other
|
|
*/
|
|
public equals(bit: BitFieldResolvable<Flags>) {
|
|
return this.bitField === this.constructor.resolve(bit);
|
|
}
|
|
|
|
/**
|
|
* Checks whether the bit field has a bit, or multiple bits.
|
|
*
|
|
* @param bit - Bit(s) to check for
|
|
* @returns Whether the bit field has the bit(s)
|
|
*/
|
|
public has(bit: BitFieldResolvable<Flags>, ..._hasParams: unknown[]) {
|
|
const resolvedBit = this.constructor.resolve(bit);
|
|
return (this.bitField & resolvedBit) === resolvedBit;
|
|
}
|
|
|
|
/**
|
|
* Gets all given bits that are missing from the bit field.
|
|
*
|
|
* @param bits - Bit(s) to check for
|
|
* @param hasParams - Additional parameters for the has method, if any
|
|
* @returns A bit field containing the missing bits
|
|
*/
|
|
public missing(bits: BitFieldResolvable<Flags>, ...hasParams: readonly unknown[]) {
|
|
return new this.constructor(bits).remove(this).toArray(...hasParams);
|
|
}
|
|
|
|
/**
|
|
* Freezes these bits, making them immutable.
|
|
*
|
|
* @returns This bit field but frozen
|
|
*/
|
|
public freeze() {
|
|
return Object.freeze(this);
|
|
}
|
|
|
|
/**
|
|
* Adds bits to these ones.
|
|
*
|
|
* @param bits - Bits to add
|
|
* @returns These bits or new BitField if the instance is frozen.
|
|
*/
|
|
public add(...bits: BitFieldResolvable<Flags>[]) {
|
|
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 bits - Bits to remove
|
|
* @returns These bits or new BitField if the instance is frozen.
|
|
*/
|
|
public remove(...bits: BitFieldResolvable<Flags>[]) {
|
|
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 boolean indicating whether the bit is available.
|
|
*
|
|
* @param hasParams - Additional parameters for the has method, if any
|
|
* @returns An object mapping field names to a boolean indicating whether the bit is available
|
|
*/
|
|
public serialize(...hasParams: readonly unknown[]) {
|
|
const serialized: Partial<Record<keyof Flags, boolean>> = {};
|
|
for (const [flag, bit] of Object.entries(this.constructor.Flags)) {
|
|
if (Number.isNaN(Number(flag))) serialized[flag as keyof Flags] = this.has(bit as bigint | number, ...hasParams);
|
|
}
|
|
|
|
return serialized;
|
|
}
|
|
|
|
/**
|
|
* Gets an Array of bit field names based on the bits available.
|
|
*
|
|
* @param hasParams - Additional parameters for the has method, if any
|
|
* @returns An Array of bit field names
|
|
*/
|
|
public toArray(...hasParams: readonly unknown[]) {
|
|
return [...this[Symbol.iterator](...hasParams)];
|
|
}
|
|
|
|
public toJSON(asNumber?: boolean) {
|
|
if (asNumber) {
|
|
if (this.bitField > Number.MAX_SAFE_INTEGER) {
|
|
throw new RangeError(
|
|
`Cannot convert bitfield value ${this.bitField} to number, as it is bigger than ${Number.MAX_SAFE_INTEGER} (the maximum safe integer)`,
|
|
);
|
|
}
|
|
|
|
return Number(this.bitField);
|
|
}
|
|
|
|
return this.bitField.toString();
|
|
}
|
|
|
|
public valueOf() {
|
|
return this.bitField;
|
|
}
|
|
|
|
public *[Symbol.iterator](...hasParams: unknown[]) {
|
|
for (const bitName of Object.keys(this.constructor.Flags)) {
|
|
if (Number.isNaN(Number(bitName)) && this.has(bitName as Flags, ...hasParams)) yield bitName as Flags;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resolves bit fields to their numeric form.
|
|
*
|
|
* @param bit - bit(s) to resolve
|
|
* @returns the numeric value of the bit fields
|
|
*/
|
|
public static resolve<Flags extends string = string>(bit: BitFieldResolvable<Flags>): bigint {
|
|
const DefaultBit = this.DefaultBit;
|
|
if (typeof bit === 'bigint' && bit >= DefaultBit) return bit;
|
|
if (typeof bit === 'number' && BigInt(bit) >= DefaultBit) return BigInt(bit);
|
|
if (bit instanceof BitField) return bit.bitField;
|
|
if (Array.isArray(bit)) {
|
|
return bit.map((bit_) => this.resolve(bit_)).reduce((prev, bit_) => prev | bit_, DefaultBit);
|
|
}
|
|
|
|
if (typeof bit === 'string') {
|
|
if (!Number.isNaN(Number(bit))) return BigInt(bit);
|
|
if (bit in this.Flags) return this.Flags[bit as keyof typeof this.Flags];
|
|
}
|
|
|
|
throw new Error(`BitFieldInvalid: ${JSON.stringify(bit)}`);
|
|
}
|
|
}
|