Skip to content
This repository has been archived by the owner on Apr 27, 2024. It is now read-only.

begin work on permissions_new changes #88

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
export interface BitFieldObject {
bitfield: number;
bitfield: bigint;
}

export type BitFieldResolvable = string | number | BitFieldObject | (string | number | BitFieldObject)[];
export type BitFieldResolvable<V extends string> = V | number | bigint | BitFieldObject | (V | number | bigint | BitFieldObject)[];

/* eslint-disable no-bitwise */

/**
* The base class for handling BitField data
*/
export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
export class BitField<T extends BitFieldResolvable<string>> implements BitFieldObject {

/**
* The bitfield data
*/
public bitfield: number;
public bitfield: bigint;

public constructor(bits?: T) {
this.bitfield = (this.constructor as typeof BitField).resolve<T>(bits);
Expand Down Expand Up @@ -57,7 +57,7 @@ export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
* @param bits The bit/s to add
*/
public add(...bits: T[]): BitField<T> {
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0);
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0n);
if (Object.isFrozen(this)) return new (this.constructor as typeof BitField)<T>((this.bitfield | total) as T);
this.bitfield |= total;
return this;
Expand All @@ -68,7 +68,7 @@ export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
* @param bits The bit/s to remove
*/
public remove(...bits: T[]): BitField<T> {
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0);
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0n);
if (Object.isFrozen(this)) return new (this.constructor as typeof BitField)<T>((this.bitfield & ~total) as T);
this.bitfield &= ~total;
return this;
Expand All @@ -79,7 +79,7 @@ export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
* @param bits The bit/s to mask
*/
public mask(...bits: T[]): BitField<T> {
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0);
const total = bits.reduce((acc, bit) => acc | (this.constructor as typeof BitField).resolve<T>(bit), 0n);
if (Object.isFrozen(this)) return new (this.constructor as typeof BitField)<T>((this.bitfield & total) as T);
this.bitfield &= total;
return this;
Expand All @@ -104,14 +104,14 @@ export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
/**
* Defines what this Bitfield is when converted to JSON
*/
public toJSON(): number {
return this.bitfield;
public toJSON(): string {
return this.bitfield.toString();
}

/**
* Defines value behavior of this BitField
*/
public valueOf(): number {
public valueOf(): bigint {
return this.bitfield;
}

Expand All @@ -125,29 +125,31 @@ export class BitField<T extends BitFieldResolvable> implements BitFieldObject {
/**
* Flags for this BitField (Should be implemented in child classes)
*/
public static FLAGS: Record<string, number> = {} as const;
public static FLAGS: Record<string, bigint> = {} as const;

/**
* The default flags for the bitfield
*/
public static DEFAULT = 0;
public static DEFAULT = 0n;

/**
* The value of all bits in this bitfield
*/
public static get ALL(): number {
return Object.values<number>(this.FLAGS).reduce((all, byte) => all | byte, 0);
public static get ALL(): bigint {
return Object.values<bigint>(this.FLAGS).reduce((all, byte) => all | byte, 0n);
}

/**
* Resolves a BitFieldResolvable into a number
* @param bit The bit/s to resolve
*/
public static resolve<T extends BitFieldResolvable>(bit?: T): number {
if (typeof bit === 'undefined') return 0;
if (typeof bit === 'number' && bit >= 0) return bit;
public static resolve<T extends BitFieldResolvable<string>>(bit?: T): bigint {
if (typeof bit === 'undefined') return 0n;
// eslint-disable-next-line no-undef
if (typeof bit === 'number' && bit >= 0) return BigInt(bit);
if (typeof bit === 'bigint' && bit >= 0n) return bit;
if (bit instanceof BitField) return bit.bitfield;
if (Array.isArray(bit)) return (bit as (string | number | BitFieldObject)[]).map((byte) => this.resolve(byte)).reduce((bytes, byte) => bytes | byte, 0);
if (Array.isArray(bit)) return (bit as (string | number | BitFieldObject)[]).map((byte) => this.resolve(byte)).reduce((bytes, byte) => bytes | byte, 0n);
if (typeof bit === 'string') return this.FLAGS[bit];
throw new RangeError(`An invalid bit was provided. Received: ${typeof bit}`);
}
Expand Down
44 changes: 22 additions & 22 deletions test/Util.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import ava from 'ava';
import { BitField, BitFieldObject } from '../src';
import { BitField, BitFieldResolvable } from '../src';

const enum TestBitsFlags {
A = 'A',
B = 'B',
C = 'C'
}

type TestResolvable = TestBitsFlags | number | BitFieldObject | (TestBitsFlags | number | BitFieldObject)[]
type TestResolvable = BitFieldResolvable<TestBitsFlags>;

/* eslint-disable no-bitwise, id-length */

class TestBits extends BitField<TestResolvable> {

static FLAGS = {
[TestBitsFlags.A]: 1 << 0,
[TestBitsFlags.B]: 1 << 1,
[TestBitsFlags.C]: 1 << 2
[TestBitsFlags.A]: 1n << 0n,
[TestBitsFlags.B]: 1n << 1n,
[TestBitsFlags.C]: 1n << 2n
} as const;

}
Expand Down Expand Up @@ -69,7 +69,7 @@ ava('freeze', (test): void => {
const testBits = new TestBits(1).freeze();

test.throws(() => {
testBits.bitfield = 2;
testBits.bitfield = 2n;
}, { instanceOf: Error });
});

Expand All @@ -78,7 +78,7 @@ ava('add', (test): void => {

testBits.add(TestBitsFlags.B);

test.is(testBits.bitfield, 3);
test.is(testBits.bitfield, 3n);
});

ava('frozen add', (test): void => {
Expand All @@ -87,16 +87,16 @@ ava('frozen add', (test): void => {
const testBits = new TestBits(1).freeze();
const otherBits = testBits.add(TestBitsFlags.B);

test.is(testBits.bitfield, 1);
test.is(otherBits.bitfield, 3);
test.is(testBits.bitfield, 1n);
test.is(otherBits.bitfield, 3n);
});

ava('remove', (test): void => {
const testBits = new TestBits(3);

testBits.remove(TestBitsFlags.B);

test.is(testBits.bitfield, 1);
test.is(testBits.bitfield, 1n);
});

ava('frozen remove', (test): void => {
Expand All @@ -105,16 +105,16 @@ ava('frozen remove', (test): void => {
const testBits = new TestBits(3).freeze();
const otherBits = testBits.remove(TestBitsFlags.B);

test.is(testBits.bitfield, 3);
test.is(otherBits.bitfield, 1);
test.is(testBits.bitfield, 3n);
test.is(otherBits.bitfield, 1n);
});

ava('mask', (test): void => {
const testBits = new TestBits(3);

testBits.mask(TestBitsFlags.B);

test.is(testBits.bitfield, 2);
test.is(testBits.bitfield, 2n);
});

ava('frozen mask', (test): void => {
Expand All @@ -123,8 +123,8 @@ ava('frozen mask', (test): void => {
const testBits = new TestBits(3).freeze();
const otherBits = testBits.mask(TestBitsFlags.B);

test.is(testBits.bitfield, 3);
test.is(otherBits.bitfield, 2);
test.is(testBits.bitfield, 3n);
test.is(otherBits.bitfield, 2n);
});

ava('serialize', (test): void => {
Expand All @@ -143,13 +143,13 @@ ava('toArray', (test): void => {
ava('toJSON', (test): void => {
const testBits = new TestBits(3);

test.is(testBits.toJSON(), 3);
test.is(testBits.toJSON(), '3');
});

ava('valueOf', (test): void => {
const testBits = new TestBits(3);

test.is(testBits.valueOf(), 3);
test.is(testBits.valueOf(), 3n);
});

ava('Symbol.iterator', (test): void => {
Expand All @@ -159,23 +159,23 @@ ava('Symbol.iterator', (test): void => {
});

ava('resolve', (test): void => {
test.is(TestBits.resolve<TestResolvable>(), 0);
test.is(TestBits.resolve<TestResolvable>(), 0n);
});

ava('resolve number', (test): void => {
test.is(TestBits.resolve<TestResolvable>(1), 1);
test.is(TestBits.resolve<TestResolvable>(1), 1n);
});

ava('resolve string', (test): void => {
test.is(TestBits.resolve<TestResolvable>(TestBitsFlags.B), 2);
test.is(TestBits.resolve<TestResolvable>(TestBitsFlags.B), 2n);
});

ava('resolve bitfield', (test): void => {
test.is(TestBits.resolve<TestResolvable>(new TestBits(TestBitsFlags.B)), 2);
test.is(TestBits.resolve<TestResolvable>(new TestBits(TestBitsFlags.B)), 2n);
});

ava('resolve array mixed', (test): void => {
test.is(TestBits.resolve<TestResolvable>([1, TestBitsFlags.B, new TestBits(TestBitsFlags.C)]), 7);
test.is(TestBits.resolve<TestResolvable>([1, TestBitsFlags.B, new TestBits(TestBitsFlags.C)]), 7n);
});

ava('resolve bad input', (test): void => {
Expand Down