copied set implementations from MultiFlag JS
This commit is contained in:
9
node/.gitignore
vendored
Normal file
9
node/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
node_modules
|
||||
|
||||
coverage
|
||||
coverage.xml
|
||||
|
||||
.idea
|
||||
14
node/.npmignore
Normal file
14
node/.npmignore
Normal file
@@ -0,0 +1,14 @@
|
||||
src
|
||||
build
|
||||
tests
|
||||
.idea
|
||||
.prettierrc
|
||||
jest.config.js
|
||||
tsconfig.json
|
||||
.editorconfig
|
||||
.eslintrc.json
|
||||
.gitignore
|
||||
.travis.yml
|
||||
rollup.config.dev.js
|
||||
rollup.config.js
|
||||
yarn-error.log
|
||||
6
node/.prettierrc
Normal file
6
node/.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
10
node/README.md
Normal file
10
node/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Multiflag for JavaScript and TypeScript
|
||||
|
||||
## Browser compatibility
|
||||
|
||||
| | Chrome | Firefox | Safari | *All platforms* |
|
||||
|---------------------|:----------------:|:----------------:|:--------------:|----------------------------------------------------------------------------------|
|
||||
| `DynamicBitflagSet` | ✓ 67 | ✓ 68 | ✓ 14 | [View on caniuse.com](https://caniuse.com/mdn-javascript_builtins_bigint_bigint) |
|
||||
| `CollectionFlagSet` | ∗ 38 <br/> ✓ 122 | ∗ 13 <br/> ✓ 127 | ∗ 9 <br/> ✓ 17 | [View on caniuse.com](https://caniuse.com/mdn-javascript_builtins_set) |
|
||||
|
||||
✓ Full support    ∗ Supported through polyfills
|
||||
5270
node/package-lock.json
generated
Normal file
5270
node/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
53
node/package.json
Normal file
53
node/package.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "multiflag",
|
||||
"version": "2.0.0",
|
||||
"description": "flag/bitflag helper",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"postbuild": "cp package.json README.md ../LICENSE dist",
|
||||
"test": "jest",
|
||||
"type-check": "tsc --noEmit",
|
||||
"format": "prettier --write src/ tests/"
|
||||
},
|
||||
"tsup": {
|
||||
"entry": ["src/index.ts"],
|
||||
"splitting": false,
|
||||
"dts": true,
|
||||
"minify": true,
|
||||
"sourcemap": true,
|
||||
"clean": true
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node",
|
||||
"moduleNameMapper": {
|
||||
"~": "<rootDir>/src/index.ts"
|
||||
},
|
||||
"collectCoverageFrom": ["src/**/*.ts"],
|
||||
"coverageReporters": [ ["cobertura", {"file": "coverage.xml"}] ]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/louisdevie/multiflag.git"
|
||||
},
|
||||
"keywords": [
|
||||
"flag",
|
||||
"bitflag"
|
||||
],
|
||||
"author": "Louis DEVIE",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/louisdevie/multiflag/issues"
|
||||
},
|
||||
"homepage": "https://github.com/louisdevie/multiflag#readme",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-jest": "^29.3.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
75
node/src/base64.ts
Normal file
75
node/src/base64.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* The character code for "A", 0 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const ZERO = 65
|
||||
|
||||
/**
|
||||
* The character code for "a", 26 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const TWENTY_SIX = 97
|
||||
|
||||
/**
|
||||
* The character code for "0", 52 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const FIFTY_TWO = 48
|
||||
|
||||
/**
|
||||
* The character code for "-", 62 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const SIXTY_TWO = 45
|
||||
|
||||
/**
|
||||
* The character code for "_", 63 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const SIXTY_THREE = 95
|
||||
|
||||
/**
|
||||
* The string "A", 0 in base 64.
|
||||
* @internal
|
||||
*/
|
||||
export const ZERO_STRING = 'A'
|
||||
|
||||
/** @internal */
|
||||
export function encodeB64Byte(byte: number): string {
|
||||
let charCode
|
||||
if (byte < 26) {
|
||||
charCode = byte + ZERO
|
||||
} else if (byte < 52) {
|
||||
charCode = byte - 26 + TWENTY_SIX
|
||||
} else if (byte < 62) {
|
||||
charCode = byte - 52 + FIFTY_TWO
|
||||
} else {
|
||||
charCode = byte == 62 ? SIXTY_TWO : SIXTY_THREE
|
||||
}
|
||||
return String.fromCharCode(charCode)
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function decodeB64Byte(encodedByte: string): number {
|
||||
const charCode = encodedByte.charCodeAt(0)
|
||||
if (charCode == SIXTY_THREE) {
|
||||
return 63
|
||||
} else if (charCode == SIXTY_TWO) {
|
||||
return 62
|
||||
} else if (charCode >= TWENTY_SIX) {
|
||||
return charCode - TWENTY_SIX + 26
|
||||
} else if (charCode >= ZERO) {
|
||||
return charCode - ZERO
|
||||
} else {
|
||||
return charCode - FIFTY_TWO + 52
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function normaliseB64String(encoded: string): string {
|
||||
let lastNonZeroByteIndex = encoded.length - 1
|
||||
while (encoded.charAt(lastNonZeroByteIndex) === ZERO_STRING) {
|
||||
lastNonZeroByteIndex--
|
||||
}
|
||||
return encoded.substring(0, lastNonZeroByteIndex + 1)
|
||||
}
|
||||
1
node/src/builders/index.ts
Normal file
1
node/src/builders/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { FlagSetBuilder } from './root'
|
||||
32
node/src/builders/number.ts
Normal file
32
node/src/builders/number.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { BitFlagSet } from '../flagsets'
|
||||
import {
|
||||
DefineFlag,
|
||||
RequireParentsOrDefineFlag,
|
||||
SetValueOrCompose,
|
||||
} from './syntax'
|
||||
|
||||
export class BitFlagSetBuilder
|
||||
implements
|
||||
RequireParentsOrDefineFlag<BitFlagSet>,
|
||||
SetValueOrCompose<BitFlagSet>
|
||||
{
|
||||
public define(name: string): SetValueOrCompose<BitFlagSet> {
|
||||
return this
|
||||
}
|
||||
|
||||
public requires(...flags: string[]): DefineFlag<BitFlagSet> {
|
||||
return this
|
||||
}
|
||||
|
||||
public withValue(value: number): RequireParentsOrDefineFlag<BitFlagSet> {
|
||||
return this
|
||||
}
|
||||
|
||||
public compose(...flags: string[]): DefineFlag<BitFlagSet> {
|
||||
return this
|
||||
}
|
||||
|
||||
public build(): BitFlagSet {
|
||||
return new BitFlagSet()
|
||||
}
|
||||
}
|
||||
9
node/src/builders/root.ts
Normal file
9
node/src/builders/root.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { SelectFlagSetType, DefineFlag } from './syntax'
|
||||
import { BitFlagSetBuilder } from './number'
|
||||
import { BitFlagSet } from '../flagsets'
|
||||
|
||||
export class FlagSetBuilder implements SelectFlagSetType {
|
||||
public useBitFlags(): DefineFlag<BitFlagSet> {
|
||||
return new BitFlagSetBuilder()
|
||||
}
|
||||
}
|
||||
21
node/src/builders/syntax.ts
Normal file
21
node/src/builders/syntax.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { BitFlagSet } from '../flagsets'
|
||||
|
||||
export interface SelectFlagSetType {
|
||||
useBitFlags(): DefineFlag<BitFlagSet>
|
||||
}
|
||||
|
||||
export interface DefineFlag<T> {
|
||||
define(name: string): SetValueOrCompose<T>
|
||||
|
||||
build(): T
|
||||
}
|
||||
|
||||
export interface RequireParentsOrDefineFlag<T> extends DefineFlag<T> {
|
||||
requires(...flags: string[]): DefineFlag<T>
|
||||
}
|
||||
|
||||
export interface SetValueOrCompose<T> {
|
||||
withValue(value: number): RequireParentsOrDefineFlag<T>
|
||||
|
||||
compose(...flags: string[]): DefineFlag<T>
|
||||
}
|
||||
52
node/src/enumeration/base64.ts
Normal file
52
node/src/enumeration/base64.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { decodeB64Byte, ZERO_STRING } from '../base64'
|
||||
|
||||
export class Base64BitflagIterator implements Iterator<number> {
|
||||
private _value: string
|
||||
private _currentByte: number
|
||||
private _currentBit: number
|
||||
|
||||
public constructor(value: string) {
|
||||
this._value = value
|
||||
this._currentByte = 0
|
||||
this._currentBit = 0
|
||||
}
|
||||
|
||||
private moveToNextByte(): boolean {
|
||||
// next multiple of 6
|
||||
let index = Math.ceil(this._currentBit / 6)
|
||||
let byte = this._value.charAt(index)
|
||||
|
||||
while (byte === ZERO_STRING) {
|
||||
// skip bytes equal to zero
|
||||
byte = this._value.charAt(++index)
|
||||
}
|
||||
|
||||
if (byte === '') {
|
||||
// reached the end of the string
|
||||
return false
|
||||
} else {
|
||||
// found a non-zero byte
|
||||
this._currentByte = decodeB64Byte(byte)
|
||||
this._currentBit = index * 6
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public next(): IteratorResult<number, undefined> {
|
||||
if (this._currentByte == 0) {
|
||||
if (!this.moveToNextByte()) {
|
||||
return { done: true, value: undefined }
|
||||
}
|
||||
}
|
||||
|
||||
while ((this._currentByte & 1) == 0) {
|
||||
this._currentByte >>= 1
|
||||
this._currentBit += 1
|
||||
}
|
||||
|
||||
this._currentByte >>= 1
|
||||
this._currentBit += 1
|
||||
|
||||
return { done: false, value: this._currentBit }
|
||||
}
|
||||
}
|
||||
32
node/src/enumeration/bigint.ts
Normal file
32
node/src/enumeration/bigint.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ENV_BI } from '../env'
|
||||
|
||||
export class BigBitFlagsIterator implements Iterator<bigint> {
|
||||
private _value: bigint
|
||||
private _current: bigint
|
||||
|
||||
public constructor(value: bigint) {
|
||||
this._value = value
|
||||
this._current = ENV_BI.ONE
|
||||
}
|
||||
|
||||
public [Symbol.iterator](): IterableIterator<bigint> {
|
||||
return this
|
||||
}
|
||||
|
||||
public next(): IteratorResult<bigint, undefined> {
|
||||
if (this._value == ENV_BI.ZERO) {
|
||||
return { done: true, value: undefined }
|
||||
}
|
||||
|
||||
while ((this._value & ENV_BI.ONE) == ENV_BI.ZERO) {
|
||||
this._value >>= ENV_BI.ONE
|
||||
this._current <<= ENV_BI.ONE
|
||||
}
|
||||
|
||||
const result = this._current
|
||||
this._value >>= ENV_BI.ONE
|
||||
this._current <<= ENV_BI.ONE
|
||||
|
||||
return { done: false, value: result }
|
||||
}
|
||||
}
|
||||
24
node/src/enumeration/factory.ts
Normal file
24
node/src/enumeration/factory.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { EnumerateFlags } from '.'
|
||||
|
||||
export function useIterator<S, F>(
|
||||
value: S,
|
||||
IterConstructor: { new (value: S): Iterator<F> }
|
||||
): EnumerateFlags<F> {
|
||||
const enumerate = {
|
||||
_value: value,
|
||||
|
||||
[Symbol.iterator]: function () {
|
||||
return new IterConstructor(this._value)
|
||||
},
|
||||
|
||||
forEach: function (callback: (value: F) => void, thisArg?: any) {
|
||||
const iter = new IterConstructor(this._value)
|
||||
let result = iter.next()
|
||||
while (!result.done) {
|
||||
callback.call(thisArg, result.value)
|
||||
result = iter.next()
|
||||
}
|
||||
},
|
||||
}
|
||||
return enumerate as EnumerateFlags<F>
|
||||
}
|
||||
9
node/src/enumeration/index.ts
Normal file
9
node/src/enumeration/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export interface EnumerateFlags<T> extends Iterable<T> {
|
||||
forEach(callback: (value: T) => void, thisArg?: any): void
|
||||
}
|
||||
|
||||
export { useIterator } from './factory'
|
||||
|
||||
export { Base64BitflagIterator } from './base64'
|
||||
export { BigBitFlagsIterator } from './bigint'
|
||||
export { BitFlagsIterator } from './number'
|
||||
26
node/src/enumeration/number.ts
Normal file
26
node/src/enumeration/number.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export class BitFlagsIterator implements Iterator<number> {
|
||||
private _value: number
|
||||
private _current: number
|
||||
|
||||
public constructor(value: number) {
|
||||
this._value = value
|
||||
this._current = 1
|
||||
}
|
||||
|
||||
public next(): IteratorResult<number, undefined> {
|
||||
if (this._value == 0) {
|
||||
return { done: true, value: undefined }
|
||||
}
|
||||
|
||||
while ((this._value & 1) == 0) {
|
||||
this._value >>= 1
|
||||
this._current <<= 1
|
||||
}
|
||||
|
||||
const result = this._current
|
||||
this._value >>= 1
|
||||
this._current <<= 1
|
||||
|
||||
return { done: false, value: result }
|
||||
}
|
||||
}
|
||||
111
node/src/env.ts
Normal file
111
node/src/env.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
export const ENV_BI = Object.freeze(
|
||||
typeof BigInt === 'function'
|
||||
? { AVAILABLE: true, ZERO: BigInt(0), ONE: BigInt(1) }
|
||||
: { AVAILABLE: false }
|
||||
) as {
|
||||
readonly AVAILABLE: boolean
|
||||
readonly ZERO: bigint
|
||||
readonly ONE: bigint
|
||||
}
|
||||
|
||||
type SetBinaryOperation = <T>(this: Set<T>, other: Set<T>) => Set<T>
|
||||
type SetBinaryPredicate = <T>(this: Set<T>, other: Set<T>) => boolean
|
||||
|
||||
export const ENV_SET = Object.freeze(
|
||||
typeof Set === 'function'
|
||||
? {
|
||||
AVAILABLE: true,
|
||||
union: polyfillUnion(Set.prototype),
|
||||
intersection: polyfillIntersection(Set.prototype),
|
||||
difference: polyfillDifference(Set.prototype),
|
||||
isSupersetOf: polyfillIsSupersetOf(Set.prototype),
|
||||
}
|
||||
: { AVAILABLE: false }
|
||||
) as {
|
||||
readonly AVAILABLE: boolean
|
||||
readonly union: SetBinaryOperation
|
||||
readonly intersection: SetBinaryOperation
|
||||
readonly difference: SetBinaryOperation
|
||||
readonly isSupersetOf: SetBinaryPredicate
|
||||
}
|
||||
|
||||
function polyfillUnion(proto: object | undefined): SetBinaryOperation {
|
||||
if (proto && 'union' in proto) {
|
||||
return proto.union as SetBinaryOperation
|
||||
} else {
|
||||
return function <T>(this: Set<T>, other: Set<T>) {
|
||||
if (!(this instanceof Set) || !(this instanceof Set)) {
|
||||
throw new TypeError('Arguments must be instances of Set')
|
||||
}
|
||||
|
||||
const unionSet = new Set(this)
|
||||
for (const item of other) {
|
||||
unionSet.add(item)
|
||||
}
|
||||
|
||||
return unionSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function polyfillIntersection(proto: object | undefined): SetBinaryOperation {
|
||||
if (proto && 'intersection' in proto) {
|
||||
return proto.intersection as SetBinaryOperation
|
||||
} else {
|
||||
return function <T>(this: Set<T>, other: Set<T>) {
|
||||
if (!(this instanceof Set) || !(other instanceof Set)) {
|
||||
throw new TypeError('Arguments must be instances of Set')
|
||||
}
|
||||
|
||||
const differenceSet = new Set<T>()
|
||||
for (const item of this) {
|
||||
if (other.has(item)) {
|
||||
differenceSet.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
return differenceSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function polyfillDifference(proto: object | undefined): SetBinaryOperation {
|
||||
if (proto && 'difference' in proto) {
|
||||
return proto.difference as SetBinaryOperation
|
||||
} else {
|
||||
return function <T>(this: Set<T>, other: Set<T>) {
|
||||
if (!(this instanceof Set) || !(other instanceof Set)) {
|
||||
throw new TypeError('Arguments must be instances of Set')
|
||||
}
|
||||
|
||||
const differenceSet = new Set<T>()
|
||||
for (const item of this) {
|
||||
if (!other.has(item)) {
|
||||
differenceSet.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
return differenceSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function polyfillIsSupersetOf(proto: object | undefined): SetBinaryPredicate {
|
||||
if (proto && 'isSupersetOf' in proto) {
|
||||
return proto.isSupersetOf as SetBinaryPredicate
|
||||
} else {
|
||||
return function <T>(this: Set<T>, other: Set<T>) {
|
||||
if (!(this instanceof Set) || !(other instanceof Set)) {
|
||||
throw new TypeError('Arguments must be instances of Set')
|
||||
}
|
||||
|
||||
for (const item of other) {
|
||||
if (!this.has(item)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
31
node/src/errors.ts
Normal file
31
node/src/errors.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Error thrown when a feature is not available in the current environment.
|
||||
*/
|
||||
export class UnavailableFeatureError extends Error {
|
||||
/** @internal */
|
||||
public constructor(feature: string) {
|
||||
super(`This environment does not seem to support ${feature}.`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown by `FlagSet`s that store the flags using a binary format when a
|
||||
* flag value isn't a power of two.
|
||||
*/
|
||||
export class InvalidBitFlagValueError extends Error {
|
||||
/** @internal */
|
||||
public constructor() {
|
||||
super('Flag values for bit flags must be powers of two.')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown if the {@link FlagSet.flag} method is called with a value that
|
||||
* was already used for another flag in the same `FlagSet`.
|
||||
*/
|
||||
export class ReusedFlagValueError extends Error {
|
||||
/** @internal */
|
||||
public constructor(value: any) {
|
||||
super(`The flag value ${value} is already being used for another flag.`)
|
||||
}
|
||||
}
|
||||
64
node/src/flagsets/array.ts
Normal file
64
node/src/flagsets/array.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { FlagSet } from '.'
|
||||
import { EnumerateFlags } from '../enumeration'
|
||||
|
||||
export class ArrayFlagSet<T> implements FlagSet<T, T[]> {
|
||||
public none(): T[] {
|
||||
return []
|
||||
}
|
||||
|
||||
public union(first: T[], second: T[]): T[] {
|
||||
const unionArray: T[] = []
|
||||
for (const item of first) {
|
||||
if (!unionArray.includes(item)) {
|
||||
unionArray.push(item)
|
||||
}
|
||||
}
|
||||
for (const item of second) {
|
||||
if (!unionArray.includes(item)) {
|
||||
unionArray.push(item)
|
||||
}
|
||||
}
|
||||
return unionArray
|
||||
}
|
||||
|
||||
public intersection(first: T[], second: T[]): T[] {
|
||||
const intersectionArray: T[] = []
|
||||
for (const item of first) {
|
||||
if (!intersectionArray.includes(item) && second.includes(item)) {
|
||||
intersectionArray.push(item)
|
||||
}
|
||||
}
|
||||
return intersectionArray
|
||||
}
|
||||
|
||||
public difference(first: T[], second: T[]): T[] {
|
||||
const differenceArray: T[] = []
|
||||
for (const item of first) {
|
||||
if (!differenceArray.includes(item) && !second.includes(item)) {
|
||||
differenceArray.push(item)
|
||||
}
|
||||
}
|
||||
return differenceArray
|
||||
}
|
||||
|
||||
public isSuperset(first: T[], second: T[]): boolean {
|
||||
for (const item of second) {
|
||||
if (!first.includes(item)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public enumerate(flags: T[]): EnumerateFlags<T> {
|
||||
return flags
|
||||
}
|
||||
|
||||
maximum(flags: T[]): T[] {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
|
||||
minimum(flags: T[]): T[] {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
}
|
||||
130
node/src/flagsets/base64.ts
Normal file
130
node/src/flagsets/base64.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import type { FlagSet } from '.'
|
||||
import {
|
||||
decodeB64Byte,
|
||||
encodeB64Byte,
|
||||
normaliseB64String,
|
||||
ZERO_STRING,
|
||||
} from '../base64'
|
||||
import {
|
||||
Base64BitflagIterator,
|
||||
EnumerateFlags,
|
||||
useIterator,
|
||||
} from '../enumeration'
|
||||
|
||||
/**
|
||||
* Provides flags that are stored in strings using a little-endian base 64
|
||||
* representation.
|
||||
*
|
||||
* This format is compact, easily serializable and allows for an unlimited
|
||||
* number of flags, but it is specific to Tatsuki. Use {@link CollectionFlagSet}
|
||||
* instead if you need the data to be easily understandable by other systems.
|
||||
*/
|
||||
export class Base64BitFlagSet implements FlagSet<number, string> {
|
||||
/*protected wrapValue(value: number): string {
|
||||
if (value < 1) {
|
||||
throw new RangeError(
|
||||
'Indices should be greater than or equal to 1.'
|
||||
)
|
||||
}
|
||||
const indexFromZero = value - 1
|
||||
const leadingBytes = ZERO_STRING.repeat(indexFromZero / 6)
|
||||
const bigEnd = encodeByte(1 << indexFromZero % 6)
|
||||
return leadingBytes + bigEnd
|
||||
}*/
|
||||
|
||||
public none(): string {
|
||||
return ''
|
||||
}
|
||||
|
||||
public union(first: string, second: string): string {
|
||||
let result = ''
|
||||
|
||||
let shorter, longer
|
||||
if (first.length < second.length) {
|
||||
shorter = first
|
||||
longer = second
|
||||
} else {
|
||||
shorter = second
|
||||
longer = first
|
||||
}
|
||||
|
||||
let i = 0
|
||||
// OR the bytes one by one
|
||||
for (; i < shorter.length; i++) {
|
||||
const value = decodeB64Byte(shorter[i]) | decodeB64Byte(longer[i])
|
||||
result += encodeB64Byte(value)
|
||||
}
|
||||
// if one string is longer than the other, append the remaining bytes (x | 0 = x)
|
||||
for (; i < longer.length; i++) {
|
||||
result += longer[i]
|
||||
}
|
||||
|
||||
return normaliseB64String(result)
|
||||
}
|
||||
|
||||
public intersection(first: string, second: string): string {
|
||||
let result = ''
|
||||
|
||||
const shorterLength = Math.min(first.length, second.length)
|
||||
let i = 0
|
||||
// AND the bytes one by one
|
||||
for (; i < shorterLength; i++) {
|
||||
const value = decodeB64Byte(first[i]) & decodeB64Byte(second[i])
|
||||
result += encodeB64Byte(value)
|
||||
}
|
||||
// if one string is longer than the other, don't add anything else (x & 0 = 0)
|
||||
|
||||
return normaliseB64String(result)
|
||||
}
|
||||
|
||||
public difference(first: string, second: string): string {
|
||||
let result = ''
|
||||
|
||||
const shorterLength = Math.min(first.length, second.length)
|
||||
let i = 0
|
||||
// AND the bytes one by one
|
||||
for (; i < shorterLength; i++) {
|
||||
const value = decodeB64Byte(first[i]) & ~decodeB64Byte(second[i])
|
||||
result += encodeB64Byte(value)
|
||||
}
|
||||
// if the first string is longer than the other, append its remaining bytes (x & ~0 = x)
|
||||
// if the second string is longer, don't add anything (0 & ~y = 0)
|
||||
for (; i < first.length; i++) {
|
||||
result += first[i]
|
||||
}
|
||||
|
||||
return normaliseB64String(result)
|
||||
}
|
||||
|
||||
public isSuperset(first: string, second: string): boolean {
|
||||
let result = true
|
||||
|
||||
const shorterLength = Math.min(first.length, second.length)
|
||||
let i = 0
|
||||
// AND the bytes one by one and check
|
||||
// if one is false we don't need to decode further
|
||||
for (; i < shorterLength && result; i++) {
|
||||
const secondValue = decodeB64Byte(second[i])
|
||||
result = (decodeB64Byte(first[i]) & secondValue) == secondValue
|
||||
}
|
||||
// if there are more characters in the second string, they must all be zeros
|
||||
// (0 & x is only equal to x when x is also 0)
|
||||
for (; i < second.length && result; i++) {
|
||||
result = second[i] == ZERO_STRING
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public enumerate(flags: string): EnumerateFlags<number> {
|
||||
return useIterator(flags, Base64BitflagIterator)
|
||||
}
|
||||
|
||||
maximum(flags: string): string {
|
||||
throw new Error('not implemented')
|
||||
}
|
||||
|
||||
minimum(flags: string): string {
|
||||
throw new Error('not implemented')
|
||||
}
|
||||
}
|
||||
54
node/src/flagsets/bigint.ts
Normal file
54
node/src/flagsets/bigint.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type { FlagSet } from '.'
|
||||
import { UnavailableFeatureError } from '../errors'
|
||||
import { ENV_BI } from '../env'
|
||||
import {
|
||||
BigBitFlagsIterator,
|
||||
EnumerateFlags,
|
||||
useIterator,
|
||||
} from '../enumeration'
|
||||
|
||||
export class BigBitFlagSet implements FlagSet<bigint, bigint> {
|
||||
/**
|
||||
* Creates a new empty flag set.
|
||||
*
|
||||
* @throws UnavailableFeatureError When this constructor is called in an
|
||||
* environment that does not natively support {@link BigInt}s.
|
||||
*/
|
||||
public constructor() {
|
||||
if (!ENV_BI.AVAILABLE) {
|
||||
throw new UnavailableFeatureError('BigInts')
|
||||
}
|
||||
}
|
||||
|
||||
minimum(flags: bigint): bigint {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
|
||||
maximum(flags: bigint): bigint {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
|
||||
public none(): bigint {
|
||||
return ENV_BI.ZERO
|
||||
}
|
||||
|
||||
public union(first: bigint, second: bigint): bigint {
|
||||
return first | second
|
||||
}
|
||||
|
||||
public intersection(first: bigint, second: bigint): bigint {
|
||||
return first & second
|
||||
}
|
||||
|
||||
public difference(first: bigint, second: bigint): bigint {
|
||||
return first & ~second
|
||||
}
|
||||
|
||||
public isSuperset(first: bigint, second: bigint): boolean {
|
||||
return (first & second) == second
|
||||
}
|
||||
|
||||
public enumerate(flags: bigint): EnumerateFlags<bigint> {
|
||||
return useIterator(flags, BigBitFlagsIterator)
|
||||
}
|
||||
}
|
||||
49
node/src/flagsets/collection.ts
Normal file
49
node/src/flagsets/collection.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { FlagSet } from '.'
|
||||
import { EnumerateFlags, useIterator } from '../enumeration'
|
||||
import { ENV_SET } from '../env'
|
||||
import { UnavailableFeatureError } from '../errors'
|
||||
|
||||
export class CollectionFlagSet<T> implements FlagSet<T, Set<T>> {
|
||||
/**
|
||||
* Creates a new empty flag set.
|
||||
*
|
||||
* @throws UnavailableFeatureError When this constructor is called in an
|
||||
* environment that does not natively support {@link Set}s.
|
||||
*/
|
||||
public constructor() {
|
||||
if (!ENV_SET.AVAILABLE) {
|
||||
throw new UnavailableFeatureError('Sets')
|
||||
}
|
||||
}
|
||||
|
||||
public none(): Set<T> {
|
||||
return new Set()
|
||||
}
|
||||
|
||||
public union(first: Set<T>, second: Set<T>): Set<T> {
|
||||
return ENV_SET.union.call(first, second) as Set<T>
|
||||
}
|
||||
|
||||
public intersection(first: Set<T>, second: Set<T>): Set<T> {
|
||||
return ENV_SET.intersection.call(first, second) as Set<T>
|
||||
}
|
||||
|
||||
public difference(first: Set<T>, second: Set<T>): Set<T> {
|
||||
return ENV_SET.difference.call(first, second) as Set<T>
|
||||
}
|
||||
|
||||
public isSuperset(first: Set<T>, second: Set<T>): boolean {
|
||||
return ENV_SET.isSupersetOf.call(first, second)
|
||||
}
|
||||
|
||||
public enumerate(flags: Set<T>): EnumerateFlags<T> {
|
||||
return flags
|
||||
}
|
||||
|
||||
minimum(flags: Set<T>): Set<T> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
maximum(flags: Set<T>): Set<T> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
}
|
||||
95
node/src/flagsets/index.ts
Normal file
95
node/src/flagsets/index.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { EnumerateFlags } from '../enumeration'
|
||||
|
||||
/**
|
||||
* Represents a group of flags of type `F` and the relationships between
|
||||
* them. It also provides methods to use `S` as a set of those flags.
|
||||
*
|
||||
* @typeParam F – The type of values in the set.
|
||||
* @typeParam S – The type to be used as a set.
|
||||
*/
|
||||
export interface FlagSet<F, S> {
|
||||
/**
|
||||
* Creates an empty set of flags.
|
||||
*/
|
||||
none(): S
|
||||
|
||||
/**
|
||||
* Computes the union of two sets of flags.
|
||||
*
|
||||
* @param first - The first set of flags.
|
||||
* @param second - The second set of flags.
|
||||
*
|
||||
* @returns A new set that contains the flags of both sets.
|
||||
*/
|
||||
union(first: S, second: S): S
|
||||
|
||||
/**
|
||||
* Computes the intersection of two set of flags.
|
||||
*
|
||||
* @param first - The first set of flags.
|
||||
* @param second - The second set of flags.
|
||||
*
|
||||
* @returns A new set that contains the flags that appear both in the first
|
||||
* set and the second set.
|
||||
*/
|
||||
intersection(first: S, second: S): S
|
||||
|
||||
/**
|
||||
* Computes the difference of two set of flags.
|
||||
*
|
||||
* @param first - The first set of flags.
|
||||
* @param second - The second set of flags (that will be subtracted from the
|
||||
* first).
|
||||
*
|
||||
* @returns A new set that contains the flags of the first set that do not
|
||||
* appear in the second.
|
||||
*/
|
||||
difference(first: S, second: S): S
|
||||
|
||||
/**
|
||||
* Checks whether the first set of flags is a superset of the second.
|
||||
*
|
||||
* @param first - The first set of flags.
|
||||
* @param second - The second set of flags.
|
||||
*/
|
||||
isSuperset(first: S, second: S): boolean
|
||||
|
||||
/**
|
||||
* Returns an iterable over the individual flags in a set.
|
||||
*
|
||||
* @param flags - A set of flags.
|
||||
*/
|
||||
enumerate(flags: S): EnumerateFlags<F>
|
||||
|
||||
/**
|
||||
* Filters a flag set so that it only contains the flags that were declared
|
||||
* with the {@link flag} method. If a flags is missing some of its parents,
|
||||
* it will not be included in the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
*
|
||||
* @returns A new set of flags.
|
||||
*
|
||||
* @see maximum
|
||||
*/
|
||||
minimum(flags: S): S
|
||||
|
||||
/**
|
||||
* Creates a copy of a flag set that will contain all the flags that were
|
||||
* declared with the {@link flag} method. If a flags is missing some of its
|
||||
* parents in the original set, they will be added to the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
*
|
||||
* @returns A new set of flags.
|
||||
*
|
||||
* @see minimum
|
||||
*/
|
||||
maximum(flags: S): S
|
||||
}
|
||||
|
||||
export { ArrayFlagSet } from './array'
|
||||
export { Base64BitFlagSet } from './base64'
|
||||
export { BigBitFlagSet } from './bigint'
|
||||
export { CollectionFlagSet } from './collection'
|
||||
export { BitFlagSet } from './number'
|
||||
36
node/src/flagsets/number.ts
Normal file
36
node/src/flagsets/number.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { FlagSet } from '.'
|
||||
import { BitFlagsIterator, EnumerateFlags, useIterator } from '../enumeration'
|
||||
|
||||
export class BitFlagSet implements FlagSet<number, number> {
|
||||
public none(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public union(first: number, second: number): number {
|
||||
return first | second
|
||||
}
|
||||
|
||||
public intersection(first: number, second: number): number {
|
||||
return first & second
|
||||
}
|
||||
|
||||
public difference(first: number, second: number): number {
|
||||
return first & ~second
|
||||
}
|
||||
|
||||
public isSuperset(first: number, second: number): boolean {
|
||||
return (first & second) == second
|
||||
}
|
||||
|
||||
public enumerate(flags: number): EnumerateFlags<number> {
|
||||
return useIterator(flags, BitFlagsIterator)
|
||||
}
|
||||
|
||||
public maximum(flags: number): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public minimum(flags: number): number {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
9
node/src/index.ts
Normal file
9
node/src/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export { FlagSetBuilder } from './builders'
|
||||
export {
|
||||
ArrayFlagSet,
|
||||
Base64BitFlagSet,
|
||||
BigBitFlagSet,
|
||||
BitFlagSet,
|
||||
CollectionFlagSet,
|
||||
} from './flagsets'
|
||||
export { InvalidBitFlagValueError } from './errors'
|
||||
81
node/tests/_archive/array.test.ts
Normal file
81
node/tests/_archive/array.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { ArrayFlagSet } from '@module'
|
||||
|
||||
|
||||
test('Normalise to minimum', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B', flagA)
|
||||
const flagC = flags.flag('C', flagA)
|
||||
const flagD = flags.flag('D', flagC)
|
||||
|
||||
expect(flags.minimum([])).toEqual([])
|
||||
expect(flags.minimum(['A'])).toEqual(['A'])
|
||||
expect(flags.minimum(['B'])).toEqual([])
|
||||
expect(flags.minimum(['A', 'B'])).toEqual(['A', 'B'])
|
||||
expect(flags.minimum(['A', 'B', 'D'])).toEqual(['A', 'B'])
|
||||
expect(flags.minimum(['A', 'C', 'D'])).toEqual(['A', 'C', 'D'])
|
||||
expect(flags.minimum(['A', 'E'])).toEqual(['A'])
|
||||
})
|
||||
|
||||
test('Normalise to maximum', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B', flagA)
|
||||
const flagC = flags.flag('C', flagA)
|
||||
const flagD = flags.flag('D', flagC)
|
||||
|
||||
expect(flags.maximum([])).toEqual([])
|
||||
expect(flags.maximum(['A'])).toEqual(['A'])
|
||||
expect(flags.maximum(['B'])).toEqual(['B', 'A'])
|
||||
expect(flags.maximum(['A', 'B'])).toEqual(['A', 'B'])
|
||||
expect(flags.maximum(['A', 'B', 'D'])).toEqual(['A', 'B', 'D', 'C'])
|
||||
expect(flags.maximum(['A', 'C', 'D'])).toEqual(['A', 'C', 'D'])
|
||||
expect(flags.maximum(['A', 'E'])).toEqual(['A'])
|
||||
})
|
||||
|
||||
test('Add to array', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C')
|
||||
const flagsBAndC = flags.flag(flagB, flagC)
|
||||
|
||||
expect(flagB.addTo(['A'])).toEqual(['A', 'B'])
|
||||
expect(flagC.addTo(['A'])).toEqual(['A', 'C'])
|
||||
expect(flagsBAndC.addTo(['A'])).toEqual(['A', 'B', 'C'])
|
||||
})
|
||||
|
||||
test('Remove from array', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C', flagA)
|
||||
|
||||
expect(flagA.removeFrom(['A', 'B', 'C'])).toEqual(['B'])
|
||||
expect(flagB.removeFrom(['A', 'B', 'C'])).toEqual(['A', 'C'])
|
||||
expect(flagC.removeFrom(['A', 'B', 'C'])).toEqual(['A', 'B'])
|
||||
})
|
||||
|
||||
test('Is in array', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C', flagA)
|
||||
|
||||
expect(flagA.isIn(['A'])).toBe(true)
|
||||
expect(flagB.isIn(['A', 'B'])).toBe(true)
|
||||
expect(flagC.isIn(['C'])).toBe(false)
|
||||
expect(flagC.isIn(['A', 'C'])).toBe(true)
|
||||
})
|
||||
|
||||
test('Is abstract', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagsAAndB = flags.flag(flagA, flagB)
|
||||
const flagC = flags.flag('C', flagsAAndB)
|
||||
|
||||
expect(flagA.isAbstract).toBe(false)
|
||||
expect(flagB.isAbstract).toBe(false)
|
||||
expect(flagsAAndB.isAbstract).toBe(true)
|
||||
expect(flagC.isAbstract).toBe(false)
|
||||
})
|
||||
270
node/tests/_archive/base64.test.ts
Normal file
270
node/tests/_archive/base64.test.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
import { Base64BitflagSet } from '@module'
|
||||
import { decodeByte, encodeByte } from '../src/base64'
|
||||
|
||||
test('Create from an index', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
|
||||
const flag2 = flags.flag(2)
|
||||
expect(flag2.addTo('')).toEqual('C')
|
||||
|
||||
expect(() => flags.flag(0)).toThrow(RangeError)
|
||||
expect(() => flags.flag(-2)).toThrow(RangeError)
|
||||
})
|
||||
|
||||
test('Union of two base-64 strings', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
|
||||
expect(flags.union('', '')).toEqual('A')
|
||||
expect(flags.union('A', 'A')).toEqual('A')
|
||||
expect(flags.union('B', 'A')).toEqual('B')
|
||||
expect(flags.union('A', 'C')).toEqual('C')
|
||||
expect(flags.union('B', 'C')).toEqual('D')
|
||||
expect(flags.union('D', 'G')).toEqual('H')
|
||||
})
|
||||
|
||||
test('Difference of two base-64 strings', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
|
||||
expect(flags.difference('', '')).toEqual('A')
|
||||
expect(flags.difference('A', 'A')).toEqual('A')
|
||||
expect(flags.difference('B', 'A')).toEqual('B')
|
||||
expect(flags.difference('D', 'G')).toEqual('B')
|
||||
expect(flags.difference('G', 'D')).toEqual('E')
|
||||
expect(flags.difference('IB', 'R')).toEqual('IB')
|
||||
})
|
||||
|
||||
test('Intersection of two base-64 strings', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
|
||||
expect(flags.intersection('', '')).toEqual('A')
|
||||
expect(flags.intersection('A', 'A')).toEqual('A')
|
||||
expect(flags.intersection('B', 'A')).toEqual('A')
|
||||
expect(flags.intersection('B', 'C')).toEqual('A')
|
||||
expect(flags.intersection('B', 'D')).toEqual('B')
|
||||
expect(flags.intersection('L', 'F')).toEqual('B')
|
||||
expect(flags.intersection('L', 'H')).toEqual('D')
|
||||
})
|
||||
|
||||
test('Iterate over a base-64 string', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
|
||||
expect([...flags.iterate('A')]).toEqual([])
|
||||
expect([...flags.iterate('B')]).toEqual([1])
|
||||
expect([...flags.iterate('C')]).toEqual([2])
|
||||
expect([...flags.iterate('D')]).toEqual([1, 2])
|
||||
expect([...flags.iterate('L')]).toEqual([1, 2, 4])
|
||||
expect([...flags.iterate('kB')]).toEqual([3, 6, 7])
|
||||
})
|
||||
|
||||
test('Normalise to minimum', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2, flag1)
|
||||
const flag3 = flags.flag(3, flag1)
|
||||
const flag4 = flags.flag(4, flag3)
|
||||
|
||||
expect(flags.minimum('A')).toEqual('A')
|
||||
expect(flags.minimum('B')).toEqual('B')
|
||||
expect(flags.minimum('C')).toEqual('A')
|
||||
expect(flags.minimum('D')).toEqual('D')
|
||||
expect(flags.minimum('L')).toEqual('D')
|
||||
expect(flags.minimum('N')).toEqual('N')
|
||||
expect(flags.minimum('R')).toEqual('B')
|
||||
})
|
||||
|
||||
test('Normalise to maximum', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2, flag1)
|
||||
const flag3 = flags.flag(3, flag1)
|
||||
const flag4 = flags.flag(4, flag3)
|
||||
|
||||
expect(flags.maximum('A')).toEqual('A')
|
||||
expect(flags.maximum('B')).toEqual('B')
|
||||
expect(flags.maximum('C')).toEqual('D')
|
||||
expect(flags.maximum('D')).toEqual('D')
|
||||
expect(flags.maximum('L')).toEqual('P')
|
||||
expect(flags.maximum('N')).toEqual('N')
|
||||
expect(flags.maximum('R')).toEqual('B')
|
||||
})
|
||||
|
||||
test('Add to base64 string', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag2 = flags.flag(2)
|
||||
const flag3 = flags.flag(3)
|
||||
const flags2And3 = flags.flag(flag2, flag3)
|
||||
|
||||
expect(flag2.addTo('B')).toEqual('D')
|
||||
expect(flag3.addTo('B')).toEqual('F')
|
||||
expect(flags2And3.addTo('B')).toEqual('H')
|
||||
})
|
||||
|
||||
test('Remove from base64 string', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2)
|
||||
const flag3 = flags.flag(3, flag1)
|
||||
|
||||
expect(flag1.removeFrom('H')).toEqual('C')
|
||||
expect(flag2.removeFrom('H')).toEqual('F')
|
||||
expect(flag3.removeFrom('H')).toEqual('D')
|
||||
})
|
||||
|
||||
test('Is in base64 string', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2)
|
||||
const flag3 = flags.flag(3, flag1)
|
||||
|
||||
expect(flag1.isIn('B')).toBe(true)
|
||||
expect(flag2.isIn('D')).toBe(true)
|
||||
expect(flag3.isIn('E')).toBe(false)
|
||||
expect(flag3.isIn('F')).toBe(true)
|
||||
})
|
||||
|
||||
test('Is abstract', () => {
|
||||
const flags = new Base64BitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2)
|
||||
const flags1And2 = flags.flag(flag1, flag2)
|
||||
const flag3 = flags.flag(3, flags1And2)
|
||||
|
||||
expect(flag1.isAbstract).toBe(false)
|
||||
expect(flag2.isAbstract).toBe(false)
|
||||
expect(flags1And2.isAbstract).toBe(true)
|
||||
expect(flag3.isAbstract).toBe(false)
|
||||
})
|
||||
|
||||
test('encode a base-64 byte', () => {
|
||||
expect(encodeByte(0)).toEqual('A')
|
||||
expect(encodeByte(1)).toEqual('B')
|
||||
expect(encodeByte(2)).toEqual('C')
|
||||
expect(encodeByte(3)).toEqual('D')
|
||||
expect(encodeByte(4)).toEqual('E')
|
||||
expect(encodeByte(5)).toEqual('F')
|
||||
expect(encodeByte(6)).toEqual('G')
|
||||
expect(encodeByte(7)).toEqual('H')
|
||||
expect(encodeByte(8)).toEqual('I')
|
||||
expect(encodeByte(9)).toEqual('J')
|
||||
expect(encodeByte(10)).toEqual('K')
|
||||
expect(encodeByte(11)).toEqual('L')
|
||||
expect(encodeByte(12)).toEqual('M')
|
||||
expect(encodeByte(13)).toEqual('N')
|
||||
expect(encodeByte(14)).toEqual('O')
|
||||
expect(encodeByte(15)).toEqual('P')
|
||||
expect(encodeByte(16)).toEqual('Q')
|
||||
expect(encodeByte(17)).toEqual('R')
|
||||
expect(encodeByte(18)).toEqual('S')
|
||||
expect(encodeByte(19)).toEqual('T')
|
||||
expect(encodeByte(20)).toEqual('U')
|
||||
expect(encodeByte(21)).toEqual('V')
|
||||
expect(encodeByte(22)).toEqual('W')
|
||||
expect(encodeByte(23)).toEqual('X')
|
||||
expect(encodeByte(24)).toEqual('Y')
|
||||
expect(encodeByte(25)).toEqual('Z')
|
||||
expect(encodeByte(26)).toEqual('a')
|
||||
expect(encodeByte(27)).toEqual('b')
|
||||
expect(encodeByte(28)).toEqual('c')
|
||||
expect(encodeByte(29)).toEqual('d')
|
||||
expect(encodeByte(30)).toEqual('e')
|
||||
expect(encodeByte(31)).toEqual('f')
|
||||
expect(encodeByte(32)).toEqual('g')
|
||||
expect(encodeByte(33)).toEqual('h')
|
||||
expect(encodeByte(34)).toEqual('i')
|
||||
expect(encodeByte(35)).toEqual('j')
|
||||
expect(encodeByte(36)).toEqual('k')
|
||||
expect(encodeByte(37)).toEqual('l')
|
||||
expect(encodeByte(38)).toEqual('m')
|
||||
expect(encodeByte(39)).toEqual('n')
|
||||
expect(encodeByte(40)).toEqual('o')
|
||||
expect(encodeByte(41)).toEqual('p')
|
||||
expect(encodeByte(42)).toEqual('q')
|
||||
expect(encodeByte(43)).toEqual('r')
|
||||
expect(encodeByte(44)).toEqual('s')
|
||||
expect(encodeByte(45)).toEqual('t')
|
||||
expect(encodeByte(46)).toEqual('u')
|
||||
expect(encodeByte(47)).toEqual('v')
|
||||
expect(encodeByte(48)).toEqual('w')
|
||||
expect(encodeByte(49)).toEqual('x')
|
||||
expect(encodeByte(50)).toEqual('y')
|
||||
expect(encodeByte(51)).toEqual('z')
|
||||
expect(encodeByte(52)).toEqual('0')
|
||||
expect(encodeByte(53)).toEqual('1')
|
||||
expect(encodeByte(54)).toEqual('2')
|
||||
expect(encodeByte(55)).toEqual('3')
|
||||
expect(encodeByte(56)).toEqual('4')
|
||||
expect(encodeByte(57)).toEqual('5')
|
||||
expect(encodeByte(58)).toEqual('6')
|
||||
expect(encodeByte(59)).toEqual('7')
|
||||
expect(encodeByte(60)).toEqual('8')
|
||||
expect(encodeByte(61)).toEqual('9')
|
||||
expect(encodeByte(62)).toEqual('-')
|
||||
expect(encodeByte(63)).toEqual('_')
|
||||
})
|
||||
|
||||
test('encode a base-64 byte', () => {
|
||||
expect(decodeByte('A')).toEqual(0)
|
||||
expect(decodeByte('B')).toEqual(1)
|
||||
expect(decodeByte('C')).toEqual(2)
|
||||
expect(decodeByte('D')).toEqual(3)
|
||||
expect(decodeByte('E')).toEqual(4)
|
||||
expect(decodeByte('F')).toEqual(5)
|
||||
expect(decodeByte('G')).toEqual(6)
|
||||
expect(decodeByte('H')).toEqual(7)
|
||||
expect(decodeByte('I')).toEqual(8)
|
||||
expect(decodeByte('J')).toEqual(9)
|
||||
expect(decodeByte('K')).toEqual(10)
|
||||
expect(decodeByte('L')).toEqual(11)
|
||||
expect(decodeByte('M')).toEqual(12)
|
||||
expect(decodeByte('N')).toEqual(13)
|
||||
expect(decodeByte('O')).toEqual(14)
|
||||
expect(decodeByte('P')).toEqual(15)
|
||||
expect(decodeByte('Q')).toEqual(16)
|
||||
expect(decodeByte('R')).toEqual(17)
|
||||
expect(decodeByte('S')).toEqual(18)
|
||||
expect(decodeByte('T')).toEqual(19)
|
||||
expect(decodeByte('U')).toEqual(20)
|
||||
expect(decodeByte('V')).toEqual(21)
|
||||
expect(decodeByte('W')).toEqual(22)
|
||||
expect(decodeByte('X')).toEqual(23)
|
||||
expect(decodeByte('Y')).toEqual(24)
|
||||
expect(decodeByte('Z')).toEqual(25)
|
||||
expect(decodeByte('a')).toEqual(26)
|
||||
expect(decodeByte('b')).toEqual(27)
|
||||
expect(decodeByte('c')).toEqual(28)
|
||||
expect(decodeByte('d')).toEqual(29)
|
||||
expect(decodeByte('e')).toEqual(30)
|
||||
expect(decodeByte('f')).toEqual(31)
|
||||
expect(decodeByte('g')).toEqual(32)
|
||||
expect(decodeByte('h')).toEqual(33)
|
||||
expect(decodeByte('i')).toEqual(34)
|
||||
expect(decodeByte('j')).toEqual(35)
|
||||
expect(decodeByte('k')).toEqual(36)
|
||||
expect(decodeByte('l')).toEqual(37)
|
||||
expect(decodeByte('m')).toEqual(38)
|
||||
expect(decodeByte('n')).toEqual(39)
|
||||
expect(decodeByte('o')).toEqual(40)
|
||||
expect(decodeByte('p')).toEqual(41)
|
||||
expect(decodeByte('q')).toEqual(42)
|
||||
expect(decodeByte('r')).toEqual(43)
|
||||
expect(decodeByte('s')).toEqual(44)
|
||||
expect(decodeByte('t')).toEqual(45)
|
||||
expect(decodeByte('u')).toEqual(46)
|
||||
expect(decodeByte('v')).toEqual(47)
|
||||
expect(decodeByte('w')).toEqual(48)
|
||||
expect(decodeByte('x')).toEqual(49)
|
||||
expect(decodeByte('y')).toEqual(50)
|
||||
expect(decodeByte('z')).toEqual(51)
|
||||
expect(decodeByte('0')).toEqual(52)
|
||||
expect(decodeByte('1')).toEqual(53)
|
||||
expect(decodeByte('2')).toEqual(54)
|
||||
expect(decodeByte('3')).toEqual(55)
|
||||
expect(decodeByte('4')).toEqual(56)
|
||||
expect(decodeByte('5')).toEqual(57)
|
||||
expect(decodeByte('6')).toEqual(58)
|
||||
expect(decodeByte('7')).toEqual(59)
|
||||
expect(decodeByte('8')).toEqual(60)
|
||||
expect(decodeByte('9')).toEqual(61)
|
||||
expect(decodeByte('-')).toEqual(62)
|
||||
expect(decodeByte('_')).toEqual(63)
|
||||
})
|
||||
116
node/tests/_archive/bigint.test.ts
Normal file
116
node/tests/_archive/bigint.test.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { BigBitFlagSet } from '~'
|
||||
|
||||
const bigPowerOfTwo = 2n ** 100n
|
||||
|
||||
|
||||
test('Iterate over a number', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect([...flags.iterate(0n)]).toEqual([])
|
||||
expect([...flags.iterate(1n)]).toEqual([1n])
|
||||
expect([...flags.iterate(2n)]).toEqual([2n])
|
||||
expect([...flags.iterate(3n)]).toEqual([1n, 2n])
|
||||
expect([...flags.iterate(11n)]).toEqual([1n, 2n, 8n])
|
||||
expect([...flags.iterate(100n)]).toEqual([4n, 32n, 64n])
|
||||
})
|
||||
|
||||
test('Normalise to minimum', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag1 = flags.flag(1n)
|
||||
const flag2 = flags.flag(2n, flag1)
|
||||
const flag4 = flags.flag(4n, flag1)
|
||||
const flag8 = flags.flag(8n, flag4)
|
||||
|
||||
expect(flags.minimum(0n)).toEqual(0n)
|
||||
expect(flags.minimum(1n)).toEqual(1n)
|
||||
expect(flags.minimum(2n)).toEqual(0n)
|
||||
expect(flags.minimum(3n)).toEqual(3n)
|
||||
expect(flags.minimum(11n)).toEqual(3n)
|
||||
expect(flags.minimum(13n)).toEqual(13n)
|
||||
expect(flags.minimum(17n)).toEqual(1n)
|
||||
})
|
||||
|
||||
test('Normalise to maximum', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag1 = flags.flag(1n)
|
||||
const flag2 = flags.flag(2n, flag1)
|
||||
const flag4 = flags.flag(4n, flag1)
|
||||
const flag8 = flags.flag(8n, flag4)
|
||||
|
||||
expect(flags.maximum(0n)).toEqual(0n)
|
||||
expect(flags.maximum(1n)).toEqual(1n)
|
||||
expect(flags.maximum(2n)).toEqual(3n)
|
||||
expect(flags.maximum(3n)).toEqual(3n)
|
||||
expect(flags.maximum(11n)).toEqual(15n)
|
||||
expect(flags.maximum(13n)).toEqual(13n)
|
||||
expect(flags.maximum(17n)).toEqual(1n)
|
||||
})
|
||||
|
||||
test('Add to bigint', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag2 = flags.flag(2n)
|
||||
const flag4 = flags.flag(4n)
|
||||
const flags2And4 = flags.flag(flag2, flag4)
|
||||
const flag100 = flags.flag(bigPowerOfTwo)
|
||||
|
||||
expect(flag2.addTo(1n)).toEqual(3n)
|
||||
expect(flag4.addTo(1n)).toEqual(5n)
|
||||
expect(flags2And4.addTo(1n)).toEqual(7n)
|
||||
expect(flag100.addTo(1n)).toEqual(bigPowerOfTwo + 1n)
|
||||
expect(flag2.addTo(bigPowerOfTwo)).toEqual(bigPowerOfTwo + 2n)
|
||||
})
|
||||
|
||||
test('Remove from bigint', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag1 = flags.flag(1n)
|
||||
const flag2 = flags.flag(2n)
|
||||
const flag4 = flags.flag(4n, flag1)
|
||||
const flag100 = flags.flag(bigPowerOfTwo)
|
||||
|
||||
expect(flag1.removeFrom(7n)).toEqual(2n)
|
||||
expect(flag2.removeFrom(7n)).toEqual(5n)
|
||||
expect(flag4.removeFrom(7n)).toEqual(3n)
|
||||
expect(flag100.removeFrom(bigPowerOfTwo + 2n)).toEqual(2n)
|
||||
expect(flag100.removeFrom(2n)).toEqual(2n)
|
||||
expect(flag1.removeFrom(bigPowerOfTwo - 1n)).toEqual(bigPowerOfTwo - 6n)
|
||||
})
|
||||
|
||||
test('Is in bigint', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag1 = flags.flag(1n)
|
||||
const flag2 = flags.flag(2n)
|
||||
const flag4 = flags.flag(4n, flag1)
|
||||
|
||||
expect(flag1.isIn(1n)).toBe(true)
|
||||
expect(flag2.isIn(3n)).toBe(true)
|
||||
expect(flag4.isIn(4n)).toBe(false)
|
||||
expect(flag4.isIn(5n)).toBe(true)
|
||||
expect(flag1.isIn(bigPowerOfTwo + 1n)).toBe(true)
|
||||
})
|
||||
|
||||
test('Is abstract', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
const flag1 = flags.flag(1n)
|
||||
const flag2 = flags.flag(2n)
|
||||
const flags1And2 = flags.flag(flag1, flag2)
|
||||
const flag4 = flags.flag(4n, flags1And2)
|
||||
|
||||
expect(flag1.isAbstract).toBe(false)
|
||||
expect(flag2.isAbstract).toBe(false)
|
||||
expect(flags1And2.isAbstract).toBe(true)
|
||||
expect(flag4.isAbstract).toBe(false)
|
||||
})
|
||||
|
||||
test('Environment without bigint', async () => {
|
||||
const originalBigInt = globalThis.BigInt
|
||||
// @ts-ignore
|
||||
delete globalThis.BigInt
|
||||
let module: { BigBitFlagSet: typeof BigBitFlagSet }
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
|
||||
expect(() => new module.BigBitFlagSet()).toThrow()
|
||||
|
||||
globalThis.BigInt = originalBigInt
|
||||
})
|
||||
240
node/tests/_archive/collection.test.ts
Normal file
240
node/tests/_archive/collection.test.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { CollectionFlagSet } from '@module'
|
||||
import { ok } from 'node:assert'
|
||||
|
||||
function set<T>(...values: T[]): Set<T> {
|
||||
return new Set<T>(values)
|
||||
}
|
||||
|
||||
test('Union of two sets', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.union(set(), set())).toEqual(set())
|
||||
expect(flags.union(set('A'), set())).toEqual(set('A'))
|
||||
expect(flags.union(set(), set('B'))).toEqual(set('B'))
|
||||
expect(flags.union(set('A'), set('B'))).toEqual(set('A', 'B'))
|
||||
expect(flags.union(set('A', 'B'), set('B', 'C'))).toEqual(
|
||||
set('A', 'B', 'C')
|
||||
)
|
||||
})
|
||||
|
||||
test('Difference of two sets', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.difference(set(), set())).toEqual(set())
|
||||
expect(flags.difference(set('A'), set())).toEqual(set('A'))
|
||||
expect(flags.difference(set('A', 'B'), set('B', 'C'))).toEqual(set('A'))
|
||||
expect(flags.difference(set('B', 'C'), set('A', 'B'))).toEqual(set('C'))
|
||||
expect(flags.difference(set('D'), set('A', 'E'))).toEqual(set('D'))
|
||||
})
|
||||
|
||||
test('Intersection of two sets', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.intersection(set(), set())).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set())).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set('B'))).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set('A', 'B'))).toEqual(set('A'))
|
||||
expect(flags.intersection(set('A', 'B', 'D'), set('A', 'C'))).toEqual(
|
||||
set('A')
|
||||
)
|
||||
expect(flags.intersection(set('A', 'B', 'D'), set('A', 'B', 'C'))).toEqual(
|
||||
set('A', 'B')
|
||||
)
|
||||
})
|
||||
|
||||
test('Iterate over a set', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect([...flags.iterate(set())]).toEqual([])
|
||||
expect([...flags.iterate(set('A'))]).toEqual(['A'])
|
||||
expect([...flags.iterate(set('A', 'B', 'C'))]).toEqual(['A', 'B', 'C'])
|
||||
})
|
||||
|
||||
test('Normalise to minimum', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B', flagA)
|
||||
const flagC = flags.flag('C', flagA)
|
||||
const flagD = flags.flag('D', flagC)
|
||||
|
||||
expect(flags.minimum(set())).toEqual(set())
|
||||
expect(flags.minimum(set('A'))).toEqual(set('A'))
|
||||
expect(flags.minimum(set('B'))).toEqual(set())
|
||||
expect(flags.minimum(set('A', 'B'))).toEqual(set('A', 'B'))
|
||||
expect(flags.minimum(set('A', 'B', 'D'))).toEqual(set('A', 'B'))
|
||||
expect(flags.minimum(set('A', 'C', 'D'))).toEqual(set('A', 'C', 'D'))
|
||||
expect(flags.minimum(set('A', 'E'))).toEqual(set('A'))
|
||||
})
|
||||
|
||||
test('Normalise to maximum', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B', flagA)
|
||||
const flagC = flags.flag('C', flagA)
|
||||
const flagD = flags.flag('D', flagC)
|
||||
|
||||
expect(flags.maximum(set())).toEqual(set())
|
||||
expect(flags.maximum(set('A'))).toEqual(set('A'))
|
||||
expect(flags.maximum(set('B'))).toEqual(set('B', 'A'))
|
||||
expect(flags.maximum(set('A', 'B'))).toEqual(set('A', 'B'))
|
||||
expect(flags.maximum(set('A', 'B', 'D'))).toEqual(set('A', 'B', 'D', 'C'))
|
||||
expect(flags.maximum(set('A', 'C', 'D'))).toEqual(set('A', 'C', 'D'))
|
||||
expect(flags.maximum(set('A', 'E'))).toEqual(set('A'))
|
||||
})
|
||||
|
||||
test('Add to set', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C')
|
||||
const flagsBAndC = flags.flag(flagB, flagC)
|
||||
|
||||
expect(flagB.addTo(set('A'))).toEqual(set('A', 'B'))
|
||||
expect(flagC.addTo(set('A'))).toEqual(set('A', 'C'))
|
||||
expect(flagsBAndC.addTo(set('A'))).toEqual(set('A', 'B', 'C'))
|
||||
})
|
||||
|
||||
test('Remove from set', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C', flagA)
|
||||
|
||||
expect(flagA.removeFrom(set('A', 'B', 'C'))).toEqual(set('B'))
|
||||
expect(flagB.removeFrom(set('A', 'B', 'C'))).toEqual(set('A', 'C'))
|
||||
expect(flagC.removeFrom(set('A', 'B', 'C'))).toEqual(set('A', 'B'))
|
||||
})
|
||||
|
||||
test('Is in set', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagC = flags.flag('C', flagA)
|
||||
|
||||
expect(flagA.isIn(set('A'))).toBe(true)
|
||||
expect(flagB.isIn(set('A', 'B'))).toBe(true)
|
||||
expect(flagC.isIn(set('C'))).toBe(false)
|
||||
expect(flagC.isIn(set('A', 'C'))).toBe(true)
|
||||
})
|
||||
|
||||
test('Is abstract', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
const flagA = flags.flag('A')
|
||||
const flagB = flags.flag('B')
|
||||
const flagsAAndB = flags.flag(flagA, flagB)
|
||||
const flagC = flags.flag('C', flagsAAndB)
|
||||
|
||||
expect(flagA.isAbstract).toBe(false)
|
||||
expect(flagB.isAbstract).toBe(false)
|
||||
expect(flagsAAndB.isAbstract).toBe(true)
|
||||
expect(flagC.isAbstract).toBe(false)
|
||||
})
|
||||
|
||||
test('Environment without Set', async () => {
|
||||
const originalSet = globalThis.Set
|
||||
// @ts-ignore
|
||||
delete globalThis.Set
|
||||
let module: { CollectionFlagSet: typeof CollectionFlagSet }
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
|
||||
expect(() => new module.CollectionFlagSet()).toThrow()
|
||||
|
||||
globalThis.Set = originalSet
|
||||
})
|
||||
|
||||
test('Environment with Set.prototype.union', async () => {
|
||||
ok(!('union' in globalThis.Set.prototype))
|
||||
|
||||
const mockUnion = jest.fn((_) => new Set())
|
||||
// @ts-ignore
|
||||
globalThis.Set.prototype.union = mockUnion
|
||||
let module: { CollectionFlagSet: typeof CollectionFlagSet } | undefined
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
ok(module !== undefined)
|
||||
|
||||
const set1 = new Set()
|
||||
const set2 = new Set()
|
||||
const flags = new module.CollectionFlagSet()
|
||||
flags.union(set1, set2)
|
||||
expect(mockUnion).toHaveBeenCalledTimes(1)
|
||||
expect(mockUnion.mock.contexts[0]).toBe(set1)
|
||||
expect(mockUnion.mock.calls[0][0]).toBe(set2)
|
||||
|
||||
// @ts-ignore
|
||||
delete globalThis.Set.prototype.union
|
||||
})
|
||||
|
||||
test('Environment with Set.prototype.difference', async () => {
|
||||
ok(!('difference' in globalThis.Set.prototype))
|
||||
|
||||
const mockDifference = jest.fn((_) => new Set())
|
||||
// @ts-ignore
|
||||
globalThis.Set.prototype.difference = mockDifference
|
||||
let module: { CollectionFlagSet: typeof CollectionFlagSet } | undefined
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
ok(module !== undefined)
|
||||
|
||||
const set1 = new Set()
|
||||
const set2 = new Set()
|
||||
const flags = new module.CollectionFlagSet()
|
||||
flags.difference(set1, set2)
|
||||
expect(mockDifference).toHaveBeenCalledTimes(1)
|
||||
expect(mockDifference.mock.contexts[0]).toBe(set1)
|
||||
expect(mockDifference.mock.calls[0][0]).toBe(set2)
|
||||
|
||||
// @ts-ignore
|
||||
delete globalThis.Set.prototype.difference
|
||||
})
|
||||
|
||||
test('Environment with Set.prototype.intersection', async () => {
|
||||
ok(!('intersection' in globalThis.Set.prototype))
|
||||
|
||||
const mockIntersection = jest.fn((_) => new Set())
|
||||
// @ts-ignore
|
||||
globalThis.Set.prototype.intersection = mockIntersection
|
||||
let module: { CollectionFlagSet: typeof CollectionFlagSet } | undefined
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
ok(module !== undefined)
|
||||
|
||||
const set1 = new Set()
|
||||
const set2 = new Set()
|
||||
const flags = new module.CollectionFlagSet()
|
||||
flags.intersection(set1, set2)
|
||||
expect(mockIntersection).toHaveBeenCalledTimes(1)
|
||||
expect(mockIntersection.mock.contexts[0]).toBe(set1)
|
||||
expect(mockIntersection.mock.calls[0][0]).toBe(set2)
|
||||
|
||||
// @ts-ignore
|
||||
delete globalThis.Set.prototype.intersection
|
||||
})
|
||||
|
||||
test('Environment with Set.prototype.isSupersetOf', async () => {
|
||||
ok(!('isSupersetOf' in globalThis.Set.prototype))
|
||||
|
||||
const mockIsSupersetOf = jest.fn((_) => new Set())
|
||||
// @ts-ignore
|
||||
globalThis.Set.prototype.isSupersetOf = mockIsSupersetOf
|
||||
let module: { CollectionFlagSet: typeof CollectionFlagSet } | undefined
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
module = await import('@module')
|
||||
})
|
||||
ok(module !== undefined)
|
||||
|
||||
const set1 = new Set()
|
||||
const set2 = new Set()
|
||||
const flags = new module.CollectionFlagSet()
|
||||
flags.isSupersetOf(set1, set2)
|
||||
expect(mockIsSupersetOf).toHaveBeenCalledTimes(1)
|
||||
expect(mockIsSupersetOf.mock.contexts[0]).toBe(set1)
|
||||
expect(mockIsSupersetOf.mock.calls[0][0]).toBe(set2)
|
||||
|
||||
// @ts-ignore
|
||||
delete globalThis.Set.prototype.isSupersetOf
|
||||
})
|
||||
12
node/tests/_archive/flag.test.ts
Normal file
12
node/tests/_archive/flag.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { NumberBitflagSet, ForeignFlagError } from '@module'
|
||||
|
||||
test('cannot create a flag with a foreign parent', () => {
|
||||
const flags = new NumberBitflagSet()
|
||||
const flagA = flags.flag(1)
|
||||
|
||||
const otherFlags = new NumberBitflagSet()
|
||||
const flagX = otherFlags.flag(1)
|
||||
|
||||
flags.flag(2, flagA) // OK
|
||||
expect(() => flags.flag(4, flagX)).toThrow(ForeignFlagError)
|
||||
})
|
||||
25
node/tests/_archive/flagset.test.ts
Normal file
25
node/tests/_archive/flagset.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NumberBitflagSet, ReusedFlagValueError } from '@module'
|
||||
|
||||
test('cannot create an abstract flag with less than two parents', () => {
|
||||
const flags = new NumberBitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
|
||||
expect(() => flags.flag()).toThrow(TypeError)
|
||||
expect(() => flags.flag(flag1)).toThrow(TypeError)
|
||||
expect(() => flags.flag(flag1, flag1)).toThrow(TypeError)
|
||||
})
|
||||
|
||||
test('calls to flag() with arguments in the wrong order throw a TypeError', () => {
|
||||
const flags = new NumberBitflagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2)
|
||||
|
||||
// @ts-ignore
|
||||
expect(() => flags.flag(flag1, 2, flag2)).toThrow(TypeError)
|
||||
})
|
||||
|
||||
test('Use same value twice', () => {
|
||||
const flags = new NumberBitflagSet()
|
||||
const flag = flags.flag(1)
|
||||
expect(() => flags.flag(1)).toThrow(ReusedFlagValueError)
|
||||
})
|
||||
39
node/tests/_archive/number.test.ts
Normal file
39
node/tests/_archive/number.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { NumberBitflagSet, InvalidBitflagValueError } from '@module'
|
||||
|
||||
test('Not powers of two', () => {
|
||||
const flags = new BitFlagSet()
|
||||
expect(() => flags.flag(0)).toThrow(InvalidBitFlagValueError)
|
||||
expect(() => flags.flag(11)).toThrow(InvalidBitFlagValueError)
|
||||
})
|
||||
|
||||
test('Normalise to minimum', () => {
|
||||
const flags = new BitFlagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2, flag1)
|
||||
const flag4 = flags.flag(4, flag1)
|
||||
const flag8 = flags.flag(8, flag4)
|
||||
|
||||
expect(flags.minimum(0)).toEqual(0)
|
||||
expect(flags.minimum(1)).toEqual(1)
|
||||
expect(flags.minimum(2)).toEqual(0)
|
||||
expect(flags.minimum(3)).toEqual(3)
|
||||
expect(flags.minimum(11)).toEqual(3)
|
||||
expect(flags.minimum(13)).toEqual(13)
|
||||
expect(flags.minimum(17)).toEqual(1)
|
||||
})
|
||||
|
||||
test('Normalise to maximum', () => {
|
||||
const flags = new BitFlagSet()
|
||||
const flag1 = flags.flag(1)
|
||||
const flag2 = flags.flag(2, flag1)
|
||||
const flag4 = flags.flag(4, flag1)
|
||||
const flag8 = flags.flag(8, flag4)
|
||||
|
||||
expect(flags.maximum(0)).toEqual(0)
|
||||
expect(flags.maximum(1)).toEqual(1)
|
||||
expect(flags.maximum(2)).toEqual(3)
|
||||
expect(flags.maximum(3)).toEqual(3)
|
||||
expect(flags.maximum(11)).toEqual(15)
|
||||
expect(flags.maximum(13)).toEqual(13)
|
||||
expect(flags.maximum(17)).toEqual(1)
|
||||
})
|
||||
62
node/tests/flagsets/array.test.ts
Normal file
62
node/tests/flagsets/array.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { ArrayFlagSet } from '~'
|
||||
|
||||
describe(ArrayFlagSet, () => {
|
||||
test('none', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect(flags.none()).toEqual([])
|
||||
})
|
||||
|
||||
test('union', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect(flags.union([], [])).toEqual([])
|
||||
expect(flags.union(['A'], [])).toEqual(['A'])
|
||||
expect(flags.union([], ['B'])).toEqual(['B'])
|
||||
expect(flags.union(['A'], ['B'])).toEqual(['A', 'B'])
|
||||
expect(flags.union(['A', 'B'], ['B', 'C'])).toEqual(['A', 'B', 'C'])
|
||||
})
|
||||
|
||||
test('difference', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect(flags.difference([], [])).toEqual([])
|
||||
expect(flags.difference(['A'], [])).toEqual(['A'])
|
||||
expect(flags.difference(['A', 'B'], ['B', 'C'])).toEqual(['A'])
|
||||
expect(flags.difference(['B', 'C'], ['A', 'B'])).toEqual(['C'])
|
||||
expect(flags.difference(['D'], ['A', 'E'])).toEqual(['D'])
|
||||
})
|
||||
|
||||
test('intersection', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect(flags.intersection([], [])).toEqual([])
|
||||
expect(flags.intersection(['A'], [])).toEqual([])
|
||||
expect(flags.intersection(['A'], ['B'])).toEqual([])
|
||||
expect(flags.intersection(['A'], ['A', 'B'])).toEqual(['A'])
|
||||
expect(flags.intersection(['A', 'B', 'D'], ['A', 'C'])).toEqual(['A'])
|
||||
expect(flags.intersection(['A', 'B', 'D'], ['A', 'B', 'C'])).toEqual([
|
||||
'A',
|
||||
'B',
|
||||
])
|
||||
})
|
||||
|
||||
test('isSuperset', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect(flags.isSuperset([], [])).toBe(true)
|
||||
expect(flags.isSuperset(['A', 'B'], [])).toBe(true)
|
||||
expect(flags.isSuperset(['A', 'B'], ['A'])).toBe(true)
|
||||
expect(flags.isSuperset(['A', 'B'], ['A', 'B'])).toBe(true)
|
||||
expect(flags.isSuperset([], ['A', 'B'])).toBe(false)
|
||||
expect(flags.isSuperset(['C', 'D'], ['B'])).toBe(false)
|
||||
})
|
||||
|
||||
test('enumerate', () => {
|
||||
const flags = new ArrayFlagSet<string>()
|
||||
|
||||
expect([...flags.enumerate([])]).toEqual([])
|
||||
expect([...flags.enumerate(['A'])]).toEqual(['A'])
|
||||
expect([...flags.enumerate(['A', 'B', 'C'])]).toEqual(['A', 'B', 'C'])
|
||||
})
|
||||
})
|
||||
66
node/tests/flagsets/base64.test.ts
Normal file
66
node/tests/flagsets/base64.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Base64BitFlagSet } from '~'
|
||||
|
||||
describe(Base64BitFlagSet, () => {
|
||||
test('none', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect(flags.none()).toEqual('')
|
||||
})
|
||||
|
||||
test('union', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect(flags.union('', '')).toEqual('')
|
||||
expect(flags.union('A', 'A')).toEqual('')
|
||||
expect(flags.union('B', 'A')).toEqual('B')
|
||||
expect(flags.union('A', 'C')).toEqual('C')
|
||||
expect(flags.union('B', 'C')).toEqual('D')
|
||||
expect(flags.union('D', 'G')).toEqual('H')
|
||||
})
|
||||
|
||||
test('difference', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect(flags.difference('', '')).toEqual('')
|
||||
expect(flags.difference('A', 'A')).toEqual('')
|
||||
expect(flags.difference('B', 'A')).toEqual('B')
|
||||
expect(flags.difference('D', 'G')).toEqual('B')
|
||||
expect(flags.difference('G', 'D')).toEqual('E')
|
||||
expect(flags.difference('IB', 'R')).toEqual('IB')
|
||||
})
|
||||
|
||||
test('intersection', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect(flags.intersection('', '')).toEqual('')
|
||||
expect(flags.intersection('A', 'A')).toEqual('')
|
||||
expect(flags.intersection('B', 'A')).toEqual('')
|
||||
expect(flags.intersection('B', 'C')).toEqual('')
|
||||
expect(flags.intersection('B', 'D')).toEqual('B')
|
||||
expect(flags.intersection('L', 'F')).toEqual('B')
|
||||
expect(flags.intersection('L', 'H')).toEqual('D')
|
||||
})
|
||||
|
||||
test('isSuperset', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect(flags.isSuperset('A', 'A')).toBe(true)
|
||||
expect(flags.isSuperset('D', 'A')).toBe(true)
|
||||
expect(flags.isSuperset('D', 'B')).toBe(true)
|
||||
expect(flags.isSuperset('D', 'D')).toBe(true)
|
||||
expect(flags.isSuperset('A', 'D')).toBe(false)
|
||||
expect(flags.isSuperset('I', 'E')).toBe(false)
|
||||
})
|
||||
|
||||
test('enumerate', () => {
|
||||
const flags = new Base64BitFlagSet()
|
||||
|
||||
expect([...flags.enumerate('A')]).toEqual([])
|
||||
expect([...flags.enumerate('B')]).toEqual([1])
|
||||
expect([...flags.enumerate('C')]).toEqual([2])
|
||||
expect([...flags.enumerate('D')]).toEqual([1, 2])
|
||||
expect([...flags.enumerate('L')]).toEqual([1, 2, 4])
|
||||
expect([...flags.enumerate('kB')]).toEqual([3, 6, 7])
|
||||
expect([...flags.enumerate('AAB')]).toEqual([13])
|
||||
})
|
||||
})
|
||||
62
node/tests/flagsets/bigint.test.ts
Normal file
62
node/tests/flagsets/bigint.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { BigBitFlagSet } from '~'
|
||||
|
||||
describe(BigBitFlagSet, () => {
|
||||
test('none', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect(flags.none()).toEqual(0n)
|
||||
})
|
||||
|
||||
test('union', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect(flags.union(0n, 0n)).toEqual(0n)
|
||||
expect(flags.union(1n, 0n)).toEqual(1n)
|
||||
expect(flags.union(0n, 2n)).toEqual(2n)
|
||||
expect(flags.union(1n, 2n)).toEqual(3n)
|
||||
expect(flags.union(3n, 6n)).toEqual(7n)
|
||||
})
|
||||
|
||||
test('difference', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect(flags.difference(0n, 0n)).toEqual(0n)
|
||||
expect(flags.difference(1n, 0n)).toEqual(1n)
|
||||
expect(flags.difference(3n, 6n)).toEqual(1n)
|
||||
expect(flags.difference(6n, 3n)).toEqual(4n)
|
||||
expect(flags.difference(8n, 17n)).toEqual(8n)
|
||||
})
|
||||
|
||||
test('intersection', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect(flags.intersection(0n, 0n)).toEqual(0n)
|
||||
expect(flags.intersection(1n, 0n)).toEqual(0n)
|
||||
expect(flags.intersection(1n, 2n)).toEqual(0n)
|
||||
expect(flags.intersection(1n, 3n)).toEqual(1n)
|
||||
expect(flags.intersection(11n, 5n)).toEqual(1n)
|
||||
expect(flags.intersection(11n, 7n)).toEqual(3n)
|
||||
})
|
||||
|
||||
test('isSuperset', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect(flags.isSuperset(0n, 0n)).toBe(true)
|
||||
expect(flags.isSuperset(3n, 0n)).toBe(true)
|
||||
expect(flags.isSuperset(3n, 1n)).toBe(true)
|
||||
expect(flags.isSuperset(3n, 3n)).toBe(true)
|
||||
expect(flags.isSuperset(0n, 3n)).toBe(false)
|
||||
expect(flags.isSuperset(8n, 4n)).toBe(false)
|
||||
})
|
||||
|
||||
test('enumerate', () => {
|
||||
const flags = new BigBitFlagSet()
|
||||
|
||||
expect([...flags.enumerate(0n)]).toEqual([])
|
||||
expect([...flags.enumerate(1n)]).toEqual([1n])
|
||||
expect([...flags.enumerate(2n)]).toEqual([2n])
|
||||
expect([...flags.enumerate(3n)]).toEqual([1n, 2n])
|
||||
expect([...flags.enumerate(11n)]).toEqual([1n, 2n, 8n])
|
||||
expect([...flags.enumerate(100n)]).toEqual([4n, 32n, 64n])
|
||||
})
|
||||
})
|
||||
73
node/tests/flagsets/collection.test.ts
Normal file
73
node/tests/flagsets/collection.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { CollectionFlagSet } from '~'
|
||||
|
||||
function set<T>(...values: T[]): Set<T> {
|
||||
return new Set<T>(values)
|
||||
}
|
||||
|
||||
describe(CollectionFlagSet, () => {
|
||||
test('none', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.none()).toEqual(set())
|
||||
})
|
||||
|
||||
test('union', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.union(set(), set())).toEqual(set())
|
||||
expect(flags.union(set('A'), set())).toEqual(set('A'))
|
||||
expect(flags.union(set(), set('B'))).toEqual(set('B'))
|
||||
expect(flags.union(set('A'), set('B'))).toEqual(set('A', 'B'))
|
||||
expect(flags.union(set('A', 'B'), set('B', 'C'))).toEqual(
|
||||
set('A', 'B', 'C')
|
||||
)
|
||||
})
|
||||
|
||||
test('difference', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.difference(set(), set())).toEqual(set())
|
||||
expect(flags.difference(set('A'), set())).toEqual(set('A'))
|
||||
expect(flags.difference(set('A', 'B'), set('B', 'C'))).toEqual(set('A'))
|
||||
expect(flags.difference(set('B', 'C'), set('A', 'B'))).toEqual(set('C'))
|
||||
expect(flags.difference(set('D'), set('A', 'E'))).toEqual(set('D'))
|
||||
})
|
||||
|
||||
test('intersection', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.intersection(set(), set())).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set())).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set('B'))).toEqual(set())
|
||||
expect(flags.intersection(set('A'), set('A', 'B'))).toEqual(set('A'))
|
||||
expect(flags.intersection(set('A', 'B', 'D'), set('A', 'C'))).toEqual(
|
||||
set('A')
|
||||
)
|
||||
expect(
|
||||
flags.intersection(set('A', 'B', 'D'), set('A', 'B', 'C'))
|
||||
).toEqual(set('A', 'B'))
|
||||
})
|
||||
|
||||
test('isSuperset', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect(flags.isSuperset(set(), set())).toBe(true)
|
||||
expect(flags.isSuperset(set('A', 'B'), set())).toBe(true)
|
||||
expect(flags.isSuperset(set('A', 'B'), set('A'))).toBe(true)
|
||||
expect(flags.isSuperset(set('A', 'B'), set('A', 'B'))).toBe(true)
|
||||
expect(flags.isSuperset(set(), set('A', 'B'))).toBe(false)
|
||||
expect(flags.isSuperset(set('C', 'D'), set('B'))).toBe(false)
|
||||
})
|
||||
|
||||
test('enumerate', () => {
|
||||
const flags = new CollectionFlagSet<string>()
|
||||
|
||||
expect([...flags.enumerate(set())]).toEqual([])
|
||||
expect([...flags.enumerate(set('A'))]).toEqual(['A'])
|
||||
expect([...flags.enumerate(set('A', 'B', 'C'))]).toEqual([
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
])
|
||||
})
|
||||
})
|
||||
62
node/tests/flagsets/number.test.ts
Normal file
62
node/tests/flagsets/number.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { BitFlagSet } from '~'
|
||||
|
||||
describe(BitFlagSet, () => {
|
||||
test('none', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect(flags.none()).toEqual(0)
|
||||
})
|
||||
|
||||
test('union', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect(flags.union(0, 0)).toEqual(0)
|
||||
expect(flags.union(1, 0)).toEqual(1)
|
||||
expect(flags.union(0, 2)).toEqual(2)
|
||||
expect(flags.union(1, 2)).toEqual(3)
|
||||
expect(flags.union(3, 6)).toEqual(7)
|
||||
})
|
||||
|
||||
test('difference', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect(flags.difference(0, 0)).toEqual(0)
|
||||
expect(flags.difference(1, 0)).toEqual(1)
|
||||
expect(flags.difference(3, 6)).toEqual(1)
|
||||
expect(flags.difference(6, 3)).toEqual(4)
|
||||
expect(flags.difference(8, 17)).toEqual(8)
|
||||
})
|
||||
|
||||
test('intersection', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect(flags.intersection(0, 0)).toEqual(0)
|
||||
expect(flags.intersection(1, 0)).toEqual(0)
|
||||
expect(flags.intersection(1, 2)).toEqual(0)
|
||||
expect(flags.intersection(1, 3)).toEqual(1)
|
||||
expect(flags.intersection(11, 5)).toEqual(1)
|
||||
expect(flags.intersection(11, 7)).toEqual(3)
|
||||
})
|
||||
|
||||
test('isSuperset', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect(flags.isSuperset(0, 0)).toBe(true)
|
||||
expect(flags.isSuperset(3, 0)).toBe(true)
|
||||
expect(flags.isSuperset(3, 1)).toBe(true)
|
||||
expect(flags.isSuperset(3, 3)).toBe(true)
|
||||
expect(flags.isSuperset(0, 3)).toBe(false)
|
||||
expect(flags.isSuperset(8, 4)).toBe(false)
|
||||
})
|
||||
|
||||
test('enumerate', () => {
|
||||
const flags = new BitFlagSet()
|
||||
|
||||
expect([...flags.enumerate(0)]).toEqual([])
|
||||
expect([...flags.enumerate(1)]).toEqual([1])
|
||||
expect([...flags.enumerate(2)]).toEqual([2])
|
||||
expect([...flags.enumerate(3)]).toEqual([1, 2])
|
||||
expect([...flags.enumerate(11)]).toEqual([1, 2, 8])
|
||||
expect([...flags.enumerate(100)]).toEqual([4, 32, 64])
|
||||
})
|
||||
})
|
||||
111
node/tsconfig.json
Normal file
111
node/tsconfig.json
Normal file
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
"paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
"~": ["./src/index.ts"]
|
||||
},
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
"stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
"noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user