Comparing version 0.3.4 to 0.4.0
/// <reference types="node" resolution-mode="require"/> | ||
import type * as FS from 'fs'; | ||
import { UnionToTuple } from './types.js'; | ||
export declare function filterObject<O extends object, R extends object>(object: O, predicate: (key: keyof O, value: O[keyof O]) => boolean): R; | ||
@@ -8,3 +9,9 @@ export declare function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly K[]): Pick<T, K>; | ||
export declare function omit<T extends object, K extends keyof T>(object: T, ...keys: readonly (readonly K[])[]): Omit<T, K>; | ||
export declare function assignWithDefaults<To extends object, From extends object>(to: To, from: From, defaults?: Partial<To>): void; | ||
export declare function assignWithDefaults<To extends Record<keyof any, any>, From extends Partial<To>>(to: To, from: From, defaults?: Partial<To>): void; | ||
/** | ||
* Entries of T | ||
*/ | ||
export type Entries<T extends object> = UnionToTuple<{ | ||
[K in keyof T]: [K, T[K]]; | ||
}[keyof T]>; | ||
export declare function isJSON(str: string): boolean; | ||
@@ -23,3 +30,3 @@ export declare abstract class FileMap<V> implements Map<string, V> { | ||
get size(): number; | ||
get [Symbol.iterator](): any; | ||
get [Symbol.iterator](): () => IterableIterator<[string, V]>; | ||
get keys(): typeof this._map.keys; | ||
@@ -64,3 +71,3 @@ get values(): typeof this._map.values; | ||
suffix: string; | ||
fs?: typeof FS; | ||
fs: typeof FS; | ||
} | ||
@@ -84,7 +91,1 @@ /** | ||
export declare function resolveConstructors(object: object): string[]; | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export declare function getRandomIntWithRecursiveProbability(probability?: number): number; |
@@ -13,3 +13,3 @@ export function filterObject(object, predicate) { | ||
export function omit(object, ...keys) { | ||
return filterObject(object, (key) => !keys.flat().includes(key)); | ||
return filterObject(object, key => !keys.flat().includes(key)); | ||
} | ||
@@ -142,3 +142,3 @@ export function assignWithDefaults(to, from, defaults = to) { | ||
.readdirSync(this.path) | ||
.filter(p => p.endsWith(this.options.suffix)) | ||
.filter(p => p.endsWith(this.options.suffix || '')) | ||
.map(p => p.slice(0, -this.options.suffix.length)); | ||
@@ -170,5 +170,6 @@ } | ||
get(key) { | ||
if (this.has(key)) { | ||
return this.fs.readFileSync(this._join(key), 'utf8'); | ||
if (!this.has(key)) { | ||
throw new ReferenceError('Key not found'); | ||
} | ||
return this.fs.readFileSync(this._join(key), 'utf8'); | ||
} | ||
@@ -192,9 +193,1 @@ has(key) { | ||
} | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export function getRandomIntWithRecursiveProbability(probability = 0.5) { | ||
return -Math.floor(Math.log(Math.random()) / Math.log(1 / probability)); | ||
} |
@@ -6,1 +6,7 @@ export declare function randomFloat(min?: number, max?: number): number; | ||
export declare function randomInt(min?: number, max?: number): number; | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export declare function getRandomIntWithRecursiveProbability(probability?: number): number; |
@@ -24,1 +24,9 @@ export function randomFloat(min = 0, max = 1) { | ||
} | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export function getRandomIntWithRecursiveProbability(probability = 0.5) { | ||
return -Math.floor(Math.log(Math.random()) / Math.log(1 / probability)); | ||
} |
export declare function capitalize<T extends string>(value: T): Capitalize<T>; | ||
export declare function uncapitalize<T extends string>(value: T): Uncapitalize<T>; | ||
export type ConcatString<T extends string[]> = T extends [infer F extends string, ...infer R extends string[]] ? `${F}${ConcatString<R>}` : ''; | ||
export type Join<T extends string[], S extends string = ','> = T extends [infer F extends string, ...infer R extends string[]] ? `${F}${R extends [] ? '' : `${S}${Join<R, S>}`}` : ''; | ||
export type Whitespace = ' ' | '\t'; | ||
export type Trim<T extends string> = T extends `${Whitespace}${infer R extends string}` ? Trim<R> : T; |
@@ -0,15 +1,9 @@ | ||
import * as Struct from './internal/struct.js'; | ||
import { ClassLike } from './types.js'; | ||
export type PrimitiveType = `${'int' | 'uint'}${8 | 16 | 32 | 64}` | `float${32 | 64}`; | ||
export type ValidPrimitiveType = PrimitiveType | Capitalize<PrimitiveType> | 'char'; | ||
import * as primitive from './internal/primitives.js'; | ||
export { Struct }; | ||
/** | ||
* Options for struct initialization | ||
*/ | ||
export interface StructOptions { | ||
align: number; | ||
bigEndian: boolean; | ||
} | ||
/** | ||
* Gets the size in bytes of a type | ||
*/ | ||
export declare function sizeof(type: ValidPrimitiveType | ClassLike | object): number; | ||
export declare function sizeof<T extends primitive.Valid | Struct.StaticLike | Struct.InstanceLike>(type: T): Struct.Size<T>; | ||
/** | ||
@@ -22,7 +16,7 @@ * Aligns a number | ||
*/ | ||
export declare function struct(options?: Partial<StructOptions>): (target: ClassLike, _?: ClassDecoratorContext) => void; | ||
export declare function struct(options?: Partial<Struct.Options>): (target: Struct.StaticLike, _?: ClassDecoratorContext) => void; | ||
/** | ||
* Decorates a class member to be serialized | ||
*/ | ||
export declare function member(type: ValidPrimitiveType | ClassLike, length?: number): (target: object, context?: ClassMemberDecoratorContext | string | symbol) => void; | ||
export declare function member(type: primitive.Valid | ClassLike, length?: number): (target: object, context?: ClassMemberDecoratorContext | string | symbol) => void; | ||
/** | ||
@@ -37,2 +31,6 @@ * Serializes a struct into a Uint8Array | ||
/** | ||
* Also can be a name when legacy decorators are used | ||
*/ | ||
type Context = string | symbol | ClassMemberDecoratorContext; | ||
/** | ||
* Shortcut types | ||
@@ -44,85 +42,85 @@ * | ||
int8: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
int16: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
int32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
int64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
uint8: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
uint16: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
uint32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
uint64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
float32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
float64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Int8: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Int16: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Int32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Int64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Uint8: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Uint16: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Uint32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Uint64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Float32: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
Float64: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
char: { | ||
(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
(length: number): (target: object, context?: Context) => void; | ||
(target: object, context?: Context): void; | ||
}; | ||
}; |
@@ -0,25 +1,5 @@ | ||
import * as Struct from './internal/struct.js'; | ||
import { capitalize } from './string.js'; | ||
const primitiveTypes = ['int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float32', 'float64']; | ||
const validPrimitiveTypes = [...primitiveTypes, ...primitiveTypes.map(t => capitalize(t)), 'char']; | ||
const numberRegex = /^(u?int)(8|16|32|64)|(float)(32|64)$/i; | ||
function normalizePrimitive(type) { | ||
return type == 'char' ? 'uint8' : type.toLowerCase(); | ||
} | ||
function isPrimitiveType(type) { | ||
return numberRegex.test(type.toString()); | ||
} | ||
function isValidPrimitive(type) { | ||
return type == 'char' || numberRegex.test(type.toString().toLowerCase()); | ||
} | ||
const init = Symbol('struct_init'); | ||
const metadata = Symbol('struct'); | ||
function isStatic(arg) { | ||
return typeof arg == 'function' && metadata in arg; | ||
} | ||
function isInstance(arg) { | ||
return metadata in (arg?.constructor || {}); | ||
} | ||
function isStruct(arg) { | ||
return isInstance(arg) || isStatic(arg); | ||
} | ||
import * as primitive from './internal/primitives.js'; | ||
export { Struct }; | ||
/** | ||
@@ -31,11 +11,11 @@ * Gets the size in bytes of a type | ||
if (typeof type == 'string') { | ||
if (!isValidPrimitive(type)) { | ||
if (!primitive.isValid(type)) { | ||
throw new TypeError('Invalid primitive type: ' + type); | ||
} | ||
return +normalizePrimitive(type).match(numberRegex)[2] / 8; | ||
return (+primitive.normalize(type).match(primitive.regex)[2] / 8); | ||
} | ||
if (!isStruct(type)) { | ||
if (!Struct.isStruct(type)) { | ||
throw new TypeError('Not a struct'); | ||
} | ||
const meta = metadata in type ? type[metadata] : type.constructor[metadata]; | ||
const meta = Struct.isStatic(type) ? type[Struct.metadata] : type.constructor[Struct.metadata]; | ||
return meta.size; | ||
@@ -55,7 +35,7 @@ } | ||
return function (target, _) { | ||
target[init] ||= []; | ||
target[Struct.init] ||= []; | ||
let size = 0; | ||
const members = new Map(); | ||
for (const { name, type, length } of target[init]) { | ||
if (!isValidPrimitive(type) && !isStatic(type)) { | ||
for (const { name, type, length } of target[Struct.init]) { | ||
if (!primitive.isValid(type) && !Struct.isStatic(type)) { | ||
throw new TypeError('Not a valid type: ' + type); | ||
@@ -65,3 +45,3 @@ } | ||
offset: size, | ||
type: isValidPrimitive(type) ? normalizePrimitive(type) : type, | ||
type: primitive.isValid(type) ? primitive.normalize(type) : type, | ||
length, | ||
@@ -72,4 +52,3 @@ }); | ||
} | ||
target[metadata] = { options, members, size }; | ||
delete target[init]; | ||
target[Struct.metadata] = { options, members, size }; | ||
}; | ||
@@ -87,7 +66,14 @@ } | ||
} | ||
if ((typeof target != 'object' || typeof target != 'function') && !('constructor' in target)) { | ||
if (!name) { | ||
throw new ReferenceError('Invalid name for struct member'); | ||
} | ||
if (typeof target != 'object') { | ||
throw new TypeError('Invalid member for struct field'); | ||
} | ||
target.constructor[init] ||= []; | ||
target.constructor[init].push({ name, type, length }); | ||
if (!('constructor' in target)) { | ||
throw new TypeError('Invalid member for struct field'); | ||
} | ||
const struct = target.constructor; | ||
struct[Struct.init] ||= []; | ||
struct[Struct.init].push({ name, type, length }); | ||
}; | ||
@@ -99,6 +85,6 @@ } | ||
export function serialize(instance) { | ||
if (!isInstance(instance)) { | ||
if (!Struct.isInstance(instance)) { | ||
throw new TypeError('Can not serialize, not a struct instance'); | ||
} | ||
const { options, members } = instance.constructor[metadata]; | ||
const { options, members } = instance.constructor[Struct.metadata]; | ||
const buffer = new Uint8Array(sizeof(instance)); | ||
@@ -109,2 +95,3 @@ const view = new DataView(buffer.buffer); | ||
const iOff = offset + sizeof(type) * i; | ||
// @ts-expect-error 7053 | ||
let value = length > 0 ? instance[name][i] : instance[name]; | ||
@@ -114,3 +101,3 @@ if (typeof value == 'string') { | ||
} | ||
if (!isPrimitiveType(type)) { | ||
if (!primitive.isType(type)) { | ||
buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff); | ||
@@ -138,6 +125,6 @@ continue; | ||
export function deserialize(instance, _buffer) { | ||
if (!isInstance(instance)) { | ||
if (!Struct.isInstance(instance)) { | ||
throw new TypeError('Can not deserialize, not a struct instance'); | ||
} | ||
const { options, members } = instance.constructor[metadata]; | ||
const { options, members } = instance.constructor[Struct.metadata]; | ||
const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer); | ||
@@ -147,9 +134,12 @@ const view = new DataView(buffer.buffer); | ||
for (let i = 0; i < (length || 1); i++) { | ||
// @ts-expect-error 7053 | ||
let object = length > 0 ? instance[name] : instance; | ||
const key = length > 0 ? i : name, iOff = offset + sizeof(type) * i; | ||
// @ts-expect-error 7053 | ||
if (typeof instance[name] == 'string') { | ||
// @ts-expect-error 7053 | ||
instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1); | ||
continue; | ||
} | ||
if (!isPrimitiveType(type)) { | ||
if (!primitive.isType(type)) { | ||
if (object[key] === null || object[key] === undefined) { | ||
@@ -192,2 +182,2 @@ continue; | ||
*/ | ||
export const types = Object.fromEntries(validPrimitiveTypes.map(t => [t, _member(t)])); | ||
export const types = Object.fromEntries(primitive.valids.map(t => [t, _member(t)])); |
@@ -74,30 +74,27 @@ /** | ||
*/ | ||
export type Shift<T> = T extends unknown[] ? (((...x: T) => void) extends (h: any, ...t: infer I) => void ? I : []) : unknown; | ||
export type Shift<T extends unknown[]> = T extends [unknown, ...infer Rest] ? Rest : never; | ||
/** | ||
* Gets the first element of T | ||
*/ | ||
export type First<T> = T extends unknown[] ? (((...x: T) => void) extends (h: infer I, ...t: any) => void ? I : []) : never; | ||
export type First<T extends unknown[]> = T extends [infer F, ...unknown[]] ? F : never; | ||
/** | ||
* Inserts A into T at the start of T | ||
* Inserts V into T at the start of T | ||
*/ | ||
export type Unshift<T, A> = T extends unknown[] ? (((h: A, ...t: T) => void) extends (...i: infer I) => void ? I : unknown) : never; | ||
export type Unshift<T extends unknown[], V> = [V, ...T]; | ||
/** | ||
* Removes the last element of T | ||
*/ | ||
export type Pop<T> = T extends unknown[] ? (((...x: T) => void) extends (...i: [...infer I, any]) => void ? I : unknown) : never; | ||
export type Pop<T extends unknown[]> = T extends [...infer _, unknown] ? _ : never; | ||
/** | ||
* Gets the last element of T | ||
*/ | ||
export type Last<T> = T extends unknown[] ? (((...x: T) => void) extends (...i: [...infer H, infer I]) => void ? I : unknown) : never; | ||
export type Last<T extends unknown[]> = T extends [...unknown[], infer Last] ? Last : never; | ||
/** | ||
* Appends A to T | ||
* Appends V to T | ||
*/ | ||
export type Push<T, A> = T extends unknown[] ? (((...a: [...T, A]) => void) extends (...i: infer I) => void ? I : unknown) : never; | ||
export type Push<T extends unknown[], V> = [...T, V]; | ||
/** | ||
* Concats A and B | ||
*/ | ||
export type Concat<A, B> = { | ||
0: A; | ||
1: Concat<Unshift<A, 0>, Shift<B>>; | ||
}[Empty extends B ? 0 : 1]; | ||
export type Concat<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Concat<Unshift<A, 0>, Shift<B>>; | ||
/** | ||
@@ -109,16 +106,10 @@ * Extracts from A what is not B | ||
*/ | ||
export type Remove<A, B> = { | ||
0: A; | ||
1: Remove<Shift<A>, Shift<B>>; | ||
}[Empty extends B ? 0 : 1]; | ||
export type Remove<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Remove<Shift<A>, Shift<B>>; | ||
/** | ||
* The length of T | ||
*/ | ||
export type Length<T> = T extends { | ||
export type Length<T extends { | ||
length: number; | ||
} ? T['length'] : never; | ||
type _FromLength<N extends number, R = Empty> = { | ||
0: R; | ||
1: _FromLength<N, Unshift<R, 0>>; | ||
}[Length<R> extends N ? 0 : 1]; | ||
}> = T['length']; | ||
type _FromLength<N extends number, R extends unknown[] = Empty> = Length<R> extends N ? R : _FromLength<N, Unshift<R, 0>>; | ||
/** | ||
@@ -180,2 +171,17 @@ * Creates a tuple of length N | ||
export type ClassLike<Instance = unknown> = abstract new (...args: unknown[]) => Instance; | ||
/** | ||
* Converts a union to an intersection | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
/** | ||
* Gets the last element of a union | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type LastOfUnion<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never; | ||
/** | ||
* Converts a union to a tuple | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type UnionToTuple<T, L = LastOfUnion<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<UnionToTuple<Exclude<T, L>>, L>; | ||
export {}; |
{ | ||
"name": "utilium", | ||
"version": "0.3.4", | ||
"version": "0.4.0", | ||
"description": "Typescript utilies", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
import type * as FS from 'fs'; | ||
import { UnionToTuple } from './types.js'; | ||
@@ -21,7 +22,7 @@ export function filterObject<O extends object, R extends object>(object: O, predicate: (key: keyof O, value: O[keyof O]) => boolean): R { | ||
export function omit<T extends object, K extends keyof T>(object: T, ...keys: readonly K[] | readonly (readonly K[])[]): Omit<T, K> { | ||
return filterObject<T, Omit<T, K>>(object, (key: K) => !keys.flat().includes(key)); | ||
return filterObject<T, Omit<T, K>>(object, key => !keys.flat().includes(key as K)); | ||
} | ||
export function assignWithDefaults<To extends object, From extends object>(to: To, from: From, defaults: Partial<To> = to): void { | ||
const keys = new Set([...Object.keys(to), ...Object.keys(from)]); | ||
export function assignWithDefaults<To extends Record<keyof any, any>, From extends Partial<To>>(to: To, from: From, defaults: Partial<To> = to): void { | ||
const keys = new Set<keyof To | keyof From>([...Object.keys(to), ...Object.keys(from)]); | ||
for (const key of keys) { | ||
@@ -36,2 +37,7 @@ try { | ||
/** | ||
* Entries of T | ||
*/ | ||
export type Entries<T extends object> = UnionToTuple<{ [K in keyof T]: [K, T[K]] }[keyof T]>; | ||
export function isJSON(str: string) { | ||
@@ -189,3 +195,3 @@ try { | ||
fs?: typeof FS; | ||
fs: typeof FS; | ||
} | ||
@@ -205,3 +211,3 @@ | ||
) { | ||
super(path, options.fs); | ||
super(path, options.fs!); | ||
} | ||
@@ -212,4 +218,4 @@ | ||
.readdirSync(this.path) | ||
.filter(p => p.endsWith(this.options.suffix)) | ||
.map(p => p.slice(0, -this.options.suffix.length)); | ||
.filter(p => p.endsWith(this.options.suffix || '')) | ||
.map(p => p.slice(0, -this.options.suffix!.length)); | ||
} | ||
@@ -222,3 +228,3 @@ | ||
protected get _map(): Map<string, string> { | ||
const entries = []; | ||
const entries: [string, string][] = []; | ||
for (const name of this._names) { | ||
@@ -247,5 +253,6 @@ const content = this.fs.readFileSync(this._join(name), 'utf8'); | ||
public get(key: string): string { | ||
if (this.has(key)) { | ||
return this.fs.readFileSync(this._join(key), 'utf8'); | ||
if (!this.has(key)) { | ||
throw new ReferenceError('Key not found'); | ||
} | ||
return this.fs.readFileSync(this._join(key), 'utf8'); | ||
} | ||
@@ -272,10 +279,1 @@ | ||
} | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export function getRandomIntWithRecursiveProbability(probability = 0.5): number { | ||
return -Math.floor(Math.log(Math.random()) / Math.log(1 / probability)); | ||
} |
@@ -28,1 +28,10 @@ export function randomFloat(min = 0, max = 1): number { | ||
} | ||
/** | ||
* Gets a random int, r, with the probability P(r) = (base)**r | ||
* For example, with a probability of 1/2: P(1) = 1/2, P(2) = 1/4, etc. | ||
* @param probability the probability | ||
*/ | ||
export function getRandomIntWithRecursiveProbability(probability = 0.5): number { | ||
return -Math.floor(Math.log(Math.random()) / Math.log(1 / probability)); | ||
} |
export function capitalize<T extends string>(value: T): Capitalize<T> { | ||
return <Capitalize<T>>(value.at(0).toUpperCase() + value.slice(1)); | ||
return <Capitalize<T>>(value.at(0)!.toUpperCase() + value.slice(1)); | ||
} | ||
export function uncapitalize<T extends string>(value: T): Uncapitalize<T> { | ||
return <Uncapitalize<T>>(value.at(0).toLowerCase() + value.slice(1)); | ||
return <Uncapitalize<T>>(value.at(0)!.toLowerCase() + value.slice(1)); | ||
} | ||
export type ConcatString<T extends string[]> = T extends [infer F extends string, ...infer R extends string[]] ? `${F}${ConcatString<R>}` : ''; | ||
export type Join<T extends string[], S extends string = ','> = T extends [infer F extends string, ...infer R extends string[]] | ||
? `${F}${R extends [] ? '' : `${S}${Join<R, S>}`}` | ||
: ''; | ||
export type Whitespace = ' ' | '\t'; | ||
export type Trim<T extends string> = T extends `${Whitespace}${infer R extends string}` ? Trim<R> : T; |
@@ -0,96 +1,27 @@ | ||
import * as Struct from './internal/struct.js'; | ||
import { capitalize } from './string.js'; | ||
import { ClassLike } from './types.js'; | ||
import * as primitive from './internal/primitives.js'; | ||
export { Struct }; | ||
export type PrimitiveType = `${'int' | 'uint'}${8 | 16 | 32 | 64}` | `float${32 | 64}`; | ||
export type ValidPrimitiveType = PrimitiveType | Capitalize<PrimitiveType> | 'char'; | ||
const primitiveTypes = ['int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float32', 'float64'] satisfies PrimitiveType[]; | ||
const validPrimitiveTypes = [...primitiveTypes, ...primitiveTypes.map(t => capitalize(t)), 'char'] satisfies ValidPrimitiveType[]; | ||
const numberRegex = /^(u?int)(8|16|32|64)|(float)(32|64)$/i; | ||
function normalizePrimitive(type: ValidPrimitiveType): PrimitiveType { | ||
return type == 'char' ? 'uint8' : <PrimitiveType>type.toLowerCase(); | ||
} | ||
function isPrimitiveType(type: unknown): type is PrimitiveType { | ||
return numberRegex.test(type.toString()); | ||
} | ||
function isValidPrimitive(type: unknown): type is ValidPrimitiveType { | ||
return type == 'char' || numberRegex.test(type.toString().toLowerCase()); | ||
} | ||
interface MemberInit { | ||
name: string; | ||
type: string | ClassLike; | ||
length?: number; | ||
} | ||
const init = Symbol('struct_init'); | ||
/** | ||
* Options for struct initialization | ||
*/ | ||
export interface StructOptions { | ||
align: number; | ||
bigEndian: boolean; | ||
} | ||
interface Member { | ||
type: PrimitiveType | Static; | ||
offset: number; | ||
length?: number; | ||
} | ||
interface Metadata { | ||
options: Partial<StructOptions>; | ||
members: Map<string, Member>; | ||
size: number; | ||
} | ||
const metadata = Symbol('struct'); | ||
interface Static { | ||
[metadata]?: Metadata; | ||
new (): Instance; | ||
prototype: Instance; | ||
} | ||
function isStatic(arg: unknown): arg is Static { | ||
return typeof arg == 'function' && metadata in arg; | ||
} | ||
interface Instance { | ||
constructor: Static; | ||
} | ||
function isInstance(arg: unknown): arg is Instance { | ||
return metadata in (arg?.constructor || {}); | ||
} | ||
function isStruct(arg: unknown): arg is Instance | Static { | ||
return isInstance(arg) || isStatic(arg); | ||
} | ||
/** | ||
* Gets the size in bytes of a type | ||
*/ | ||
export function sizeof(type: ValidPrimitiveType | ClassLike | object): number { | ||
export function sizeof<T extends primitive.Valid | Struct.StaticLike | Struct.InstanceLike>(type: T): Struct.Size<T> { | ||
// primitive | ||
if (typeof type == 'string') { | ||
if (!isValidPrimitive(type)) { | ||
if (!primitive.isValid(type)) { | ||
throw new TypeError('Invalid primitive type: ' + type); | ||
} | ||
return +normalizePrimitive(type).match(numberRegex)[2] / 8; | ||
return (+primitive.normalize(type).match(primitive.regex)![2] / 8) as Struct.Size<T>; | ||
} | ||
if (!isStruct(type)) { | ||
if (!Struct.isStruct(type)) { | ||
throw new TypeError('Not a struct'); | ||
} | ||
const meta: Metadata = metadata in type ? type[metadata] : type.constructor[metadata]; | ||
return meta.size; | ||
const meta: Struct.Metadata = Struct.isStatic(type) ? type[Struct.metadata] : type.constructor[Struct.metadata]; | ||
return meta.size as Struct.Size<T>; | ||
} | ||
@@ -108,10 +39,10 @@ | ||
*/ | ||
export function struct(options: Partial<StructOptions> = {}) { | ||
export function struct(options: Partial<Struct.Options> = {}) { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
return function (target: ClassLike, _?: ClassDecoratorContext) { | ||
target[init] ||= []; | ||
return function (target: Struct.StaticLike, _?: ClassDecoratorContext) { | ||
target[Struct.init] ||= []; | ||
let size = 0; | ||
const members = new Map(); | ||
for (const { name, type, length } of target[init] as MemberInit[]) { | ||
if (!isValidPrimitive(type) && !isStatic(type)) { | ||
for (const { name, type, length } of target[Struct.init]) { | ||
if (!primitive.isValid(type) && !Struct.isStatic(type)) { | ||
throw new TypeError('Not a valid type: ' + type); | ||
@@ -121,3 +52,3 @@ } | ||
offset: size, | ||
type: isValidPrimitive(type) ? normalizePrimitive(type) : type, | ||
type: primitive.isValid(type) ? primitive.normalize(type) : type, | ||
length, | ||
@@ -129,4 +60,3 @@ }); | ||
target[metadata] = { options, members, size } satisfies Metadata; | ||
delete target[init]; | ||
target[Struct.metadata] = { options, members, size } satisfies Struct.Metadata; | ||
}; | ||
@@ -138,3 +68,3 @@ } | ||
*/ | ||
export function member(type: ValidPrimitiveType | ClassLike, length?: number) { | ||
export function member(type: primitive.Valid | ClassLike, length?: number) { | ||
return function (target: object, context?: ClassMemberDecoratorContext | string | symbol) { | ||
@@ -147,8 +77,18 @@ let name = typeof context == 'object' ? context.name : context; | ||
if ((typeof target != 'object' || typeof target != 'function') && !('constructor' in target)) { | ||
if (!name) { | ||
throw new ReferenceError('Invalid name for struct member'); | ||
} | ||
if (typeof target != 'object') { | ||
throw new TypeError('Invalid member for struct field'); | ||
} | ||
target.constructor[init] ||= []; | ||
target.constructor[init].push({ name, type, length } satisfies MemberInit); | ||
if (!('constructor' in target)) { | ||
throw new TypeError('Invalid member for struct field'); | ||
} | ||
const struct = (target as Struct.InstanceLike).constructor; | ||
struct[Struct.init] ||= []; | ||
struct[Struct.init].push({ name, type, length } satisfies Struct.MemberInit); | ||
}; | ||
@@ -161,6 +101,6 @@ } | ||
export function serialize(instance: unknown): Uint8Array { | ||
if (!isInstance(instance)) { | ||
if (!Struct.isInstance(instance)) { | ||
throw new TypeError('Can not serialize, not a struct instance'); | ||
} | ||
const { options, members } = instance.constructor[metadata]; | ||
const { options, members } = instance.constructor[Struct.metadata]; | ||
@@ -174,3 +114,4 @@ const buffer = new Uint8Array(sizeof(instance)); | ||
let value = length > 0 ? instance[name][i] : instance[name]; | ||
// @ts-expect-error 7053 | ||
let value = length! > 0 ? instance[name][i] : instance[name]; | ||
if (typeof value == 'string') { | ||
@@ -180,3 +121,3 @@ value = value.charCodeAt(0); | ||
if (!isPrimitiveType(type)) { | ||
if (!primitive.isType(type)) { | ||
buffer.set(value ? serialize(value) : new Uint8Array(sizeof(type)), iOff); | ||
@@ -209,6 +150,6 @@ continue; | ||
export function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBufferView) { | ||
if (!isInstance(instance)) { | ||
if (!Struct.isInstance(instance)) { | ||
throw new TypeError('Can not deserialize, not a struct instance'); | ||
} | ||
const { options, members } = instance.constructor[metadata]; | ||
const { options, members } = instance.constructor[Struct.metadata]; | ||
@@ -221,7 +162,10 @@ const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer); | ||
for (let i = 0; i < (length || 1); i++) { | ||
let object = length > 0 ? instance[name] : instance; | ||
const key = length > 0 ? i : name, | ||
// @ts-expect-error 7053 | ||
let object = length! > 0 ? instance[name] : instance; | ||
const key = length! > 0 ? i : name, | ||
iOff = offset + sizeof(type) * i; | ||
// @ts-expect-error 7053 | ||
if (typeof instance[name] == 'string') { | ||
// @ts-expect-error 7053 | ||
instance[name] = instance[name].slice(0, i) + String.fromCharCode(view.getUint8(iOff)) + instance[name].slice(i + 1); | ||
@@ -231,3 +175,3 @@ continue; | ||
if (!isPrimitiveType(type)) { | ||
if (!primitive.isType(type)) { | ||
if (object[key] === null || object[key] === undefined) { | ||
@@ -240,3 +184,3 @@ continue; | ||
if (length > 0) { | ||
if (length! > 0) { | ||
object ||= []; | ||
@@ -262,6 +206,11 @@ } | ||
function _member<T extends ValidPrimitiveType>(type: T) { | ||
function _(length?: number): (target: object, context?: string | symbol | ClassMemberDecoratorContext) => void; | ||
function _(target: object, context?: string | symbol | ClassMemberDecoratorContext): void; | ||
function _(targetOrLength: object | number, context?: string | symbol | ClassMemberDecoratorContext) { | ||
/** | ||
* Also can be a name when legacy decorators are used | ||
*/ | ||
type Context = string | symbol | ClassMemberDecoratorContext; | ||
function _member<T extends primitive.Valid>(type: T) { | ||
function _(length: number): (target: object, context?: Context) => void; | ||
function _(target: object, context?: Context): void; | ||
function _(targetOrLength: object | number, context?: Context) { | ||
if (typeof targetOrLength == 'number') { | ||
@@ -281,2 +230,2 @@ return member(type, targetOrLength); | ||
*/ | ||
export const types = Object.fromEntries(validPrimitiveTypes.map(t => [t, _member(t)])) as { [K in ValidPrimitiveType]: ReturnType<typeof _member<K>> }; | ||
export const types = Object.fromEntries(primitive.valids.map(t => [t, _member(t)])) as { [K in primitive.Valid]: ReturnType<typeof _member<K>> }; |
@@ -88,3 +88,3 @@ /** | ||
*/ | ||
export type Shift<T> = T extends unknown[] ? (((...x: T) => void) extends (h: any, ...t: infer I) => void ? I : []) : unknown; | ||
export type Shift<T extends unknown[]> = T extends [unknown, ...infer Rest] ? Rest : never; | ||
@@ -94,8 +94,8 @@ /** | ||
*/ | ||
export type First<T> = T extends unknown[] ? (((...x: T) => void) extends (h: infer I, ...t: any) => void ? I : []) : never; | ||
export type First<T extends unknown[]> = T extends [infer F, ...unknown[]] ? F : never; | ||
/** | ||
* Inserts A into T at the start of T | ||
* Inserts V into T at the start of T | ||
*/ | ||
export type Unshift<T, A> = T extends unknown[] ? (((h: A, ...t: T) => void) extends (...i: infer I) => void ? I : unknown) : never; | ||
export type Unshift<T extends unknown[], V> = [V, ...T]; | ||
@@ -105,3 +105,3 @@ /** | ||
*/ | ||
export type Pop<T> = T extends unknown[] ? (((...x: T) => void) extends (...i: [...infer I, any]) => void ? I : unknown) : never; | ||
export type Pop<T extends unknown[]> = T extends [...infer _, unknown] ? _ : never; | ||
@@ -111,8 +111,8 @@ /** | ||
*/ | ||
export type Last<T> = T extends unknown[] ? (((...x: T) => void) extends (...i: [...infer H, infer I]) => void ? I : unknown) : never; | ||
export type Last<T extends unknown[]> = T extends [...unknown[], infer Last] ? Last : never; | ||
/** | ||
* Appends A to T | ||
* Appends V to T | ||
*/ | ||
export type Push<T, A> = T extends unknown[] ? (((...a: [...T, A]) => void) extends (...i: infer I) => void ? I : unknown) : never; | ||
export type Push<T extends unknown[], V> = [...T, V]; | ||
@@ -122,3 +122,3 @@ /** | ||
*/ | ||
export type Concat<A, B> = { 0: A; 1: Concat<Unshift<A, 0>, Shift<B>> }[Empty extends B ? 0 : 1]; | ||
export type Concat<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Concat<Unshift<A, 0>, Shift<B>>; | ||
@@ -131,3 +131,3 @@ /** | ||
*/ | ||
export type Remove<A, B> = { 0: A; 1: Remove<Shift<A>, Shift<B>> }[Empty extends B ? 0 : 1]; | ||
export type Remove<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Remove<Shift<A>, Shift<B>>; | ||
@@ -137,5 +137,5 @@ /** | ||
*/ | ||
export type Length<T> = T extends { length: number } ? T['length'] : never; | ||
export type Length<T extends { length: number }> = T['length']; | ||
type _FromLength<N extends number, R = Empty> = { 0: R; 1: _FromLength<N, Unshift<R, 0>> }[Length<R> extends N ? 0 : 1]; | ||
type _FromLength<N extends number, R extends unknown[] = Empty> = Length<R> extends N ? R : _FromLength<N, Unshift<R, 0>>; | ||
@@ -212,1 +212,19 @@ /** | ||
export type ClassLike<Instance = unknown> = abstract new (...args: unknown[]) => Instance; | ||
/** | ||
* Converts a union to an intersection | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
/** | ||
* Gets the last element of a union | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type LastOfUnion<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never; | ||
/** | ||
* Converts a union to a tuple | ||
* @see https://stackoverflow.com/a/55128956/17637456 | ||
*/ | ||
export type UnionToTuple<T, L = LastOfUnion<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<UnionToTuple<Exclude<T, L>>, L>; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
60234
32
1725