@pivanov/utils 0.0.3 → 1.0.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.
- package/README.md +125 -335
- package/dist/cjs/assertion/index.js +7 -0
- package/dist/cjs/cache/index.js +7 -0
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/object/index.js +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/promise/index.js +7 -0
- package/dist/cjs/string/index.js +7 -0
- package/dist/cjs/tools/index.js +7 -0
- package/dist/cjs/types/index.js +7 -0
- package/dist/esm/assertion/index.js +7 -0
- package/dist/esm/cache/index.js +7 -0
- package/dist/esm/chunk-3ymwkv74.js +8 -0
- package/dist/esm/chunk-jtvcg9xg.js +6 -0
- package/dist/esm/chunk-m1ymbxy0.js +8 -0
- package/dist/esm/chunk-m7vtwv05.js +8 -0
- package/dist/esm/chunk-vtcj34cd.js +8 -0
- package/dist/esm/chunk-y84wjyfx.js +7 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/object/index.js +7 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/promise/index.js +7 -0
- package/dist/esm/string/index.js +7 -0
- package/dist/esm/tools/index.js +7 -0
- package/dist/esm/types/index.js +7 -0
- package/dist/types/assertion/index.d.ts +145 -0
- package/dist/types/cache/index.d.ts +16 -0
- package/dist/types/cache/internal.d.ts +12 -0
- package/dist/types/cache/response.d.ts +91 -0
- package/dist/types/cache/storage.d.ts +75 -0
- package/dist/types/cache/support.d.ts +14 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/object/index.d.ts +118 -0
- package/dist/types/promise/index.d.ts +81 -0
- package/dist/types/string/index.d.ts +127 -0
- package/dist/types/tools/deepClone.d.ts +2 -0
- package/dist/types/tools/dom.d.ts +82 -0
- package/dist/types/tools/eventBus/eventBus.d.ts +37 -0
- package/dist/types/tools/eventBus/index.d.ts +3 -0
- package/dist/types/tools/eventBus/types.d.ts +47 -0
- package/dist/types/tools/eventBus/useEventBus.d.ts +3 -0
- package/dist/types/tools/index.d.ts +5 -0
- package/dist/types/tools/isEqual.d.ts +21 -0
- package/dist/types/types/index.d.ts +61 -0
- package/package.json +74 -35
- package/dist/index.d.ts +0 -691
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `JSON.stringify` replacer that converts `BigInt` values to strings.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* JSON.stringify({ id: 9007199254740993n }, stringifyBigIntValues);
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export declare const stringifyBigIntValues: (_key: string, value: unknown) => unknown;
|
|
10
|
+
/**
|
|
11
|
+
* Stores a JSON-serializable value in the browser Cache API.
|
|
12
|
+
*
|
|
13
|
+
* Note: values are serialized via `JSON.stringify`. `Date`, `Map`, `Set`,
|
|
14
|
+
* `undefined`, and `Symbol` values are lossy. `BigInt` is auto-stringified.
|
|
15
|
+
*/
|
|
16
|
+
export declare const storageSetItem: (cacheName: string, key: string, value: unknown) => Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves a value from the Cache API. Returns `null` if not found.
|
|
19
|
+
*/
|
|
20
|
+
export declare const storageGetItem: <T>(cacheName: string, key: string) => Promise<T | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Stores a value with a TTL (time-to-live in milliseconds). After the TTL
|
|
23
|
+
* elapses, reads via `storageGetItemWithTTL` will return `null` and delete
|
|
24
|
+
* the expired entry.
|
|
25
|
+
*
|
|
26
|
+
* Wire format is a self-describing envelope: `{ __ttl: true, v, exp }`.
|
|
27
|
+
* Entries stored this way are only correctly read via the `WithTTL` variants.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* await storageSetItemWithTTL('my-cache', 'token', 'abc123', 60_000);
|
|
32
|
+
* const token = await storageGetItemWithTTL<string>('my-cache', 'token');
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const storageSetItemWithTTL: (cacheName: string, key: string, value: unknown, ttlMs: number) => Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Reads a value previously stored with `storageSetItemWithTTL`. Returns
|
|
38
|
+
* `null` if absent or expired; expired entries are deleted.
|
|
39
|
+
*/
|
|
40
|
+
export declare const storageGetItemWithTTL: <T>(cacheName: string, key: string) => Promise<T | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Removes a single key. Returns `true` if the key existed and was deleted.
|
|
43
|
+
*/
|
|
44
|
+
export declare const storageRemoveItem: (cacheName: string, key: string) => Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Clears every entry in the named cache.
|
|
47
|
+
*/
|
|
48
|
+
export declare const storageClear: (cacheName: string) => Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Clears every cache entry whose key matches `str` as prefix or suffix.
|
|
51
|
+
*
|
|
52
|
+
* @deprecated Prefer `storageClearByPrefix` / `storageClearBySuffix` for
|
|
53
|
+
* readability. This function will remain through v1.x.
|
|
54
|
+
*/
|
|
55
|
+
export declare const storageClearByPrefixOrSuffix: (cacheName: string, str: string, isPrefix?: boolean) => Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Clears every cache entry whose key starts with `prefix`.
|
|
58
|
+
*/
|
|
59
|
+
export declare const storageClearByPrefix: (cacheName: string, prefix: string) => Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Clears every cache entry whose key ends with `suffix`.
|
|
62
|
+
*/
|
|
63
|
+
export declare const storageClearBySuffix: (cacheName: string, suffix: string) => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Checks whether a key exists in the cache.
|
|
66
|
+
*/
|
|
67
|
+
export declare const storageExists: (cacheName: string, key: string) => Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Returns every key currently stored in the cache.
|
|
70
|
+
*/
|
|
71
|
+
export declare const storageGetAllKeys: (cacheName: string) => Promise<string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Calculates the size in bytes of the cache, or of a single entry.
|
|
74
|
+
*/
|
|
75
|
+
export declare const storageCalculateSize: (cacheName: string, cacheKey?: string) => Promise<number>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reports whether the Cache Storage API is reachable in the current realm.
|
|
3
|
+
*
|
|
4
|
+
* Use it to guard cache access during SSR, in Node, or in any runtime that does
|
|
5
|
+
* not expose `caches`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* if (isCacheStorageSupported()) {
|
|
10
|
+
* await cacheClear('assets-v1');
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const isCacheStorageSupported: () => boolean;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { TDict } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new object with the specified keys removed.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* omit({ name: 'John', age: 30 }, ['age']); // { name: 'John' }
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare const omit: <T extends TDict, K extends keyof T>(object: T, keys: K[]) => Omit<T, K>;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new object with only the specified keys.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* pick({ name: 'John', age: 30 }, ['name']); // { name: 'John' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const pick: <T extends TDict, K extends keyof T>(object: T, keys: K[]) => Pick<T, K>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a new object keeping entries where the predicate returns true.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* pickBy({ a: 1, b: 2, c: 3 }, (v) => v > 1); // { b: 2, c: 3 }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare const pickBy: <T extends TDict>(object: T, predicate: (value: T[keyof T], key: keyof T) => boolean) => Partial<T>;
|
|
29
|
+
/**
|
|
30
|
+
* Returns a new object dropping entries where the predicate returns true.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* omitBy({ a: 1, b: null, c: 3 }, (v) => v === null); // { a: 1, c: 3 }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const omitBy: <T extends TDict>(object: T, predicate: (value: T[keyof T], key: keyof T) => boolean) => Partial<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Returns a new object with values mapped via the transform function.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* mapValues({ a: 1, b: 2 }, (v) => v * 2); // { a: 2, b: 4 }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const mapValues: <T extends TDict, R>(object: T, mapper: (value: T[keyof T], key: keyof T) => R) => Record<keyof T, R>;
|
|
47
|
+
/**
|
|
48
|
+
* Returns a new object with keys mapped via the transform function.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* mapKeys({ a: 1, b: 2 }, (_, k) => k.toUpperCase()); // { A: 1, B: 2 }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare const mapKeys: <T extends TDict>(object: T, mapper: (value: T[keyof T], key: keyof T) => string) => Record<string, T[keyof T]>;
|
|
56
|
+
/**
|
|
57
|
+
* Groups items by the key returned by the iteratee.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* groupBy(['apple', 'banana', 'cherry'], (s) => s[0]);
|
|
62
|
+
* // { a: ['apple'], b: ['banana'], c: ['cherry'] }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare const groupBy: <T, K extends string | number>(items: readonly T[], iteratee: (item: T, index: number) => K) => Record<K, T[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Swaps keys with values. Values must be valid object keys.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* invert({ a: 'x', b: 'y' }); // { x: 'a', y: 'b' }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare const invert: <K extends string, V extends string | number | symbol>(object: Record<K, V>) => Record<V, K>;
|
|
75
|
+
/**
|
|
76
|
+
* Typed `Object.hasOwn`. Narrows the key into the object's own keys.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* if (hasOwn(obj, 'name')) obj.name; // narrowed
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const hasOwn: <T extends object, K extends PropertyKey>(object: T, key: K) => object is T & Record<K, unknown>;
|
|
84
|
+
/**
|
|
85
|
+
* Typed `Object.keys`. Returns `(keyof T)[]` instead of `string[]`.
|
|
86
|
+
*
|
|
87
|
+
* Note: like `Object.keys`, the runtime keys are just the own enumerable
|
|
88
|
+
* string keys, so this typing can be unsound if the object has extra runtime
|
|
89
|
+
* properties not in its compile-time type.
|
|
90
|
+
*/
|
|
91
|
+
export declare const keysOf: <T extends object>(object: T) => (keyof T)[];
|
|
92
|
+
/**
|
|
93
|
+
* Typed `Object.entries`. Returns `[keyof T, T[keyof T]][]`.
|
|
94
|
+
*/
|
|
95
|
+
export declare const entriesOf: <T extends object>(object: T) => [keyof T, T[keyof T]][];
|
|
96
|
+
/**
|
|
97
|
+
* Typed `Object.fromEntries` for tuple arrays with literal key types.
|
|
98
|
+
*/
|
|
99
|
+
export declare const fromEntries: <K extends PropertyKey, V>(entries: readonly (readonly [K, V])[]) => Record<K, V>;
|
|
100
|
+
/**
|
|
101
|
+
* Shallow-merges multiple objects into a new object. Does not mutate inputs.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* merge({ a: 1 }, { b: 2 }, { c: 3 }); // { a: 1, b: 2, c: 3 }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare const merge: <T extends object>(target: T, ...sources: Partial<T>[]) => T;
|
|
109
|
+
/**
|
|
110
|
+
* Recursively merges multiple objects into a new object. Does not mutate
|
|
111
|
+
* inputs. Nested plain objects are merged; arrays and other values replace.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* deepMerge({ a: { b: 1 } }, { a: { c: 2 } }); // { a: { b: 1, c: 2 } }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare const deepMerge: <T extends object>(target: T, ...sources: Partial<T>[]) => T;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asynchronously waits for the specified number of milliseconds.
|
|
3
|
+
*
|
|
4
|
+
* Accepts an optional `AbortSignal` - when the signal aborts, the returned
|
|
5
|
+
* promise rejects with the signal's `reason` and the pending timer is cleared.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* await sleep(1000);
|
|
10
|
+
*
|
|
11
|
+
* const ctrl = new AbortController();
|
|
12
|
+
* setTimeout(() => ctrl.abort(), 50);
|
|
13
|
+
* await sleep(1000, ctrl.signal); // rejects after 50ms
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Races a promise against a timeout. Rejects with the given reason (or a
|
|
19
|
+
* default `TimeoutError`) if the promise doesn't settle in time.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* await timeout(fetch('/slow'), 3000);
|
|
24
|
+
* await timeout(work(), 5000, new Error('took too long'));
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare const timeout: <T>(promise: Promise<T>, ms: number, reason?: unknown) => Promise<T>;
|
|
28
|
+
interface IRetryOptions {
|
|
29
|
+
/** Maximum number of attempts (including the first). Default: 3. */
|
|
30
|
+
attempts?: number;
|
|
31
|
+
/** Milliseconds to wait between attempts. Can be a fixed number or a function
|
|
32
|
+
* `(attempt) => ms` where attempt is 1-indexed. Default: 0 (no delay). */
|
|
33
|
+
backoff?: number | ((attempt: number) => number);
|
|
34
|
+
/** Cancels in-flight retries. */
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
/** Optional predicate - return false to abort retrying for a given error. */
|
|
37
|
+
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Runs `fn` and retries on rejection up to `attempts` times with optional
|
|
41
|
+
* backoff. Re-throws the last error if all attempts fail.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* await retry(() => fetch('/api'), { attempts: 3, backoff: 500 });
|
|
46
|
+
* await retry(work, {
|
|
47
|
+
* attempts: 5,
|
|
48
|
+
* backoff: (n) => 100 * 2 ** n, // exponential
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare const retry: <T>(fn: (attempt: number) => Promise<T> | T, options?: IRetryOptions) => Promise<T>;
|
|
53
|
+
interface IDeferred<T> {
|
|
54
|
+
promise: Promise<T>;
|
|
55
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
56
|
+
reject: (reason?: unknown) => void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Creates an externally-resolvable promise. Equivalent to `Promise.withResolvers`
|
|
60
|
+
* (ES2024) but works in older runtimes.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const { promise, resolve } = defer<string>();
|
|
65
|
+
* setTimeout(() => resolve('hi'), 100);
|
|
66
|
+
* const value = await promise;
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare const defer: <T>() => IDeferred<T>;
|
|
70
|
+
/**
|
|
71
|
+
* Maps `items` through `fn` with bounded concurrency. Results preserve input
|
|
72
|
+
* order. If any task rejects, the returned promise rejects as soon as that
|
|
73
|
+
* error surfaces (but already-started tasks continue running).
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const bodies = await parallelLimit(urls, 4, (url) => fetch(url));
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare const parallelLimit: <T, R>(items: readonly T[], concurrency: number, fn: (item: T, index: number) => Promise<R> | R) => Promise<R[]>;
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a string to camelCase.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* camelCase('foo-bar'); // 'fooBar'
|
|
7
|
+
* camelCase('FOO_BAR'); // 'fooBar'
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare const camelCase: (str: string) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Converts a string to PascalCase.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* pascalCase('foo-bar'); // 'FooBar'
|
|
17
|
+
* pascalCase('foo123bar'); // 'Foo123Bar'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const pascalCase: (str: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Capitalizes the first character of a string (runtime).
|
|
23
|
+
* For TypeScript literal-type preservation, use `capitalize` instead.
|
|
24
|
+
*/
|
|
25
|
+
export declare const capitalizeFirstLetter: (string: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Converts a string to kebab-case.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* kebabCase('fooBar'); // 'foo-bar'
|
|
32
|
+
* kebabCase('XMLHttpRequest'); // 'xml-http-request'
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const kebabCase: (str: string) => string;
|
|
36
|
+
/**
|
|
37
|
+
* Converts a string to snake_case.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* snakeCase('fooBar'); // 'foo_bar'
|
|
42
|
+
* snakeCase('XMLHttpRequest'); // 'xml_http_request'
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare const snakeCase: (str: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Converts a string to Title Case - each word capitalized, separators
|
|
48
|
+
* normalized to single spaces.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* titleCase('hello world'); // 'Hello World'
|
|
53
|
+
* titleCase('foo-bar_baz'); // 'Foo Bar Baz'
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const titleCase: (str: string) => string;
|
|
57
|
+
/**
|
|
58
|
+
* Converts a string into a URL-friendly slug. More aggressive than
|
|
59
|
+
* `kebabCase` - strips all non-ASCII-word characters.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* slugify('Hello World!'); // 'hello-world'
|
|
64
|
+
* slugify('Über Café'); // 'uber-cafe'
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare const slugify: (str: string) => string;
|
|
68
|
+
/**
|
|
69
|
+
* Capitalizes the first character; preserves TypeScript literal types.
|
|
70
|
+
*/
|
|
71
|
+
export declare const capitalize: <S extends string>(str: S) => Capitalize<S>;
|
|
72
|
+
/**
|
|
73
|
+
* Lower-cases the first character; preserves TypeScript literal types.
|
|
74
|
+
*/
|
|
75
|
+
export declare const uncapitalize: <S extends string>(str: S) => Uncapitalize<S>;
|
|
76
|
+
/**
|
|
77
|
+
* Truncates a string to `maxLength` characters, appending an ellipsis
|
|
78
|
+
* (default `…`) if truncation happened. The ellipsis is included in
|
|
79
|
+
* the final length.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* truncate('Hello, world!', 8); // 'Hello, …'
|
|
84
|
+
* truncate('Hello, world!', 8, '...'); // 'Hello...'
|
|
85
|
+
* truncate('Short', 20); // 'Short'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare const truncate: (str: string, maxLength: number, ellipsis?: string) => string;
|
|
89
|
+
/**
|
|
90
|
+
* Escapes HTML special characters for safe interpolation into markup.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* escapeHtml('<script>alert(1)</script>');
|
|
95
|
+
* // '<script>alert(1)</script>'
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare const escapeHtml: (str: string) => string;
|
|
99
|
+
/**
|
|
100
|
+
* Escapes characters that have special meaning in a regular expression so the
|
|
101
|
+
* string can be safely embedded as a literal match.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* new RegExp(escapeRegExp('a.b*c')); // matches the literal "a.b*c"
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare const escapeRegExp: (str: string) => string;
|
|
109
|
+
/**
|
|
110
|
+
* Splits a string into words by whitespace, dashes, and underscores.
|
|
111
|
+
* Preserves case; filters out empty segments.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* words('hello_world-foo bar'); // ['hello', 'world', 'foo', 'bar']
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare const words: (str: string) => string[];
|
|
119
|
+
/**
|
|
120
|
+
* Splits a string by line breaks (`\r\n`, `\n`, or `\r`).
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* lines('a\nb\r\nc'); // ['a', 'b', 'c']
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare const lines: (str: string) => string[];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true when running in a browser-like environment.
|
|
3
|
+
*
|
|
4
|
+
* Checks for both `window` and `document` so service-worker and
|
|
5
|
+
* partially-mocked contexts are correctly reported as non-browser.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* if (isBrowser()) window.addEventListener('resize', onResize);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const isBrowser: () => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Sets CSS custom properties on an element. Safely no-ops when element is null.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* setStyleProperties(el, { '--primary': '#3b82f6', '--gap': '1rem' });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const setStyleProperties: (el: HTMLElement | null, cssVars: Record<string, string>) => void;
|
|
22
|
+
interface CheckVisibilityOptions {
|
|
23
|
+
/** Require the element to intersect the viewport. Default: true. */
|
|
24
|
+
checkViewport?: boolean;
|
|
25
|
+
/** Require computed `display` to be non-"none". Default: true. */
|
|
26
|
+
checkDisplay?: boolean;
|
|
27
|
+
/** Require computed `visibility` to be "visible". Default: true. */
|
|
28
|
+
checkVisibility?: boolean;
|
|
29
|
+
/** Require computed `opacity` to be > 0. Default: true. */
|
|
30
|
+
checkOpacity?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Checks whether an element is visible to the user.
|
|
34
|
+
*
|
|
35
|
+
* By default verifies: attached to DOM, `display` not `none`,
|
|
36
|
+
* `visibility` is `visible`, `opacity > 0`, and intersects the viewport
|
|
37
|
+
* on both axes. Each check can be toggled via options.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* if (checkVisibility(el)) el.classList.add('seen');
|
|
42
|
+
* checkVisibility(el, { checkViewport: false }); // visible per CSS only
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare const checkVisibility: (element: HTMLElement, options?: CheckVisibilityOptions) => boolean;
|
|
46
|
+
/**
|
|
47
|
+
* @internal Resets the cached canvas - for tests only.
|
|
48
|
+
*/
|
|
49
|
+
export declare const __resetTextMeasurementCache: () => void;
|
|
50
|
+
interface IViewportOptions {
|
|
51
|
+
/** Require vertical intersection. Default: true. */
|
|
52
|
+
vertical?: boolean;
|
|
53
|
+
/** Require horizontal intersection. Default: true. */
|
|
54
|
+
horizontal?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns true when the element's bounding rect intersects the viewport.
|
|
58
|
+
* Pure geometry - ignores CSS visibility. Use `checkVisibility` for a full
|
|
59
|
+
* visibility check.
|
|
60
|
+
*
|
|
61
|
+
* Zero-sized rects (no layout yet) return true - we can't clip against
|
|
62
|
+
* nothing, and failing them would produce false negatives in test environments.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* if (isInViewport(el)) track();
|
|
67
|
+
* isInViewport(el, { horizontal: false }); // vertical only
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare const isInViewport: (element: HTMLElement, options?: IViewportOptions) => boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Measures the rendered width of text in pixels using a cached off-screen
|
|
73
|
+
* canvas. Returns `0` when 2D context is unavailable.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* calculateRenderedTextWidth('Hello World', 16);
|
|
78
|
+
* calculateRenderedTextWidth('Hi', 14, true, 'Arial');
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare const calculateRenderedTextWidth: (text: string, fontSize: number, isUppercase?: boolean, fontFamily?: string) => number;
|
|
82
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IEventBus, IEventBusSubscribeOptions, TEventBusListener, TEventBusUnsubscribe } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Dispatches a message to every subscriber on `topic`.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* busDispatch('user-updated', { id: 1, name: 'John' });
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare const busDispatch: <T extends IEventBus>(topic: T["topic"], message: T["message"]) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Subscribes to messages on a specific topic. Returns an unsubscribe function.
|
|
13
|
+
*
|
|
14
|
+
* Pass `options.onError` to handle listener exceptions (default: `console.error`).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const unsubscribe = busSubscribe('user-updated', (msg) => {
|
|
19
|
+
* console.log(msg);
|
|
20
|
+
* });
|
|
21
|
+
* unsubscribe();
|
|
22
|
+
*
|
|
23
|
+
* // Custom error handler
|
|
24
|
+
* busSubscribe('x', handler, { onError: (e) => reportBug(e) });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare const busSubscribe: <T extends IEventBus>(topic: T["topic"], listener: TEventBusListener<T["message"]>, options?: IEventBusSubscribeOptions) => TEventBusUnsubscribe;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribes to a topic and automatically unsubscribes after the first
|
|
30
|
+
* matching dispatch.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* busOnce('ready', () => startApp());
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const busOnce: <T extends IEventBus>(topic: T["topic"], listener: TEventBusListener<T["message"]>, options?: IEventBusSubscribeOptions) => TEventBusUnsubscribe;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic event-bus shape. Extend this interface for typed dispatch/subscribe.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* interface UserLoggedIn extends IEventBus<{ id: number; name: string }> {
|
|
7
|
+
* topic: 'user:logged-in';
|
|
8
|
+
* }
|
|
9
|
+
* busDispatch<UserLoggedIn>('user:logged-in', { id: 1, name: 'John' });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export interface IEventBus<T = unknown> {
|
|
13
|
+
topic: string;
|
|
14
|
+
message: T;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Listener callback shape.
|
|
18
|
+
*/
|
|
19
|
+
export type TEventBusListener<T = unknown> = (message: T) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Function returned by `busSubscribe` that removes the subscription.
|
|
22
|
+
*/
|
|
23
|
+
export type TEventBusUnsubscribe = () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Optional behavior for a subscription.
|
|
26
|
+
*/
|
|
27
|
+
export interface IEventBusSubscribeOptions {
|
|
28
|
+
/** Called with the error when the listener throws. Defaults to `console.error`. */
|
|
29
|
+
onError?: (error: unknown) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Type helper: given an event map, extract the set of valid topic names.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* type Events = {
|
|
37
|
+
* 'user:login': { id: number };
|
|
38
|
+
* 'user:logout': void;
|
|
39
|
+
* };
|
|
40
|
+
* type Topic = TEventTopic<Events>; // 'user:login' | 'user:logout'
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export type TEventTopic<Map> = keyof Map & string;
|
|
44
|
+
/**
|
|
45
|
+
* Type helper: given an event map and a topic, extract the message payload.
|
|
46
|
+
*/
|
|
47
|
+
export type TEventMessage<Map, Topic extends TEventTopic<Map>> = Map[Topic];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deeply compares two values for structural equality.
|
|
3
|
+
*
|
|
4
|
+
* Supports: primitives (with NaN-equals-NaN), Arrays, Sets, Maps, Dates,
|
|
5
|
+
* RegExp (source + flags), Errors (name + message), TypedArrays,
|
|
6
|
+
* ArrayBuffer/DataView (byte-wise), and plain objects. Handles circular
|
|
7
|
+
* references via cycle tracking.
|
|
8
|
+
*
|
|
9
|
+
* Sets with non-primitive members use order-independent deep comparison
|
|
10
|
+
* (O(n²) worst case).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* isEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // true
|
|
15
|
+
* isEqual([1, 2, 3], [1, 2, 3]); // true
|
|
16
|
+
* isEqual(new Set([{ id: 1 }]), new Set([{ id: 1 }])); // true
|
|
17
|
+
* isEqual(/foo/gi, /foo/gi); // true
|
|
18
|
+
* isEqual(new Uint8Array([1, 2]), new Uint8Array([1, 2])); // true
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const isEqual: <T, K>(obj: T | T[], objToCompare: K | K[]) => boolean;
|