Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

utilium

Package Overview
Dependencies
Maintainers
1
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

utilium - npm Package Compare versions

Comparing version 0.3.4 to 0.4.0

dist/internal/primitives.d.ts

19

dist/objects.d.ts
/// <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>;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc