ctx-core 2.2.2 → 2.4.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/all/debounce/index.js +2 -2
- package/all/index.d.ts +5 -1
- package/all/index.js +5 -1
- package/all/intersection_set/index.js +1 -1
- package/all/isPrimitive/index.d.ts +1 -0
- package/all/isPrimitive/index.js +6 -0
- package/all/isPrimitive/index.test.ts +17 -0
- package/all/isPromiseLike/index.d.ts +4 -0
- package/all/{isPromise → isPromiseLike}/index.js +4 -1
- package/all/memo/index.d.ts +6 -0
- package/all/memo/index.js +61 -0
- package/all/memo/index.test.ts +75 -0
- package/all/noop/index.js +1 -1
- package/all/primitive/index.d.ts +2 -0
- package/all/primitive/index.js +1 -0
- package/all/prototype/index.d.ts +5 -0
- package/all/prototype/index.js +6 -0
- package/all/prototype/index.test.ts +14 -0
- package/all/rememo/index.d.ts +20 -0
- package/all/rememo/index.js +82 -0
- package/all/rememo/index.test.ts +241 -0
- package/function/index.d.ts +2 -1
- package/function/index.js +2 -1
- package/object/index.d.ts +1 -0
- package/object/index.js +1 -0
- package/package.json +34 -4
- package/rememo/index.d.ts +1 -0
- package/rememo/index.js +1 -0
- package/tsconfig.json +6 -3
- package/all/isPromise/index.d.ts +0 -1
package/all/debounce/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPromiseLike } from '../isPromiseLike/index.js'
|
|
2
2
|
/**
|
|
3
3
|
* Returns an async function, that, as long as it continues to be invoked, will not
|
|
4
4
|
* be triggered. The function will be called after it stops being called for
|
|
@@ -35,7 +35,7 @@ export function debounce(func, wait, immediate) {
|
|
|
35
35
|
async function invoke() {
|
|
36
36
|
try {
|
|
37
37
|
const in_rv = func.apply(apply_this, arg_a)
|
|
38
|
-
resolve(
|
|
38
|
+
resolve(isPromiseLike(in_rv) ? await in_rv : in_rv)
|
|
39
39
|
} catch (e) {
|
|
40
40
|
reject(e)
|
|
41
41
|
}
|
package/all/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './Map__object/index.js'
|
|
|
5
5
|
export * from './NumericRange/index.js'
|
|
6
6
|
export * from './NumericUnit/index.js'
|
|
7
7
|
export * from './PHI/index.js'
|
|
8
|
+
export * from './primitive/index.js'
|
|
8
9
|
export * from './Request/index.js'
|
|
9
10
|
export * from './Response/index.js'
|
|
10
11
|
export * from './Timeout/index.js'
|
|
@@ -188,7 +189,8 @@ export * from './isNumber/index.js'
|
|
|
188
189
|
export * from './isNumber_andor/index.js'
|
|
189
190
|
export * from './isNumber_or/index.js'
|
|
190
191
|
export * from './isObject/index.js'
|
|
191
|
-
export * from './
|
|
192
|
+
export * from './isPrimitive/index.js'
|
|
193
|
+
export * from './isPromiseLike/index.js'
|
|
192
194
|
export * from './item_r_idx/index.js'
|
|
193
195
|
export * from './key_compare/index.js'
|
|
194
196
|
export * from './key_r/index.js'
|
|
@@ -222,6 +224,7 @@ export * from './matrix__validate_length/index.js'
|
|
|
222
224
|
export * from './maybe/index.js'
|
|
223
225
|
export * from './mean/index.js'
|
|
224
226
|
export * from './median/index.js'
|
|
227
|
+
export * from './memo/index.js'
|
|
225
228
|
export * from './merge/index.js'
|
|
226
229
|
export * from './minute/index.js'
|
|
227
230
|
export * from './minute/index.js'
|
|
@@ -291,6 +294,7 @@ export * from './prev_idx/index.js'
|
|
|
291
294
|
export * from './promise/index.js'
|
|
292
295
|
export * from './promise_o/index.js'
|
|
293
296
|
export * from './promise_timeout/index.js'
|
|
297
|
+
export * from './prototype/index.js'
|
|
294
298
|
export * from './prototype_mixin/index.js'
|
|
295
299
|
export * from './push/index.js'
|
|
296
300
|
export * from './quantile/index.js'
|
package/all/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export * from './Map__object/index.js'
|
|
|
5
5
|
export * from './NumericRange/index.js'
|
|
6
6
|
export * from './NumericUnit/index.js'
|
|
7
7
|
export * from './PHI/index.js'
|
|
8
|
+
export * from './primitive/index.js'
|
|
8
9
|
export * from './Request/index.js'
|
|
9
10
|
export * from './Response/index.js'
|
|
10
11
|
export * from './Timeout/index.js'
|
|
@@ -188,7 +189,8 @@ export * from './isNumber/index.js'
|
|
|
188
189
|
export * from './isNumber_andor/index.js'
|
|
189
190
|
export * from './isNumber_or/index.js'
|
|
190
191
|
export * from './isObject/index.js'
|
|
191
|
-
export * from './
|
|
192
|
+
export * from './isPrimitive/index.js'
|
|
193
|
+
export * from './isPromiseLike/index.js'
|
|
192
194
|
export * from './item_r_idx/index.js'
|
|
193
195
|
export * from './key_compare/index.js'
|
|
194
196
|
export * from './key_r/index.js'
|
|
@@ -222,6 +224,7 @@ export * from './matrix__validate_length/index.js'
|
|
|
222
224
|
export * from './maybe/index.js'
|
|
223
225
|
export * from './mean/index.js'
|
|
224
226
|
export * from './median/index.js'
|
|
227
|
+
export * from './memo/index.js'
|
|
225
228
|
export * from './merge/index.js'
|
|
226
229
|
export * from './minute/index.js'
|
|
227
230
|
export * from './minute/index.js'
|
|
@@ -291,6 +294,7 @@ export * from './prev_idx/index.js'
|
|
|
291
294
|
export * from './promise/index.js'
|
|
292
295
|
export * from './promise_o/index.js'
|
|
293
296
|
export * from './promise_timeout/index.js'
|
|
297
|
+
export * from './prototype/index.js'
|
|
294
298
|
export * from './prototype_mixin/index.js'
|
|
295
299
|
export * from './push/index.js'
|
|
296
300
|
export * from './quantile/index.js'
|
|
@@ -13,7 +13,7 @@ export function intersection_set_(member_a_nowrap_a_nowrap) {
|
|
|
13
13
|
const rest_a_nowrap = rest_a_nowrap_a[i]
|
|
14
14
|
const rest_a = wrap_a_(rest_a_nowrap)
|
|
15
15
|
const current_set = new Set(rest_a)
|
|
16
|
-
member_set.forEach(
|
|
16
|
+
member_set.forEach(member=>{
|
|
17
17
|
if (!current_set.has(member)) member_set.delete(member)
|
|
18
18
|
})
|
|
19
19
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPrimitive(v:unknown):boolean
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { test } from 'uvu'
|
|
2
|
+
import { equal } from 'uvu/assert'
|
|
3
|
+
import { isPrimitive } from './index.js'
|
|
4
|
+
test('isPrimitive', ()=>{
|
|
5
|
+
equal(isPrimitive(1), true)
|
|
6
|
+
equal(isPrimitive('foo'), true)
|
|
7
|
+
equal(isPrimitive(null), true)
|
|
8
|
+
equal(isPrimitive(undefined), true)
|
|
9
|
+
equal(isPrimitive(true), true)
|
|
10
|
+
equal(isPrimitive(false), true)
|
|
11
|
+
equal(isPrimitive(Symbol('foo')), true)
|
|
12
|
+
equal(isPrimitive({}), false)
|
|
13
|
+
equal(isPrimitive([]), false)
|
|
14
|
+
equal(isPrimitive(()=>1), false)
|
|
15
|
+
equal(isPrimitive(new Date), false)
|
|
16
|
+
})
|
|
17
|
+
test.run()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isPrimitive } from '../isPrimitive/index.js'
|
|
2
|
+
import { prototype_ } from '../prototype/index.js'
|
|
3
|
+
let empty_sym, WeakRef_proto
|
|
4
|
+
/**
|
|
5
|
+
* @param {(...arg_a:any[])=>any}fn
|
|
6
|
+
* @returns A memo caching arguments & return values. Arguments that are Objects are cached with a WeakRef.
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
export function memo_(fn) {
|
|
10
|
+
let m = new Map
|
|
11
|
+
let wm = new WeakMap
|
|
12
|
+
if (!empty_sym) {
|
|
13
|
+
empty_sym = Symbol('E')
|
|
14
|
+
WeakRef_proto = WeakRef.prototype
|
|
15
|
+
}
|
|
16
|
+
let memo = (...arg_a)=>{
|
|
17
|
+
if (!arg_a.length) {
|
|
18
|
+
if (!m.has(empty_sym)) {
|
|
19
|
+
m.set(empty_sym, fn())
|
|
20
|
+
}
|
|
21
|
+
return m.get(empty_sym)
|
|
22
|
+
}
|
|
23
|
+
let arg0 = arg_a[0]
|
|
24
|
+
let map = isPrimitive(arg0) ? m : wm
|
|
25
|
+
/** @type {[unknown[], unknown][]} */
|
|
26
|
+
let cache__arg_a_T_ret__a = map.get(arg0)
|
|
27
|
+
if (!cache__arg_a_T_ret__a) {
|
|
28
|
+
cache__arg_a_T_ret__a = []
|
|
29
|
+
map.set(arg0, cache__arg_a_T_ret__a)
|
|
30
|
+
}
|
|
31
|
+
cache__arg_a_T_ret__a:for (let cache__arg_a_T_ret__a__i = cache__arg_a_T_ret__a.length; cache__arg_a_T_ret__a__i--;) {
|
|
32
|
+
let cache__arg_a_T_ret = cache__arg_a_T_ret__a[cache__arg_a_T_ret__a__i]
|
|
33
|
+
let cache__arg_a = cache__arg_a_T_ret[0]
|
|
34
|
+
let { length } = arg_a
|
|
35
|
+
if (cache__arg_a.length !== length) continue
|
|
36
|
+
for (let arg_a__i = length; arg_a__i--;) {
|
|
37
|
+
let cache__arg_val = cache__arg_a[arg_a__i]
|
|
38
|
+
if (prototype_(cache__arg_val) === WeakRef_proto) {
|
|
39
|
+
cache__arg_val = cache__arg_val.deref()
|
|
40
|
+
if (!cache__arg_val) { // cleanup cache__arg_a when arg is GC
|
|
41
|
+
cache__arg_a_T_ret__a.splice(cache__arg_a_T_ret__a__i, 1)
|
|
42
|
+
continue cache__arg_a_T_ret__a
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let arg_val = arg_a[arg_a__i]
|
|
46
|
+
if (arg_val !== cache__arg_val) break
|
|
47
|
+
if (!arg_a__i) { // arguments match
|
|
48
|
+
return cache__arg_a_T_ret[1]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let ret = fn(...arg_a)
|
|
53
|
+
cache__arg_a_T_ret__a.push([arg_a.map(arg=>isPrimitive(arg) ? arg : new WeakRef(arg)), ret])
|
|
54
|
+
return ret
|
|
55
|
+
}
|
|
56
|
+
memo.clear = ()=>{
|
|
57
|
+
m.clear()
|
|
58
|
+
wm = new WeakMap
|
|
59
|
+
}
|
|
60
|
+
return memo
|
|
61
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { test } from 'uvu'
|
|
2
|
+
import { equal } from 'uvu/assert'
|
|
3
|
+
import { memo_ } from './index.js'
|
|
4
|
+
test('memo_|empty', ()=>{
|
|
5
|
+
let call_count = 0
|
|
6
|
+
let fn = ()=>{
|
|
7
|
+
call_count++
|
|
8
|
+
return 'memo-return'
|
|
9
|
+
}
|
|
10
|
+
let memo = memo_(fn)
|
|
11
|
+
equal(call_count, 0)
|
|
12
|
+
equal(memo(), 'memo-return')
|
|
13
|
+
equal(call_count, 1)
|
|
14
|
+
equal(memo(), 'memo-return')
|
|
15
|
+
equal(call_count, 1)
|
|
16
|
+
})
|
|
17
|
+
test('memo_|primitive arguments', ()=>{
|
|
18
|
+
let call_count = 0
|
|
19
|
+
let fn = (arg0:number, arg1:number)=>{
|
|
20
|
+
call_count++
|
|
21
|
+
return arg0 + arg1
|
|
22
|
+
}
|
|
23
|
+
let memo = memo_(fn)
|
|
24
|
+
equal(call_count, 0)
|
|
25
|
+
equal(memo(1, 2), 3)
|
|
26
|
+
equal(call_count, 1)
|
|
27
|
+
equal(memo(1, 2), 3)
|
|
28
|
+
equal(call_count, 1)
|
|
29
|
+
equal(memo(1, 3), 4)
|
|
30
|
+
equal(call_count, 2)
|
|
31
|
+
memo.clear()
|
|
32
|
+
equal(memo(1, 2), 3)
|
|
33
|
+
equal(call_count, 3)
|
|
34
|
+
})
|
|
35
|
+
test('memo_|primitive|with objects', ()=>{
|
|
36
|
+
let call_count = 0
|
|
37
|
+
let fn = (arg0:number, arg1:object)=>{
|
|
38
|
+
call_count++
|
|
39
|
+
return { ...arg1, arg0 }
|
|
40
|
+
}
|
|
41
|
+
let memo = memo_(fn)
|
|
42
|
+
let arg1 = { arg1: true }
|
|
43
|
+
let arg1_2 = { arg1_2: true }
|
|
44
|
+
equal(call_count, 0)
|
|
45
|
+
equal(memo(1, arg1), { arg1: true, arg0: 1 })
|
|
46
|
+
equal(call_count, 1)
|
|
47
|
+
equal(memo(1, arg1), { arg1: true, arg0: 1 })
|
|
48
|
+
equal(call_count, 1)
|
|
49
|
+
equal(memo(1, arg1_2), { arg1_2: true, arg0: 1 })
|
|
50
|
+
equal(call_count, 2)
|
|
51
|
+
memo.clear()
|
|
52
|
+
equal(memo(1, arg1), { arg1: true, arg0: 1 })
|
|
53
|
+
equal(call_count, 3)
|
|
54
|
+
})
|
|
55
|
+
test('memo_|objects|with primitives', ()=>{
|
|
56
|
+
let call_count = 0
|
|
57
|
+
let fn = (arg0:object, arg1:number)=>{
|
|
58
|
+
call_count++
|
|
59
|
+
return { ...arg0, arg1 }
|
|
60
|
+
}
|
|
61
|
+
let memo = memo_(fn)
|
|
62
|
+
let arg0 = { arg0: true }
|
|
63
|
+
let arg0_2 = { arg0_2: true }
|
|
64
|
+
equal(call_count, 0)
|
|
65
|
+
equal(memo(arg0, 1), { arg0: true, arg1: 1 })
|
|
66
|
+
equal(call_count, 1)
|
|
67
|
+
equal(memo(arg0, 1), { arg0: true, arg1: 1 })
|
|
68
|
+
equal(call_count, 1)
|
|
69
|
+
equal(memo(arg0_2, 1), { arg0_2: true, arg1: 1 })
|
|
70
|
+
equal(call_count, 2)
|
|
71
|
+
memo.clear()
|
|
72
|
+
equal(memo(arg0, 1), { arg0: true, arg1: 1 })
|
|
73
|
+
equal(call_count, 3)
|
|
74
|
+
})
|
|
75
|
+
test.run()
|
package/all/noop/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { nullish } from '../nullish/index.js'
|
|
2
|
+
import type { primitive_T } from '../primitive/index.js'
|
|
3
|
+
export declare function prototype_(val:Exclude<any, nullish>):Object
|
|
4
|
+
export declare function prototype__set(obj:Exclude<any, primitive_T>, val:Object):Object
|
|
5
|
+
export declare const fn__proto:Object
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { test } from 'uvu'
|
|
2
|
+
import { is, not } from 'uvu/assert'
|
|
3
|
+
import { prototype_ } from './index.js'
|
|
4
|
+
test('prototype_', ()=>{
|
|
5
|
+
is(prototype_({}), Object.prototype)
|
|
6
|
+
is(prototype_(new WeakRef({})), WeakRef.prototype)
|
|
7
|
+
is(prototype_(1), Number.prototype)
|
|
8
|
+
is(prototype_(true), Boolean.prototype)
|
|
9
|
+
is(prototype_(false), Boolean.prototype)
|
|
10
|
+
not.equal(prototype_(new Date), Boolean.prototype)
|
|
11
|
+
not.equal(prototype_({}), Boolean.prototype)
|
|
12
|
+
not.equal(prototype_(1), Boolean.prototype)
|
|
13
|
+
})
|
|
14
|
+
test.run()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function rememo_<val_T>(
|
|
2
|
+
def:(rememo:rememo__T<val_T>)=>val_T,
|
|
3
|
+
...subscriber_a:rememo_subscriber_T<val_T>[]
|
|
4
|
+
):rememo_T<val_T>
|
|
5
|
+
export declare function signal_<val_T>(
|
|
6
|
+
init_val:val_T,
|
|
7
|
+
...subscriber_a:rememo_subscriber_T<val_T>[]
|
|
8
|
+
):rememo_T<val_T>
|
|
9
|
+
export type rememo__T<val_T> =
|
|
10
|
+
(def:rememo_def_T<val_T>, ...subscriber_a:rememo_subscriber_T<val_T>[])=>val_T
|
|
11
|
+
export type rememo_T<val_T> = ((val?:val_T)=>val_T)&rememo_o_T<val_T>
|
|
12
|
+
export type rememo_def_T<val_T> = (rememo:rememo__T<val>)=>val_T
|
|
13
|
+
export type rememo_subscriber_T<val_T> = (rememo:rememo_T<val_T>)=>unknown
|
|
14
|
+
export type rememo_o_T<val_T> = {
|
|
15
|
+
_:val_T
|
|
16
|
+
readonly val:val_T
|
|
17
|
+
init():unknown
|
|
18
|
+
onset(val:val_T):unknown
|
|
19
|
+
refresh():val_T
|
|
20
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** @typedef {import('./index.d.ts').rememo_T} */
|
|
2
|
+
/** @typedef {import('./index.d.ts').rememo_subscriber_T} */
|
|
3
|
+
/** @type {(()=>unknown)[]} */
|
|
4
|
+
let queue = []
|
|
5
|
+
/** @type {WeakRef<rememo_T>} */
|
|
6
|
+
let cur_ref
|
|
7
|
+
/**
|
|
8
|
+
* @param {(rememo:rememo_T<unknown>)=>unknown}_f
|
|
9
|
+
* @param {rememo_subscriber_T<unknown>[]}subscriber_a
|
|
10
|
+
* @returns {rememo_T}
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
export function rememo_(_f, ...subscriber_a) {
|
|
14
|
+
let _a = []
|
|
15
|
+
let _rS = new Set
|
|
16
|
+
let rememo$ = (...arg_a)=>arg_a.length ? rememo$._ = arg_a[0] : rememo$._
|
|
17
|
+
rememo$._a = _a
|
|
18
|
+
rememo$._f = _f
|
|
19
|
+
rememo$._rS = _rS
|
|
20
|
+
rememo$._r = new WeakRef(()=>rememo$.refresh(_f(rememo$)))
|
|
21
|
+
rememo$.onset = ()=>0
|
|
22
|
+
rememo$._r.l = 0
|
|
23
|
+
rememo$.init = ()=>(rememo$(), rememo$)
|
|
24
|
+
Object.defineProperty(rememo$, '_', {
|
|
25
|
+
get() {
|
|
26
|
+
// allow self-referencing
|
|
27
|
+
if (!_a.length) {
|
|
28
|
+
let prev_ref = cur_ref
|
|
29
|
+
cur_ref = rememo$._r
|
|
30
|
+
try {
|
|
31
|
+
_a[0] = _f(rememo$)
|
|
32
|
+
} finally {
|
|
33
|
+
cur_ref = prev_ref
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (cur_ref && cur_ref !== rememo$._r) {
|
|
37
|
+
cur_ref.l = Math.max(rememo$._r.l + 1, cur_ref.l)
|
|
38
|
+
_rS.add(cur_ref)
|
|
39
|
+
}
|
|
40
|
+
return _a[0]
|
|
41
|
+
},
|
|
42
|
+
set(val) {
|
|
43
|
+
if (!_a.length || val !== _a[0]) {
|
|
44
|
+
rememo$.refresh(val)
|
|
45
|
+
}
|
|
46
|
+
return val
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
rememo$.refresh = val=>{
|
|
50
|
+
let { length } = _a
|
|
51
|
+
_a[0] = val
|
|
52
|
+
rememo$.onset(val)
|
|
53
|
+
if (length) {
|
|
54
|
+
let run_queue = !queue[0]
|
|
55
|
+
for (let ref of _rS) {
|
|
56
|
+
if (!~queue.indexOf(ref)) queue.push(ref)
|
|
57
|
+
}
|
|
58
|
+
if (run_queue) {
|
|
59
|
+
for (let ref; ref = queue.shift();) {
|
|
60
|
+
queue.some(_ref=>ref.l > _ref.l) ? queue.push(ref) : ref.deref()?.() ?? _rS.delete(ref)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return rememo$
|
|
65
|
+
}
|
|
66
|
+
rememo$._sa = subscriber_a.map(subscriber=>
|
|
67
|
+
rememo_(()=>subscriber(rememo$)).init())
|
|
68
|
+
return rememo$
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @param {unknown}init_val
|
|
72
|
+
* @param {rememo_subscriber_T[]}subscriber_a
|
|
73
|
+
* @returns {rememo_T}
|
|
74
|
+
* @private
|
|
75
|
+
*/
|
|
76
|
+
export function signal_(init_val, ...subscriber_a) {
|
|
77
|
+
let signal$ =
|
|
78
|
+
rememo_(signal$=>signal$._v, ...subscriber_a)
|
|
79
|
+
signal$.onset = val=>signal$._v = val
|
|
80
|
+
signal$._v = init_val
|
|
81
|
+
return signal$
|
|
82
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { deepStrictEqual } from 'node:assert'
|
|
2
|
+
import { clock } from 'sinon'
|
|
3
|
+
import { test } from 'uvu'
|
|
4
|
+
import { equal } from 'uvu/assert'
|
|
5
|
+
import { sleep } from '../sleep/index.js'
|
|
6
|
+
import { rememo_, signal_ } from './index.js'
|
|
7
|
+
test('rememo_|static value', ()=>{
|
|
8
|
+
let count = 0
|
|
9
|
+
let rememo$ = rememo_(rememo=>{
|
|
10
|
+
count++
|
|
11
|
+
return 'rememo-value'
|
|
12
|
+
})
|
|
13
|
+
equal(count, 0)
|
|
14
|
+
equal(rememo$(), 'rememo-value')
|
|
15
|
+
equal(count, 1)
|
|
16
|
+
equal(rememo$(), 'rememo-value')
|
|
17
|
+
equal(count, 1)
|
|
18
|
+
})
|
|
19
|
+
test('signal_', ()=>{
|
|
20
|
+
let signal$ = signal_('val0')
|
|
21
|
+
equal(signal$(), 'val0')
|
|
22
|
+
signal$('val1')
|
|
23
|
+
equal(signal$(), 'val1')
|
|
24
|
+
})
|
|
25
|
+
test('rememo_|async subsubscriber', async ()=>{
|
|
26
|
+
let resolve:(user:{ id:string })=>void
|
|
27
|
+
let user0 = { id: 'id-0' }
|
|
28
|
+
let user1 = { id: 'id-1' }
|
|
29
|
+
let id$ = signal_('id-0')
|
|
30
|
+
let user$ = signal_<{ id:string }|null>(
|
|
31
|
+
null,
|
|
32
|
+
async (_user$)=>{
|
|
33
|
+
id$()
|
|
34
|
+
let user:{ id:string } = await new Promise(_resolve=>resolve = _resolve)
|
|
35
|
+
_user$(user)
|
|
36
|
+
})
|
|
37
|
+
equal(user$(), null)
|
|
38
|
+
resolve!(user0)
|
|
39
|
+
await sleep(0)
|
|
40
|
+
equal(user$(), user0)
|
|
41
|
+
id$('id-1')
|
|
42
|
+
equal(user$(), user0)
|
|
43
|
+
resolve!(user1)
|
|
44
|
+
await sleep(0)
|
|
45
|
+
})
|
|
46
|
+
test('rememo_+signal_|simple graph', ()=>{
|
|
47
|
+
let base$ = signal_('base0')
|
|
48
|
+
let dep0$ = rememo_(()=>base$() + '-dep0')
|
|
49
|
+
let dep1$ = rememo_(()=>dep0$() + '-dep1')
|
|
50
|
+
let dep2$ = rememo_(()=>dep1$() + '-dep2')
|
|
51
|
+
let dep3$ = rememo_(()=>dep2$() + '-dep3')
|
|
52
|
+
let dep4$ = rememo_(()=>dep3$() + '-dep4')
|
|
53
|
+
equal(dep4$(), 'base0-dep0-dep1-dep2-dep3-dep4')
|
|
54
|
+
equal(dep3$(), 'base0-dep0-dep1-dep2-dep3')
|
|
55
|
+
equal(dep2$(), 'base0-dep0-dep1-dep2')
|
|
56
|
+
equal(dep1$(), 'base0-dep0-dep1')
|
|
57
|
+
equal(dep0$(), 'base0-dep0')
|
|
58
|
+
equal(base$(), 'base0')
|
|
59
|
+
base$('base1')
|
|
60
|
+
equal(base$(), 'base1')
|
|
61
|
+
equal(dep0$(), 'base1-dep0')
|
|
62
|
+
equal(dep1$(), 'base1-dep0-dep1')
|
|
63
|
+
equal(dep2$(), 'base1-dep0-dep1-dep2')
|
|
64
|
+
equal(dep3$(), 'base1-dep0-dep1-dep2-dep3')
|
|
65
|
+
equal(dep4$(), 'base1-dep0-dep1-dep2-dep3-dep4')
|
|
66
|
+
})
|
|
67
|
+
test('prevents diamond dependency problem 1', ()=>{
|
|
68
|
+
let store$ = signal_(0)
|
|
69
|
+
let values:string[] = []
|
|
70
|
+
let a$ = rememo_(()=>`a${store$()}`)
|
|
71
|
+
let b$ = rememo_(()=>a$().replace('a', 'b'))
|
|
72
|
+
let c$ = rememo_(()=>a$().replace('a', 'c'))
|
|
73
|
+
let d$ = rememo_(()=>a$().replace('a', 'd'))
|
|
74
|
+
let combined$ = rememo_(()=>`${b$()}${c$()}${d$()}`,
|
|
75
|
+
combined$=>
|
|
76
|
+
values.push(combined$()))
|
|
77
|
+
deepStrictEqual(values, ['b0c0d0'])
|
|
78
|
+
store$(1)
|
|
79
|
+
store$(2)
|
|
80
|
+
deepStrictEqual(values, ['b0c0d0', 'b1c1d1', 'b2c2d2'])
|
|
81
|
+
})
|
|
82
|
+
test('prevents diamond dependency problem 2', ()=>{
|
|
83
|
+
let store$ = signal_(0)
|
|
84
|
+
let values:string[] = []
|
|
85
|
+
let a$ = rememo_(()=>`a${store$()}`)
|
|
86
|
+
let b$ = rememo_(()=>a$().replace('a', 'b'))
|
|
87
|
+
let c$ = rememo_(()=>b$().replace('b', 'c'))
|
|
88
|
+
let d$ = rememo_(()=>c$().replace('c', 'd'))
|
|
89
|
+
let e$ = rememo_(()=>d$().replace('d', 'e'))
|
|
90
|
+
let combined$ = rememo_<string>(
|
|
91
|
+
()=>[a$(), e$()].join(''),
|
|
92
|
+
combined$=>values.push(combined$()))
|
|
93
|
+
deepStrictEqual(values, ['a0e0'])
|
|
94
|
+
store$(1)
|
|
95
|
+
deepStrictEqual(values, ['a0e0', 'a1e1'])
|
|
96
|
+
})
|
|
97
|
+
test('prevents diamond dependency problem 3', ()=>{
|
|
98
|
+
let store$ = signal_(0)
|
|
99
|
+
let values:string[] = []
|
|
100
|
+
let a$ = rememo_(()=>`a${store$()}`)
|
|
101
|
+
let b$ = rememo_(()=>a$().replace('a', 'b'))
|
|
102
|
+
let c$ = rememo_(()=>b$().replace('b', 'c'))
|
|
103
|
+
let d$ = rememo_(()=>c$().replace('c', 'd'))
|
|
104
|
+
rememo_<string>(
|
|
105
|
+
()=>`${a$()}${b$()}${c$()}${d$()}`,
|
|
106
|
+
combined$=>values.push(combined$()))
|
|
107
|
+
deepStrictEqual(values, ['a0b0c0d0'])
|
|
108
|
+
store$(1)
|
|
109
|
+
deepStrictEqual(values, ['a0b0c0d0', 'a1b1c1d1'])
|
|
110
|
+
})
|
|
111
|
+
test('autosubscribe: prevents diamond dependency problem 4 (complex)', ()=>{
|
|
112
|
+
let store1$ = signal_(0)
|
|
113
|
+
let store2$ = signal_(0)
|
|
114
|
+
let values:string[] = []
|
|
115
|
+
let fn =
|
|
116
|
+
(name:string)=>
|
|
117
|
+
(...v:(number|string)[])=>
|
|
118
|
+
`${name}${v.join('')}`
|
|
119
|
+
let a$ = rememo_(()=>`a${store1$()}`)
|
|
120
|
+
let b$ = rememo_(()=>`b${store2$()}`)
|
|
121
|
+
let c$ = rememo_(()=>`c${a$()}${b$()}`)
|
|
122
|
+
let d$ = rememo_(()=>`d${a$()}`)
|
|
123
|
+
let e$ = rememo_(()=>`e${c$()}${d$()}`)
|
|
124
|
+
let f$ = rememo_(()=>`f${e$()}`)
|
|
125
|
+
let g$ = rememo_(()=>`g${f$()}`)
|
|
126
|
+
rememo_(
|
|
127
|
+
()=>e$(),
|
|
128
|
+
combined1$=>values.push(combined1$()))
|
|
129
|
+
rememo_(
|
|
130
|
+
()=>[e$(), g$()].join(''),
|
|
131
|
+
combined2$=>values.push(combined2$()))
|
|
132
|
+
deepStrictEqual(values, ['eca0b0da0', 'eca0b0da0gfeca0b0da0'])
|
|
133
|
+
store1$(1)
|
|
134
|
+
store2$(2)
|
|
135
|
+
deepStrictEqual(values, [
|
|
136
|
+
'eca0b0da0',
|
|
137
|
+
'eca0b0da0gfeca0b0da0',
|
|
138
|
+
'eca1b0da1',
|
|
139
|
+
'eca1b0da1gfeca1b0da1',
|
|
140
|
+
'eca1b2da1',
|
|
141
|
+
'eca1b2da1gfeca1b2da1'
|
|
142
|
+
])
|
|
143
|
+
})
|
|
144
|
+
test('prevents diamond dependency problem 5', ()=>{
|
|
145
|
+
let events = ''
|
|
146
|
+
let firstName$ = signal_('John')
|
|
147
|
+
let lastName$ = signal_('Doe')
|
|
148
|
+
let fullName$ = rememo_(()=>{
|
|
149
|
+
events += 'full '
|
|
150
|
+
return `${firstName$()} ${lastName$()}`
|
|
151
|
+
})
|
|
152
|
+
let isFirstShort$ = rememo_(()=>{
|
|
153
|
+
events += 'short '
|
|
154
|
+
return firstName$().length < 10
|
|
155
|
+
})
|
|
156
|
+
let displayName$ = rememo_(
|
|
157
|
+
()=>{
|
|
158
|
+
events += 'display '
|
|
159
|
+
return isFirstShort$() ? fullName$() : firstName$()
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
equal(events, '')
|
|
163
|
+
equal(displayName$(), 'John Doe')
|
|
164
|
+
equal(events, 'display short full ')
|
|
165
|
+
firstName$('Benedict')
|
|
166
|
+
equal(displayName$(), 'Benedict Doe')
|
|
167
|
+
equal(events, 'display short full short full display ')
|
|
168
|
+
firstName$('Montgomery')
|
|
169
|
+
equal(displayName$(), 'Montgomery')
|
|
170
|
+
equal(events, 'display short full short full display short full display ')
|
|
171
|
+
})
|
|
172
|
+
test('prevents diamond dependency problem 6', ()=>{
|
|
173
|
+
let store1$ = signal_(0)
|
|
174
|
+
let store2$ = signal_(0)
|
|
175
|
+
let values:string[] = []
|
|
176
|
+
let a$ = rememo_(()=>`a${store1$()}`)
|
|
177
|
+
let b$ = rememo_(()=>`b${store2$()}`)
|
|
178
|
+
let c$ = rememo_(()=>b$().replace('b', 'c'))
|
|
179
|
+
rememo_(
|
|
180
|
+
()=>`${a$()}${c$()}`,
|
|
181
|
+
combined$=>values.push(combined$()))
|
|
182
|
+
deepStrictEqual(values, ['a0c0'])
|
|
183
|
+
store1$(1)
|
|
184
|
+
deepStrictEqual(values, ['a0c0', 'a1c0'])
|
|
185
|
+
})
|
|
186
|
+
test('prevents dependency listeners from being out of order', ()=>{
|
|
187
|
+
let base$ = signal_(0)
|
|
188
|
+
let a$ = rememo_(()=>{
|
|
189
|
+
return `${base$()}a`
|
|
190
|
+
})
|
|
191
|
+
let values:string[] = []
|
|
192
|
+
let b$ = rememo_(()=>{
|
|
193
|
+
return `${a$()}b`
|
|
194
|
+
}, b$=>values.push(b$()))
|
|
195
|
+
equal(b$(), '0ab')
|
|
196
|
+
deepStrictEqual(values, ['0ab'])
|
|
197
|
+
equal(a$(), '0a')
|
|
198
|
+
base$(1)
|
|
199
|
+
deepStrictEqual(values, ['0ab', '1ab'])
|
|
200
|
+
})
|
|
201
|
+
test('computes initial value when argument is undefined', ()=>{
|
|
202
|
+
let one$ = signal_<string|undefined>(undefined)
|
|
203
|
+
let two$ = rememo_(()=>!!one$())
|
|
204
|
+
equal(one$(), undefined)
|
|
205
|
+
equal(two$(), false)
|
|
206
|
+
})
|
|
207
|
+
test('async computed using task', async ()=>{
|
|
208
|
+
let a$ = signal_(1)
|
|
209
|
+
let b$ = signal_(2)
|
|
210
|
+
let sleepCycles = 5
|
|
211
|
+
let taskArgumentsCalls:number[][] = []
|
|
212
|
+
let sum$ = signal_<null|number>(null,
|
|
213
|
+
async sum$=>{
|
|
214
|
+
taskArgumentsCalls.push([a$(), b$()])
|
|
215
|
+
for (let i = 0; i < sleepCycles; i++) {
|
|
216
|
+
await Promise.resolve()
|
|
217
|
+
}
|
|
218
|
+
sum$(a$() + b$())
|
|
219
|
+
})
|
|
220
|
+
equal(sum$(), null)
|
|
221
|
+
deepStrictEqual(taskArgumentsCalls, [[1, 2]])
|
|
222
|
+
// sleepCycles = 0
|
|
223
|
+
a$(10)
|
|
224
|
+
b$(20)
|
|
225
|
+
for (let i = 0; i < sleepCycles; i++) {
|
|
226
|
+
equal(sum$(), null)
|
|
227
|
+
await Promise.resolve()
|
|
228
|
+
deepStrictEqual(taskArgumentsCalls, [
|
|
229
|
+
[1, 2],
|
|
230
|
+
[10, 2],
|
|
231
|
+
[10, 20]
|
|
232
|
+
])
|
|
233
|
+
}
|
|
234
|
+
equal(sum$(), 30)
|
|
235
|
+
deepStrictEqual(taskArgumentsCalls, [
|
|
236
|
+
[1, 2],
|
|
237
|
+
[10, 2],
|
|
238
|
+
[10, 20]
|
|
239
|
+
])
|
|
240
|
+
})
|
|
241
|
+
test.run()
|
package/function/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export * from '../all/ifelse/index.js'
|
|
|
36
36
|
export * from '../all/iife/index.js'
|
|
37
37
|
export * from '../all/invert/index.js'
|
|
38
38
|
export * from '../all/isArray/index.js'
|
|
39
|
-
export * from '../all/
|
|
39
|
+
export * from '../all/isPromiseLike/index.js'
|
|
40
40
|
export * from '../all/left_and/index.js'
|
|
41
41
|
export * from '../all/left_or/index.js'
|
|
42
42
|
export * from '../all/many_andand/index.js'
|
|
@@ -45,6 +45,7 @@ export * from '../all/map_apply/index.js'
|
|
|
45
45
|
export * from '../all/map_call/index.js'
|
|
46
46
|
export * from '../all/map_fn/index.js'
|
|
47
47
|
export * from '../all/maybe/index.js'
|
|
48
|
+
export * from '../all/memo/index.js'
|
|
48
49
|
export * from '../all/neq/index.js'
|
|
49
50
|
export * from '../all/neql/index.js'
|
|
50
51
|
export * from '../all/nf/index.js'
|
package/function/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export * from '../all/ifelse/index.js'
|
|
|
36
36
|
export * from '../all/iife/index.js'
|
|
37
37
|
export * from '../all/invert/index.js'
|
|
38
38
|
export * from '../all/isArray/index.js'
|
|
39
|
-
export * from '../all/
|
|
39
|
+
export * from '../all/isPromiseLike/index.js'
|
|
40
40
|
export * from '../all/left_and/index.js'
|
|
41
41
|
export * from '../all/left_or/index.js'
|
|
42
42
|
export * from '../all/many_andand/index.js'
|
|
@@ -45,6 +45,7 @@ export * from '../all/map_apply/index.js'
|
|
|
45
45
|
export * from '../all/map_call/index.js'
|
|
46
46
|
export * from '../all/map_fn/index.js'
|
|
47
47
|
export * from '../all/maybe/index.js'
|
|
48
|
+
export * from '../all/memo/index.js'
|
|
48
49
|
export * from '../all/neq/index.js'
|
|
49
50
|
export * from '../all/neql/index.js'
|
|
50
51
|
export * from '../all/nf/index.js'
|
package/object/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export * from '../all/or_null/index.js'
|
|
|
40
40
|
export * from '../all/pick/index.js'
|
|
41
41
|
export * from '../all/pick_keys/index.js'
|
|
42
42
|
export * from '../all/pick_val_a/index.js'
|
|
43
|
+
export * from '../all/prototype/index.js'
|
|
43
44
|
export * from '../all/rc_be/index.js'
|
|
44
45
|
export * from '../all/rc_be_/index.js'
|
|
45
46
|
export * from '../all/toString/index.js'
|
package/object/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export * from '../all/or_null/index.js'
|
|
|
39
39
|
export * from '../all/pick/index.js'
|
|
40
40
|
export * from '../all/pick_keys/index.js'
|
|
41
41
|
export * from '../all/pick_val_a/index.js'
|
|
42
|
+
export * from '../all/prototype/index.js'
|
|
42
43
|
export * from '../all/rc_be/index.js'
|
|
43
44
|
export * from '../all/rc_be_/index.js'
|
|
44
45
|
export * from '../all/toString/index.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctx-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "ctx-core core library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ctx-core",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"queue",
|
|
54
54
|
"random",
|
|
55
55
|
"regex",
|
|
56
|
+
"rememo",
|
|
56
57
|
"set",
|
|
57
58
|
"sleep",
|
|
58
59
|
"string",
|
|
@@ -93,6 +94,7 @@
|
|
|
93
94
|
"./queue": "./queue/index.js",
|
|
94
95
|
"./random": "./random/index.js",
|
|
95
96
|
"./regex": "./regex/index.js",
|
|
97
|
+
"./rememo": "./rememo/index.js",
|
|
96
98
|
"./set": "./set/index.js",
|
|
97
99
|
"./sleep": "./sleep/index.js",
|
|
98
100
|
"./string": "./string/index.js",
|
|
@@ -104,10 +106,13 @@
|
|
|
104
106
|
},
|
|
105
107
|
"devDependencies": {
|
|
106
108
|
"@arethetypeswrong/cli": "^0.13.1",
|
|
109
|
+
"@size-limit/preset-small-lib": "^11.0.0",
|
|
110
|
+
"@types/node": "^20.9.1",
|
|
107
111
|
"@types/sinon": "^17.0.1",
|
|
108
112
|
"c8": "^8.0.1",
|
|
109
113
|
"check-dts": "^0.7.2",
|
|
110
114
|
"sinon": "^17.0.1",
|
|
115
|
+
"size-limit": "^11.0.0",
|
|
111
116
|
"ts-node": "^10.9.1",
|
|
112
117
|
"tsx": "^4.1.2",
|
|
113
118
|
"typescript": "next",
|
|
@@ -118,12 +123,37 @@
|
|
|
118
123
|
"cache": "~/.npm"
|
|
119
124
|
},
|
|
120
125
|
"sideEffects": false,
|
|
126
|
+
"size-limit": [
|
|
127
|
+
{
|
|
128
|
+
"name": "be",
|
|
129
|
+
"import": {
|
|
130
|
+
"./be": "{ be_ }"
|
|
131
|
+
},
|
|
132
|
+
"limit": "600 B"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "rememo",
|
|
136
|
+
"import": {
|
|
137
|
+
"./rememo": "{ rememo_ }"
|
|
138
|
+
},
|
|
139
|
+
"limit": "358 B"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "rememo signal",
|
|
143
|
+
"import": {
|
|
144
|
+
"./rememo": "{ signal_ }"
|
|
145
|
+
},
|
|
146
|
+
"limit": "385 B"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
121
149
|
"scripts": {
|
|
122
150
|
"build": ":",
|
|
123
151
|
"clean": ":",
|
|
124
152
|
"exec": "$@",
|
|
125
|
-
"test": "pnpm test
|
|
126
|
-
"test
|
|
127
|
-
"test
|
|
153
|
+
"test": "pnpm run /^test:/",
|
|
154
|
+
"test:size": "size-limit",
|
|
155
|
+
"test:type": "check-dts",
|
|
156
|
+
"test:unit": "tsx node_modules/uvu/bin.js . '\\.test\\.(ts|js)$'",
|
|
157
|
+
"disable:test:coverage": "c8 pnpm test-unit"
|
|
128
158
|
}
|
|
129
159
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../all/rememo/index.js'
|
package/rememo/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../all/rememo/index.js'
|
package/tsconfig.json
CHANGED
package/all/isPromise/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function isPromise(obj:any):boolean
|