@elyukai/utils 0.2.1 → 0.2.4

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [0.2.4](https://github.com/elyukai/ts-utils/compare/v0.2.3...v0.2.4) (2026-02-20)
6
+
7
+ ## [0.2.3](https://github.com/elyukai/ts-utils/compare/v0.2.2...v0.2.3) (2026-02-20)
8
+
9
+
10
+ ### Features
11
+
12
+ * add basic reader monad ([1b25fb2](https://github.com/elyukai/ts-utils/commit/1b25fb2d948cb02d0d122eeefdc512fd4b781b4a))
13
+ * add identity function ([1f5836c](https://github.com/elyukai/ts-utils/commit/1f5836cf015a554ba0cf1140467fe3bc1e44df05))
14
+ * add more reader methods ([00408ed](https://github.com/elyukai/ts-utils/commit/00408edcbfa6b18fb20eede78c5f19efbe07fcd1))
15
+
16
+ ## [0.2.2](https://github.com/elyukai/ts-utils/compare/v0.2.1...v0.2.2) (2026-02-11)
17
+
18
+
19
+ ### Features
20
+
21
+ * add FixedArray helper ([4a1b61a](https://github.com/elyukai/ts-utils/commit/4a1b61a51ad53c35767adf716d4a64ef10f4dc10))
22
+ * add static groupBy method to dictionary ([2ee4802](https://github.com/elyukai/ts-utils/commit/2ee4802db8f1b821819f4ced5f79079153a6c11e))
23
+
5
24
  ## [0.2.1](https://github.com/elyukai/ts-utils/compare/v0.2.0...v0.2.1) (2026-02-07)
6
25
 
7
26
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * A helper type that builds a tuple type of a desired length.
3
+ * @module
4
+ */
5
+ /**
6
+ * A recursive type that constructs an array of type `T` with a length of `N`.
7
+ */
8
+ type FixedArrayAux<T, N extends number, A extends T[]> = A["length"] extends N ? A : FixedArrayAux<T, N, [...A, T]>;
9
+ /**
10
+ * A type representing an array of a fixed size `N` containing elements of type `T`.
11
+ */
12
+ export type FixedArray<T, N extends number> = FixedArrayAux<T, N, []>;
13
+ export {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A helper type that builds a tuple type of a desired length.
3
+ * @module
4
+ */
5
+ export {};
@@ -21,6 +21,10 @@ export declare class Dictionary<T extends AnyNonNullish | null, K extends string
21
21
  * Constructs a dictionary from an array of key-value pairs.
22
22
  */
23
23
  static fromEntries<T extends AnyNonNullish | null, K extends string = string>(entries: [K, T][]): Dictionary<T, K>;
24
+ /**
25
+ * Groups the given items by the key returned by the given function and returns a dictionary mapping each key to an array of items with that key.
26
+ */
27
+ static groupBy<T, K extends string>(items: T[], keyFn: (item: T) => K): Dictionary<T[], K>;
24
28
  /**
25
29
  * Returns the value associated with the given key, or `undefined` if the key does not exist.
26
30
  */
@@ -25,6 +25,22 @@ export class Dictionary {
25
25
  static fromEntries(entries) {
26
26
  return new Dictionary(Object.fromEntries(entries));
27
27
  }
28
+ /**
29
+ * Groups the given items by the key returned by the given function and returns a dictionary mapping each key to an array of items with that key.
30
+ */
31
+ static groupBy(items, keyFn) {
32
+ const record = {};
33
+ for (const item of items) {
34
+ const key = keyFn(item);
35
+ if (record[key] === undefined) {
36
+ record[key] = [item];
37
+ }
38
+ else {
39
+ record[key].push(item);
40
+ }
41
+ }
42
+ return new Dictionary(record);
43
+ }
28
44
  /**
29
45
  * Returns the value associated with the given key, or `undefined` if the key does not exist.
30
46
  */
@@ -2,6 +2,10 @@
2
2
  * Utility functions for combining functions.
3
3
  * @module
4
4
  */
5
+ /**
6
+ * Returns the input value unchanged.
7
+ */
8
+ export declare const identity: <T>(value: T) => T;
5
9
  /**
6
10
  * Returns a function that always returns the given value.
7
11
  * @param value The value to return from the new function.
package/dist/function.js CHANGED
@@ -2,6 +2,10 @@
2
2
  * Utility functions for combining functions.
3
3
  * @module
4
4
  */
5
+ /**
6
+ * Returns the input value unchanged.
7
+ */
8
+ export const identity = (value) => value;
5
9
  /**
6
10
  * Returns a function that always returns the given value.
7
11
  * @param value The value to return from the new function.
@@ -0,0 +1,69 @@
1
+ /**
2
+ * A simple implementation of the Reader monad, which allows you to write functions that depend on some shared environment.
3
+ * @module
4
+ */
5
+ /**
6
+ * The Reader monad represents a computation that depends on some shared environment. It allows you to write functions that can access this environment without having to pass it explicitly as an argument.
7
+ * @template T The type of the value produced by the Reader.
8
+ * @template R The type of the environment that the Reader depends on.
9
+ */
10
+ export declare class Reader<in R, out T> {
11
+ #private;
12
+ private constructor();
13
+ /**
14
+ * Always produce the given value, regardless of the environment.
15
+ */
16
+ static of<R = unknown, T = never>(value: T): Reader<R, T>;
17
+ /**
18
+ * Retrieve the entire environment.
19
+ */
20
+ static ask<R>(): Reader<R, R>;
21
+ /**
22
+ * Retrieve a transformed value of the environment.
23
+ */
24
+ static asks<R, T>(f: (env: R) => T): Reader<R, T>;
25
+ /**
26
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result.
27
+ */
28
+ map<U>(f: (value: T) => U): Reader<R, U>;
29
+ /**
30
+ * Combines this Reader with another Reader by applying a function to both of their results and returning a new Reader that produces the result.
31
+ */
32
+ map2<U, V>(other: Reader<R, U>, f: (first: T, second: U) => V): Reader<R, V>;
33
+ /**
34
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on the same environment.
35
+ */
36
+ then<U>(f: (value: T) => Reader<R, U>): Reader<R, U>;
37
+ /**
38
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on a shared environment. The environments do not have to be the same, but will need to be combined.
39
+ *
40
+ * The suffix ‘W’ stands for ‘widening’, as this method allows you to widen the environment that the Reader depends on.
41
+ */
42
+ thenW<U, S>(f: (value: T) => Reader<S, U>): Reader<R & S, U>;
43
+ /**
44
+ * Modifies the environment for this Reader by applying the given function to it before running the computation.
45
+ *
46
+ * This allows you to adapt the environment for a specific computation without changing the original Reader.
47
+ */
48
+ with<S>(modifyEnv: (env: S) => R): Reader<S, T>;
49
+ /**
50
+ * Computes the result by providing the required environment.
51
+ */
52
+ run(env: R): T;
53
+ /**
54
+ * Evaluate each reader in the array, and collect the results in a single reader instance.
55
+ */
56
+ static sequence<R, T>(readers: Reader<R, T>[]): Reader<R, T[]>;
57
+ /**
58
+ * Transforms a function that returns a Reader into a Reader that produces a function.
59
+ *
60
+ * This makes functions producing Readers that depend on more arguments sometimes easier to work with.
61
+ */
62
+ static defer<Args extends unknown[], R, T>(fn: (...args: Args) => Reader<R, T>): Reader<R, (...args: Args) => T>;
63
+ /**
64
+ * Transforms a Reader that produces a function into a function that returns a Reader.
65
+ *
66
+ * This is the inverse of {@link defer}.
67
+ */
68
+ static undefer<Args extends unknown[], R, T>(reader: Reader<R, (...args: Args) => T>): (...args: Args) => Reader<R, T>;
69
+ }
package/dist/reader.js ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * A simple implementation of the Reader monad, which allows you to write functions that depend on some shared environment.
3
+ * @module
4
+ */
5
+ // A simpler wrapper for working with text that is generated based on different contexts, which encapsulates the context and reduces main code clutter. The context is only applied in the end.
6
+ /**
7
+ * The Reader monad represents a computation that depends on some shared environment. It allows you to write functions that can access this environment without having to pass it explicitly as an argument.
8
+ * @template T The type of the value produced by the Reader.
9
+ * @template R The type of the environment that the Reader depends on.
10
+ */
11
+ export class Reader {
12
+ #fn;
13
+ constructor(fn) {
14
+ this.#fn = fn;
15
+ }
16
+ /**
17
+ * Always produce the given value, regardless of the environment.
18
+ */
19
+ static of(value) {
20
+ return new Reader(() => value);
21
+ }
22
+ /**
23
+ * Retrieve the entire environment.
24
+ */
25
+ static ask() {
26
+ return new Reader((env) => env);
27
+ }
28
+ /**
29
+ * Retrieve a transformed value of the environment.
30
+ */
31
+ static asks(f) {
32
+ return new Reader((env) => f(env));
33
+ }
34
+ /**
35
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result.
36
+ */
37
+ map(f) {
38
+ return new Reader((env) => f(this.#fn(env)));
39
+ }
40
+ /**
41
+ * Combines this Reader with another Reader by applying a function to both of their results and returning a new Reader that produces the result.
42
+ */
43
+ map2(other, f) {
44
+ return new Reader((env) => f(this.#fn(env), other.#fn(env)));
45
+ }
46
+ /**
47
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on the same environment.
48
+ */
49
+ then(f) {
50
+ return new Reader((env) => f(this.#fn(env)).#fn(env));
51
+ }
52
+ /**
53
+ * Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on a shared environment. The environments do not have to be the same, but will need to be combined.
54
+ *
55
+ * The suffix ‘W’ stands for ‘widening’, as this method allows you to widen the environment that the Reader depends on.
56
+ */
57
+ thenW(f) {
58
+ return new Reader((env) => f(this.#fn(env)).#fn(env));
59
+ }
60
+ /**
61
+ * Modifies the environment for this Reader by applying the given function to it before running the computation.
62
+ *
63
+ * This allows you to adapt the environment for a specific computation without changing the original Reader.
64
+ */
65
+ with(modifyEnv) {
66
+ return new Reader((env) => this.#fn(modifyEnv(env)));
67
+ }
68
+ /**
69
+ * Computes the result by providing the required environment.
70
+ */
71
+ run(env) {
72
+ return this.#fn(env);
73
+ }
74
+ /**
75
+ * Evaluate each reader in the array, and collect the results in a single reader instance.
76
+ */
77
+ static sequence(readers) {
78
+ return new Reader((env) => readers.map((reader) => reader.run(env)));
79
+ }
80
+ /**
81
+ * Transforms a function that returns a Reader into a Reader that produces a function.
82
+ *
83
+ * This makes functions producing Readers that depend on more arguments sometimes easier to work with.
84
+ */
85
+ static defer(fn) {
86
+ return new Reader((env) => (...args) => fn(...args).run(env));
87
+ }
88
+ /**
89
+ * Transforms a Reader that produces a function into a function that returns a Reader.
90
+ *
91
+ * This is the inverse of {@link defer}.
92
+ */
93
+ static undefer(reader) {
94
+ return (...args) => new Reader((env) => reader.run(env)(...args));
95
+ }
96
+ }
97
+ // type Readable<T> =
98
+ // T extends Record<string, unknown>
99
+ // ? { [K in keyof T]: Readable<T[K]> }
100
+ // : T
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elyukai/utils",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "description": "A set of JavaScript helper functions.",
5
5
  "files": [
6
6
  "dist",
@@ -32,16 +32,15 @@
32
32
  },
33
33
  "homepage": "https://github.com/elyukai/ts-utils#readme",
34
34
  "devDependencies": {
35
- "@eslint/js": "^9.39.2",
36
- "@types/node": "^25.0.10",
35
+ "@eslint/js": "^10.0.1",
36
+ "@types/node": "^25.3.0",
37
37
  "commit-and-tag-version": "^12.6.1",
38
- "eslint": "^9.39.2",
39
- "eslint-plugin-jsdoc": "^62.4.1",
40
- "glob": "^13.0.0",
38
+ "eslint": "^10.0.1",
39
+ "eslint-plugin-jsdoc": "^62.7.0",
41
40
  "prettier": "^3.8.1",
42
41
  "tsx": "^4.21.0",
43
42
  "typescript": "^5.9.3",
44
- "typescript-eslint": "^8.53.1"
43
+ "typescript-eslint": "^8.56.0"
45
44
  },
46
45
  "type": "module"
47
46
  }