@orioro/util 0.2.0 → 0.3.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/dist/PromiseLikeEventEmitter/index.d.ts +10 -0
- package/dist/array/arrayChunk.d.ts +1 -0
- package/dist/array/index.d.ts +1 -0
- package/dist/debug/debugFn/index.d.ts +15 -0
- package/dist/debug/debugFn/util.d.ts +1 -0
- package/dist/debug/debugFn.d.ts +15 -0
- package/dist/debug/deepFreeze.d.ts +5 -0
- package/dist/debug/index.d.ts +3 -0
- package/dist/debug/wait.d.ts +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.mjs +11 -11
- package/dist/interpolate/index.d.ts +14 -0
- package/dist/maybeFn.d.ts +1 -0
- package/dist/pickPaths/index.d.ts +4 -0
- package/dist/promise/batchFn.d.ts +47 -0
- package/dist/promise/index.d.ts +3 -0
- package/dist/promise/promiseReduce.d.ts +1 -0
- package/dist/promise/resolveNestedPromises.d.ts +14 -0
- package/dist/promise/types.d.ts +2 -0
- package/dist/resolvePaths/index.d.ts +4 -0
- package/dist/switchValue.d.ts +9 -0
- package/dist/typeOf.d.ts +7 -0
- package/dist/validate/async/index.d.ts +18 -0
- package/dist/validate/async/validateAsyncFn.d.ts +2 -0
- package/dist/validate/async/validators/index.d.ts +2 -0
- package/dist/validate/async/validators/logical.d.ts +4 -0
- package/dist/validate/async/validators/shape.d.ts +7 -0
- package/dist/validate/async/validators/tmpand.d.ts +2 -0
- package/dist/validate/async/validators/tmpor.d.ts +2 -0
- package/dist/validate/common/ValidationError.d.ts +11 -0
- package/dist/validate/common/util/defaultErrorMessage.d.ts +2 -0
- package/dist/validate/common/util/index.d.ts +3 -0
- package/dist/validate/common/util/parseValidatorInput.d.ts +5 -0
- package/dist/validate/common/util/resolveValidationResult.d.ts +6 -0
- package/dist/validate/common/validators/index.d.ts +1 -0
- package/dist/validate/common/validators/type.d.ts +9 -0
- package/dist/validate/index.d.ts +3 -0
- package/dist/validate/sync/index.d.ts +18 -0
- package/dist/validate/sync/validateSyncFn.d.ts +2 -0
- package/dist/validate/sync/validators/index.d.ts +2 -0
- package/dist/validate/sync/validators/logical.d.ts +4 -0
- package/dist/validate/sync/validators/shape.d.ts +7 -0
- package/dist/validate/types/async.d.ts +5 -0
- package/dist/validate/types/common.d.ts +27 -0
- package/dist/validate/types/index.d.ts +3 -0
- package/dist/validate/types/sync.d.ts +5 -0
- package/package.json +6 -2
- package/babel.config.cjs +0 -13
- package/coverage/clover.xml +0 -491
- package/coverage/coverage-final.json +0 -29
- package/coverage/lcov-report/ValidationError.ts.html +0 -184
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -296
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov-report/src/debug/deepFreeze.ts.html +0 -157
- package/coverage/lcov-report/src/debug/index.html +0 -146
- package/coverage/lcov-report/src/debug/index.ts.html +0 -91
- package/coverage/lcov-report/src/debug/wait.ts.html +0 -127
- package/coverage/lcov-report/src/index.html +0 -131
- package/coverage/lcov-report/src/interpolate/index.html +0 -116
- package/coverage/lcov-report/src/interpolate/index.ts.html +0 -277
- package/coverage/lcov-report/src/maybeFn.ts.html +0 -94
- package/coverage/lcov-report/src/promise/index.html +0 -146
- package/coverage/lcov-report/src/promise/index.ts.html +0 -91
- package/coverage/lcov-report/src/promise/promiseReduce.ts.html +0 -130
- package/coverage/lcov-report/src/promise/resolveNestedPromises.ts.html +0 -271
- package/coverage/lcov-report/src/switchValue.ts.html +0 -253
- package/coverage/lcov-report/src/typeOf.ts.html +0 -328
- package/coverage/lcov-report/src/validate/ValidationError.ts.html +0 -184
- package/coverage/lcov-report/src/validate/async/index.html +0 -131
- package/coverage/lcov-report/src/validate/async/index.ts.html +0 -241
- package/coverage/lcov-report/src/validate/async/parseValidator.ts.html +0 -136
- package/coverage/lcov-report/src/validate/async/validateAsyncFn.ts.html +0 -208
- package/coverage/lcov-report/src/validate/async/validators/and.ts.html +0 -154
- package/coverage/lcov-report/src/validate/async/validators/index.html +0 -146
- package/coverage/lcov-report/src/validate/async/validators/index.ts.html +0 -91
- package/coverage/lcov-report/src/validate/async/validators/logical.ts.html +0 -253
- package/coverage/lcov-report/src/validate/async/validators/or.ts.html +0 -151
- package/coverage/lcov-report/src/validate/async/validators/shape.ts.html +0 -565
- package/coverage/lcov-report/src/validate/common/ValidationError.ts.html +0 -184
- package/coverage/lcov-report/src/validate/common/index.html +0 -116
- package/coverage/lcov-report/src/validate/common/util/defaultErrorMessage.ts.html +0 -163
- package/coverage/lcov-report/src/validate/common/util/index.html +0 -161
- package/coverage/lcov-report/src/validate/common/util/index.ts.html +0 -94
- package/coverage/lcov-report/src/validate/common/util/parseValidator.ts.html +0 -316
- package/coverage/lcov-report/src/validate/common/util/parseValidatorInput.ts.html +0 -316
- package/coverage/lcov-report/src/validate/common/util/resolveValidationResult.ts.html +0 -277
- package/coverage/lcov-report/src/validate/common/util/validatorParser.ts.html +0 -316
- package/coverage/lcov-report/src/validate/common/validators/index.html +0 -131
- package/coverage/lcov-report/src/validate/common/validators/index.ts.html +0 -88
- package/coverage/lcov-report/src/validate/common/validators/type.ts.html +0 -388
- package/coverage/lcov-report/src/validate/fmtValidationResult.ts.html +0 -268
- package/coverage/lcov-report/src/validate/index.html +0 -116
- package/coverage/lcov-report/src/validate/index.ts.html +0 -94
- package/coverage/lcov-report/src/validate/makeValidate.ts.html +0 -634
- package/coverage/lcov-report/src/validate/specUtil/commonTests.js.html +0 -1324
- package/coverage/lcov-report/src/validate/specUtil/index.html +0 -116
- package/coverage/lcov-report/src/validate/sync/index.html +0 -131
- package/coverage/lcov-report/src/validate/sync/index.ts.html +0 -244
- package/coverage/lcov-report/src/validate/sync/parseValidator.ts.html +0 -136
- package/coverage/lcov-report/src/validate/sync/validateSyncFn.ts.html +0 -223
- package/coverage/lcov-report/src/validate/sync/validators/and.ts.html +0 -148
- package/coverage/lcov-report/src/validate/sync/validators/index.html +0 -146
- package/coverage/lcov-report/src/validate/sync/validators/index.ts.html +0 -91
- package/coverage/lcov-report/src/validate/sync/validators/logical.ts.html +0 -226
- package/coverage/lcov-report/src/validate/sync/validators/or.ts.html +0 -130
- package/coverage/lcov-report/src/validate/sync/validators/shape.ts.html +0 -523
- package/coverage/lcov-report/src/validate/sync/validators/type.ts.html +0 -154
- package/coverage/lcov-report/src/validate/syncValidators/and.ts.html +0 -157
- package/coverage/lcov-report/src/validate/syncValidators/index.html +0 -176
- package/coverage/lcov-report/src/validate/syncValidators/index.ts.html +0 -97
- package/coverage/lcov-report/src/validate/syncValidators/or.ts.html +0 -127
- package/coverage/lcov-report/src/validate/syncValidators/shape.ts.html +0 -559
- package/coverage/lcov-report/src/validate/syncValidators/string.ts.html +0 -163
- package/coverage/lcov-report/src/validate/syncValidators/type.ts.html +0 -154
- package/coverage/lcov-report/src/validate/util/defaultErrorMessage.ts.html +0 -169
- package/coverage/lcov-report/src/validate/util/index.html +0 -146
- package/coverage/lcov-report/src/validate/util/index.ts.html +0 -91
- package/coverage/lcov-report/src/validate/util/resolveValidationResult.ts.html +0 -253
- package/coverage/lcov-report/src/validate/validate.ts.html +0 -220
- package/coverage/lcov-report/src/validate/validateAsync.ts.html +0 -220
- package/coverage/lcov-report/src/validate/validators/and.ts.html +0 -157
- package/coverage/lcov-report/src/validate/validators/index.html +0 -176
- package/coverage/lcov-report/src/validate/validators/index.ts.html +0 -97
- package/coverage/lcov-report/src/validate/validators/or.ts.html +0 -127
- package/coverage/lcov-report/src/validate/validators/shape.ts.html +0 -541
- package/coverage/lcov-report/src/validate/validators/type.ts.html +0 -154
- package/coverage/lcov-report/src/validate_/ValidationError.ts.html +0 -184
- package/coverage/lcov-report/src/validate_/fmtValidationResult.ts.html +0 -268
- package/coverage/lcov-report/src/validate_/index.html +0 -161
- package/coverage/lcov-report/src/validate_/makeValidate.ts.html +0 -634
- package/coverage/lcov-report/src/validate_/validate.ts.html +0 -220
- package/coverage/lcov-report/switchValue.ts.html +0 -253
- package/coverage/lcov-report/typeOf.ts.html +0 -331
- package/coverage/lcov-report/validate.ts.html +0 -757
- package/coverage/lcov.info +0 -1056
- package/jest.config.js +0 -6
- package/rollup.config.mjs +0 -6
- package/src/PromiseLikeEventEmitter/index.ts +0 -35
- package/src/array/arrayChunk.ts +0 -7
- package/src/array/index.ts +0 -1
- package/src/debug/debugFn/index.ts +0 -48
- package/src/debug/debugFn/util.ts +0 -27
- package/src/debug/deepFreeze.ts +0 -26
- package/src/debug/index.ts +0 -3
- package/src/debug/wait.ts +0 -14
- package/src/index.ts +0 -9
- package/src/interpolate/index.spec.ts +0 -20
- package/src/interpolate/index.ts +0 -64
- package/src/maybeFn.ts +0 -3
- package/src/promise/batchFn.spec.ts +0 -92
- package/src/promise/batchFn.ts +0 -176
- package/src/promise/index.ts +0 -3
- package/src/promise/promiseReduce.ts +0 -15
- package/src/promise/resolveNestedPromises.spec.ts +0 -205
- package/src/promise/resolveNestedPromises.ts +0 -83
- package/src/promise/types.ts +0 -2
- package/src/resolvePaths/index.spec.ts +0 -42
- package/src/resolvePaths/index.ts +0 -21
- package/src/switchValue.spec.ts +0 -30
- package/src/switchValue.ts +0 -59
- package/src/typeOf.spec.ts +0 -47
- package/src/typeOf.ts +0 -81
- package/src/validate/__snapshots__/index.spec.ts.snap +0 -9
- package/src/validate/async/index.spec.ts +0 -236
- package/src/validate/async/index.ts +0 -52
- package/src/validate/async/validateAsyncFn.ts +0 -41
- package/src/validate/async/validators/index.ts +0 -2
- package/src/validate/async/validators/logical.ts +0 -56
- package/src/validate/async/validators/shape.ts +0 -160
- package/src/validate/async/validators/tmpand.ts +0 -24
- package/src/validate/async/validators/tmpor.ts +0 -21
- package/src/validate/common/ValidationError.ts +0 -33
- package/src/validate/common/util/defaultErrorMessage.ts +0 -26
- package/src/validate/common/util/index.ts +0 -3
- package/src/validate/common/util/parseValidatorInput.ts +0 -77
- package/src/validate/common/util/resolveValidationResult.ts +0 -64
- package/src/validate/common/validators/index.ts +0 -1
- package/src/validate/common/validators/type.ts +0 -101
- package/src/validate/index.spec.ts +0 -5
- package/src/validate/index.ts +0 -3
- package/src/validate/specUtil/commonTests.js +0 -413
- package/src/validate/sync/index.spec.ts +0 -81
- package/src/validate/sync/index.ts +0 -53
- package/src/validate/sync/validateSyncFn.ts +0 -46
- package/src/validate/sync/validators/index.ts +0 -2
- package/src/validate/sync/validators/logical.ts +0 -47
- package/src/validate/sync/validators/shape.ts +0 -146
- package/src/validate/types/async.ts +0 -20
- package/src/validate/types/common.ts +0 -70
- package/src/validate/types/index.ts +0 -3
- package/src/validate/types/sync.ts +0 -20
- package/tsconfig.json +0 -11
package/jest.config.js
DELETED
package/rollup.config.mjs
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import EventEmitter from 'eventemitter3'
|
|
2
|
-
|
|
3
|
-
export class PromiseLikeEventEmitter<
|
|
4
|
-
T,
|
|
5
|
-
EventTypes extends EventEmitter.ValidEventTypes = {},
|
|
6
|
-
> extends EventEmitter<EventTypes> {
|
|
7
|
-
private promise: Promise<T>
|
|
8
|
-
public resolve!: (value: T | PromiseLike<T>) => void
|
|
9
|
-
public reject!: (reason?: any) => void
|
|
10
|
-
|
|
11
|
-
constructor() {
|
|
12
|
-
super()
|
|
13
|
-
this.promise = new Promise<T>((resolve, reject) => {
|
|
14
|
-
this.resolve = resolve
|
|
15
|
-
this.reject = reject
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public then<TResult = T, TError = any>(
|
|
20
|
-
onFulfilled?: ((value: T) => TResult | PromiseLike<TResult>) | null,
|
|
21
|
-
onRejected?: ((reason: any) => TError | PromiseLike<TError>) | null,
|
|
22
|
-
): Promise<TResult | TError> {
|
|
23
|
-
return this.promise.then(onFulfilled, onRejected)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public catch<TError = any>(
|
|
27
|
-
onRejected?: ((reason: any) => TError | PromiseLike<TError>) | null,
|
|
28
|
-
): Promise<T | TError> {
|
|
29
|
-
return this.promise.catch(onRejected)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public finally(onFinally?: (() => void) | null | undefined): Promise<T> {
|
|
33
|
-
return this.promise.finally(onFinally)
|
|
34
|
-
}
|
|
35
|
-
}
|
package/src/array/arrayChunk.ts
DELETED
package/src/array/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './arrayChunk'
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Merge } from 'type-fest'
|
|
2
|
-
import { generateDeterministicId } from './util'
|
|
3
|
-
import copy from 'fast-copy'
|
|
4
|
-
|
|
5
|
-
type AnyFn = (...args: any[]) => any
|
|
6
|
-
|
|
7
|
-
export type FnCallLog<FnType extends AnyFn = AnyFn> = {
|
|
8
|
-
type: 'call'
|
|
9
|
-
callId: string
|
|
10
|
-
fnName: string
|
|
11
|
-
args: Parameters<FnType>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type FnResultLog<FnType extends AnyFn = AnyFn> = Merge<
|
|
15
|
-
FnCallLog<FnType>,
|
|
16
|
-
{
|
|
17
|
-
type: 'result'
|
|
18
|
-
result: ReturnType<FnType>
|
|
19
|
-
}
|
|
20
|
-
>
|
|
21
|
-
|
|
22
|
-
export type FnDebugLog<FnType extends AnyFn = AnyFn> =
|
|
23
|
-
| FnCallLog<FnType>
|
|
24
|
-
| FnResultLog<FnType>
|
|
25
|
-
|
|
26
|
-
export function debugFn<FnType extends AnyFn = AnyFn>(
|
|
27
|
-
fnName: string,
|
|
28
|
-
fn: FnType,
|
|
29
|
-
logCall?: (log: FnCallLog<FnType>) => void,
|
|
30
|
-
logResult?: (log: FnResultLog<FnType>) => void,
|
|
31
|
-
) {
|
|
32
|
-
return function (...args: Parameters<FnType>): ReturnType<FnType> {
|
|
33
|
-
const callId = generateDeterministicId([fnName, fn, ...args])
|
|
34
|
-
|
|
35
|
-
if (typeof logCall === 'function') {
|
|
36
|
-
// Deep clone args, so that we may detect mutations later on
|
|
37
|
-
logCall({ type: 'call', callId, args: copy(args), fnName })
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const result = fn(...args)
|
|
41
|
-
|
|
42
|
-
if (typeof logResult === 'function') {
|
|
43
|
-
logResult({ type: 'result', callId, args, result, fnName })
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return result
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
function stringifyReplacer(key: string, value: any): any {
|
|
2
|
-
if (typeof value === 'function') {
|
|
3
|
-
// Convert functions to a consistent string representation
|
|
4
|
-
return `function:${value.toString()}`
|
|
5
|
-
}
|
|
6
|
-
return value
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function simpleHash(str: string): string {
|
|
10
|
-
let hash = 0
|
|
11
|
-
for (let i = 0; i < str.length; i++) {
|
|
12
|
-
const char = str.charCodeAt(i)
|
|
13
|
-
hash = (hash << 5) - hash + char
|
|
14
|
-
hash |= 0 // Convert to 32bit integer
|
|
15
|
-
}
|
|
16
|
-
// Ensure the hash is positive to avoid '-' signals
|
|
17
|
-
hash = Math.abs(hash)
|
|
18
|
-
return hash.toString(36) // Convert to base36 to ensure the result is alphanumeric
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function generateDeterministicId(args: any[]): string {
|
|
22
|
-
// Convert arguments to a JSON string using the custom replacer
|
|
23
|
-
const argsString = JSON.stringify(args, stringifyReplacer)
|
|
24
|
-
|
|
25
|
-
// Generate a simple hash of the string
|
|
26
|
-
return simpleHash(argsString)
|
|
27
|
-
}
|
package/src/debug/deepFreeze.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
type AnyObjOrArray = any[] | { [key: string]: any }
|
|
2
|
-
|
|
3
|
-
export function deepFreeze<T extends AnyObjOrArray = AnyObjOrArray>(
|
|
4
|
-
object: T,
|
|
5
|
-
): T {
|
|
6
|
-
Object.freeze(object)
|
|
7
|
-
|
|
8
|
-
if (Array.isArray(object)) {
|
|
9
|
-
// Handle the array case
|
|
10
|
-
object.forEach((item) => {
|
|
11
|
-
if (item && typeof item === 'object' && !Object.isFrozen(item)) {
|
|
12
|
-
deepFreeze(item)
|
|
13
|
-
}
|
|
14
|
-
})
|
|
15
|
-
} else {
|
|
16
|
-
// Handle the object case
|
|
17
|
-
Object.keys(object).forEach((key) => {
|
|
18
|
-
const value = object[key]
|
|
19
|
-
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
20
|
-
deepFreeze(value)
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return object
|
|
26
|
-
}
|
package/src/debug/index.ts
DELETED
package/src/debug/wait.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export async function wait<ResultType = any>(
|
|
2
|
-
ms: number = 1000,
|
|
3
|
-
result?: ResultType | Error,
|
|
4
|
-
): Promise<ResultType> {
|
|
5
|
-
return new Promise((resolve, reject) => {
|
|
6
|
-
setTimeout(() => {
|
|
7
|
-
if (result instanceof Error) {
|
|
8
|
-
reject(result)
|
|
9
|
-
} else {
|
|
10
|
-
resolve(result as ResultType)
|
|
11
|
-
}
|
|
12
|
-
}, ms)
|
|
13
|
-
})
|
|
14
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export * from './PromiseLikeEventEmitter'
|
|
2
|
-
export * from './debug'
|
|
3
|
-
export * from './interpolate'
|
|
4
|
-
export * from './maybeFn'
|
|
5
|
-
export * from './promise'
|
|
6
|
-
export * from './resolvePaths'
|
|
7
|
-
export * from './switchValue'
|
|
8
|
-
export * from './typeOf'
|
|
9
|
-
export * from './validate'
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { interpolate } from './'
|
|
2
|
-
|
|
3
|
-
describe('interpolate', () => {
|
|
4
|
-
test('basic', () => {
|
|
5
|
-
// const date = new Date('2024-05-02T08:42:51.303Z')
|
|
6
|
-
expect(
|
|
7
|
-
interpolate(
|
|
8
|
-
'Hello ${ name }! Today is ${now.day}, ${now.hour}:${now.min}',
|
|
9
|
-
{
|
|
10
|
-
name: 'World',
|
|
11
|
-
now: {
|
|
12
|
-
day: '02',
|
|
13
|
-
hour: '08',
|
|
14
|
-
min: '51',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
),
|
|
18
|
-
).toEqual('Hello World! Today is 02, 08:51')
|
|
19
|
-
})
|
|
20
|
-
})
|
package/src/interpolate/index.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { getProperty } from 'dot-prop'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* /\$\{\s*([\w$.]+)\s*\}/g
|
|
5
|
-
* 
|
|
6
|
-
*
|
|
7
|
-
* RegExp used for matching interpolation expressions.
|
|
8
|
-
* Allows a non-interrupted sequence of alphanumeric chars ([A-Za-z0-9_]),
|
|
9
|
-
* dollar signs ($) and dots (.) wrapped in curly braces ({})
|
|
10
|
-
* with or without any number of whitespace chars (' ') between braces and the
|
|
11
|
-
* value identifier.
|
|
12
|
-
*
|
|
13
|
-
* Some resources on RegExp safety concerning RegExp Denial of Service (ReDOS)
|
|
14
|
-
* through Catastrophic backtracking, for future study and reference:
|
|
15
|
-
*
|
|
16
|
-
* - [Catastrophic backtracking](https://www.regular-expressions.info/catastrophic.html)
|
|
17
|
-
* - [Regular expression visualizer](https://github.com/CJex/regulex)
|
|
18
|
-
* - [Validator.js](https://github.com/validatorjs/validator.js)
|
|
19
|
-
* - [Stack Overflow interesting question](https://stackoverflow.com/questions/63127145/safe-regex-patterns-from-redos-attack)
|
|
20
|
-
* - [Catastrophic backtracking - JavaScript Info](https://javascript.info/regexp-catastrophic-backtracking#preventing-backtracking)
|
|
21
|
-
* - [Google re2 library](https://github.com/google/re2)
|
|
22
|
-
* - [Google re2 for Node.js - re2](https://github.com/uhop/node-re2/)
|
|
23
|
-
*
|
|
24
|
-
* @const {RegExp} INTERPOLATION_REGEXP
|
|
25
|
-
*/
|
|
26
|
-
const INTERPOLATION_REGEXP = /\$\{\s*([\w$.]+)\s*\}/g
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @function $stringInterpolate
|
|
30
|
-
* @param {String} template Basic JS template string like `${value.path}` value
|
|
31
|
-
* interpolation. It is possible to access nested properties
|
|
32
|
-
* through dot `.` notation. Keywords between braces are
|
|
33
|
-
* only interpreted as paths to the value. No logic
|
|
34
|
-
* supported: loops, conditionals, etc.
|
|
35
|
-
* @param {Object | Array} data Data context to be used for interpolation
|
|
36
|
-
*/
|
|
37
|
-
export function interpolate(
|
|
38
|
-
template: string,
|
|
39
|
-
data: { [key: string]: any } | any[],
|
|
40
|
-
{ maxLength = 10000 }: { maxLength?: number } = {}
|
|
41
|
-
): string {
|
|
42
|
-
if (template.length > maxLength) {
|
|
43
|
-
throw new Error(`Template exceeds maxLength ${maxLength}`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return template.replace(INTERPOLATION_REGEXP, (_, path) => {
|
|
47
|
-
const value = getProperty(data, path)
|
|
48
|
-
|
|
49
|
-
switch (typeof value) {
|
|
50
|
-
case 'number': {
|
|
51
|
-
return value + ''
|
|
52
|
-
}
|
|
53
|
-
case 'string': {
|
|
54
|
-
return value
|
|
55
|
-
}
|
|
56
|
-
default: {
|
|
57
|
-
console.warn(
|
|
58
|
-
`Attempting to use non interpolatable value in interpolate ${value}`,
|
|
59
|
-
)
|
|
60
|
-
return ''
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
}
|
package/src/maybeFn.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { SKIPPED, batchFn } from './batchFn'
|
|
2
|
-
import { wait } from '../debug'
|
|
3
|
-
|
|
4
|
-
describe('basic', () => {
|
|
5
|
-
test('basic', async () => {
|
|
6
|
-
const DELAY = 100
|
|
7
|
-
const BATCH_SIZE = 3
|
|
8
|
-
const entries = 'abcdefghijklmnopqrstuvwxyz1234567890'.split('')
|
|
9
|
-
|
|
10
|
-
const onItemStart = jest.fn()
|
|
11
|
-
const onItemSkip = jest.fn()
|
|
12
|
-
const onProgress = jest.fn()
|
|
13
|
-
const onBatchStart = jest.fn()
|
|
14
|
-
const onBatchProgress = jest.fn()
|
|
15
|
-
|
|
16
|
-
const batchToUpperCase = batchFn(
|
|
17
|
-
async (input: string) => {
|
|
18
|
-
await wait(DELAY)
|
|
19
|
-
|
|
20
|
-
if (input === 'd') {
|
|
21
|
-
throw new Error('ARBITRARY_INVALID_INPUT')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return input.toUpperCase()
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
batchSize: BATCH_SIZE,
|
|
28
|
-
skip: async (input: string) => {
|
|
29
|
-
switch (input) {
|
|
30
|
-
case 'k':
|
|
31
|
-
case 'w': {
|
|
32
|
-
return true
|
|
33
|
-
}
|
|
34
|
-
default: {
|
|
35
|
-
return false
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const startTime = performance.now()
|
|
43
|
-
const promise = batchToUpperCase(entries)
|
|
44
|
-
|
|
45
|
-
promise.on('itemStart', onItemStart)
|
|
46
|
-
promise.on('itemSkip', onItemSkip)
|
|
47
|
-
promise.on('progress', onProgress)
|
|
48
|
-
promise.on('batchStart', onBatchStart)
|
|
49
|
-
promise.on('batchProgress', onBatchProgress)
|
|
50
|
-
|
|
51
|
-
const result = await promise
|
|
52
|
-
const endTime = performance.now()
|
|
53
|
-
|
|
54
|
-
expect(onItemStart).toHaveBeenCalledTimes(entries.length)
|
|
55
|
-
expect(onItemSkip).toHaveBeenCalledTimes(2)
|
|
56
|
-
expect(onBatchStart).toHaveBeenCalledTimes(
|
|
57
|
-
Math.ceil(entries.length / BATCH_SIZE),
|
|
58
|
-
)
|
|
59
|
-
expect(onBatchProgress).toHaveBeenCalledTimes(
|
|
60
|
-
Math.ceil(entries.length / BATCH_SIZE),
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
expect(result).toEqual(
|
|
64
|
-
entries.map((entry, index) => {
|
|
65
|
-
switch (entry) {
|
|
66
|
-
case 'd': {
|
|
67
|
-
return new Error('ARBITRARY_INVALID_INPUT')
|
|
68
|
-
}
|
|
69
|
-
case 'k':
|
|
70
|
-
case 'w': {
|
|
71
|
-
return SKIPPED
|
|
72
|
-
}
|
|
73
|
-
default: {
|
|
74
|
-
return entry.toUpperCase()
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}),
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
// Expect the execution time to be approximately
|
|
82
|
-
// DELAY * batch count
|
|
83
|
-
//
|
|
84
|
-
const executionTime = endTime - startTime
|
|
85
|
-
expect(executionTime).toBeGreaterThan(
|
|
86
|
-
Math.ceil(entries.length / BATCH_SIZE) * DELAY,
|
|
87
|
-
)
|
|
88
|
-
expect(executionTime).toBeLessThan(
|
|
89
|
-
Math.ceil(entries.length / BATCH_SIZE) * DELAY + 100,
|
|
90
|
-
)
|
|
91
|
-
})
|
|
92
|
-
})
|
package/src/promise/batchFn.ts
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { arrayChunk } from '../array'
|
|
2
|
-
import { promiseReduce } from './promiseReduce'
|
|
3
|
-
import { PromiseLikeEventEmitter } from '../PromiseLikeEventEmitter'
|
|
4
|
-
|
|
5
|
-
type BatchFnOptions = {
|
|
6
|
-
skip?: (input: any) => Promise<boolean> | boolean
|
|
7
|
-
batchSize?: number
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type Batch = {
|
|
11
|
-
index: number
|
|
12
|
-
items: any[]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const SKIPPED = Symbol()
|
|
16
|
-
|
|
17
|
-
type EventTypes = {
|
|
18
|
-
batchStart: (data: { batch: Batch }) => void
|
|
19
|
-
batchProgress: (data: {
|
|
20
|
-
batch: Batch
|
|
21
|
-
progress: number
|
|
22
|
-
results: any[]
|
|
23
|
-
}) => void
|
|
24
|
-
itemStart: (data: { batch: Batch; item: any }) => void
|
|
25
|
-
itemSkip: (data: { batch: Batch; item: any }) => void
|
|
26
|
-
progress: (data: {
|
|
27
|
-
type: 'data' | 'skip' | 'error'
|
|
28
|
-
batch: Batch
|
|
29
|
-
item: any
|
|
30
|
-
result: any
|
|
31
|
-
progress: number
|
|
32
|
-
}) => void
|
|
33
|
-
results: (data: { results: any[] }) => void
|
|
34
|
-
error: (err: Error) => void
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function batchFn(
|
|
38
|
-
fn: (input: any) => Promise<any> | any,
|
|
39
|
-
{ batchSize = 10, skip }: BatchFnOptions = {},
|
|
40
|
-
) {
|
|
41
|
-
return function batchExec(
|
|
42
|
-
items: any[],
|
|
43
|
-
): PromiseLikeEventEmitter<any[], EventTypes> {
|
|
44
|
-
const batches = arrayChunk(items, batchSize)
|
|
45
|
-
|
|
46
|
-
const promise = new PromiseLikeEventEmitter<any[], EventTypes>()
|
|
47
|
-
|
|
48
|
-
// const events = new EventEmitter<EventTypes>()
|
|
49
|
-
|
|
50
|
-
let progressCount = 0
|
|
51
|
-
|
|
52
|
-
const resultsPromise = promiseReduce(
|
|
53
|
-
batches,
|
|
54
|
-
async (acc, batchItems, index) => {
|
|
55
|
-
const batch = {
|
|
56
|
-
index,
|
|
57
|
-
items: batchItems,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
promise.emit('batchStart', {
|
|
61
|
-
batch,
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
// A batch items are executed in parallell
|
|
66
|
-
//
|
|
67
|
-
const batchResults: any[] = await Promise.all(
|
|
68
|
-
batchItems.map(async (item) => {
|
|
69
|
-
try {
|
|
70
|
-
promise.emit('itemStart', {
|
|
71
|
-
batch,
|
|
72
|
-
item,
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
const itemSkip = await (typeof skip === 'function' && skip(item))
|
|
76
|
-
|
|
77
|
-
if (itemSkip) {
|
|
78
|
-
promise.emit('itemSkip', {
|
|
79
|
-
batch,
|
|
80
|
-
item,
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const itemResult = itemSkip ? SKIPPED : await fn(item)
|
|
85
|
-
|
|
86
|
-
progressCount += 1
|
|
87
|
-
|
|
88
|
-
promise.emit('progress', {
|
|
89
|
-
type: itemSkip ? 'skip' : 'data',
|
|
90
|
-
batch,
|
|
91
|
-
progress: progressCount / items.length,
|
|
92
|
-
item,
|
|
93
|
-
result: itemResult,
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
return itemResult
|
|
97
|
-
} catch (err) {
|
|
98
|
-
progressCount += 1
|
|
99
|
-
|
|
100
|
-
promise.emit('progress', {
|
|
101
|
-
type: 'error',
|
|
102
|
-
batch,
|
|
103
|
-
progress: progressCount / items.length,
|
|
104
|
-
item,
|
|
105
|
-
result: err,
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
return err
|
|
109
|
-
}
|
|
110
|
-
}),
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
promise.emit('batchProgress', {
|
|
114
|
-
batch,
|
|
115
|
-
progress: batch.index + 1 / batches.length,
|
|
116
|
-
results: batchResults,
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
return [...acc, ...batchResults]
|
|
120
|
-
},
|
|
121
|
-
[] as any[],
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
resultsPromise.then(
|
|
125
|
-
(results) => {
|
|
126
|
-
promise.resolve(results)
|
|
127
|
-
promise.emit('results', {
|
|
128
|
-
results,
|
|
129
|
-
})
|
|
130
|
-
},
|
|
131
|
-
(err) => {
|
|
132
|
-
promise.reject(err)
|
|
133
|
-
promise.emit('error', err)
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
return promise
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
type ParsedBatchResults = {
|
|
142
|
-
results: any[]
|
|
143
|
-
errors: Error[]
|
|
144
|
-
skipped: any[]
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function parseBatchedResults(
|
|
148
|
-
inputs: any,
|
|
149
|
-
results: any[],
|
|
150
|
-
): ParsedBatchResults {
|
|
151
|
-
return results.reduce(
|
|
152
|
-
(acc, result, index) => {
|
|
153
|
-
if (result === SKIPPED) {
|
|
154
|
-
return {
|
|
155
|
-
...acc,
|
|
156
|
-
skipped: [...acc.skipped, inputs[index]],
|
|
157
|
-
}
|
|
158
|
-
} else if (result instanceof Error) {
|
|
159
|
-
return {
|
|
160
|
-
...acc,
|
|
161
|
-
errors: [...acc.errors, result],
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
return {
|
|
165
|
-
...acc,
|
|
166
|
-
results: [...acc.results, result],
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
results: [],
|
|
172
|
-
errors: [],
|
|
173
|
-
skipped: [],
|
|
174
|
-
} as ParsedBatchResults,
|
|
175
|
-
)
|
|
176
|
-
}
|
package/src/promise/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export function promiseReduce<ItemType = any, AccType = any>(
|
|
2
|
-
inputArr: ItemType[],
|
|
3
|
-
reducerFn: (
|
|
4
|
-
acc: AccType,
|
|
5
|
-
input: ItemType,
|
|
6
|
-
index: number,
|
|
7
|
-
) => AccType | Promise<AccType>,
|
|
8
|
-
initial: AccType,
|
|
9
|
-
) {
|
|
10
|
-
return inputArr.reduce(
|
|
11
|
-
(prevPromise, input, index) =>
|
|
12
|
-
prevPromise.then((acc) => reducerFn(acc, input, index)),
|
|
13
|
-
Promise.resolve(initial) as Promise<AccType>,
|
|
14
|
-
)
|
|
15
|
-
}
|