utilium 2.0.0-pre.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,135 +0,0 @@
1
- import type { ArrayBufferViewConstructor } from '../buffer.js';
2
- import { capitalize } from '../string.js';
3
- import type { UnionToTuple } from '../types.js';
4
-
5
- /** A definition for a primitive type */
6
- export interface Type<T = any> {
7
- readonly name: string;
8
- readonly size: number;
9
- readonly array: ArrayBufferViewConstructor;
10
- get(this: void, view: DataView, offset: number, littleEndian: boolean): T;
11
- set(this: void, view: DataView, offset: number, littleEndian: boolean, value: T): void;
12
- }
13
-
14
- export function isType<T = any>(type: unknown): type is Type<T> {
15
- return (
16
- typeof type == 'object'
17
- && type != null
18
- && 'size' in type
19
- && 'get' in type
20
- && 'set' in type
21
- && typeof type.size == 'number'
22
- && typeof type.get == 'function'
23
- && typeof type.set == 'function'
24
- );
25
- }
26
-
27
- export const types = {
28
- int8: {
29
- name: 'int8',
30
- size: 1,
31
- array: Int8Array,
32
- get: (view, offset) => view.getInt8(offset),
33
- set: (view, offset, _le, value) => view.setInt8(offset, value),
34
- },
35
-
36
- uint8: {
37
- name: 'uint8',
38
- size: 1,
39
- array: Uint8Array,
40
- get: (view, offset) => view.getUint8(offset),
41
- set: (view, offset, _le, value) => view.setUint8(offset, value),
42
- },
43
-
44
- int16: {
45
- name: 'int16',
46
- size: 2,
47
- array: Int16Array,
48
- get: (view, offset, le) => view.getInt16(offset, le),
49
- set: (view, offset, le, value) => view.setInt16(offset, value, le),
50
- },
51
-
52
- uint16: {
53
- name: 'uint16',
54
- size: 2,
55
- array: Uint16Array,
56
- get: (view, offset, le) => view.getUint16(offset, le),
57
- set: (view, offset, le, value) => view.setUint16(offset, value, le),
58
- },
59
-
60
- int32: {
61
- name: 'int32',
62
- size: 4,
63
- array: Int32Array,
64
- get: (view, offset, le) => view.getInt32(offset, le),
65
- set: (view, offset, le, value) => view.setInt32(offset, value, le),
66
- },
67
-
68
- uint32: {
69
- name: 'uint32',
70
- size: 4,
71
- array: Uint32Array,
72
- get: (view, offset, le) => view.getUint32(offset, le),
73
- set: (view, offset, le, value) => view.setUint32(offset, value, le),
74
- },
75
-
76
- int64: {
77
- name: 'int64',
78
- size: 8,
79
- array: BigInt64Array,
80
- get: (view, offset, le) => view.getBigInt64(offset, le),
81
- set: (view, offset, le, value) => view.setBigInt64(offset, value, le),
82
- },
83
-
84
- uint64: {
85
- name: 'uint64',
86
- size: 8,
87
- array: BigUint64Array,
88
- get: (view, offset, le) => view.getBigUint64(offset, le),
89
- set: (view, offset, le, value) => view.setBigUint64(offset, value, le),
90
- },
91
-
92
- float32: {
93
- name: 'float32',
94
- size: 4,
95
- array: Float32Array,
96
- get: (view, offset, le) => view.getFloat32(offset, le),
97
- set: (view, offset, le, value) => view.setFloat32(offset, value, le),
98
- },
99
-
100
- float64: {
101
- name: 'float64',
102
- size: 8,
103
- array: Float64Array,
104
- get: (view, offset, le) => view.getFloat64(offset, le),
105
- set: (view, offset, le, value) => view.setFloat64(offset, value, le),
106
- },
107
- } as const satisfies Record<string, Type>;
108
-
109
- export type TypeName = keyof typeof types;
110
-
111
- export const typeNames = Object.keys(types) as UnionToTuple<TypeName>;
112
-
113
- export function isTypeName(type: { toString(): string }): type is TypeName {
114
- return typeNames.includes(type.toString() as TypeName);
115
- }
116
-
117
- export type Valid = TypeName | Capitalize<TypeName> | 'char';
118
-
119
- export const validNames = [...typeNames, ...typeNames.map(t => capitalize(t)), 'char'] satisfies Valid[];
120
-
121
- export function isValid(type: { toString(): string }): type is Valid {
122
- return validNames.includes(type.toString() as Valid);
123
- }
124
-
125
- export function checkValid(type: { toString(): string }): asserts type is Valid {
126
- if (!isValid(type)) throw new TypeError('Not a valid primitive type: ' + type);
127
- }
128
-
129
- export type Normalize<T extends Valid> = (T extends 'char' ? 'uint8' : Uncapitalize<T>) & TypeName;
130
-
131
- export function normalize<T extends Valid>(type: T): Normalize<T> {
132
- return (type == 'char' ? 'uint8' : type.toLowerCase()) as Normalize<T>;
133
- }
134
-
135
- export type Size<T extends Valid | Type> = (T extends Valid ? (typeof types)[Normalize<T>] : T)['size'];
@@ -1,154 +0,0 @@
1
- import type { ClassLike } from '../types.js';
2
- import type * as primitive from './primitives.js';
3
-
4
- /**
5
- * Polyfill Symbol.metadata
6
- * @see https://github.com/microsoft/TypeScript/issues/53461
7
- */
8
- (Symbol as { metadata: symbol }).metadata ??= Symbol.for('Symbol.metadata');
9
-
10
- export type TypeLike = primitive.Type | Like | primitive.Valid | undefined | null;
11
-
12
- export type Type = Static | primitive.Type;
13
-
14
- /**
15
- * Options for struct initialization
16
- */
17
- export interface Options {
18
- packed: boolean;
19
- align: number;
20
- isUnion: boolean;
21
- }
22
-
23
- export interface Member {
24
- name: string;
25
- type: Type;
26
- offset: number;
27
-
28
- /** The size of the member, 0 for dynamically sized arrays */
29
- size: number;
30
- length?: number;
31
- countedBy?: string;
32
-
33
- /** A C-style type/name declaration string, used for diagnostics */
34
- decl: string;
35
-
36
- /** Whether the member is little endian */
37
- littleEndian: boolean;
38
- }
39
-
40
- export interface Metadata {
41
- options: Partial<Options>;
42
- members: Map<string, Member>;
43
- staticSize: number;
44
-
45
- /** Whether the struct is dynamically sized */
46
- isDynamic: boolean;
47
-
48
- /** Whether the struct is a union */
49
- isUnion: boolean;
50
- }
51
-
52
- export interface Init {
53
- members: Member[];
54
- size: number;
55
- isDynamic: boolean;
56
- isUnion: boolean;
57
- }
58
-
59
- type _DecoratorMetadata<T extends Metadata = Metadata> = DecoratorMetadata & {
60
- struct?: T;
61
- structInit?: Init;
62
- };
63
-
64
- export interface DecoratorContext<T extends Metadata = Metadata> {
65
- metadata: _DecoratorMetadata<T>;
66
- }
67
-
68
- /**
69
- * Initializes the struct metadata for a class
70
- * This also handles copying metadata from parent classes
71
- */
72
- export function initMetadata(context: DecoratorContext): Init {
73
- context.metadata ??= {};
74
-
75
- const existing: Partial<Init> = context.metadata.structInit ?? {};
76
-
77
- context.metadata.structInit = {
78
- members: [...(existing.members ?? [])],
79
- size: existing.size ?? 0,
80
- isDynamic: existing.isDynamic ?? false,
81
- isUnion: existing.isUnion ?? false,
82
- };
83
-
84
- return context.metadata.structInit;
85
- }
86
-
87
- export interface Static<T extends Metadata = Metadata> {
88
- [Symbol.metadata]: Required<_DecoratorMetadata<T>>;
89
- readonly prototype: Instance<T>;
90
- new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
91
- buffer: TArrayBuffer,
92
- byteOffset?: number,
93
- length?: number
94
- ): Instance<T> & ArrayBufferView<TArrayBuffer>;
95
- new (array?: ArrayLike<number> | ArrayBuffer): Instance<T>;
96
- }
97
-
98
- export interface StaticLike<T extends Metadata = Metadata> extends ClassLike {
99
- [Symbol.metadata]?: _DecoratorMetadata<T> | null;
100
- }
101
-
102
- export function isValidMetadata<T extends Metadata = Metadata>(
103
- arg: unknown
104
- ): arg is DecoratorMetadata & {
105
- struct: T;
106
- } {
107
- return arg != null && typeof arg == 'object' && 'struct' in arg;
108
- }
109
-
110
- export function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T> {
111
- return typeof arg == 'function' && Symbol.metadata in arg && isValidMetadata(arg[Symbol.metadata]);
112
- }
113
-
114
- export interface Instance<T extends Metadata = Metadata> extends ArrayBufferView, Record<PropertyKey, any> {
115
- constructor: Static<T>;
116
- }
117
-
118
- export interface InstanceLike<T extends Metadata = Metadata> {
119
- constructor: StaticLike<T>;
120
- }
121
-
122
- export function isInstance<T extends Metadata = Metadata>(arg: unknown): arg is Instance<T> {
123
- return arg != null && typeof arg == 'object' && isStatic(arg.constructor);
124
- }
125
-
126
- export function checkInstance<T extends Metadata = Metadata>(
127
- arg: unknown
128
- ): asserts arg is Instance<T> & Record<keyof any, any> {
129
- if (isInstance(arg)) return;
130
- throw new TypeError(
131
- (typeof arg == 'function' ? arg.name : typeof arg == 'object' && arg ? arg.constructor.name : arg)
132
- + ' is not a struct instance'
133
- );
134
- }
135
-
136
- export function isStruct<T extends Metadata = Metadata>(arg: unknown): arg is Instance<T> | Static<T> {
137
- return isInstance(arg) || isStatic(arg);
138
- }
139
-
140
- export function checkStruct<T extends Metadata = Metadata>(arg: unknown): asserts arg is Instance<T> | Static<T> {
141
- if (isStruct(arg)) return;
142
- throw new TypeError(
143
- (typeof arg == 'function' ? arg.name : typeof arg == 'object' && arg ? arg.constructor.name : arg)
144
- + ' is not a struct'
145
- );
146
- }
147
-
148
- export type Like<T extends Metadata = Metadata> = InstanceLike<T> | StaticLike<T>;
149
-
150
- export type Size<T extends TypeLike> = T extends undefined | null
151
- ? 0
152
- : T extends primitive.Valid
153
- ? primitive.Size<T>
154
- : number;
package/src/list.ts DELETED
@@ -1,150 +0,0 @@
1
- import { EventEmitter } from 'eventemitter3';
2
-
3
- export class List<T>
4
- extends EventEmitter<{
5
- update: [];
6
- add: [T];
7
- }>
8
- implements RelativeIndexable<T>
9
- {
10
- public readonly [Symbol.toStringTag] = 'List';
11
-
12
- public constructor(values?: readonly T[] | Iterable<T> | null) {
13
- super();
14
- if (values) {
15
- this.push(...values);
16
- }
17
- }
18
-
19
- protected data = new Set<T>();
20
-
21
- public toSet(): Set<T> {
22
- return new Set(this.data);
23
- }
24
-
25
- public toArray(): T[] {
26
- return Array.from(this.data);
27
- }
28
-
29
- public toJSON() {
30
- return JSON.stringify(Array.from(this.data));
31
- }
32
-
33
- public toString() {
34
- return this.join(',');
35
- }
36
-
37
- protected _set(index: number, value: T, _delete: boolean = false) {
38
- if (Math.abs(index) > this.data.size) {
39
- throw new ReferenceError('Can not set an element outside the bounds of the list');
40
- }
41
-
42
- const data = Array.from(this.data);
43
- data.splice(index, +_delete, value);
44
- this.data = new Set<T>(data);
45
- this.emit('update');
46
- }
47
-
48
- public set(index: number, value: T): void {
49
- this._set(index, value, true);
50
- }
51
-
52
- public deleteAt(index: number): void {
53
- if (Math.abs(index) > this.data.size) {
54
- throw new ReferenceError('Can not delete an element outside the bounds of the list');
55
- }
56
-
57
- this.delete(Array.from(this.data).at(index)!);
58
- }
59
-
60
- public insert(value: T, index: number = this.data.size) {
61
- this._set(index, value, false);
62
- }
63
-
64
- // Array methods
65
-
66
- public at(index: number): T {
67
- if (Math.abs(index) > this.data.size) {
68
- throw new ReferenceError('Can not access an element outside the bounds of the list');
69
- }
70
-
71
- return Array.from(this.data).at(index)!;
72
- }
73
-
74
- public pop(): T | undefined {
75
- const item = Array.from(this.data).pop();
76
- if (item !== undefined) {
77
- this.delete(item);
78
- }
79
- return item;
80
- }
81
-
82
- public push(...items: T[]): number {
83
- for (const item of items) {
84
- this.add(item);
85
- }
86
- return this.data.size;
87
- }
88
-
89
- public join(separator?: string): string {
90
- return Array.from(this.data).join(separator);
91
- }
92
-
93
- public splice(start: number, deleteCount: number, ...items: T[]): T[] {
94
- if (Math.abs(start) > this.data.size) {
95
- throw new ReferenceError('Can not splice elements outside the bounds of the list');
96
- }
97
-
98
- const data = Array.from(this.data);
99
- const deleted = data.splice(start, deleteCount, ...items);
100
- this.data = new Set<T>(data);
101
- this.emit('update');
102
- return deleted;
103
- }
104
-
105
- // Set methods
106
-
107
- public add(value: T): this {
108
- this.data.add(value);
109
- this.emit('update');
110
- this.emit('add', value);
111
- return this;
112
- }
113
-
114
- public clear(): void {
115
- this.data.clear();
116
- this.emit('update');
117
- }
118
-
119
- public delete(value: T): boolean {
120
- const success = this.data.delete(value);
121
- this.emit('update');
122
- return success;
123
- }
124
-
125
- public has(value: T): boolean {
126
- return this.data.has(value);
127
- }
128
-
129
- public get size(): number {
130
- return this.data.size;
131
- }
132
-
133
- // Iteration
134
-
135
- public entries(): IterableIterator<[number, T]> {
136
- return this.toArray().entries();
137
- }
138
-
139
- public keys(): IterableIterator<number> {
140
- return this.toArray().keys();
141
- }
142
-
143
- public values(): IterableIterator<T> {
144
- return this.data.values();
145
- }
146
-
147
- public [Symbol.iterator](): IterableIterator<T> {
148
- return this.data[Symbol.iterator]();
149
- }
150
- }
package/src/misc.ts DELETED
@@ -1,80 +0,0 @@
1
- export function wait(time: number) {
2
- return new Promise(resolve => setTimeout(resolve, time));
3
- }
4
-
5
- export const greekLetterNames = [
6
- 'Alpha',
7
- 'Beta',
8
- 'Gamma',
9
- 'Delta',
10
- 'Epsilon',
11
- 'Zeta',
12
- 'Eta',
13
- 'Theta',
14
- 'Iota',
15
- 'Kappa',
16
- 'Lambda',
17
- 'Mu',
18
- 'Nu',
19
- 'Xi',
20
- 'Omicron',
21
- 'Pi',
22
- 'Rho',
23
- 'Sigma',
24
- 'Tau',
25
- 'Upsilon',
26
- 'Phi',
27
- 'Chi',
28
- 'Psi',
29
- 'Omega',
30
- ];
31
-
32
- const hexRegex = /^[0-9a-f-.]+$/;
33
-
34
- export function isHex(str: string) {
35
- return hexRegex.test(str);
36
- }
37
-
38
- /** Prevent infinite loops */
39
- export function canary(error: Error = new Error()) {
40
- const timeout = setTimeout(() => {
41
- throw error;
42
- }, 5000);
43
-
44
- return () => clearTimeout(timeout);
45
- }
46
-
47
- /**
48
- * A wrapper for throwing things in an expression context.
49
- * You will likely want to remove this if you can just use `throw` in expressions.
50
- * @see https://github.com/tc39/proposal-throw-expressions
51
- */
52
- export function _throw(e: unknown): never {
53
- throw e;
54
- }
55
-
56
- interface MemoizeMetadata extends DecoratorMetadata {
57
- memoized?: Record<PropertyKey, any>;
58
- }
59
-
60
- /**
61
- * Decorator for memoizing the result of a getter.
62
- */
63
- export function memoize<T, This>(
64
- get: () => T,
65
- context: ClassGetterDecoratorContext<This, T> & { metadata?: MemoizeMetadata }
66
- ) {
67
- if (context.kind != 'getter') throw new Error('@memoize can only be used on getters');
68
-
69
- return function (this: This): T {
70
- context.metadata ??= {};
71
- const { memoized = {} } = context.metadata;
72
-
73
- if (context.name in memoized) {
74
- console.log('Using cached value for', context.name, JSON.stringify(memoized[context.name]));
75
- return memoized[context.name];
76
- }
77
- memoized[context.name] = get.call(this);
78
- return memoized[context.name];
79
- };
80
- }
package/src/numbers.ts DELETED
@@ -1,19 +0,0 @@
1
- export function range(min: number, max: number): number[] {
2
- const a = [];
3
- for (let i = min; i < max; i++) {
4
- a.push(i);
5
- }
6
- return a;
7
- }
8
-
9
- export function toDegrees(radians: number): number {
10
- return (radians * 180) / Math.PI;
11
- }
12
-
13
- export function toRadians(degrees: number): number {
14
- return (degrees / 180) * Math.PI;
15
- }
16
-
17
- const __formatter = Intl.NumberFormat('en', { notation: 'compact' });
18
-
19
- export const formatCompact = __formatter.format.bind(__formatter);
package/src/objects.ts DELETED
@@ -1,145 +0,0 @@
1
- import type { UnionToTuple } from './types.js';
2
-
3
- export function filterObject<O extends object, R extends object>(
4
- object: O,
5
- predicate: (key: keyof O, value: O[keyof O]) => boolean
6
- ): R {
7
- const entries = Object.entries(object) as [keyof O, O[keyof O]][];
8
- return Object.fromEntries(entries.filter(([key, value]) => predicate(key, value))) as R;
9
- }
10
-
11
- export function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly K[]): Pick<T, K>;
12
- export function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly (readonly K[])[]): Pick<T, K>;
13
- export function pick<T extends object, K extends keyof T>(
14
- object: T,
15
- ...keys: readonly K[] | readonly (readonly K[])[]
16
- ): Pick<T, K> {
17
- const picked = {} as Pick<T, K>;
18
- for (const key of keys.flat() as K[]) {
19
- picked[key] = object[key];
20
- }
21
- return picked;
22
- }
23
-
24
- export function omit<T extends object, K extends keyof T>(object: T, ...keys: readonly K[]): Omit<T, K>;
25
- export function omit<T extends object, K extends keyof T>(object: T, ...keys: readonly (readonly K[])[]): Omit<T, K>;
26
- export function omit<T extends object, K extends keyof T>(
27
- object: T,
28
- ...keys: readonly K[] | readonly (readonly K[])[]
29
- ): Omit<T, K> {
30
- return filterObject<T, Omit<T, K>>(object, key => !keys.flat().includes(key as K));
31
- }
32
-
33
- export function assignWithDefaults<To extends Record<keyof any, any>, From extends Partial<To>>(
34
- to: To,
35
- from: From,
36
- defaults: Partial<To> = to
37
- ): void {
38
- const keys = new Set<keyof To | keyof From>([...Object.keys(to), ...Object.keys(from)]);
39
- for (const key of keys) {
40
- try {
41
- to[key] = from[key] ?? defaults[key] ?? to[key];
42
- } catch {
43
- // Do nothing
44
- }
45
- }
46
- }
47
-
48
- /**
49
- * Entries of T
50
- */
51
- export type EntriesTuple<T extends object> = UnionToTuple<{ [K in keyof T]: [K, T[K]] }[keyof T]>
52
- & [unknown, unknown][];
53
-
54
- /**
55
- * Entries of T
56
- */
57
- export type Entries<T extends object> = ({ [K in keyof T]: [K, T[K]] }[keyof T] & unknown[])[];
58
-
59
- export function isJSON(str: string) {
60
- try {
61
- JSON.parse(str);
62
- return true;
63
- } catch {
64
- return false;
65
- }
66
- }
67
-
68
- export function resolveConstructors(object: object): string[] {
69
- const constructors = [];
70
- for (
71
- let prototype = object;
72
- prototype && !['Function', 'Object'].includes(prototype.constructor.name);
73
- prototype = Object.getPrototypeOf(prototype)
74
- ) {
75
- constructors.push(prototype.constructor.name);
76
- }
77
- return constructors;
78
- }
79
-
80
- export function* getAllPrototypes(object: object): IterableIterator<object> {
81
- for (let prototype = object; prototype; prototype = Object.getPrototypeOf(prototype)) {
82
- yield prototype;
83
- }
84
- }
85
-
86
- /**
87
- * Allows you to convert an object with specific member types into a Map that will give you the correct type for the correct member
88
- */
89
- export interface ConstMap<T extends Partial<Record<keyof any, any>>, K extends keyof any = keyof T, V = T[keyof T]>
90
- extends Map<K, V> {
91
- get<TK extends keyof T>(key: TK): T[TK];
92
- get(key: K): V;
93
- set<TK extends keyof T>(key: TK, value: T[TK]): this;
94
- set(key: K, value: V): this;
95
- has(key: keyof T | K): boolean;
96
- }
97
-
98
- export function map<const T extends Partial<Record<any, any>>>(items: T): Map<keyof T, T[keyof T]> {
99
- return new Map(Object.entries(items) as [keyof T, T[keyof T]][]);
100
- }
101
-
102
- export function getByString(object: Record<string, any>, path: string, separator = /[.[\]'"]/) {
103
- return path
104
- .split(separator)
105
- .filter(p => p)
106
- .reduce((o, p) => o?.[p], object);
107
- }
108
-
109
- export function setByString(object: Record<string, any>, path: string, value: unknown, separator = /[.[\]'"]/) {
110
- return path
111
- .split(separator)
112
- .filter(p => p)
113
- .reduce((o, p, i) => (o[p] = path.split(separator).filter(p => p).length === ++i ? value : o[p] || {}), object);
114
- }
115
-
116
- export type JSONPrimitive = null | string | number | boolean;
117
-
118
- export type JSONObject = { [K in string]: JSONValue };
119
-
120
- export type JSONValue = JSONPrimitive | JSONObject | JSONValue[];
121
-
122
- /**
123
- * An object `T` with all of its functions bound to a `This` value
124
- */
125
- export type Bound<T extends object, This = any> = T & {
126
- [k in keyof T]: T[k] extends (...args: any[]) => any
127
- ? (this: This, ...args: Parameters<T[k]>) => ReturnType<T[k]>
128
- : T[k];
129
- };
130
-
131
- /**
132
- * Binds a this value for all of the functions in an object (not recursive)
133
- */
134
- export function bindFunctions<T extends object, This = any>(fns: T, thisValue: This): Bound<T, This> {
135
- return Object.fromEntries(
136
- Object.entries(fns).map(([k, v]) => [k, typeof v == 'function' ? v.bind(thisValue) : v])
137
- ) as Bound<T, This>;
138
- }
139
-
140
- /**
141
- * Makes all properties in T mutable
142
- */
143
- export type Mutable<T> = {
144
- -readonly [P in keyof T]: T[P];
145
- };