@livestore/utils 0.0.0-snapshot-909cdd1ac2fd591945c2be2b0f53e14d87f3c9d4
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/dist/.tsbuildinfo.json +1 -0
- package/dist/Deferred.d.ts +10 -0
- package/dist/Deferred.d.ts.map +1 -0
- package/dist/Deferred.js +21 -0
- package/dist/Deferred.js.map +1 -0
- package/dist/NoopTracer.d.ts +10 -0
- package/dist/NoopTracer.d.ts.map +1 -0
- package/dist/NoopTracer.js +52 -0
- package/dist/NoopTracer.js.map +1 -0
- package/dist/base64.d.ts +13 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +117 -0
- package/dist/base64.js.map +1 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +28 -0
- package/dist/browser.js.map +1 -0
- package/dist/cuid/cuid.browser.d.ts +18 -0
- package/dist/cuid/cuid.browser.d.ts.map +1 -0
- package/dist/cuid/cuid.browser.js +80 -0
- package/dist/cuid/cuid.browser.js.map +1 -0
- package/dist/cuid/cuid.node.d.ts +18 -0
- package/dist/cuid/cuid.node.d.ts.map +1 -0
- package/dist/cuid/cuid.node.js +83 -0
- package/dist/cuid/cuid.node.js.map +1 -0
- package/dist/effect/Effect.d.ts +28 -0
- package/dist/effect/Effect.d.ts.map +1 -0
- package/dist/effect/Effect.js +82 -0
- package/dist/effect/Effect.js.map +1 -0
- package/dist/effect/Error.d.ts +11 -0
- package/dist/effect/Error.d.ts.map +1 -0
- package/dist/effect/Error.js +7 -0
- package/dist/effect/Error.js.map +1 -0
- package/dist/effect/Schedule.d.ts +4 -0
- package/dist/effect/Schedule.d.ts.map +1 -0
- package/dist/effect/Schedule.js +5 -0
- package/dist/effect/Schedule.js.map +1 -0
- package/dist/effect/Scheduler.d.ts +4 -0
- package/dist/effect/Scheduler.d.ts.map +1 -0
- package/dist/effect/Scheduler.js +10 -0
- package/dist/effect/Scheduler.js.map +1 -0
- package/dist/effect/Schema/debug-diff.d.ts +12 -0
- package/dist/effect/Schema/debug-diff.d.ts.map +1 -0
- package/dist/effect/Schema/debug-diff.js +51 -0
- package/dist/effect/Schema/debug-diff.js.map +1 -0
- package/dist/effect/Schema/debug-diff.test.d.ts +2 -0
- package/dist/effect/Schema/debug-diff.test.d.ts.map +1 -0
- package/dist/effect/Schema/debug-diff.test.js +91 -0
- package/dist/effect/Schema/debug-diff.test.js.map +1 -0
- package/dist/effect/Schema/index.d.ts +18 -0
- package/dist/effect/Schema/index.d.ts.map +1 -0
- package/dist/effect/Schema/index.js +29 -0
- package/dist/effect/Schema/index.js.map +1 -0
- package/dist/effect/Schema/msgpack.d.ts +3 -0
- package/dist/effect/Schema/msgpack.d.ts.map +1 -0
- package/dist/effect/Schema/msgpack.js +7 -0
- package/dist/effect/Schema/msgpack.js.map +1 -0
- package/dist/effect/ServiceContext.d.ts +37 -0
- package/dist/effect/ServiceContext.d.ts.map +1 -0
- package/dist/effect/ServiceContext.js +55 -0
- package/dist/effect/ServiceContext.js.map +1 -0
- package/dist/effect/Stream.d.ts +10 -0
- package/dist/effect/Stream.d.ts.map +1 -0
- package/dist/effect/Stream.js +17 -0
- package/dist/effect/Stream.js.map +1 -0
- package/dist/effect/SubscriptionRef.d.ts +11 -0
- package/dist/effect/SubscriptionRef.d.ts.map +1 -0
- package/dist/effect/SubscriptionRef.js +5 -0
- package/dist/effect/SubscriptionRef.js.map +1 -0
- package/dist/effect/WebChannel.d.ts +30 -0
- package/dist/effect/WebChannel.d.ts.map +1 -0
- package/dist/effect/WebChannel.js +44 -0
- package/dist/effect/WebChannel.js.map +1 -0
- package/dist/effect/WebLock.d.ts +9 -0
- package/dist/effect/WebLock.d.ts.map +1 -0
- package/dist/effect/WebLock.js +73 -0
- package/dist/effect/WebLock.js.map +1 -0
- package/dist/effect/index.d.ts +21 -0
- package/dist/effect/index.d.ts.map +1 -0
- package/dist/effect/index.js +20 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/fast-deep-equal.d.ts +2 -0
- package/dist/fast-deep-equal.d.ts.map +1 -0
- package/dist/fast-deep-equal.js +79 -0
- package/dist/fast-deep-equal.js.map +1 -0
- package/dist/global.d.ts +5 -0
- package/dist/global.d.ts.map +1 -0
- package/dist/global.js +2 -0
- package/dist/global.js.map +1 -0
- package/dist/guards.d.ts +6 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +6 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +176 -0
- package/dist/index.js.map +1 -0
- package/dist/misc.d.ts +3 -0
- package/dist/misc.d.ts.map +1 -0
- package/dist/misc.js +24 -0
- package/dist/misc.js.map +1 -0
- package/dist/nanoid/index.d.ts +2 -0
- package/dist/nanoid/index.d.ts.map +1 -0
- package/dist/nanoid/index.js +2 -0
- package/dist/nanoid/index.js.map +1 -0
- package/dist/object/index.d.ts +10 -0
- package/dist/object/index.d.ts.map +1 -0
- package/dist/object/index.js +10 -0
- package/dist/object/index.js.map +1 -0
- package/dist/object/omit.d.ts +3 -0
- package/dist/object/omit.d.ts.map +1 -0
- package/dist/object/omit.js +14 -0
- package/dist/object/omit.js.map +1 -0
- package/dist/object/pick.d.ts +14 -0
- package/dist/object/pick.d.ts.map +1 -0
- package/dist/object/pick.js +17 -0
- package/dist/object/pick.js.map +1 -0
- package/dist/promise.d.ts +6 -0
- package/dist/promise.d.ts.map +1 -0
- package/dist/promise.js +27 -0
- package/dist/promise.js.map +1 -0
- package/dist/set.d.ts +2 -0
- package/dist/set.d.ts.map +1 -0
- package/dist/set.js +10 -0
- package/dist/set.js.map +1 -0
- package/dist/string.d.ts +5 -0
- package/dist/string.d.ts.map +1 -0
- package/dist/string.js +8 -0
- package/dist/string.js.map +1 -0
- package/dist/time.d.ts +12 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +22 -0
- package/dist/time.js.map +1 -0
- package/package.json +74 -0
- package/src/Deferred.ts +24 -0
- package/src/NoopTracer.ts +75 -0
- package/src/ambient.d.ts +3 -0
- package/src/base64.ts +123 -0
- package/src/browser.ts +32 -0
- package/src/cuid/cuid.browser.ts +95 -0
- package/src/cuid/cuid.node.ts +103 -0
- package/src/effect/Effect.ts +180 -0
- package/src/effect/Error.ts +6 -0
- package/src/effect/Schedule.ts +10 -0
- package/src/effect/Scheduler.ts +14 -0
- package/src/effect/Schema/debug-diff.test.ts +102 -0
- package/src/effect/Schema/debug-diff.ts +58 -0
- package/src/effect/Schema/index.ts +58 -0
- package/src/effect/Schema/msgpack.ts +8 -0
- package/src/effect/ServiceContext.ts +108 -0
- package/src/effect/Stream.ts +63 -0
- package/src/effect/SubscriptionRef.ts +22 -0
- package/src/effect/WebChannel.ts +116 -0
- package/src/effect/WebLock.ts +95 -0
- package/src/effect/index.ts +91 -0
- package/src/fast-deep-equal.ts +72 -0
- package/src/global.ts +5 -0
- package/src/guards.ts +8 -0
- package/src/index.ts +240 -0
- package/src/misc.ts +26 -0
- package/src/nanoid/index.ts +1 -0
- package/src/object/index.ts +24 -0
- package/src/object/omit.ts +17 -0
- package/src/object/pick.ts +27 -0
- package/src/promise.ts +43 -0
- package/src/set.ts +10 -0
- package/src/string.ts +9 -0
- package/src/time.ts +25 -0
- package/tsconfig.json +10 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
export * from './string.js'
|
|
2
|
+
export * from './guards.js'
|
|
3
|
+
export * from './object/index.js'
|
|
4
|
+
export * from './promise.js'
|
|
5
|
+
export * from './time.js'
|
|
6
|
+
export * from './NoopTracer.js'
|
|
7
|
+
export * from './set.js'
|
|
8
|
+
export * from './browser.js'
|
|
9
|
+
export * from './Deferred.js'
|
|
10
|
+
export * from './misc.js'
|
|
11
|
+
export * from './fast-deep-equal.js'
|
|
12
|
+
export * as base64 from './base64.js'
|
|
13
|
+
export { default as prettyBytes } from 'pretty-bytes'
|
|
14
|
+
|
|
15
|
+
import type * as otel from '@opentelemetry/api'
|
|
16
|
+
|
|
17
|
+
import { objectToString } from './misc.js'
|
|
18
|
+
|
|
19
|
+
export type Prettify<T> = T extends infer U ? { [K in keyof U]: Prettify<U[K]> } : never
|
|
20
|
+
export type PrettifyFlat<T> = T extends infer U ? { [K in keyof U]: U[K] } : never
|
|
21
|
+
|
|
22
|
+
export type TypeEq<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false
|
|
23
|
+
|
|
24
|
+
/** `A` is subtype of `B` */
|
|
25
|
+
export type IsSubtype<A, B> = A extends B ? true : false
|
|
26
|
+
export type AssertTrue<T extends true> = T
|
|
27
|
+
|
|
28
|
+
export type Writeable<T> = { -readonly [P in keyof T]: T[P] }
|
|
29
|
+
export type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> }
|
|
30
|
+
|
|
31
|
+
export type Primitive = null | undefined | string | number | boolean | symbol | bigint
|
|
32
|
+
|
|
33
|
+
export type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>)
|
|
34
|
+
|
|
35
|
+
export type GetValForKey<T, K> = K extends keyof T ? T[K] : never
|
|
36
|
+
|
|
37
|
+
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
38
|
+
|
|
39
|
+
export const ref = <T>(val: T): { current: T } => ({ current: val })
|
|
40
|
+
|
|
41
|
+
export const times = (n: number, fn: (index: number) => {}): void => {
|
|
42
|
+
for (let i = 0; i < n; i++) {
|
|
43
|
+
fn(i)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const debugCatch = <T>(try_: () => T): T => {
|
|
48
|
+
try {
|
|
49
|
+
return try_()
|
|
50
|
+
} catch (e: any) {
|
|
51
|
+
debugger
|
|
52
|
+
throw e
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const recRemoveUndefinedValues = (val: any): void => {
|
|
57
|
+
if (Array.isArray(val)) {
|
|
58
|
+
val.forEach(recRemoveUndefinedValues)
|
|
59
|
+
} else if (typeof val === 'object') {
|
|
60
|
+
Object.keys(val).forEach((key) => {
|
|
61
|
+
if (val[key] === undefined) {
|
|
62
|
+
delete val[key]
|
|
63
|
+
} else {
|
|
64
|
+
recRemoveUndefinedValues(val[key])
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const prop =
|
|
71
|
+
<T extends {}, K extends keyof T>(key: K) =>
|
|
72
|
+
(obj: T): T[K] =>
|
|
73
|
+
obj[key]
|
|
74
|
+
|
|
75
|
+
export const capitalizeFirstLetter = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1)
|
|
76
|
+
|
|
77
|
+
export const isReadonlyArray = <I, T>(value: ReadonlyArray<I> | T): value is ReadonlyArray<I> => Array.isArray(value)
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Use this to make assertion at end of if-else chain that all members of a
|
|
81
|
+
* union have been accounted for.
|
|
82
|
+
*/
|
|
83
|
+
/* eslint-disable-next-line prefer-arrow/prefer-arrow-functions */
|
|
84
|
+
export function casesHandled(unexpectedCase: never): never {
|
|
85
|
+
debugger
|
|
86
|
+
throw new Error(`A case was not handled for value: ${truncate(objectToString(unexpectedCase), 1000)}`)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const shouldNeverHappen = (msg?: string, ...args: any[]): never => {
|
|
90
|
+
console.error(msg, ...args)
|
|
91
|
+
if (isDev()) {
|
|
92
|
+
debugger
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw new Error(`This should never happen: ${msg}`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const assertNever = (failIfFalse: boolean, msg?: string): void => {
|
|
99
|
+
if (failIfFalse === false) {
|
|
100
|
+
debugger
|
|
101
|
+
throw new Error(`This should never happen: ${msg}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const debuggerPipe = <T>(val: T): T => {
|
|
106
|
+
debugger
|
|
107
|
+
return val
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const truncate = (str: string, length: number): string => {
|
|
111
|
+
if (str.length > length) {
|
|
112
|
+
return str.slice(0, length) + '...'
|
|
113
|
+
} else {
|
|
114
|
+
return str
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const notYetImplemented = (msg?: string): never => {
|
|
119
|
+
debugger
|
|
120
|
+
throw new Error(`Not yet implemented: ${msg}`)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const noop = () => {}
|
|
124
|
+
|
|
125
|
+
export type Thunk<T> = () => T
|
|
126
|
+
|
|
127
|
+
export const unwrapThunk = <T>(_: T | (() => T)): T => {
|
|
128
|
+
if (typeof _ === 'function') {
|
|
129
|
+
return (_ as any)()
|
|
130
|
+
} else {
|
|
131
|
+
return _
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export type NullableFieldsToOptional<T> = PrettifyFlat<
|
|
136
|
+
Partial<T> & {
|
|
137
|
+
[K in keyof T as null extends T[K] ? K : never]?: Exclude<T[K], null>
|
|
138
|
+
} & {
|
|
139
|
+
[K in keyof T as null extends T[K] ? never : K]: T[K]
|
|
140
|
+
}
|
|
141
|
+
>
|
|
142
|
+
|
|
143
|
+
/** `end` is not included */
|
|
144
|
+
export const range = (start: number, end: number): number[] => {
|
|
145
|
+
const length = end - start
|
|
146
|
+
return Array.from({ length }, (_, i) => start + i)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const throttle = (fn: () => void, ms: number) => {
|
|
150
|
+
let shouldWait = false
|
|
151
|
+
let shouldCallAgain = false
|
|
152
|
+
|
|
153
|
+
const timeoutFunc = () => {
|
|
154
|
+
if (shouldCallAgain) {
|
|
155
|
+
fn()
|
|
156
|
+
shouldCallAgain = false
|
|
157
|
+
setTimeout(timeoutFunc, ms)
|
|
158
|
+
} else {
|
|
159
|
+
shouldWait = false
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return () => {
|
|
164
|
+
if (shouldWait) {
|
|
165
|
+
shouldCallAgain = true
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
fn()
|
|
170
|
+
shouldWait = true
|
|
171
|
+
setTimeout(timeoutFunc, ms)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const getTraceParentHeader = (parentSpan: otel.Span) => {
|
|
176
|
+
const spanContext = parentSpan.spanContext()
|
|
177
|
+
// Format: {version}-{trace_id}-{span_id}-{trace_flags}
|
|
178
|
+
// https://www.w3.org/TR/trace-context/#examples-of-http-traceparent-headers
|
|
179
|
+
return `00-${spanContext.traceId}-${spanContext.spanId}-01`
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const assertTag = <TObj extends { _tag: string }, TTag extends TObj['_tag']>(
|
|
183
|
+
obj: TObj,
|
|
184
|
+
tag: TTag,
|
|
185
|
+
): Extract<TObj, { _tag: TTag }> => {
|
|
186
|
+
if (obj._tag !== tag) {
|
|
187
|
+
throw new Error(`Expected tag ${tag} but got ${obj._tag}`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return obj as any
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export const memoizeByStringifyArgs = <T extends (...args: any[]) => any>(fn: T): T => {
|
|
194
|
+
const cache = new Map<string, ReturnType<T>>()
|
|
195
|
+
|
|
196
|
+
return ((...args: any[]) => {
|
|
197
|
+
const key = JSON.stringify(args)
|
|
198
|
+
if (cache.has(key)) {
|
|
199
|
+
return cache.get(key)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const result = fn(...args)
|
|
203
|
+
cache.set(key, result)
|
|
204
|
+
return result
|
|
205
|
+
}) as any
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const memoizeByRef = <T extends (arg: any) => any>(fn: T): T => {
|
|
209
|
+
const cache = new Map<Parameters<T>[0], ReturnType<T>>()
|
|
210
|
+
|
|
211
|
+
return ((arg: any) => {
|
|
212
|
+
if (cache.has(arg)) {
|
|
213
|
+
return cache.get(arg)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const result = fn(arg)
|
|
217
|
+
cache.set(arg, result)
|
|
218
|
+
return result
|
|
219
|
+
}) as any
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export const isNonEmptyString = (str: string | undefined | null): str is string => {
|
|
223
|
+
return typeof str === 'string' && str.length > 0
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const isPromise = (value: any): value is Promise<unknown> => typeof value?.then === 'function'
|
|
227
|
+
|
|
228
|
+
export const isIterable = <T>(value: any): value is Iterable<T> => typeof value?.[Symbol.iterator] === 'function'
|
|
229
|
+
|
|
230
|
+
export { objectToString as errorToString } from './misc.js'
|
|
231
|
+
|
|
232
|
+
const isDev = memoizeByRef(() => {
|
|
233
|
+
if (import.meta.env !== undefined) {
|
|
234
|
+
return import.meta.env.DEV || import.meta.env.VITE_DEV
|
|
235
|
+
} else if (typeof process !== 'undefined' && process.env !== undefined) {
|
|
236
|
+
return process.env.DEV
|
|
237
|
+
} else {
|
|
238
|
+
return false
|
|
239
|
+
}
|
|
240
|
+
})
|
package/src/misc.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const objectToString = (error: any): string => {
|
|
2
|
+
const str = error?.toString()
|
|
3
|
+
if (str !== '[object Object]') return str
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
return JSON.stringify(error, null, 2)
|
|
7
|
+
} catch (e: any) {
|
|
8
|
+
console.log(error)
|
|
9
|
+
|
|
10
|
+
return 'Error while printing error: ' + e
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const tryAsFunctionAndNew = <TArg, TResult>(
|
|
15
|
+
fnOrConstructor: ((arg: TArg) => TResult) | (new (arg: TArg) => TResult),
|
|
16
|
+
arg: TArg,
|
|
17
|
+
): TResult => {
|
|
18
|
+
try {
|
|
19
|
+
// @ts-expect-error try out as constructor
|
|
20
|
+
return new fnOrConstructor(arg)
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
22
|
+
} catch (e) {
|
|
23
|
+
// @ts-expect-error try out as function
|
|
24
|
+
return fnOrConstructor(arg)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { nanoid } from 'nanoid'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { pipe } from 'effect'
|
|
2
|
+
|
|
3
|
+
export * from './pick.js'
|
|
4
|
+
export * from './omit.js'
|
|
5
|
+
|
|
6
|
+
type ValueOfRecord<R extends Record<any, any>> = R extends Record<any, infer V> ? V : never
|
|
7
|
+
|
|
8
|
+
export const mapObjectValues = <O_In extends Record<string, any>, V_Out>(
|
|
9
|
+
obj: O_In,
|
|
10
|
+
mapValue: (key: keyof O_In, val: ValueOfRecord<O_In>) => V_Out,
|
|
11
|
+
): { [K in keyof O_In]: V_Out } => {
|
|
12
|
+
const mappedEntries = Object.entries(obj).map(([key, val]) => [key, mapValue(key as keyof O_In, val)] as const)
|
|
13
|
+
return Object.fromEntries(mappedEntries) as any
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][]
|
|
17
|
+
|
|
18
|
+
export const objectEntries = <T extends Record<string, any>>(obj: T): Entries<T> => Object.entries(obj) as Entries<T>
|
|
19
|
+
|
|
20
|
+
export const keyObjectFromObject = <TObj extends Record<string, any>>(obj: TObj): { [K in keyof TObj]: K } =>
|
|
21
|
+
pipe(
|
|
22
|
+
objectEntries(obj).map(([k]) => [k, k]),
|
|
23
|
+
Object.fromEntries,
|
|
24
|
+
) as any
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// type ConvertUndefined<T> = OrUndefined<{ [K in keyof T as undefined extends T[K] ? K : never]-?: T[K] }>
|
|
2
|
+
// type OrUndefined<T> = { [K in keyof T]: T[K] | undefined }
|
|
3
|
+
// type PickRequired<T> = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] }
|
|
4
|
+
// type ConvertPick<T> = ConvertUndefined<T> & PickRequired<T>
|
|
5
|
+
|
|
6
|
+
/** Returns a shallowly cloned object with the provided keys omitted */
|
|
7
|
+
export const omit = <Obj extends Record<string, any>, Keys extends keyof Obj>(
|
|
8
|
+
obj: Obj,
|
|
9
|
+
keys: Keys[],
|
|
10
|
+
): Omit<Obj, Keys> => {
|
|
11
|
+
return Object.keys(obj).reduce((acc, key: any) => {
|
|
12
|
+
if (!keys.includes(key)) {
|
|
13
|
+
acc[key] = (obj as any)[key]
|
|
14
|
+
}
|
|
15
|
+
return acc
|
|
16
|
+
}, {} as any)
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
type ConvertUndefined<T> = OrUndefined<{ [K in keyof T as undefined extends T[K] ? K : never]-?: T[K] }>
|
|
2
|
+
type OrUndefined<T> = { [K in keyof T]: T[K] | undefined }
|
|
3
|
+
type PickRequired<T> = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] }
|
|
4
|
+
type ConvertPick<T> = ConvertUndefined<T> & PickRequired<T>
|
|
5
|
+
|
|
6
|
+
export const pick = <Obj, Keys extends keyof Obj>(obj: Obj, keys: Keys[]): ConvertPick<{ [K in Keys]: Obj[K] }> => {
|
|
7
|
+
return keys.reduce((acc, key) => {
|
|
8
|
+
acc[key] = obj[key]
|
|
9
|
+
return acc
|
|
10
|
+
}, {} as any)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const pickAllOrElse = <Obj, Keys extends keyof Obj, TElse>(
|
|
14
|
+
obj: Obj,
|
|
15
|
+
keys: Keys[],
|
|
16
|
+
elseValue: TElse,
|
|
17
|
+
): ConvertPick<{ [K in Keys]: NonNullable<Obj[K]> }> | TElse => {
|
|
18
|
+
const ret = {} as any
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
if (obj[key] === undefined) {
|
|
21
|
+
return elseValue
|
|
22
|
+
}
|
|
23
|
+
ret[key] = obj[key]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return ret
|
|
27
|
+
}
|
package/src/promise.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Promise.all + Array.map */
|
|
2
|
+
export const promiseMap = <T, Res>(arr: T[], map: (el: T, index?: number) => Res | Promise<Res>) =>
|
|
3
|
+
Promise.all(arr.map(map))
|
|
4
|
+
|
|
5
|
+
export const promiseMapDict = async <T, Res>(
|
|
6
|
+
dict: Record<string, T>,
|
|
7
|
+
map: (el: T, index?: number) => Res | Promise<Res>,
|
|
8
|
+
): Promise<Record<string, Res>> => {
|
|
9
|
+
const mappedEntries = await Promise.all(Object.entries(dict).map(async ([key, val]) => [key, await map(val)]))
|
|
10
|
+
return Object.fromEntries(mappedEntries)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const promiseMapToDict = async <T, Res>(
|
|
14
|
+
arr: T[],
|
|
15
|
+
mapValue: (el: T, index?: number) => Res | Promise<Res>,
|
|
16
|
+
mapKey: (el: T, index?: number) => string,
|
|
17
|
+
): Promise<Record<string, Res>> => {
|
|
18
|
+
const mappedEntries = await Promise.all(arr.map(async (el, index) => [mapKey(el, index), await mapValue(el, index)]))
|
|
19
|
+
|
|
20
|
+
return Object.fromEntries(mappedEntries)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const promiseMapPool = async <T, Res>(
|
|
24
|
+
arr: T[],
|
|
25
|
+
map: (el: T, index?: number) => Promise<Res>,
|
|
26
|
+
poolLimit: number,
|
|
27
|
+
): Promise<Res[]> => {
|
|
28
|
+
const ret: Promise<Res>[] = []
|
|
29
|
+
const executing: Promise<Res>[] = []
|
|
30
|
+
for (const [index, item] of arr.entries()) {
|
|
31
|
+
const p = Promise.resolve().then(() => map(item, index))
|
|
32
|
+
ret.push(p)
|
|
33
|
+
|
|
34
|
+
if (poolLimit <= arr.length) {
|
|
35
|
+
const e: any = p.then(() => executing.splice(executing.indexOf(e), 1))
|
|
36
|
+
executing.push(e)
|
|
37
|
+
if (executing.length >= poolLimit) {
|
|
38
|
+
await Promise.race(executing)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return Promise.all(ret)
|
|
43
|
+
}
|
package/src/set.ts
ADDED
package/src/string.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const lowercaseFirstChar = (str: string) => str.charAt(0).toLowerCase() + str.slice(1)
|
|
2
|
+
export const uppercaseFirstChar = (str: string) => str.charAt(0).toUpperCase() + str.slice(1)
|
|
3
|
+
|
|
4
|
+
/** Indents a string each line by `n` characters (default: spaces) */
|
|
5
|
+
export const indent = (str: string, n: number, char = ' '): string =>
|
|
6
|
+
str
|
|
7
|
+
.split('\n')
|
|
8
|
+
.map((line) => char.repeat(n) + line)
|
|
9
|
+
.join('\n')
|
package/src/time.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const minuteInMs = 1000 * 60
|
|
2
|
+
|
|
3
|
+
export const time = {
|
|
4
|
+
ms: 1,
|
|
5
|
+
sec: 1000,
|
|
6
|
+
min: 60 * 1000,
|
|
7
|
+
hour: 60 * 60 * 1000,
|
|
8
|
+
day: 24 * 60 * 60 * 1000,
|
|
9
|
+
week: 7 * 24 * 60 * 60 * 1000,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Returns a string of format `m:ss` / `mm:ss` / `h:mm:ss` / ... */
|
|
13
|
+
export const msAsTimeString = (ms: number) => {
|
|
14
|
+
const seconds = Math.floor(ms / 1000)
|
|
15
|
+
const minutes = Math.floor(seconds / 60)
|
|
16
|
+
const hours = Math.floor(minutes / 60)
|
|
17
|
+
const remainingSeconds = (seconds % 60).toString().padStart(2, '0')
|
|
18
|
+
const remainingMinutes = hours > 0 ? (minutes % 60).toString().padStart(2, '0') : minutes % 60
|
|
19
|
+
|
|
20
|
+
const timeString = [hours > 0 ? `${hours}:` : '', `${remainingMinutes}:`, `${remainingSeconds}`]
|
|
21
|
+
.filter((val) => val !== '')
|
|
22
|
+
.join('')
|
|
23
|
+
|
|
24
|
+
return timeString
|
|
25
|
+
}
|
package/tsconfig.json
ADDED