@eliyya/flagged-bitfield
v1.1.1
Published
Type-safe flagged bitfield utility for TypeScript/JavaScript
Maintainers
Readme
flagged-bitfield
Type-safe flagged bitfield utility for TypeScript/JavaScript using bigint under the hood. Provides a clean API for combining, testing, and transforming named flags with excellent IntelliSense support via TSDoc.
- Tiny, dependency-free
- Type-safe flag names via generics
- Mutable and immutable-style operations
- Mask-aware and bigint-based for large flag sets
Installation
npm install @eliyya/flagged-bitfieldQuick start
import { FlaggedBitfield } from '@eliyya/flagged-bitfield'
// 1) Define your flags by extending the class
class Permissions extends FlaggedBitfield<typeof Permissions.Flags> {
static Flags = {
Read: 1n << 0n,
Write: 1n << 1n,
Execute: 1n << 2n,
Admin: 1n << 3n,
} as const
}
// 2) Create instances
const p = new Permissions(['Read', 'Write'])
// 3) Test and manipulate
p.has('Read') // true
p.has('Execute') // false
// Mutating operations
p.add('Execute')
p.remove('Write')
p.invert() // invert bits within the mask
// Immutable-style operations (return a new instance)
const q = p.with('Admin').without('Read')
// Interop
q.toArray() // => ['Admin', 'Execute'] (order by bit value)
q.toObject() // => { Read: false, Write: false, Execute: true, Admin: true }
q.toString(2) // => binary string of the bigint
q.toNumber() // => numeric representation (may truncate for huge values)API overview
The class exposes both mutating and non-mutating methods. All operations respect the mask derived from your Flags definition.
Mutable methods
add(bit)remove(bit)invert()freeze()(turns the instance into a read-only, no-op for mutations)
Immutable methods (return a new instance)
with(bit)without(bit)missing()(complement within the mask)union(bit)(alias ofwith)intersection(bit)difference(bit)symmetricDifference(bit)complement()
Queries and utilities
has(bit)— any overlapequals(bit)— exact equalityany(bit)— intersection != 0ngetFlags()— returns the flags definitionisFrozen()toArray()toObject()toJSON()toString(radix?)toNumber()- Iteration support:
[Symbol.iterator]()yields present flags in ascending bit order - Helpers:
find,findIndex,forEach,map,entries,keys,values
Accepted bit inputs
Most methods accept any of the following as a bit input:
- A single flag key (e.g.,
'Read') - A numeric
numberorbigintvalue - An array of the above
- Another
FlaggedBitfieldinstance
Advanced usage
Freezing instances
const frozen = p.freeze()
frozen.add('Admin') // no-op, still frozen
frozen.isFrozen() // trueCustom default bit
class Defaults extends FlaggedBitfield<typeof Defaults.Flags> {
static Flags = { A: 1n, B: 2n, C: 4n } as const
static DefaultBit = 1n // Start with flag A enabled
}
const d = new Defaults() // bitfield starts at 1nWorking with raw numbers/bigints, strings, arrays and other FlaggedBitfield instances
new Permissions(0b001 | 0b100) // Read + Execute
new Permissions(5) // Read + Execute
new Permissions(5n) // Read + Execute
new Permissions('5') // Read + Execute
new Permissions(['Read', 'Execute']) // Read + Execute
new Permissions(Permissions.Flags.Read | Permissions.Flags.Execute) // Read + Execute
new Permissions([Permissions.Flags.Read, Permissions.Flags.Execute]) // Read + Execute
new Permissions(new Permissions(['Read', 'Execute'])) // same as aboveCombining sets
const a = new Permissions(['Read'])
const b = new Permissions(['Write'])
const union = a.union(b) // Read | Write
const inter = union.intersection(a) // Read
const diff = union.difference(a) // Write
const symDiff = a.symmetricDifference(b) // Read ^ WriteTypeScript notes
- All bits are normalized to
bigintinternally. - The mask is computed from your
Flagsobject:Object.values(Flags)OR-reduced. - Ordering for iteration and derived arrays is ascending by bit value.
Contributing
Issues and PRs are welcome! Please open an issue first to discuss major changes.
License
MIT
