@cognite/underscore 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.
- package/README.md +40 -0
- package/dist/arrays.d.ts +41 -0
- package/dist/arrays.js +23 -0
- package/dist/assert.d.ts +8 -0
- package/dist/assert.js +6 -0
- package/dist/brand.d.ts +42 -0
- package/dist/chunk-and-process-in-parallel.d.ts +112 -0
- package/dist/chunk-and-process-in-parallel.js +30 -0
- package/dist/chunk-array.d.ts +27 -0
- package/dist/chunk-array.js +7 -0
- package/dist/class.d.ts +12 -0
- package/dist/class.js +6 -0
- package/dist/exhaustive-guard.d.ts +17 -0
- package/dist/exhaustive-guard.js +6 -0
- package/dist/exponential-backoff-with-jitter.d.ts +15 -0
- package/dist/exponential-backoff-with-jitter.js +8 -0
- package/dist/generate-unique-name.d.ts +19 -0
- package/dist/generate-unique-name.js +11 -0
- package/dist/get-numbers-between.d.ts +17 -0
- package/dist/get-numbers-between.js +6 -0
- package/dist/humanize-value.d.ts +5 -0
- package/dist/humanize-value.js +16 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/is-function.d.ts +7 -0
- package/dist/is-function.js +6 -0
- package/dist/is-primitive.d.ts +9 -0
- package/dist/is-primitive.js +7 -0
- package/dist/is-valid-url.d.ts +16 -0
- package/dist/is-valid-url.js +17 -0
- package/dist/iterators.d.ts +9 -0
- package/dist/iterators.js +7 -0
- package/dist/math.d.ts +14 -0
- package/dist/math.js +9 -0
- package/dist/random.d.ts +32 -0
- package/dist/random.js +22 -0
- package/dist/react/use-debounce.d.ts +23 -0
- package/dist/react/use-debounce.js +15 -0
- package/dist/react/use-derived-promise.d.ts +34 -0
- package/dist/react/use-derived-promise.js +34 -0
- package/dist/react/use-stable-sync-external-store.d.ts +27 -0
- package/dist/react/use-stable-sync-external-store.js +12 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.js +4 -0
- package/dist/repeat.d.ts +7 -0
- package/dist/repeat.js +6 -0
- package/dist/retry-async.d.ts +92 -0
- package/dist/retry-async.js +18 -0
- package/dist/sleep.d.ts +7 -0
- package/dist/sleep.js +6 -0
- package/dist/string.d.ts +41 -0
- package/dist/string.js +12 -0
- package/dist/structMap/index.d.ts +3 -0
- package/dist/structMap/stableStringify.d.ts +23 -0
- package/dist/structMap/stableStringify.js +24 -0
- package/dist/structMap/structMap.d.ts +110 -0
- package/dist/structMap/structMap.js +29 -0
- package/dist/structMap/testUtils.d.ts +17 -0
- package/dist/structMap/types.d.ts +7 -0
- package/package.json +45 -0
package/dist/math.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines if a number is even.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The number to check.
|
|
5
|
+
* @returns `true` if the number is even, otherwise `false`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isEven(value: number): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Determines if a number is odd.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The number to check.
|
|
12
|
+
* @returns `true` if the number is odd, otherwise `false`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isOdd(value: number): boolean;
|
package/dist/math.js
ADDED
package/dist/random.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a random string of the specified length using alphanumeric characters.
|
|
3
|
+
*
|
|
4
|
+
* @param {number} length - The length of the random string to generate. Must be greater than 0.
|
|
5
|
+
* @returns {string} A random string of the specified length.
|
|
6
|
+
* @throws {Error} If the length is less than 1.
|
|
7
|
+
*/
|
|
8
|
+
export declare function randomString(length: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* Returns a random element from the given array.
|
|
11
|
+
*
|
|
12
|
+
* @template T - The type of elements in the array.
|
|
13
|
+
* @param {T[]} array - The array from which to select a random element.
|
|
14
|
+
* @returns {T} A random element from the array.
|
|
15
|
+
*/
|
|
16
|
+
export declare function randomElement<T>(array: readonly T[]): T;
|
|
17
|
+
/**
|
|
18
|
+
* Returns a random integer between minInclusive and maxExclusive.
|
|
19
|
+
*
|
|
20
|
+
* @param minInclusive
|
|
21
|
+
* @param maxExclusive
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
export declare function randomInteger(minInclusive: number, maxExclusive: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Generates a random float within the given range [min, max).
|
|
27
|
+
*
|
|
28
|
+
* @param {number} minInclusive - The minimum value (inclusive).
|
|
29
|
+
* @param {number} maxExclusive - The maximum value (exclusive).
|
|
30
|
+
* @returns {number} A random float within the range [min, max).
|
|
31
|
+
*/
|
|
32
|
+
export declare function randomFloat(minInclusive: number, maxExclusive: number): number;
|
package/dist/random.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { repeat as e } from "./repeat.js";
|
|
2
|
+
//#region libs/shared/underscore/src/random.ts
|
|
3
|
+
function t(t) {
|
|
4
|
+
if (t < 1) throw Error("Length must be greater than 0");
|
|
5
|
+
let r = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"], i = "";
|
|
6
|
+
return e(() => {
|
|
7
|
+
i += n(r);
|
|
8
|
+
}, t), i;
|
|
9
|
+
}
|
|
10
|
+
function n(e) {
|
|
11
|
+
return e[r(0, e.length)];
|
|
12
|
+
}
|
|
13
|
+
function r(e, t) {
|
|
14
|
+
if (e >= t) throw Error("The `minInclusive` value must be less than the `maxExclusive` value.");
|
|
15
|
+
return Math.floor(Math.random() * (t - e)) + e;
|
|
16
|
+
}
|
|
17
|
+
function i(e, t) {
|
|
18
|
+
if (e >= t) throw Error("The `minInclusive` value must be less than the `maxExclusive` value.");
|
|
19
|
+
return Math.random() * (t - e) + e;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { n as randomElement, i as randomFloat, r as randomInteger, t as randomString };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook that debounces a value by a specified delay.
|
|
3
|
+
*
|
|
4
|
+
* The returned value will only update after the specified delay has passed
|
|
5
|
+
* since the last change to the input value. This is useful for reducing
|
|
6
|
+
* the frequency of expensive operations triggered by rapidly changing values.
|
|
7
|
+
*
|
|
8
|
+
* @param value - The value to debounce
|
|
9
|
+
* @param delayInMs - The delay in milliseconds
|
|
10
|
+
* @returns The debounced value
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const [searchTerm, setSearchTerm] = useState('');
|
|
15
|
+
* const debouncedSearchTerm = useDebounce(searchTerm, 300);
|
|
16
|
+
*
|
|
17
|
+
* // API call only triggers when user stops typing for 300ms
|
|
18
|
+
* useEffect(() => {
|
|
19
|
+
* searchApi(debouncedSearchTerm);
|
|
20
|
+
* }, [debouncedSearchTerm]);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function useDebounce<T>(value: T, delayInMs: number): T;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useEffect as e, useState as t } from "react";
|
|
2
|
+
//#region libs/shared/underscore/src/react/use-debounce.ts
|
|
3
|
+
function n(n, r) {
|
|
4
|
+
let [i, a] = t(n);
|
|
5
|
+
return e(() => {
|
|
6
|
+
let e = setTimeout(() => {
|
|
7
|
+
a(n);
|
|
8
|
+
}, r);
|
|
9
|
+
return () => {
|
|
10
|
+
clearTimeout(e);
|
|
11
|
+
};
|
|
12
|
+
}, [n, r]), i;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { n as useDebounce };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type UseDerivedPromiseResult<T> = {
|
|
2
|
+
data: T | undefined;
|
|
3
|
+
error: Error | undefined;
|
|
4
|
+
isLoading: true;
|
|
5
|
+
} | {
|
|
6
|
+
data: T;
|
|
7
|
+
error: undefined;
|
|
8
|
+
isLoading: false;
|
|
9
|
+
} | {
|
|
10
|
+
data: undefined;
|
|
11
|
+
error: Error;
|
|
12
|
+
isLoading: false;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A custom React hook that executes a promise function whenever its dependencies change.
|
|
16
|
+
* It manages the loading state, error handling, and the result of the promise.
|
|
17
|
+
*
|
|
18
|
+
* @param promiseFn - A function that returns a promise.
|
|
19
|
+
* @param deps - An array of dependencies that trigger the promise execution when changed.
|
|
20
|
+
* @returns An object containing the data, loading state, and error from the promise execution.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Usage inside a React component
|
|
24
|
+
* const { data: user, error, isLoading } = useDerivedPromise(
|
|
25
|
+
* () => getUserFromId(userId),
|
|
26
|
+
* [userId]
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
30
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
31
|
+
* return <div>User: {user.name}</div>;
|
|
32
|
+
*/
|
|
33
|
+
export declare function useDerivedPromise<T>(promiseFn: () => Promise<T>, deps: React.DependencyList): UseDerivedPromiseResult<T>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useEffect as e, useState as t } from "react";
|
|
2
|
+
//#region libs/shared/underscore/src/react/use-derived-promise.ts
|
|
3
|
+
function n(n, r) {
|
|
4
|
+
let [i, a] = t(void 0), [o, s] = t(!0), [c, l] = t(void 0);
|
|
5
|
+
return e(() => {
|
|
6
|
+
let e = !0;
|
|
7
|
+
return s(!0), (async () => {
|
|
8
|
+
try {
|
|
9
|
+
let t = await n();
|
|
10
|
+
e && a(t);
|
|
11
|
+
} catch (t) {
|
|
12
|
+
e && l(t instanceof Error ? t : Error(String(t)));
|
|
13
|
+
} finally {
|
|
14
|
+
e && s(!1);
|
|
15
|
+
}
|
|
16
|
+
})(), () => {
|
|
17
|
+
e = !1;
|
|
18
|
+
};
|
|
19
|
+
}, r), o ? {
|
|
20
|
+
data: i,
|
|
21
|
+
error: c,
|
|
22
|
+
isLoading: !0
|
|
23
|
+
} : c ? {
|
|
24
|
+
data: void 0,
|
|
25
|
+
error: c,
|
|
26
|
+
isLoading: !1
|
|
27
|
+
} : {
|
|
28
|
+
data: i,
|
|
29
|
+
error: void 0,
|
|
30
|
+
isLoading: !1
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { n as useDerivedPromise };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A wrapper around React's `useSyncExternalStore` that returns a referentially
|
|
3
|
+
* stable value from a mutable data source.
|
|
4
|
+
*
|
|
5
|
+
* This hook uses structural cloning and deep equality checks to keep returning
|
|
6
|
+
* the same reference for the same value, making it safe to use with dependency
|
|
7
|
+
* arrays in other hooks.
|
|
8
|
+
*
|
|
9
|
+
* This is performance-sensitive and should be used with small slices of data.
|
|
10
|
+
*
|
|
11
|
+
* @template T - structurally-cloneable data type from your store
|
|
12
|
+
*
|
|
13
|
+
* @param subscribe - A function that subscribes to the external store and
|
|
14
|
+
* returns an unsubscribe function. Called with a callback that should be
|
|
15
|
+
* invoked whenever the store changes. Should be memoized.
|
|
16
|
+
* @param getSnapshot - A function that retrieves the current value from the
|
|
17
|
+
* external store. Must be a pure function and can be called multiple times
|
|
18
|
+
* per render. Must return a structurally-cloneable value. Does not need to be
|
|
19
|
+
* memoized.
|
|
20
|
+
*
|
|
21
|
+
* @returns The current value from the store, with referential stability
|
|
22
|
+
* guaranteed when the value content hasn't changed.
|
|
23
|
+
*
|
|
24
|
+
* @see [React
|
|
25
|
+
* useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore)
|
|
26
|
+
*/
|
|
27
|
+
export declare function useStableSyncExternalStore<T>(subscribe: (callback: VoidFunction) => VoidFunction, getSnapshot: () => T): T;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isEqual as e } from "lodash-es";
|
|
2
|
+
import { useRef as t, useSyncExternalStore as n } from "react";
|
|
3
|
+
//#region libs/shared/underscore/src/react/use-stable-sync-external-store.ts
|
|
4
|
+
function r(r, i) {
|
|
5
|
+
let a = t(null);
|
|
6
|
+
return n(r, () => {
|
|
7
|
+
let t = i(), n = structuredClone(t), r = a.current;
|
|
8
|
+
return r !== null && e(r, n) ? r : (a.current = n, n);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { r as useStableSyncExternalStore };
|
package/dist/react.d.ts
ADDED
package/dist/react.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { useDebounce as e } from "./react/use-debounce.js";
|
|
2
|
+
import { useDerivedPromise as t } from "./react/use-derived-promise.js";
|
|
3
|
+
import { useStableSyncExternalStore as n } from "./react/use-stable-sync-external-store.js";
|
|
4
|
+
export { e as useDebounce, t as useDerivedPromise, n as useStableSyncExternalStore };
|
package/dist/repeat.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repeats the execution of a given function a specified number of times.
|
|
3
|
+
*
|
|
4
|
+
* @param fn - The function to be executed repeatedly.
|
|
5
|
+
* @param times - The number of times to execute the function.
|
|
6
|
+
*/
|
|
7
|
+
export declare function repeat(fn: VoidFunction, times: number): void;
|
package/dist/repeat.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retries an operation a configurable number of times.
|
|
3
|
+
*
|
|
4
|
+
* The flow is as follows:
|
|
5
|
+
* 1. Call the `operation` function.
|
|
6
|
+
* 2. If it resolves, return the resolved value.
|
|
7
|
+
* 3. If it throws an error, check if we should retry (based on `maxAttempts` and `shouldRetry`).
|
|
8
|
+
* 4. If we should retry, calculate the delay using `delayInMsCalculator`, call `onAttemptFail`, wait for that duration, and then repeat from step 1.
|
|
9
|
+
* 5. If we shouldn't retry (either because we've exhausted attempts or `shouldRetry` returned false), re-throw the error.
|
|
10
|
+
*
|
|
11
|
+
* By default, we use exponential backoff with jitter for delays between attempts.
|
|
12
|
+
*
|
|
13
|
+
* @param operation The function to execute and retry.
|
|
14
|
+
* @param config Configuration for the retry mechanism.
|
|
15
|
+
* @returns A Promise that resolves with the result of the successful operation.
|
|
16
|
+
* @throws Will throw if, and only if, all retry attempts failed. Only the last exception from `operation` will be re-thrown.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Basic usage: retry a function that may fail
|
|
21
|
+
* await retryAsync(() => {
|
|
22
|
+
* if (Math.random() < 0.7) throw new Error('Transient error');
|
|
23
|
+
* return 'success';
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* * @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* try {
|
|
30
|
+
* return retryAsync(() => fetchAllUsers());
|
|
31
|
+
* } catch (err) {
|
|
32
|
+
* console.error('Failed to fetch users after several attempts:', err);
|
|
33
|
+
* notifyUser('Failed to fetch users. Please try again later.');
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // Custom retry logic and delay
|
|
40
|
+
* await retryAsync(
|
|
41
|
+
* async () => myFetch('https://api.example.com/data'),
|
|
42
|
+
* {
|
|
43
|
+
* maxAttempts: 10,
|
|
44
|
+
* shouldRetry: (error) => error instanceof NetworkError,
|
|
45
|
+
* delayInMsCalculator: (attempt) => 100 * attempt,
|
|
46
|
+
* onAttemptFail: (error, attempt, delay) => {
|
|
47
|
+
* console.warn(`Attempt ${attempt} failed (waiting ${delay}ms):`, error);
|
|
48
|
+
* },
|
|
49
|
+
* }
|
|
50
|
+
* );
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function retryAsync<T>(operation: () => T | Promise<T>, options?: RetryAsyncOptions): Promise<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Configuration options for {@link retryAsync}.
|
|
56
|
+
*/
|
|
57
|
+
export type RetryAsyncOptions = {
|
|
58
|
+
/**
|
|
59
|
+
* The maximum number of attempts to make, including the initial one.
|
|
60
|
+
* Must be in the range [1, 100].
|
|
61
|
+
* @default 5
|
|
62
|
+
*/
|
|
63
|
+
maxAttempts?: number;
|
|
64
|
+
/**
|
|
65
|
+
* A function to determine if the thrown error should trigger a retry.
|
|
66
|
+
*
|
|
67
|
+
* If this function returns `true`, a retry will be performed (up to `maxAttempts`).
|
|
68
|
+
* If it returns `false`, the error will be immediately thrown and not retried.
|
|
69
|
+
* @default (error) => true // Retries on any error.
|
|
70
|
+
* @returns Whether to retry based on the provided error.
|
|
71
|
+
*/
|
|
72
|
+
shouldRetry?: (error: unknown) => boolean;
|
|
73
|
+
/**
|
|
74
|
+
* An optional callback executed after a failed attempt, but before the next delay.
|
|
75
|
+
*
|
|
76
|
+
* Useful for logging or metrics.
|
|
77
|
+
* @param error The error that caused the failure.
|
|
78
|
+
* @param attempt The current failed attempt number (1, 2, 3, etc.).
|
|
79
|
+
* @param delayInMs The calculated delay before the next attempt.
|
|
80
|
+
*/
|
|
81
|
+
onAttemptFail?: (error: unknown, attempt: number, delayInMs: number) => void;
|
|
82
|
+
/**
|
|
83
|
+
* The function that calculates the delay (in milliseconds) before the
|
|
84
|
+
* next attempt.
|
|
85
|
+
*
|
|
86
|
+
* It takes the current attempt number (starting at 1) and returns the delay.
|
|
87
|
+
* @default Delay calculated using the {@link exponentialBackoffWithJitter} function.
|
|
88
|
+
*
|
|
89
|
+
* @returns The delay in milliseconds before the next attempt.
|
|
90
|
+
*/
|
|
91
|
+
delayInMsCalculator?: (attempt: number) => number;
|
|
92
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { exponentialBackoffWithJitter as e } from "./exponential-backoff-with-jitter.js";
|
|
2
|
+
import { sleep as t } from "./sleep.js";
|
|
3
|
+
//#region libs/shared/underscore/src/retry-async.ts
|
|
4
|
+
async function n(n, r = {}) {
|
|
5
|
+
let i = r.maxAttempts ?? 5, a = r.shouldRetry ?? (() => !0), o = r.onAttemptFail, s = r.delayInMsCalculator ?? e;
|
|
6
|
+
if (i < 1) throw Error("`maxAttempts` must be 1 or greater");
|
|
7
|
+
if (i > 100) throw Error("`maxAttempts` must be 100 or less");
|
|
8
|
+
let c = 1;
|
|
9
|
+
for (;;) try {
|
|
10
|
+
return await n();
|
|
11
|
+
} catch (e) {
|
|
12
|
+
if (c >= i || !a(e)) throw e;
|
|
13
|
+
let n = s(c);
|
|
14
|
+
o?.(e, c, n), await t(n), c++;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { n as retryAsync };
|
package/dist/sleep.d.ts
ADDED
package/dist/sleep.js
ADDED
package/dist/string.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capitalizes the first letter of the given string.
|
|
3
|
+
*
|
|
4
|
+
* @param str - The string to capitalize.
|
|
5
|
+
* @returns The input string with the first letter capitalized.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* capitalizeFirstLetter('hello'); // returns 'Hello'
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function capitalizeFirstLetter(str: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Converts a kebab-case string to PascalCase.
|
|
15
|
+
*
|
|
16
|
+
* @param str - The kebab-case string to convert.
|
|
17
|
+
* @returns The converted PascalCase string.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* kebabToPascalCase('kebab-case-string'); // returns 'KebabCaseString'
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function kebabToPascalCase(str: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Converts a given string to kebab-case (dash-case).
|
|
27
|
+
*
|
|
28
|
+
* @param str - The input string to be converted.
|
|
29
|
+
* @returns The kebab-case version of the input string.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* toKebabCase('HelloWorld'); // Returns 'hello-world'
|
|
34
|
+
* toKebabCase('hello_world'); // Returns 'hello-world'
|
|
35
|
+
* toKebabCase('hello world'); // Returns 'hello-world'
|
|
36
|
+
* toKebabCase('Hello World_Test'); // Returns 'hello-world-test'
|
|
37
|
+
* toKebabCase('special$Char'); // Returns 'special$-char'
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* */
|
|
41
|
+
export declare function toKebabCase(str: string): string;
|
package/dist/string.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region libs/shared/underscore/src/string.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
return e.charAt(0).toUpperCase() + e.slice(1);
|
|
4
|
+
}
|
|
5
|
+
function t(e) {
|
|
6
|
+
return e.replace(/-./g, (e) => e.charAt(1).toUpperCase()).replace(/^\w/, (e) => e.toUpperCase());
|
|
7
|
+
}
|
|
8
|
+
function n(e) {
|
|
9
|
+
return e.replace(/([a-z])([0-9])/gi, "$1-$2").replace(/([0-9])([a-zA-Z])/g, "$1-$2").replace(/([a-z0-9$])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as capitalizeFirstLetter, t as kebabToPascalCase, n as toKebabCase };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stringifies any value using JSON.stringify under the hood, but treating certain cases differently.
|
|
3
|
+
* - Objects - Properties are sorted alphabetically to ensure stable output
|
|
4
|
+
* - Non-object values - plain JSON.stringify
|
|
5
|
+
* - Functions, symbols, undefined - removed during serialization
|
|
6
|
+
*
|
|
7
|
+
* @param value - A value to serialize into a string
|
|
8
|
+
* @returns Stringified version of the provided value
|
|
9
|
+
* @throws Throws when BigInt value is encountered at any point or a circular dependency is detected
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const fileId = { externalId: 'file-1', space: 's1' };
|
|
14
|
+
* const fileIdReversed = { space: 's1', externalId: 'file-1' };
|
|
15
|
+
*
|
|
16
|
+
* console.log(stableStringify(fileId) === stableStringify(fileIdReversed)); // true
|
|
17
|
+
*
|
|
18
|
+
* const user = { name: 'Bob', age: 35, pets: ['Felix', 'Alex'] };
|
|
19
|
+
*
|
|
20
|
+
* console.log(stableStringify(user)); // {"age":35,"name":"Bob","pets":["Felix","Alex"] }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function stableStringify(value: unknown): string | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region libs/shared/underscore/src/structMap/stableStringify.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let n = /* @__PURE__ */ new WeakSet();
|
|
4
|
+
function r(e) {
|
|
5
|
+
if (t(e)) return;
|
|
6
|
+
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
7
|
+
if (n.has(e)) throw TypeError("Converting circular structure to JSON");
|
|
8
|
+
if (n.add(e), "toJSON" in e && typeof e.toJSON == "function") return r(e.toJSON());
|
|
9
|
+
if (Array.isArray(e)) return `[${e.map((e) => r(e) ?? "null").join(",")}]`;
|
|
10
|
+
let i = e, a = Object.keys(i).sort(), o = [];
|
|
11
|
+
for (let e of a) {
|
|
12
|
+
let n = i[e];
|
|
13
|
+
t(n) || o.push(`${JSON.stringify(e)}:${r(n)}`);
|
|
14
|
+
}
|
|
15
|
+
return `{${o.join(",")}}`;
|
|
16
|
+
}
|
|
17
|
+
return r(e);
|
|
18
|
+
}
|
|
19
|
+
function t(e) {
|
|
20
|
+
if (typeof e == "bigint") throw TypeError("Do not know how to serialize a BigInt");
|
|
21
|
+
return typeof e == "function" || typeof e == "symbol" || e === void 0;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { e as stableStringify };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { KeySerializer } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Custom data structure that builds on top of the native `Map` class.
|
|
4
|
+
* Unlike `Map`, it enables proper usage of objects as keys by comparing them structurally, instead of by reference.
|
|
5
|
+
* By default, objects are serialized using `stableStringify` function to ensure consistent key representation.
|
|
6
|
+
*
|
|
7
|
+
* @template K - Type of keys in the StructMap
|
|
8
|
+
* @template V - Type of values in the StructMap
|
|
9
|
+
* @param entries - Initial key-value pairs to populate the StructMap
|
|
10
|
+
* @param serializer - Custom serializer to convert keys to strings and back
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // Basic case with a Data Modeling-like scenario
|
|
15
|
+
*
|
|
16
|
+
* // Simplified list of DM-like objects
|
|
17
|
+
* const dmFiles = [
|
|
18
|
+
* { externalId: 'f1', space: 's1', properties: { name: 'file-1' } },
|
|
19
|
+
* { externalId: 'f2', space: 's1', properties: { name: 'file-2' } },
|
|
20
|
+
* ];
|
|
21
|
+
*
|
|
22
|
+
* // To create a map, we first need entries - a list of [key, value] pairs
|
|
23
|
+
* const fileEntries = dmFiles.map((file) => [
|
|
24
|
+
* { externalId: file.externalId, space: file.space }, // This object will be a key for each entry
|
|
25
|
+
* file, // Each file object will be a value in the map
|
|
26
|
+
* ]);
|
|
27
|
+
*
|
|
28
|
+
* const filesMap = new StructMap(fileEntries);
|
|
29
|
+
*
|
|
30
|
+
* // Set new values
|
|
31
|
+
* const newFile = { externalId: 'f3', space: 's2', properties: { name: 'file-3' } };
|
|
32
|
+
*
|
|
33
|
+
* filesMap.set({ externalId: 'f3', space: 's2' }, newFile);
|
|
34
|
+
*
|
|
35
|
+
* // Get an existing value
|
|
36
|
+
* const file = filesMap.get({ space: 's2', externalId: 'f3' }); // By default, order of object properties is ignored
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* // Using a custom key serializer
|
|
42
|
+
*
|
|
43
|
+
* // Custom serializer that lowercases keys and values
|
|
44
|
+
* const lowerCaseSerializer: KeySerializer<PreferencesKey> = {
|
|
45
|
+
* serialize: (key) =>
|
|
46
|
+
* JSON.stringify({
|
|
47
|
+
* user: key.user.toLowerCase(),
|
|
48
|
+
* setting: key.setting.toLowerCase(),
|
|
49
|
+
* }),
|
|
50
|
+
* deserialize: (keyString) => JSON.parse(keyString),
|
|
51
|
+
* };
|
|
52
|
+
*
|
|
53
|
+
* // Create a StructMap with our custom serializer
|
|
54
|
+
* const preferences = new StructMap<PreferencesKey, string>([], lowerCaseSerializer);
|
|
55
|
+
*
|
|
56
|
+
* // Store preferences
|
|
57
|
+
* preferences.set({ user: 'Alice', setting: 'Theme' }, 'dark');
|
|
58
|
+
* preferences.set({ user: 'Bob', setting: 'Theme' }, 'light');
|
|
59
|
+
*
|
|
60
|
+
* // Retrieve values with keys of any casing
|
|
61
|
+
* console.log(preferences.get({ user: 'alice', setting: 'theme' })); // dark
|
|
62
|
+
* console.log(preferences.get({ user: 'BOB', setting: 'THEME' })); // light
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare class StructMap<K extends object, V> {
|
|
66
|
+
private map;
|
|
67
|
+
private serializer;
|
|
68
|
+
constructor(entries?: Iterable<[K, V]>, serializer?: KeySerializer<K>);
|
|
69
|
+
/**
|
|
70
|
+
* Returns the number of elements in the map.
|
|
71
|
+
*/
|
|
72
|
+
get size(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Removes all elements from the map.
|
|
75
|
+
*/
|
|
76
|
+
clear: () => void;
|
|
77
|
+
/**
|
|
78
|
+
* Removes an element associated with the given key and returns true if element existed, false otherwise.
|
|
79
|
+
*/
|
|
80
|
+
delete: (key: K) => boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Returns an iterable of key, value pairs for every entry in the map..
|
|
83
|
+
*/
|
|
84
|
+
entries(): IterableIterator<[K, V]>;
|
|
85
|
+
/**
|
|
86
|
+
* Executes a provided function once per each key/value pair in the Map, in insertion order.
|
|
87
|
+
*/
|
|
88
|
+
forEach: (callbackFn: (value: V, key: K, map: StructMap<K, V>) => void) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Returns an element associated with the given key, or undefined if the key doesn't exist.
|
|
91
|
+
*/
|
|
92
|
+
get: (key: K) => V | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Checks if an element with the given key exists in the map.
|
|
95
|
+
*/
|
|
96
|
+
has: (key: K) => boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Returns an iterable of keys in the map.
|
|
99
|
+
*/
|
|
100
|
+
keys(): IterableIterator<K>;
|
|
101
|
+
/**
|
|
102
|
+
* Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
|
|
103
|
+
* @returns this
|
|
104
|
+
*/
|
|
105
|
+
set: (key: K, value: V) => this;
|
|
106
|
+
/**
|
|
107
|
+
* Returns an iterable of values in the map.
|
|
108
|
+
*/
|
|
109
|
+
values: () => IterableIterator<V>;
|
|
110
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { stableStringify as e } from "./stableStringify.js";
|
|
2
|
+
//#region libs/shared/underscore/src/structMap/structMap.ts
|
|
3
|
+
var t = class {
|
|
4
|
+
constructor(e = [], t = n()) {
|
|
5
|
+
this.map = /* @__PURE__ */ new Map(), this.clear = () => this.map.clear(), this.delete = (e) => this.map.delete(this.serializer.serialize(e)), this.forEach = (e) => {
|
|
6
|
+
this.map.forEach((t, n) => {
|
|
7
|
+
e(t, this.serializer.deserialize(n), this);
|
|
8
|
+
});
|
|
9
|
+
}, this.get = (e) => this.map.get(this.serializer.serialize(e)), this.has = (e) => this.map.has(this.serializer.serialize(e)), this.set = (e, t) => (this.map.set(this.serializer.serialize(e), t), this), this.values = () => this.map.values(), this.serializer = t;
|
|
10
|
+
for (let [t, n] of e) this.set(t, n);
|
|
11
|
+
}
|
|
12
|
+
get size() {
|
|
13
|
+
return this.map.size;
|
|
14
|
+
}
|
|
15
|
+
*entries() {
|
|
16
|
+
for (let [e, t] of this.map.entries()) yield [this.serializer.deserialize(e), t];
|
|
17
|
+
}
|
|
18
|
+
*keys() {
|
|
19
|
+
for (let e of this.map.keys()) yield this.serializer.deserialize(e);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function n() {
|
|
23
|
+
return {
|
|
24
|
+
serialize: (t) => String(e(t)),
|
|
25
|
+
deserialize: JSON.parse
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { t as StructMap };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type DmsId = {
|
|
2
|
+
externalId: string;
|
|
3
|
+
space: string;
|
|
4
|
+
};
|
|
5
|
+
export type MockCogniteFile = DmsId & {
|
|
6
|
+
createdTime: number;
|
|
7
|
+
lastUpdatedTime: number;
|
|
8
|
+
name: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Streamlines creation of a DM CogniteFile-like mock instance by hiding unnecessary details and providing smart defaults.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createMockCogniteFile({ externalId, space, name, createdTime, lastUpdatedTime, }?: Partial<MockCogniteFile>): MockCogniteFile;
|
|
14
|
+
/** Helper to convert a DM-like object to a DmsId. */
|
|
15
|
+
export declare function toDmsId<T extends DmsId>(item: T): DmsId;
|
|
16
|
+
/** Helper to convert a list of DM-like items to a list of initial entries for StructMap. */
|
|
17
|
+
export declare function toDmsIdEntries<T extends DmsId>(items: T[]): [DmsId, T][];
|