@geraintguan/ts-std-lib 1.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.
@@ -0,0 +1,503 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { identity } from "../identity.mjs";
5
+ class HashMapMissingKeyError extends Error {
6
+ constructor(map, key) {
7
+ super(
8
+ `Could not find key ${String(key)} (${typeof key}) in HashMap ${map.name}`
9
+ );
10
+ __publicField(this, "key");
11
+ __publicField(this, "map");
12
+ this.map = map;
13
+ this.key = key;
14
+ }
15
+ }
16
+ const _HashMap = class _HashMap {
17
+ constructor(hash, _map = /* @__PURE__ */ new Map(), name = "unknown") {
18
+ this.hash = hash;
19
+ this._map = _map;
20
+ this.name = name;
21
+ }
22
+ /**
23
+ * Create a new empty map instance.
24
+ *
25
+ * @remarks
26
+ *
27
+ * This function uses the {@link identity} function as the hashing function
28
+ * meaning that keys will be stored without any changes.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const map = HashMap.empty<number, string>();
33
+ *
34
+ * [...map]; // => []
35
+ *
36
+ * map.set(1, "one");
37
+ *
38
+ * [...map]; // => [[1, "one"]]
39
+ * ```
40
+ *
41
+ * @see {@link HashMap.emptyWithCustomHash}
42
+ *
43
+ * @param options - Options to use to create the new map instance.
44
+ *
45
+ * @returns A new empty map instance.
46
+ */
47
+ static empty(options = {}) {
48
+ return new _HashMap(identity, /* @__PURE__ */ new Map(), options.name);
49
+ }
50
+ /**
51
+ * Create a new empty map instance with a custom hashing function.
52
+ *
53
+ * @param options - Options to use to create the new map instance.
54
+ *
55
+ * @returns A new empty map instance.
56
+ */
57
+ static emptyWithCustomHash(options) {
58
+ return new _HashMap(
59
+ options.hash,
60
+ /* @__PURE__ */ new Map(),
61
+ options.name
62
+ );
63
+ }
64
+ /**
65
+ * Create a new map instance from an array of key-value pairs with
66
+ * a custom hashing function.
67
+ *
68
+ * @example Use ISO string representation of Date objects as hash keys
69
+ * ```typescript
70
+ * const map = HashMap.fromCustomEntries(
71
+ * [
72
+ * [new Date("2020-01-01"), 1],
73
+ * [new Date("2020-02-01"), 2],
74
+ * [new Date("2020-03-01"), 3],
75
+ * ],
76
+ * {
77
+ * hash(key) {
78
+ * return key.toISOString();
79
+ * },
80
+ * });
81
+ *
82
+ * [...map];
83
+ * // => [
84
+ * // ["2020-01-01T00:00:00.000Z", 1],
85
+ * // ["2020-02-01T00:00:00.000Z", 2],
86
+ * // ["2020-03-01T00:00:00.000Z", 3],
87
+ * // ];
88
+ * ```
89
+ *
90
+ * @param entries - Array of key-value pairs to create the map
91
+ * with.
92
+ * @param options - Options to use to create the new map instance.
93
+ *
94
+ * @returns A new map instance with the given key-value pairs and
95
+ * a given custom hashing function.
96
+ */
97
+ static fromCustomEntries(entries, options) {
98
+ return new _HashMap(
99
+ options.hash,
100
+ new Map(entries.map(([k, v]) => [options.hash(k), v])),
101
+ options.name
102
+ );
103
+ }
104
+ /**
105
+ * Create a new map instance from an array of key-value pairs
106
+ * using the {@link identity} as the hash function.
107
+ *
108
+ * @remarks
109
+ *
110
+ * This function uses the {@link identity} function as the hashing function
111
+ * meaning that keys will be stored without any changes which will therefore
112
+ * use the same behaviour as an ES6 `Map`.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const map = HashMap.fromEntries<number, string>([
117
+ * [1, "one"],
118
+ * [2, "two"],
119
+ * [3, "three"],
120
+ * ]);
121
+ *
122
+ * [...map];
123
+ * // => [
124
+ * // [1, "one"],
125
+ * // [2, "two"],
126
+ * // [3, "three"],
127
+ * // ];
128
+ * ```
129
+ *
130
+ * @param entries - Array of key-value pairs to create the map
131
+ * with.
132
+ * @param options - Options to use to create the new map instance.
133
+ *
134
+ * @returns A new map instance with the given key-value pairs.
135
+ */
136
+ static fromEntries(entries, options = {}) {
137
+ return new _HashMap(
138
+ identity,
139
+ new Map(entries.map(([key, value]) => [key, value])),
140
+ options.name
141
+ );
142
+ }
143
+ /**
144
+ * Clears all of the entries in this map.
145
+ *
146
+ * @remarks
147
+ *
148
+ * This function **will mutate** the map instance it is called on.
149
+ *
150
+ * * @example
151
+ * ```typescript
152
+ * const map = HashMap.fromEntries<number, string>([
153
+ * [1, "one"],
154
+ * [2, "two"],
155
+ * [3, "three"],
156
+ * ]);
157
+ *
158
+ * map.clear();
159
+ *
160
+ * [...map]; // => []
161
+ * ```
162
+ */
163
+ clear() {
164
+ this._map.clear();
165
+ }
166
+ /**
167
+ * Delete an entry from this map by its key, throwing a
168
+ * {@link HashMap.MissingKeyError} if the key does not exist in this map.
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const map = HashMap.fromEntries<number, string>([
173
+ * [1, "one"],
174
+ * [2, "two"],
175
+ * [3, "three"],
176
+ * ]);
177
+ *
178
+ * map.delete(2);
179
+ *
180
+ * [...map];
181
+ * // => [
182
+ * // [1, "one"],
183
+ * // [3, "three"],
184
+ * // ]
185
+ *
186
+ * map.delete(4); // throws HashMap.MissingKeyError
187
+ * ```
188
+ *
189
+ * @param key - The key of the entry to delete.
190
+ *
191
+ * @throws {@link HashMap.MissingKeyError} if the key does not exist in this
192
+ * map.
193
+ */
194
+ delete(key) {
195
+ if (!this.has(key)) {
196
+ throw new _HashMap.MissingKeyError(this, key);
197
+ }
198
+ this._map.delete(this.hash(key));
199
+ }
200
+ /**
201
+ * Delete an entry from this map by its key and returns `true` if it exists,
202
+ * otherwise it simply returns `false`.
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const map = HashMap.fromEntries<number, string>([
207
+ * [1, "one"],
208
+ * [2, "two"],
209
+ * [3, "three"],
210
+ * ]);
211
+ *
212
+ * map.deleteIfExists(2); // => true
213
+ * map.deleteIfExists(4); // => false
214
+ *
215
+ * [...map];
216
+ * // => [
217
+ * // [1, "one"],
218
+ * // [3, "three"],
219
+ * // ]
220
+ * ```
221
+ *
222
+ * @param key - The key of the entry to delete.
223
+ *
224
+ * @returns `true` if the key existed and the entry was deleted, `false` if
225
+ * the key did not exist.
226
+ */
227
+ deleteIfExists(key) {
228
+ if (!this.has(key)) {
229
+ return false;
230
+ }
231
+ this.delete(key);
232
+ return true;
233
+ }
234
+ /**
235
+ * Returns the entries in this map as an {@link IterableIterator} which each
236
+ * entry as an array of `[key, value]`.
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const map = HashMap.fromEntries<number, string>([
241
+ * [1, "one"],
242
+ * [2, "two"],
243
+ * [3, "three"],
244
+ * ]);
245
+ *
246
+ * [...map.entries()];
247
+ * // => [
248
+ * // [1, "one"],
249
+ * // [2, "two"],
250
+ * // [3, "three"],
251
+ * // ]
252
+ * ```
253
+ *
254
+ * @returns An {@link IterableIterator} of the entries in this
255
+ * map.
256
+ */
257
+ entries() {
258
+ const _this = this;
259
+ return function* () {
260
+ for (const [key, value] of _this._map.entries()) {
261
+ yield [key, value];
262
+ }
263
+ }();
264
+ }
265
+ /**
266
+ * Returns a new map with only the key-value pairs where the given function
267
+ * returns `true`, filtering out those that the given function returns `false`
268
+ * for.
269
+ *
270
+ * @remarks
271
+ * This function does not mutate the original map instance **unless** you call
272
+ * a mutating function on the map (4th argument) inside the given function.
273
+ *
274
+ * @example Include entries where key is greater than 2
275
+ * ```typescript
276
+ * const map = HashMap.fromEntries<number, string>([
277
+ * [1, "one"],
278
+ * [2, "two"],
279
+ * [3, "three"],
280
+ * [4, "four"],
281
+ * ]);
282
+ *
283
+ * const filtered = map.filter((value, key) => key > 2);
284
+ *
285
+ * [...filtered];
286
+ * // => [
287
+ * // [3, "three"],
288
+ * // [4, "four"],
289
+ * // ]
290
+ * ```
291
+ * @example Include entries where the value has a length greater than 3
292
+ * ```typescript
293
+ * const map = HashMap.fromEntries<number, string>([
294
+ * [1, "one"],
295
+ * [2, "two"],
296
+ * [3, "three"],
297
+ * [4, "four"],
298
+ * ]);
299
+ *
300
+ * const filtered = map.filter((value) => value.length > 3);
301
+ *
302
+ * [...filtered];
303
+ * // => [
304
+ * // [3, "three"],
305
+ * // [4, "four"],
306
+ * // ]
307
+ * ```
308
+ *
309
+ * @param fn - Function called for each key-value pair in the map that returns
310
+ * `true` to include the pair in the new map or `false` to exclude it.
311
+ *
312
+ * @returns A new map with only the key-value pairs where the given function
313
+ * returned `true` for.
314
+ */
315
+ filter(fn) {
316
+ const entries = [];
317
+ for (const [key, value] of this.entries()) {
318
+ if (fn(value, key, entries.length, this)) {
319
+ entries.push([key, value]);
320
+ }
321
+ }
322
+ return new _HashMap(this.hash, new Map(entries), this.name);
323
+ }
324
+ /**
325
+ * Get the value with the given key from this map, throwing a
326
+ * {@link HashMap.MissingKeyError} if the key does not exist.
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * const map = HashMap.fromEntries([
331
+ * [1, "one"],
332
+ * [2, "two"],
333
+ * [3, "three"]
334
+ * ]);
335
+ *
336
+ * map.get(2) // => "two"
337
+ *
338
+ * map.get(4) // => throws HashMap.MissingKeyError
339
+ * ```
340
+ *
341
+ * @param key - The key of the value to get.
342
+ *
343
+ * @returns The value with the given key.
344
+ */
345
+ get(key) {
346
+ const value = this._map.get(this.hash(key));
347
+ if (!value) {
348
+ throw new HashMapMissingKeyError(this, key);
349
+ }
350
+ return value;
351
+ }
352
+ /**
353
+ * Get the value with the given key from this map if it exists, otherwise
354
+ * return the given default value.
355
+ *
356
+ * @param key - The key whose associated value is to be returned.
357
+ * @param defaultValue - The value to return if the key is not found.
358
+ *
359
+ * @returns - The value associated with the specified key, or the default
360
+ * value if the key does not exist.
361
+ */
362
+ getOr(key, defaultValue) {
363
+ const value = this._map.get(this.hash(key));
364
+ if (!value) {
365
+ return defaultValue;
366
+ }
367
+ return value;
368
+ }
369
+ /**
370
+ * Checks if this map has an entry with the given key.
371
+ *
372
+ * @param key - The key to check for.
373
+ *
374
+ * @returns `true` if the key exists in this map, `false` otherwise.
375
+ */
376
+ has(key) {
377
+ return this._map.has(this.hash(key));
378
+ }
379
+ /**
380
+ * Get the keys in this map as an {@link IterableIterator}.
381
+ *
382
+ * @returns The keys in this map as an {@link IterableIterator}.
383
+ */
384
+ keys() {
385
+ const _this = this;
386
+ return function* () {
387
+ for (const key of _this._map.keys()) {
388
+ yield key;
389
+ }
390
+ }();
391
+ }
392
+ /**
393
+ * Create a new map with entries that are the result of calling the given
394
+ * callback function on each of the key-value pairs in this map.
395
+ *
396
+ * @example Swap the keys and values
397
+ * ```typescript
398
+ * const map = HashMap.fromEntries([
399
+ * ["one", 1],
400
+ * ["two", 2],
401
+ * ["three", 3],
402
+ * ]);
403
+ *
404
+ * const swapped = map.map(([key, value]) => [value, key]);
405
+ * // => HashMap { 1 => "one", 2 => "two", 3 => "three" }
406
+ * ```
407
+ *
408
+ * @param fn - Function to call on each key-value pair in the map. The result
409
+ * of this function is used as entries in the new map.
410
+ *
411
+ * @returns A new map with the new entries from calling the given function on
412
+ * each key-value pair in the map.
413
+ */
414
+ map(fn) {
415
+ const entries = [];
416
+ for (const [key, value] of this.entries()) {
417
+ entries.push(fn(value, key, entries.length, this));
418
+ }
419
+ return new _HashMap(this.hash, new Map(entries), this.name);
420
+ }
421
+ /**
422
+ * Create a new map with entries that have keys that are the result of calling
423
+ * the given callback function on each of the key-value pairs in this map.
424
+ *
425
+ * @remarks
426
+ *
427
+ * The new map will have the same default value as this map.
428
+ *
429
+ * This function does not mutate the original map instance **unless** you call
430
+ * a mutating function on the map (4th argument) inside the given function.
431
+ *
432
+ * @param fn - Function to call on each key-value pair in the map. The result
433
+ * of this function is used as the keys for the entries in the new map.
434
+ *
435
+ * @returns A new map with the entries with new keys from calling the given
436
+ * function on each key-value pair in the map.
437
+ */
438
+ mapKeys(fn) {
439
+ return this.map((value, key, index, original) => [
440
+ fn(key, value, index, original),
441
+ value
442
+ ]);
443
+ }
444
+ /**
445
+ * Create a new map with entries that have values that are the result of
446
+ * calling the given callback function on each of the key-value pairs in this
447
+ * map.
448
+ *
449
+ * @remarks
450
+ *
451
+ * The new map will have the same default value as this map.
452
+ *
453
+ * This function does not mutate the original map instance **unless** you call
454
+ * a mutating function on the map (4th argument) inside the given function.
455
+ *
456
+ * @param fn - Function to call on each key-value pair in the map. The result
457
+ * of this function is used as the values for the entries in the new map.
458
+ *
459
+ * @returns A new map with the entries with new values from calling the given
460
+ * function on each key-value pair in the map.
461
+ */
462
+ mapValues(fn) {
463
+ return this.map((value, key, index, original) => [
464
+ key,
465
+ fn(value, key, index, original)
466
+ ]);
467
+ }
468
+ /**
469
+ * Set the value of an entry by it's key in the map, creating a new entry if
470
+ * one doesn't exist or overriding an existing entry if one does.
471
+ *
472
+ * @param key - The key of the entry to set.
473
+ * @param value - The value to set the entry to.
474
+ */
475
+ set(key, value) {
476
+ this._map.set(this.hash(key), value);
477
+ }
478
+ /**
479
+ * Get the iterator over the entires in this map.
480
+ *
481
+ * @returns The entries in this map as an array of key-value pairs.
482
+ */
483
+ [Symbol.iterator]() {
484
+ return this.entries();
485
+ }
486
+ /**
487
+ * Get the values in this map as an {@link IterableIterator}.
488
+ *
489
+ * @returns The values in this map as an {@link IterableIterator}.
490
+ */
491
+ values() {
492
+ return this._map.values();
493
+ }
494
+ };
495
+ /**
496
+ * Error thrown when attempting to access a key in the map that
497
+ * does not exist.
498
+ */
499
+ __publicField(_HashMap, "MissingKeyError", HashMapMissingKeyError);
500
+ let HashMap = _HashMap;
501
+ export {
502
+ HashMap
503
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Provides implementations of various useful data structures.
3
+ *
4
+ * @module Data
5
+ */
6
+ export * from './DefaultMap.js';
7
+ export * from './HashMap.js';
@@ -0,0 +1,6 @@
1
+ import { DefaultMap } from "./DefaultMap.mjs";
2
+ import { HashMap } from "./HashMap.mjs";
3
+ export {
4
+ DefaultMap,
5
+ HashMap
6
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Utility type that returns the element type of an array type.
3
+ *
4
+ * @example Get type of element in an array type
5
+ * ```typescript
6
+ * type Elements = (string | number)[];
7
+ *
8
+ * type Element = Unpack<Elements> // (string | number)
9
+ * ```
10
+ */
11
+ export type Unpack<T> = T extends (infer U)[] ? U : T;
@@ -0,0 +1 @@
1
+ export * from './Unpack.js';
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Returns a function that when called always returns the given value.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const nine = constant(9);
7
+ *
8
+ * nine() // => 9
9
+ * nine() // => 9
10
+ * nine() // => 9
11
+ * ```
12
+ *
13
+ * @param value - The value that should be returned.
14
+ *
15
+ * @returns A function that when called will always return the given value.
16
+ */
17
+ export declare function constant<T>(value: T): () => T;
@@ -0,0 +1,6 @@
1
+ function constant(value) {
2
+ return () => value;
3
+ }
4
+ export {
5
+ constant
6
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Returns the value it is called with.
3
+ *
4
+ * @remarks
5
+ * This function is useful when you want to explicitly pass a function as a
6
+ * callback that always returns the value it is called with.
7
+ *
8
+ * It is functionally equivalent to writing an anonymous function that returns
9
+ * it's first argument, but can sometimes make your code more readable.
10
+ *
11
+ * For example both of these expressions are functionally equivalent:
12
+ *
13
+ * ```typescript
14
+ * [1, 2, 3].map(v => v);
15
+ *
16
+ * [1, 2, 3].map(identity);
17
+ * ```
18
+ * @param value - The value to return.
19
+ *
20
+ * @returns The value the function was called with.
21
+ */
22
+ export declare function identity<T>(value: T): T;
@@ -0,0 +1,6 @@
1
+ function identity(value) {
2
+ return value;
3
+ }
4
+ export {
5
+ identity
6
+ };
@@ -0,0 +1,4 @@
1
+ export * from './constant.js';
2
+ export * as Data from './Data/index.js';
3
+ export * from './identity.js';
4
+ export * as Types from './Types/index.js';
package/dist/index.mjs ADDED
@@ -0,0 +1,10 @@
1
+ import { constant } from "./constant.mjs";
2
+ import * as index from "./Data/index.mjs";
3
+ import { identity } from "./identity.mjs";
4
+ import * as index$1 from "./Types/index.mjs";
5
+ export {
6
+ index as Data,
7
+ index$1 as Types,
8
+ constant,
9
+ identity
10
+ };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@geraintguan/ts-std-lib",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "module": "./dist/index.mjs",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.mjs"
12
+ }
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "vite build",
17
+ "coverage": "vitest --coverage",
18
+ "docs": "typedoc",
19
+ "fix": "eslint --fix",
20
+ "lint": "eslint",
21
+ "test": "vitest",
22
+ "typecheck": "pnpm run typecheck:lib && pnpm run typecheck:node",
23
+ "typecheck:lib": "tsc --project tsconfig.lib.json --noEmit",
24
+ "typecheck:node": "tsc --project tsconfig.node.json --noEmit",
25
+ "prepare": "husky"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "volta": {
31
+ "node": "22.11.0"
32
+ },
33
+ "peerDependencies": {
34
+ "@types/node": ">=20"
35
+ },
36
+ "devDependencies": {
37
+ "@commitlint/cli": "19.5.0",
38
+ "@commitlint/config-conventional": "19.5.0",
39
+ "@eslint/js": "9.15.0",
40
+ "@tsconfig/node20": "20.1.4",
41
+ "@types/eslint__js": "8.42.3",
42
+ "@types/node": "22.9.0",
43
+ "@vitest/coverage-v8": "2.1.5",
44
+ "eslint": "9.15.0",
45
+ "eslint-config-prettier": "9.1.0",
46
+ "eslint-plugin-perfectionist": "3.9.1",
47
+ "eslint-plugin-prettier": "5.2.1",
48
+ "husky": "9.1.6",
49
+ "semantic-release": "24.2.0",
50
+ "typedoc": "0.26.11",
51
+ "typescript": "5.6.3",
52
+ "typescript-eslint": "8.14.1-alpha.8",
53
+ "vite": "5.4.11",
54
+ "vite-plugin-dts": "4.3.0",
55
+ "vitest": "2.1.5"
56
+ }
57
+ }