utilium 2.7.2 → 2.8.1

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.
@@ -0,0 +1,120 @@
1
+ import type { Subtract } from './type-math.js';
2
+ import type { Expand } from './types.js';
3
+ /**
4
+ * Filter an array by the types *not* assignable to `Predicate`
5
+ *
6
+ * @example ```ts
7
+ * type nonempty = FilterOut<['example', 'with', 'empty', ''], ''>; // ['example', 'with', 'empty']
8
+ * ```
9
+ */
10
+ export type FilterOut<Arr extends readonly any[], Predicate> = Arr extends readonly [infer Head, ...infer Rest] ? Head extends Predicate ? FilterOut<Rest, Predicate> : [Head, ...FilterOut<Rest, Predicate>] : [];
11
+ /**
12
+ * Filter an array by the types assignable to `Predicate`
13
+ *
14
+ * @example ```ts
15
+ * type negatives = Filter<['-1', '2', '-3'], `-${number}`>; // ['-1', '-3']
16
+ * ```
17
+ */
18
+ export type Filter<Arr extends readonly any[], Predicate> = Arr extends readonly [infer Head, ...infer Rest] ? Head extends Predicate ? [Head, ...Filter<Rest, Predicate>] : Filter<Rest, Predicate> : [];
19
+ export type Some<Arr extends readonly any[], Predicate> = Arr extends readonly [infer Head, ...infer Rest] ? Head extends Predicate ? true : Some<Rest, Predicate> : false;
20
+ export type Every<Arr extends readonly any[], Predicate> = Arr extends readonly [infer Head, ...infer Rest] ? Head extends Predicate ? Every<Rest, Predicate> : false : true;
21
+ /**
22
+ * Empty
23
+ */
24
+ export type Empty = [];
25
+ /**
26
+ * Removes the first element of T and shifts
27
+ */
28
+ export type Shift<T extends unknown[]> = T extends [unknown, ...infer Rest] ? Rest : never;
29
+ /**
30
+ * Gets the first element of T
31
+ */
32
+ export type First<T extends unknown[]> = T extends [infer F, ...unknown[]] ? F : never;
33
+ /**
34
+ * Inserts V into T at the start of T
35
+ */
36
+ export type Unshift<T extends unknown[], V> = [V, ...T];
37
+ /**
38
+ * Removes the last element of T
39
+ */
40
+ export type Pop<T extends unknown[]> = T extends [...infer _, unknown] ? _ : never;
41
+ /**
42
+ * Gets the last element of T
43
+ */
44
+ export type Last<T extends unknown[]> = T extends [...unknown[], infer Last] ? Last : never;
45
+ /**
46
+ * Appends V to T
47
+ */
48
+ export type Push<T extends unknown[], V> = [...T, V];
49
+ /**
50
+ * Concatenates A and B
51
+ */
52
+ export type Concat<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Concat<Unshift<A, 0>, Shift<B>>;
53
+ /**
54
+ * Extracts from A what is not B
55
+ *
56
+ * @remarks
57
+ * It does not remove duplicates (so Remove\<[0, 0, 0], [0, 0]\> yields [0]). This is intended and necessary behavior.
58
+ */
59
+ export type Remove<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Remove<Shift<A>, Shift<B>>;
60
+ /**
61
+ * The length of T
62
+ */
63
+ export type Length<T extends unknown[]> = T extends {
64
+ length: infer L extends number;
65
+ } ? L : never;
66
+ type _FromLength<N extends number, R extends unknown[] = Empty> = Length<R> extends N ? R : _FromLength<N, Unshift<R, 0>>;
67
+ /**
68
+ * Creates a tuple of length N
69
+ */
70
+ export type FromLength<N extends number> = _FromLength<N>;
71
+ /**
72
+ * Gets the type of an array's members
73
+ */
74
+ export type Member<T, D = null> = D extends 0 ? T : T extends (infer U)[] ? Member<U, D extends number ? Subtract<D, 1> : null> : T;
75
+ /**
76
+ * Flattens an array
77
+ */
78
+ export type FlattenArray<A extends unknown[], D = null> = A extends (infer U)[] ? Member<Exclude<U, A>, D>[] : A extends unknown[] ? {
79
+ [K in keyof A]: Member<A[K], D>;
80
+ } : A;
81
+ /**
82
+ * Whether T is a tuple
83
+ */
84
+ export type IsTuple<T> = T extends [] ? false : T extends [infer _Head, ...infer _Rest] ? true : false;
85
+ /**
86
+ * Flattens a tuple
87
+ */
88
+ export type FlattenTuple<A extends unknown[]> = A extends [infer U, ...infer Rest] ? U extends unknown[] ? [...U, ...FlattenTuple<Rest>] : [U, ...FlattenTuple<Rest>] : [];
89
+ /**
90
+ * Flattens an array or tuple
91
+ */
92
+ export type Flatten<A extends unknown[]> = IsTuple<A> extends true ? FlattenTuple<A> : FlattenArray<A>;
93
+ type _Tuple<T, N extends number, R extends unknown[] = Empty> = R['length'] extends N ? R : _Tuple<T, N, [T, ...R]>;
94
+ /**
95
+ * Creates a tuple of T with length N
96
+ */
97
+ export type Tuple<T, N extends number> = _Tuple<T, N>;
98
+ /**
99
+ * Makes all members of the tuple T optional
100
+ */
101
+ export type OptionalTuple<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? [Head?, ...OptionalTuple<Tail>] : T;
102
+ /**
103
+ * Converts an array of objects with a common key into a keyed object
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * type ducksArray = [
108
+ * { name: 'Gerald', quacks: 6 },
109
+ * { name: 'Dorthy', quacks: 7 },
110
+ * ];
111
+ *
112
+ * type ducks = FromKeyedArray<ducksArray, 'name'>; // { Gerald: { name: 'Gerald', quacks: 6 }, Dorthy: { name: 'Dorthy', quacks: 7 } }
113
+ * ```
114
+ */
115
+ export type FromKeyed<A extends any[], KeyName extends A extends (infer E)[] ? keyof E : never> = A extends (infer Element)[] ? {
116
+ [K in Element[KeyName] & PropertyKey]: Expand<Element & {
117
+ [_ in KeyName & PropertyKey]: K;
118
+ }>;
119
+ } : never;
120
+ export {};
package/dist/array.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ export * from './array.js';
2
+ export * from './buffer.js';
3
+ export * as cache from './cache.js';
4
+ export * from './checksum.js';
5
+ export * from './color.js';
1
6
  export * from './list.js';
2
7
  export * from './misc.js';
3
8
  export * from './numbers.js';
package/dist/index.js CHANGED
@@ -1,6 +1,11 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  // Copyright (c) 2025 James Prevett
3
3
  // For better tree shaking, import from whichever file is actually needed
4
+ export * from './array.js';
5
+ export * from './buffer.js';
6
+ export * as cache from './cache.js';
7
+ export * from './checksum.js';
8
+ export * from './color.js';
4
9
  export * from './list.js';
5
10
  export * from './misc.js';
6
11
  export * from './numbers.js';
package/dist/objects.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import type { Expand, UnionToTuple } from './types.js';
1
+ import type { FilterOut } from './array.js';
2
+ import type { Split } from './string.js';
3
+ import type { $drain, Expand, UnionToTuple } from './types.js';
2
4
  export declare function filterObject<O extends object, R extends object>(object: O, predicate: (key: keyof O, value: O[keyof O]) => boolean): R;
3
5
  export declare function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly K[]): Pick<T, K>;
4
6
  export declare function pick<T extends object, K extends keyof T>(object: T, ...keys: readonly (readonly K[])[]): Pick<T, K>;
@@ -46,9 +48,77 @@ export interface ConstMap<T extends Partial<Record<keyof any, any>>, K extends k
46
48
  has(key: keyof T | K): boolean;
47
49
  }
48
50
  export declare function map<const T extends Partial<Record<any, any>>>(items: T): Map<keyof T, T[keyof T]>;
49
- export declare function getByString<T, P extends string>(object: T, path: P, separator?: RegExp): GetByString<T, P>;
50
- export type GetByString<Data, Path extends string> = Path extends `__proto__${`${'.' | '[' | ']' | "'" | '"'}${string}` | ''}` ? never : Path extends `${infer Key extends keyof Data & (string | number)}${'.' | '[' | ']' | "'" | '"'}${infer Rest}` ? Key extends '' ? GetByString<Data, Rest> : GetByString<Data[Key], Rest> : Path extends keyof Data & (string | number) ? Data[Path] : undefined;
51
- export declare function setByString<T>(object: Record<string, any>, path: string, value: unknown, separator?: RegExp): T;
51
+ /**
52
+ * Flatten an object structure into a set of "keys".
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * type example = FlattenKeys<{ h: { s: { l: 1; v: 2 } } }>;
57
+ * type result = "h" | "h.s" | "h.s.l" | "h.s.v";
58
+ * ```
59
+ */
60
+ export type FlattenKeys<O> = {
61
+ [K in keyof O & (string | number)]: O[K] extends Record<any, any> ? K | `${K}.${$drain<FlattenKeys<O[K]>>}` : K;
62
+ }[O extends readonly unknown[] ? keyof O & `${number}` : keyof O & (string | number)];
63
+ export type KeySeparator = '.' | '[' | ']';
64
+ type GetByPath<Data, Path extends (string | number)[]> = Path extends [
65
+ infer Key extends keyof Data | '__proto__',
66
+ ...infer Rest extends (string | number)[]
67
+ ] ? Key extends '__proto__' ? never : Rest extends [] ? Data[Key & keyof Data] : GetByPath<Data[Key & keyof Data], Rest> : undefined;
68
+ /**
69
+ * Get a value using a path of property keys.
70
+ *
71
+ * @see {@link getByString}
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * interface Duck {
76
+ * taxonomy: {
77
+ * genus: 'anas';
78
+ * species: 'platyrhynchos';
79
+ * };
80
+ * }
81
+ *
82
+ * type DuckSpecies = GetByString<Duck, 'taxonomy.species'>; // 'platyrhynchos'
83
+ * ```
84
+ */
85
+ export type GetByString<Data, Path extends string | number = FlattenKeys<Data>> = GetByPath<Data, FilterOut<Split<`${Path}`, KeySeparator>, ''>>;
86
+ /**
87
+ * Get a value using a path of property keys.
88
+ *
89
+ * @example
90
+ * Translation keys mapping to locale objects
91
+ * ```ts
92
+ * const locale = {
93
+ * preference: {
94
+ * theme: {
95
+ * label: 'Theme'
96
+ * }
97
+ * }
98
+ * } as const;
99
+ *
100
+ * const text = getByString(locale, 'preference.theme.label'); // 'Theme'
101
+ * ```
102
+ *
103
+ * @example
104
+ * Arrays
105
+ * ```ts
106
+ * const pascal = {
107
+ * triangle: [
108
+ * [1],
109
+ * [1, 1],
110
+ * [1, 2, 1],
111
+ * [1, 3, 3, 1],
112
+ * [1, 4, 6, 4, 1]
113
+ * ]
114
+ * } as const;
115
+ *
116
+ * const row3 = getByString(pascal, 'triangle[3]'); // readonly [1, 3, 3, 1]
117
+ * const r4c3 = getByString(pascal, 'triangle[4][2]'); // 6
118
+ * ```
119
+ */
120
+ export declare function getByString<const T, const P extends string | number = FlattenKeys<T>>(object: T, path: P): GetByString<T, P>;
121
+ export declare function setByString<const V, const T, const P extends string | number = FlattenKeys<T>>(object: T, path: P, value: V): V;
52
122
  export type JSONPrimitive = null | string | number | boolean;
53
123
  export interface JSONObject {
54
124
  [K: string]: JSONValue | undefined;
@@ -149,4 +219,4 @@ export type Never<T> = {
149
219
  * All of the properties in T or none of them
150
220
  */
151
221
  export type AllOrNone<T> = T | Never<T>;
152
- export type Filter<Key, Arr extends readonly any[]> = Arr extends readonly [infer L, ...infer R] ? L extends Key ? Filter<Key, R> : [L, ...Filter<Key, R>] : [];
222
+ export {};
package/dist/objects.js CHANGED
@@ -88,17 +88,58 @@ export function* getAllPrototypes(object) {
88
88
  export function map(items) {
89
89
  return new Map(Object.entries(items));
90
90
  }
91
- export function getByString(object, path, separator = /[.[\]'"]/) {
91
+ const keySeparator = /[.[\]]/;
92
+ /**
93
+ * Get a value using a path of property keys.
94
+ *
95
+ * @example
96
+ * Translation keys mapping to locale objects
97
+ * ```ts
98
+ * const locale = {
99
+ * preference: {
100
+ * theme: {
101
+ * label: 'Theme'
102
+ * }
103
+ * }
104
+ * } as const;
105
+ *
106
+ * const text = getByString(locale, 'preference.theme.label'); // 'Theme'
107
+ * ```
108
+ *
109
+ * @example
110
+ * Arrays
111
+ * ```ts
112
+ * const pascal = {
113
+ * triangle: [
114
+ * [1],
115
+ * [1, 1],
116
+ * [1, 2, 1],
117
+ * [1, 3, 3, 1],
118
+ * [1, 4, 6, 4, 1]
119
+ * ]
120
+ * } as const;
121
+ *
122
+ * const row3 = getByString(pascal, 'triangle[3]'); // readonly [1, 3, 3, 1]
123
+ * const r4c3 = getByString(pascal, 'triangle[4][2]'); // 6
124
+ * ```
125
+ */
126
+ export function getByString(object, path) {
92
127
  return path
93
- .split(separator)
128
+ .toString()
129
+ .split(keySeparator)
94
130
  .filter(p => p)
95
131
  .reduce((o, p) => (p == '__proto__' ? _throw(new Error('getByString called with __proto__ in path')) : o?.[p]), object);
96
132
  }
97
- export function setByString(object, path, value, separator = /[.[\]'"]/) {
98
- return path
99
- .split(separator)
100
- .filter(p => p && p != '__proto__')
101
- .reduce((o, p, i) => (o[p] = path.split(separator).filter(p => p).length === ++i ? value : o[p] || {}), object);
133
+ export function setByString(object, path, value) {
134
+ const parts = path
135
+ .toString()
136
+ .split(keySeparator)
137
+ .filter(p => p);
138
+ return parts.reduce((o, p, i) => {
139
+ if (p == '__proto__')
140
+ throw new Error('setByString called with __proto__ in path');
141
+ return (o[p] = parts.length === i + 1 ? value : o[p] || {});
142
+ }, object);
102
143
  }
103
144
  /**
104
145
  * Binds a this value for all of the functions in an object (not recursive)
package/dist/string.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Some } from './array.js';
1
2
  import type { $Max, w_subtract } from './type-math.js';
2
3
  export declare function capitalize<T extends string>(value: T): Capitalize<T>;
3
4
  export declare function uncapitalize<T extends string>(value: T): Uncapitalize<T>;
@@ -23,11 +24,19 @@ export declare function decodeUUID(uuid: Uint8Array): UUID;
23
24
  export declare function encodeUUID(uuid: UUID): Uint8Array<ArrayBuffer>;
24
25
  export declare function stringifyUUID(uuid: bigint): UUID;
25
26
  export declare function parseUUID(uuid: UUID): bigint;
27
+ /**
28
+ * Used to support union delimiters, e.g. `'.' | ':'`
29
+ */
30
+ type _SplitVariant<T extends string, CurrentDelim extends Delimiter, Delimiter extends string = ''> = T extends `${infer Left}${CurrentDelim}${infer Right}` ? [Left, ...Split<Right, Delimiter>] : [T];
26
31
  /**
27
32
  * Split a string.
28
33
  */
29
- export type Split<T extends string, Delimiter extends string = ''> = string extends T ? string[] : T extends '' ? [] : T extends `${infer Left}${Delimiter}${infer Right}` ? [Left, ...Split<Right, Delimiter>] : [T];
34
+ export type Split<T extends string, Delimiter extends string = ''> = string extends T ? string[] : T extends '' ? [''] : {
35
+ [D in Delimiter]: Some<_SplitVariant<T, D, Delimiter>, `${string}${Delimiter}${string}`> extends true ? never : _SplitVariant<T, D, Delimiter>;
36
+ }[Delimiter];
30
37
  export type StringLength<T extends string> = Split<T>['length'];
31
38
  export type Repeat<T extends string, N extends number, Init extends string = ''> = N extends 0 ? Init : Repeat<T, w_subtract<N, StringLength<T>>, `${Init}${T}`>;
32
39
  export type PadRight<Init extends string, R extends string, N extends number> = Repeat<R, $Max<0, w_subtract<N, StringLength<Init>>>, Init>;
33
40
  export type PadLeft<Init extends string, R extends string, N extends number> = `${Repeat<R, $Max<0, w_subtract<N, StringLength<Init>>>>}${Init}`;
41
+ export type NonEmptyString = `${any}${string}`;
42
+ export {};
@@ -11,8 +11,9 @@
11
11
  * `_*` => general purpose internals
12
12
  *
13
13
  */
14
+ import type { Length } from './array.js';
14
15
  import type { Repeat, StringLength } from './string.js';
15
- import type { $drain, Length } from './types.js';
16
+ import type { $drain } from './types.js';
16
17
  /**
17
18
  * Maps a numeric literal type to a tuple type with that length
18
19
  */
@@ -5,7 +5,7 @@ const add_positive = 3;
5
5
  const add_zero = 0;
6
6
  const add_diff_signs = -1;
7
7
  const add_negative = -3;
8
- const add_float = 1.7;
8
+ const add_float = 1.6;
9
9
  // @ts-expect-error 2 + 2 != 5
10
10
  let fail = 5;
11
11
  fail = 4;
@@ -14,7 +14,7 @@ const subtract_normal = -18;
14
14
  const subtract_from_neg = -9;
15
15
  const subtract_both_neg = 5;
16
16
  const subtract_zero = -1;
17
- const subtract_floats = 3.3;
17
+ const subtract_floats = 3.1;
18
18
  // were doing multiplication in the type system now?!
19
19
  // yup.
20
20
  const multiply_normal = 6;
@@ -34,5 +34,6 @@ const fraction_normal = 0.1415;
34
34
  const fraction_negative = 0.1415;
35
35
  // With type variable
36
36
  const pi = 3.141;
37
+ // @ts-expect-error 2589 — Recently this started to become too deep even though it worked in the past
37
38
  const octo_pi = 24.1128;
38
39
  export {};
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Length, Unshift, Push, FromLength } from './array.js';
1
2
  import type { Subtract } from './type-math.js';
2
3
  /**
3
4
  * Expands the type T (for intellisense and debugging)
@@ -23,97 +24,16 @@ type StrictUnionHelper<T, TAll> = T extends unknown ? T & Partial<Record<Exclude
23
24
  * @see https://stackoverflow.com/a/65805753/17637456
24
25
  */
25
26
  export type StrictUnion<T> = Expand<StrictUnionHelper<T, T>>;
26
- /**
27
- * Empty
28
- */
29
- export type Empty = [];
30
- /**
31
- * Removes the first element of T and shifts
32
- */
33
- export type Shift<T extends unknown[]> = T extends [unknown, ...infer Rest] ? Rest : never;
34
- /**
35
- * Gets the first element of T
36
- */
37
- export type First<T extends unknown[]> = T extends [infer F, ...unknown[]] ? F : never;
38
- /**
39
- * Inserts V into T at the start of T
40
- */
41
- export type Unshift<T extends unknown[], V> = [V, ...T];
42
- /**
43
- * Removes the last element of T
44
- */
45
- export type Pop<T extends unknown[]> = T extends [...infer _, unknown] ? _ : never;
46
- /**
47
- * Gets the last element of T
48
- */
49
- export type Last<T extends unknown[]> = T extends [...unknown[], infer Last] ? Last : never;
50
- /**
51
- * Appends V to T
52
- */
53
- export type Push<T extends unknown[], V> = [...T, V];
54
- /**
55
- * Concats A and B
56
- */
57
- export type Concat<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Concat<Unshift<A, 0>, Shift<B>>;
58
- /**
59
- * Extracts from A what is not B
60
- *
61
- * @remarks
62
- * It does not remove duplicates (so Remove\<[0, 0, 0], [0, 0]\> yields [0]). This is intended and necessary behavior.
63
- */
64
- export type Remove<A extends unknown[], B extends unknown[]> = Empty extends B ? A : Remove<Shift<A>, Shift<B>>;
65
- /**
66
- * The length of T
67
- */
68
- export type Length<T extends unknown[]> = T extends {
69
- length: infer L extends number;
70
- } ? L : never;
71
- type _FromLength<N extends number, R extends unknown[] = Empty> = Length<R> extends N ? R : _FromLength<N, Unshift<R, 0>>;
72
- /**
73
- * Creates a tuple of length N
74
- */
75
- export type FromLength<N extends number> = _FromLength<N>;
76
27
  /**
77
28
  * Increments N
78
29
  * @deprecated Use Add<N, 1> instead
79
30
  */
80
- export type Increment<N extends number> = Length<Unshift<_FromLength<N>, 0>>;
31
+ export type Increment<N extends number> = Length<Unshift<FromLength<N>, 0>>;
81
32
  /**
82
33
  * Decrements N
83
34
  * @deprecated Use Subtract<N, 1> instead
84
35
  */
85
36
  export type Decrement<N extends number> = Subtract<N, 1>;
86
- /**
87
- * Gets the type of an array's members
88
- */
89
- export type Member<T, D = null> = D extends 0 ? T : T extends (infer U)[] ? Member<U, D extends number ? Subtract<D, 1> : null> : T;
90
- /**
91
- * Flattens an array
92
- */
93
- export type FlattenArray<A extends unknown[], D = null> = A extends (infer U)[] ? Member<Exclude<U, A>, D>[] : A extends unknown[] ? {
94
- [K in keyof A]: Member<A[K], D>;
95
- } : A;
96
- /**
97
- * Whether T is a tuple
98
- */
99
- export type IsTuple<T> = T extends [] ? false : T extends [infer _Head, ...infer _Rest] ? true : false;
100
- /**
101
- * Flattens a tuple
102
- */
103
- export type FlattenTuple<A extends unknown[]> = A extends [infer U, ...infer Rest] ? U extends unknown[] ? [...U, ...FlattenTuple<Rest>] : [U, ...FlattenTuple<Rest>] : [];
104
- /**
105
- * Flattens an array or tuple
106
- */
107
- export type Flatten<A extends unknown[]> = IsTuple<A> extends true ? FlattenTuple<A> : FlattenArray<A>;
108
- type _Tuple<T, N extends number, R extends unknown[] = Empty> = R['length'] extends N ? R : _Tuple<T, N, [T, ...R]>;
109
- /**
110
- * Creates a tuple of T with length N
111
- */
112
- export type Tuple<T, N extends number> = _Tuple<T, N>;
113
- /**
114
- * Makes all members of the tuple T optional
115
- */
116
- export type OptionalTuple<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? [Head?, ...OptionalTuple<Tail>] : T;
117
37
  /**
118
38
  * Keys of a Map
119
39
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "2.7.2",
3
+ "version": "2.8.1",
4
4
  "description": "Typescript utilities",
5
5
  "funding": {
6
6
  "type": "individual",