ctx-core 2.4.0 → 3.1.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/be_/index.js +44 -68
- package/all/rmemo/index.d.ts +18 -0
- package/all/rmemo/index.js +88 -0
- package/all/{rememo → rmemo}/index.test.ts +111 -102
- package/package.json +10 -10
- package/rmemo/index.d.ts +1 -0
- package/rmemo/index.js +1 -0
- package/all/rememo/index.d.ts +0 -20
- package/all/rememo/index.js +0 -82
- package/rememo/index.d.ts +0 -1
- package/rememo/index.js +0 -1
package/all/be_/index.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { globalThis__prop__ensure } from '../globalThis__prop__ensure/index.js'
|
|
2
|
-
|
|
3
|
-
let proto_ = Object.getPrototypeOf
|
|
4
|
-
let string_proto = proto_('')
|
|
5
|
-
let _null = null
|
|
6
|
-
let pending_sym = Symbol.for('pending')
|
|
7
|
-
let be_M_is_source_ = globalThis__prop__ensure(
|
|
8
|
-
Symbol.for('be_M_is_source_'),
|
|
9
|
-
()=>new WeakMap())
|
|
2
|
+
let be_M_is_source_ = globalThis.be_M_is_source_ ||= new WeakMap()
|
|
10
3
|
/** @typedef {import('./index.d.ts').Be}Be */
|
|
11
4
|
/** @typedef {import('./index.d.ts').Ctx}Ctx */
|
|
12
5
|
/** @typedef {import('./index.d.ts').MapCtx}MapCtx */
|
|
@@ -51,69 +44,60 @@ export function globalThis__be_(
|
|
|
51
44
|
export function be_(
|
|
52
45
|
id_OR_val__new,
|
|
53
46
|
val__new_OR_be__params,
|
|
54
|
-
be__params
|
|
47
|
+
be__params
|
|
55
48
|
) {
|
|
56
49
|
/** @type {string} */
|
|
57
|
-
let id
|
|
58
|
-
proto_(id_OR_val__new) === string_proto
|
|
59
|
-
? id_OR_val__new
|
|
60
|
-
: _null
|
|
50
|
+
let id
|
|
61
51
|
/** @type {be__val__T} */
|
|
62
|
-
let val__new
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
be__params
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
let be = (argv__ctx, params
|
|
52
|
+
let val__new
|
|
53
|
+
/** @type {is_source__T} */
|
|
54
|
+
let is_source_
|
|
55
|
+
/** @type {expired__T} */
|
|
56
|
+
let expired_
|
|
57
|
+
if (typeof id_OR_val__new === 'string') {
|
|
58
|
+
val__new = val__new_OR_be__params
|
|
59
|
+
id = id_OR_val__new
|
|
60
|
+
} else {
|
|
61
|
+
val__new = id_OR_val__new
|
|
62
|
+
be__params = val__new_OR_be__params
|
|
63
|
+
}
|
|
64
|
+
if (be__params) {
|
|
65
|
+
is_source_ = be__params.is_source_
|
|
66
|
+
expired_ = be__params.expired_
|
|
67
|
+
}
|
|
68
|
+
let be = (argv__ctx, params)=>{
|
|
79
69
|
if (!argv__ctx) {
|
|
80
|
-
throw new Error(`be
|
|
70
|
+
throw new Error(`be: no Ctx`)
|
|
81
71
|
}
|
|
82
72
|
let saved__val = be__val_(be, argv__ctx)
|
|
83
73
|
if (
|
|
84
|
-
|
|
85
|
-
&&
|
|
86
|
-
&&
|
|
74
|
+
!params?.force
|
|
75
|
+
&& be__has_(be, argv__ctx)
|
|
76
|
+
&& !expired_?.(argv__ctx)
|
|
87
77
|
) {
|
|
88
78
|
return saved__val
|
|
89
79
|
}
|
|
90
80
|
let ctx = source__map_ctx_(argv__ctx, is_source_)
|
|
91
81
|
if (!ctx) {
|
|
92
82
|
throw new Error(
|
|
93
|
-
`be: ${
|
|
94
|
-
String(id)
|
|
95
|
-
}: is_source_ must be true for at least one Ctx`)
|
|
83
|
+
`be: ${String(id)}: no is_source_ returns true`)
|
|
96
84
|
}
|
|
97
|
-
let pending = ctx.get(
|
|
85
|
+
let pending = ctx.get(Symbol.for('pending'))
|
|
98
86
|
if (!pending) {
|
|
99
|
-
pending = new Map
|
|
100
|
-
ctx.set(
|
|
87
|
+
pending = new Map
|
|
88
|
+
ctx.set(Symbol.for('pending'), pending)
|
|
101
89
|
}
|
|
102
90
|
if (pending.get(be)) {
|
|
103
|
-
let pending_value_a = []
|
|
104
|
-
for (let value of pending.values()) {
|
|
105
|
-
pending_value_a.push(value)
|
|
106
|
-
}
|
|
107
91
|
throw new Error(
|
|
108
92
|
`be_: ${
|
|
109
93
|
String(id)
|
|
110
|
-
}: circular
|
|
111
|
-
typeof pending_value === '
|
|
112
|
-
?
|
|
113
|
-
:
|
|
94
|
+
}: circular:\n${pending.values().map(pending_value=>
|
|
95
|
+
typeof pending_value === 'string'
|
|
96
|
+
? pending_value
|
|
97
|
+
: 'Function').join('\n')}`)
|
|
114
98
|
}
|
|
115
99
|
pending.set(be, id || be)
|
|
116
|
-
let val = val__new(argv__ctx, be, params)
|
|
100
|
+
let val = val__new ? val__new(argv__ctx, be, params) : null
|
|
117
101
|
ctx.set(be, val)
|
|
118
102
|
if (id) {
|
|
119
103
|
ctx.set(id, val)
|
|
@@ -162,7 +146,6 @@ export function ctx__set(
|
|
|
162
146
|
val,
|
|
163
147
|
is_source_
|
|
164
148
|
) {
|
|
165
|
-
if (!is_source_) is_source_ = ()=>true
|
|
166
149
|
let source__map_ctx = source__map_ctx_(ctx, is_source_)
|
|
167
150
|
if (source__map_ctx) {
|
|
168
151
|
source__map_ctx.set(be_OR_id, val)
|
|
@@ -189,25 +172,18 @@ export function ctx__delete(
|
|
|
189
172
|
ctx,
|
|
190
173
|
be_OR_id,
|
|
191
174
|
) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (isArray(ctx)) {
|
|
196
|
-
for (let i = 0; i < ctx.length; i++) {
|
|
197
|
-
if (is_source_(ctx[i], ctx)) {
|
|
198
|
-
ctx__delete(ctx[i], be_OR_id)
|
|
199
|
-
}
|
|
175
|
+
if (Array.isArray(ctx)) {
|
|
176
|
+
for (let _ctx of ctx) {
|
|
177
|
+
ctx__delete(_ctx, be_OR_id)
|
|
200
178
|
}
|
|
201
179
|
} else {
|
|
202
180
|
/** @type {MapCtx} */
|
|
203
181
|
let map_ctx = /** @type {any} */ctx
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
map_ctx.delete(id)
|
|
208
|
-
}
|
|
209
|
-
map_ctx.delete(be_OR_id)
|
|
182
|
+
let { id } = be_OR_id
|
|
183
|
+
if (id) {
|
|
184
|
+
map_ctx.delete(id)
|
|
210
185
|
}
|
|
186
|
+
map_ctx.delete(be_OR_id)
|
|
211
187
|
}
|
|
212
188
|
}
|
|
213
189
|
/**
|
|
@@ -217,7 +193,7 @@ export function ctx__delete(
|
|
|
217
193
|
* @private
|
|
218
194
|
*/
|
|
219
195
|
export function be__has_(be_or_id, argv__ctx) {
|
|
220
|
-
return
|
|
196
|
+
return Boolean(be__has__ctx_(be_or_id, argv__ctx))
|
|
221
197
|
}
|
|
222
198
|
/**
|
|
223
199
|
* @param {Be|string}be_or_id
|
|
@@ -226,7 +202,7 @@ export function be__has_(be_or_id, argv__ctx) {
|
|
|
226
202
|
* @private
|
|
227
203
|
*/
|
|
228
204
|
export function be__has__ctx_(be_or_id, argv__ctx) {
|
|
229
|
-
if (isArray(argv__ctx)) {
|
|
205
|
+
if (Array.isArray(argv__ctx)) {
|
|
230
206
|
for (let i = 0; i < argv__ctx.length; i++) {
|
|
231
207
|
const be__has__ctx = be__has__ctx_(be_or_id, argv__ctx[i])
|
|
232
208
|
if (be__has__ctx) return be__has__ctx
|
|
@@ -243,7 +219,7 @@ export function be__has__ctx_(be_or_id, argv__ctx) {
|
|
|
243
219
|
* @private
|
|
244
220
|
*/
|
|
245
221
|
export function be__val_(be_or_id, argv__ctx) {
|
|
246
|
-
if (isArray(argv__ctx)) {
|
|
222
|
+
if (Array.isArray(argv__ctx)) {
|
|
247
223
|
for (let i = 0; i < argv__ctx.length; i++) {
|
|
248
224
|
let ctx = argv__ctx[i]
|
|
249
225
|
const be__has__ctx = be__has__ctx_(be_or_id, ctx)
|
|
@@ -260,7 +236,7 @@ export function be__val_(be_or_id, argv__ctx) {
|
|
|
260
236
|
* @private
|
|
261
237
|
*/
|
|
262
238
|
export function source__map_ctx_(ctx, is_source_) {
|
|
263
|
-
if (isArray(ctx)) {
|
|
239
|
+
if (Array.isArray(ctx)) {
|
|
264
240
|
for (let i = 0; i < ctx.length; i++) {
|
|
265
241
|
let i_ctx = ctx[i]
|
|
266
242
|
let source__map_ctx = source__map_ctx_(i_ctx, is_source_)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function rmemo_<val_T>(
|
|
2
|
+
def:rmemo_def_T<val_T>,
|
|
3
|
+
...subscriber_a:rmemo_subscriber_T<val_T>[]
|
|
4
|
+
):rmemo_T<val_T>
|
|
5
|
+
export declare function rsig_<val_T>(
|
|
6
|
+
init_val:val_T,
|
|
7
|
+
...subscriber_a:rmemo_subscriber_T<val_T>[]
|
|
8
|
+
):rmemo_T<val_T>
|
|
9
|
+
export type rmemo_T<val_T> = ((val?:val_T)=>val_T)&rmemo_o_T<val_T>
|
|
10
|
+
export type rmemo_def_T<val_T> = (rmemo:rmemo_T<val_T>)=>val_T
|
|
11
|
+
export type rmemo_subscriber_T<val_T> = (rmemo:rmemo_T<val_T>)=>unknown
|
|
12
|
+
export type rmemo_o_T<val_T> = {
|
|
13
|
+
_:val_T
|
|
14
|
+
readonly val:val_T
|
|
15
|
+
go():unknown
|
|
16
|
+
onset(val:val_T):unknown
|
|
17
|
+
refresh():val_T
|
|
18
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** @typedef {import('./index.d.ts').rmemo_T} */
|
|
2
|
+
/** @typedef {import('./index.d.ts').rmemo_subscriber_T} */
|
|
3
|
+
/** @type {(()=>unknown)[]} */
|
|
4
|
+
let queue = []
|
|
5
|
+
/** @type {WeakRef<rmemo_T>} */
|
|
6
|
+
let cur_ref
|
|
7
|
+
/**
|
|
8
|
+
* @param {(rmemo:rmemo_T<unknown>)=>unknown}_f
|
|
9
|
+
* @param {rmemo_subscriber_T<unknown>[]}subscriber_a
|
|
10
|
+
* @returns {rmemo_T}
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
export function rmemo_(_f, ...subscriber_a) {
|
|
14
|
+
let rmemo$ = (...arg_a)=>arg_a.length ? rmemo$._ = arg_a[0] : rmemo$._
|
|
15
|
+
let _a = []
|
|
16
|
+
let _r = new WeakRef(()=>rmemo$.refresh(_f(rmemo$)))
|
|
17
|
+
_r.l = 0
|
|
18
|
+
rmemo$._a = _a
|
|
19
|
+
rmemo$._f = _f
|
|
20
|
+
rmemo$._r = _r
|
|
21
|
+
rmemo$._rS = new Set
|
|
22
|
+
rmemo$.go = ()=>(rmemo$(), rmemo$)
|
|
23
|
+
rmemo$.onset = ()=>0
|
|
24
|
+
Object.defineProperty(rmemo$, '_', {
|
|
25
|
+
get() {
|
|
26
|
+
if (!_a.length) {
|
|
27
|
+
let prev_ref = cur_ref
|
|
28
|
+
cur_ref = _r
|
|
29
|
+
try {
|
|
30
|
+
_a[0] = _f(rmemo$)
|
|
31
|
+
} finally {
|
|
32
|
+
cur_ref = prev_ref
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// allow self-referencing
|
|
36
|
+
if (cur_ref && cur_ref !== _r) {
|
|
37
|
+
// Math.max: bitwise is much faster on chrome
|
|
38
|
+
// https://measurethat.net/Benchmarks/Show/28483/0/mathmax-vs-bitwise
|
|
39
|
+
cur_ref.l = cur_ref.l ^ ((cur_ref.l ^ _r.l + 1) & -(cur_ref.l < _r.l + 1))
|
|
40
|
+
rmemo$._rS.add(cur_ref)
|
|
41
|
+
}
|
|
42
|
+
return _a[0]
|
|
43
|
+
},
|
|
44
|
+
set(val) {
|
|
45
|
+
if (!_a.length || val !== _a[0]) {
|
|
46
|
+
rmemo$.refresh(val)
|
|
47
|
+
}
|
|
48
|
+
return val
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
rmemo$.refresh = val=>{
|
|
52
|
+
let length = _a.length
|
|
53
|
+
_a[0] = val
|
|
54
|
+
rmemo$.onset(val)
|
|
55
|
+
if (length) {
|
|
56
|
+
let run_queue = !queue[0]
|
|
57
|
+
for (let ref of rmemo$._rS) {
|
|
58
|
+
if (!~queue.indexOf(ref)) queue.push(ref)
|
|
59
|
+
}
|
|
60
|
+
if (run_queue) {
|
|
61
|
+
for (let ref; ref = queue.shift();) {
|
|
62
|
+
if (queue.some(_ref=>ref.l > _ref.l)) {
|
|
63
|
+
queue.push(ref)
|
|
64
|
+
} else {
|
|
65
|
+
(ref.deref() || rmemo$._rS.delete)(ref)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return rmemo$
|
|
71
|
+
}
|
|
72
|
+
rmemo$._sa = subscriber_a.map(subscriber=>
|
|
73
|
+
rmemo_(()=>subscriber(rmemo$)).go())
|
|
74
|
+
return rmemo$
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* @param {unknown}init_val
|
|
78
|
+
* @param {rmemo_subscriber_T[]}subscriber_a
|
|
79
|
+
* @returns {rmemo_T}
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
export function rsig_(init_val, ...subscriber_a) {
|
|
83
|
+
let signal$ =
|
|
84
|
+
rmemo_(signal$=>signal$._v, ...subscriber_a)
|
|
85
|
+
signal$.onset = val=>signal$._v = val
|
|
86
|
+
signal$._v = init_val
|
|
87
|
+
return signal$
|
|
88
|
+
}
|
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
import { deepStrictEqual } from 'node:assert'
|
|
2
|
-
import { clock } from 'sinon'
|
|
3
2
|
import { test } from 'uvu'
|
|
4
3
|
import { equal } from 'uvu/assert'
|
|
5
4
|
import { sleep } from '../sleep/index.js'
|
|
6
|
-
import {
|
|
7
|
-
test('
|
|
5
|
+
import { rmemo_, rmemo_T, rsig_ } from './index.js'
|
|
6
|
+
test('rmemo_|static value', ()=>{
|
|
8
7
|
let count = 0
|
|
9
|
-
let
|
|
8
|
+
let rmemo$ = rmemo_(rmemo=>{
|
|
10
9
|
count++
|
|
11
|
-
return '
|
|
10
|
+
return 'rmemo-value'
|
|
12
11
|
})
|
|
13
12
|
equal(count, 0)
|
|
14
|
-
equal(
|
|
13
|
+
equal(rmemo$(), 'rmemo-value')
|
|
15
14
|
equal(count, 1)
|
|
16
|
-
equal(
|
|
15
|
+
equal(rmemo$(), 'rmemo-value')
|
|
17
16
|
equal(count, 1)
|
|
18
17
|
})
|
|
19
|
-
test('
|
|
20
|
-
let
|
|
21
|
-
equal(
|
|
22
|
-
|
|
23
|
-
equal(
|
|
18
|
+
test('rsig_', ()=>{
|
|
19
|
+
let rsig$ = rsig_('val0')
|
|
20
|
+
equal(rsig$(), 'val0')
|
|
21
|
+
rsig$('val1')
|
|
22
|
+
equal(rsig$(), 'val1')
|
|
24
23
|
})
|
|
25
|
-
test('
|
|
24
|
+
test('rmemo_|def function|rmemo$ argument', ()=>{
|
|
25
|
+
let rsig$ = rsig_('val0')
|
|
26
|
+
let rmemo$:rmemo_T<string>&{custom?:string} = rmemo_<string>((_rmemo$:rmemo_T<string>&{custom?:string})=>
|
|
27
|
+
`${_rmemo$.custom}-${rsig$()}`)
|
|
28
|
+
rmemo$.custom = 'custom_val0'
|
|
29
|
+
equal(rmemo$(), 'custom_val0-val0')
|
|
30
|
+
rmemo$.custom = 'custom_val1'
|
|
31
|
+
equal(rmemo$(), 'custom_val0-val0')
|
|
32
|
+
rsig$('val1')
|
|
33
|
+
equal(rmemo$(), 'custom_val1-val1')
|
|
34
|
+
})
|
|
35
|
+
test('rsig_|async subsubscriber|case 1', async ()=>{
|
|
26
36
|
let resolve:(user:{ id:string })=>void
|
|
27
37
|
let user0 = { id: 'id-0' }
|
|
28
38
|
let user1 = { id: 'id-1' }
|
|
29
|
-
let id$ =
|
|
30
|
-
let user$ =
|
|
39
|
+
let id$ = rsig_('id-0')
|
|
40
|
+
let user$ = rsig_<{ id:string }|null>(
|
|
31
41
|
null,
|
|
32
42
|
async (_user$)=>{
|
|
33
43
|
id$()
|
|
@@ -43,13 +53,46 @@ test('rememo_|async subsubscriber', async ()=>{
|
|
|
43
53
|
resolve!(user1)
|
|
44
54
|
await sleep(0)
|
|
45
55
|
})
|
|
46
|
-
test('
|
|
47
|
-
let
|
|
48
|
-
let
|
|
49
|
-
let
|
|
50
|
-
let
|
|
51
|
-
let
|
|
52
|
-
|
|
56
|
+
test('rsig_|async subsubscriber|case 2', async ()=>{
|
|
57
|
+
let a$ = rsig_(1)
|
|
58
|
+
let b$ = rsig_(2)
|
|
59
|
+
let sleepCycles = 5
|
|
60
|
+
let taskArgumentsCalls:number[][] = []
|
|
61
|
+
let sum$ = rsig_<null|number>(null,
|
|
62
|
+
async sum$=>{
|
|
63
|
+
taskArgumentsCalls.push([a$(), b$()])
|
|
64
|
+
for (let i = 0; i < sleepCycles; i++) {
|
|
65
|
+
await Promise.resolve()
|
|
66
|
+
}
|
|
67
|
+
sum$(a$() + b$())
|
|
68
|
+
})
|
|
69
|
+
equal(sum$(), null)
|
|
70
|
+
deepStrictEqual(taskArgumentsCalls, [[1, 2]])
|
|
71
|
+
a$(10)
|
|
72
|
+
b$(20)
|
|
73
|
+
for (let i = 0; i < sleepCycles; i++) {
|
|
74
|
+
equal(sum$(), null)
|
|
75
|
+
await Promise.resolve()
|
|
76
|
+
deepStrictEqual(taskArgumentsCalls, [
|
|
77
|
+
[1, 2],
|
|
78
|
+
[10, 2],
|
|
79
|
+
[10, 20]
|
|
80
|
+
])
|
|
81
|
+
}
|
|
82
|
+
equal(sum$(), 30)
|
|
83
|
+
deepStrictEqual(taskArgumentsCalls, [
|
|
84
|
+
[1, 2],
|
|
85
|
+
[10, 2],
|
|
86
|
+
[10, 20]
|
|
87
|
+
])
|
|
88
|
+
})
|
|
89
|
+
test('rmemo_+rsig_|simple graph', ()=>{
|
|
90
|
+
let base$ = rsig_('base0')
|
|
91
|
+
let dep0$ = rmemo_(()=>base$() + '-dep0')
|
|
92
|
+
let dep1$ = rmemo_(()=>dep0$() + '-dep1')
|
|
93
|
+
let dep2$ = rmemo_(()=>dep1$() + '-dep2')
|
|
94
|
+
let dep3$ = rmemo_(()=>dep2$() + '-dep3')
|
|
95
|
+
let dep4$ = rmemo_(()=>dep3$() + '-dep4')
|
|
53
96
|
equal(dep4$(), 'base0-dep0-dep1-dep2-dep3-dep4')
|
|
54
97
|
equal(dep3$(), 'base0-dep0-dep1-dep2-dep3')
|
|
55
98
|
equal(dep2$(), 'base0-dep0-dep1-dep2')
|
|
@@ -65,13 +108,13 @@ test('rememo_+signal_|simple graph', ()=>{
|
|
|
65
108
|
equal(dep4$(), 'base1-dep0-dep1-dep2-dep3-dep4')
|
|
66
109
|
})
|
|
67
110
|
test('prevents diamond dependency problem 1', ()=>{
|
|
68
|
-
let store$ =
|
|
111
|
+
let store$ = rsig_(0)
|
|
69
112
|
let values:string[] = []
|
|
70
|
-
let a$ =
|
|
71
|
-
let b$ =
|
|
72
|
-
let c$ =
|
|
73
|
-
let d$ =
|
|
74
|
-
let combined$ =
|
|
113
|
+
let a$ = rmemo_(()=>`a${store$()}`)
|
|
114
|
+
let b$ = rmemo_(()=>a$().replace('a', 'b'))
|
|
115
|
+
let c$ = rmemo_(()=>a$().replace('a', 'c'))
|
|
116
|
+
let d$ = rmemo_(()=>a$().replace('a', 'd'))
|
|
117
|
+
let combined$ = rmemo_(()=>`${b$()}${c$()}${d$()}`,
|
|
75
118
|
combined$=>
|
|
76
119
|
values.push(combined$()))
|
|
77
120
|
deepStrictEqual(values, ['b0c0d0'])
|
|
@@ -80,14 +123,14 @@ test('prevents diamond dependency problem 1', ()=>{
|
|
|
80
123
|
deepStrictEqual(values, ['b0c0d0', 'b1c1d1', 'b2c2d2'])
|
|
81
124
|
})
|
|
82
125
|
test('prevents diamond dependency problem 2', ()=>{
|
|
83
|
-
let store$ =
|
|
126
|
+
let store$ = rsig_(0)
|
|
84
127
|
let values:string[] = []
|
|
85
|
-
let a$ =
|
|
86
|
-
let b$ =
|
|
87
|
-
let c$ =
|
|
88
|
-
let d$ =
|
|
89
|
-
let e$ =
|
|
90
|
-
let combined$ =
|
|
128
|
+
let a$ = rmemo_(()=>`a${store$()}`)
|
|
129
|
+
let b$ = rmemo_(()=>a$().replace('a', 'b'))
|
|
130
|
+
let c$ = rmemo_(()=>b$().replace('b', 'c'))
|
|
131
|
+
let d$ = rmemo_(()=>c$().replace('c', 'd'))
|
|
132
|
+
let e$ = rmemo_(()=>d$().replace('d', 'e'))
|
|
133
|
+
let combined$ = rmemo_<string>(
|
|
91
134
|
()=>[a$(), e$()].join(''),
|
|
92
135
|
combined$=>values.push(combined$()))
|
|
93
136
|
deepStrictEqual(values, ['a0e0'])
|
|
@@ -95,13 +138,13 @@ test('prevents diamond dependency problem 2', ()=>{
|
|
|
95
138
|
deepStrictEqual(values, ['a0e0', 'a1e1'])
|
|
96
139
|
})
|
|
97
140
|
test('prevents diamond dependency problem 3', ()=>{
|
|
98
|
-
let store$ =
|
|
141
|
+
let store$ = rsig_(0)
|
|
99
142
|
let values:string[] = []
|
|
100
|
-
let a$ =
|
|
101
|
-
let b$ =
|
|
102
|
-
let c$ =
|
|
103
|
-
let d$ =
|
|
104
|
-
|
|
143
|
+
let a$ = rmemo_(()=>`a${store$()}`)
|
|
144
|
+
let b$ = rmemo_(()=>a$().replace('a', 'b'))
|
|
145
|
+
let c$ = rmemo_(()=>b$().replace('b', 'c'))
|
|
146
|
+
let d$ = rmemo_(()=>c$().replace('c', 'd'))
|
|
147
|
+
rmemo_<string>(
|
|
105
148
|
()=>`${a$()}${b$()}${c$()}${d$()}`,
|
|
106
149
|
combined$=>values.push(combined$()))
|
|
107
150
|
deepStrictEqual(values, ['a0b0c0d0'])
|
|
@@ -109,24 +152,24 @@ test('prevents diamond dependency problem 3', ()=>{
|
|
|
109
152
|
deepStrictEqual(values, ['a0b0c0d0', 'a1b1c1d1'])
|
|
110
153
|
})
|
|
111
154
|
test('autosubscribe: prevents diamond dependency problem 4 (complex)', ()=>{
|
|
112
|
-
let store1$ =
|
|
113
|
-
let store2$ =
|
|
155
|
+
let store1$ = rsig_(0)
|
|
156
|
+
let store2$ = rsig_(0)
|
|
114
157
|
let values:string[] = []
|
|
115
158
|
let fn =
|
|
116
159
|
(name:string)=>
|
|
117
160
|
(...v:(number|string)[])=>
|
|
118
161
|
`${name}${v.join('')}`
|
|
119
|
-
let a$ =
|
|
120
|
-
let b$ =
|
|
121
|
-
let c$ =
|
|
122
|
-
let d$ =
|
|
123
|
-
let e$ =
|
|
124
|
-
let f$ =
|
|
125
|
-
let g$ =
|
|
126
|
-
|
|
162
|
+
let a$ = rmemo_(()=>`a${store1$()}`)
|
|
163
|
+
let b$ = rmemo_(()=>`b${store2$()}`)
|
|
164
|
+
let c$ = rmemo_(()=>`c${a$()}${b$()}`)
|
|
165
|
+
let d$ = rmemo_(()=>`d${a$()}`)
|
|
166
|
+
let e$ = rmemo_(()=>`e${c$()}${d$()}`)
|
|
167
|
+
let f$ = rmemo_(()=>`f${e$()}`)
|
|
168
|
+
let g$ = rmemo_(()=>`g${f$()}`)
|
|
169
|
+
rmemo_(
|
|
127
170
|
()=>e$(),
|
|
128
171
|
combined1$=>values.push(combined1$()))
|
|
129
|
-
|
|
172
|
+
rmemo_(
|
|
130
173
|
()=>[e$(), g$()].join(''),
|
|
131
174
|
combined2$=>values.push(combined2$()))
|
|
132
175
|
deepStrictEqual(values, ['eca0b0da0', 'eca0b0da0gfeca0b0da0'])
|
|
@@ -143,17 +186,17 @@ test('autosubscribe: prevents diamond dependency problem 4 (complex)', ()=>{
|
|
|
143
186
|
})
|
|
144
187
|
test('prevents diamond dependency problem 5', ()=>{
|
|
145
188
|
let events = ''
|
|
146
|
-
let firstName$ =
|
|
147
|
-
let lastName$ =
|
|
148
|
-
let fullName$ =
|
|
189
|
+
let firstName$ = rsig_('John')
|
|
190
|
+
let lastName$ = rsig_('Doe')
|
|
191
|
+
let fullName$ = rmemo_(()=>{
|
|
149
192
|
events += 'full '
|
|
150
193
|
return `${firstName$()} ${lastName$()}`
|
|
151
194
|
})
|
|
152
|
-
let isFirstShort$ =
|
|
195
|
+
let isFirstShort$ = rmemo_(()=>{
|
|
153
196
|
events += 'short '
|
|
154
197
|
return firstName$().length < 10
|
|
155
198
|
})
|
|
156
|
-
let displayName$ =
|
|
199
|
+
let displayName$ = rmemo_(
|
|
157
200
|
()=>{
|
|
158
201
|
events += 'display '
|
|
159
202
|
return isFirstShort$() ? fullName$() : firstName$()
|
|
@@ -170,13 +213,13 @@ test('prevents diamond dependency problem 5', ()=>{
|
|
|
170
213
|
equal(events, 'display short full short full display short full display ')
|
|
171
214
|
})
|
|
172
215
|
test('prevents diamond dependency problem 6', ()=>{
|
|
173
|
-
let store1$ =
|
|
174
|
-
let store2$ =
|
|
216
|
+
let store1$ = rsig_(0)
|
|
217
|
+
let store2$ = rsig_(0)
|
|
175
218
|
let values:string[] = []
|
|
176
|
-
let a$ =
|
|
177
|
-
let b$ =
|
|
178
|
-
let c$ =
|
|
179
|
-
|
|
219
|
+
let a$ = rmemo_(()=>`a${store1$()}`)
|
|
220
|
+
let b$ = rmemo_(()=>`b${store2$()}`)
|
|
221
|
+
let c$ = rmemo_(()=>b$().replace('b', 'c'))
|
|
222
|
+
rmemo_(
|
|
180
223
|
()=>`${a$()}${c$()}`,
|
|
181
224
|
combined$=>values.push(combined$()))
|
|
182
225
|
deepStrictEqual(values, ['a0c0'])
|
|
@@ -184,12 +227,12 @@ test('prevents diamond dependency problem 6', ()=>{
|
|
|
184
227
|
deepStrictEqual(values, ['a0c0', 'a1c0'])
|
|
185
228
|
})
|
|
186
229
|
test('prevents dependency listeners from being out of order', ()=>{
|
|
187
|
-
let base$ =
|
|
188
|
-
let a$ =
|
|
230
|
+
let base$ = rsig_(0)
|
|
231
|
+
let a$ = rmemo_(()=>{
|
|
189
232
|
return `${base$()}a`
|
|
190
233
|
})
|
|
191
234
|
let values:string[] = []
|
|
192
|
-
let b$ =
|
|
235
|
+
let b$ = rmemo_(()=>{
|
|
193
236
|
return `${a$()}b`
|
|
194
237
|
}, b$=>values.push(b$()))
|
|
195
238
|
equal(b$(), '0ab')
|
|
@@ -199,43 +242,9 @@ test('prevents dependency listeners from being out of order', ()=>{
|
|
|
199
242
|
deepStrictEqual(values, ['0ab', '1ab'])
|
|
200
243
|
})
|
|
201
244
|
test('computes initial value when argument is undefined', ()=>{
|
|
202
|
-
let one$ =
|
|
203
|
-
let two$ =
|
|
245
|
+
let one$ = rsig_<string|undefined>(undefined)
|
|
246
|
+
let two$ = rmemo_(()=>!!one$())
|
|
204
247
|
equal(one$(), undefined)
|
|
205
248
|
equal(two$(), false)
|
|
206
249
|
})
|
|
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
250
|
test.run()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctx-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "ctx-core core library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ctx-core",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"queue",
|
|
54
54
|
"random",
|
|
55
55
|
"regex",
|
|
56
|
-
"
|
|
56
|
+
"rmemo",
|
|
57
57
|
"set",
|
|
58
58
|
"sleep",
|
|
59
59
|
"string",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"./queue": "./queue/index.js",
|
|
95
95
|
"./random": "./random/index.js",
|
|
96
96
|
"./regex": "./regex/index.js",
|
|
97
|
-
"./
|
|
97
|
+
"./rmemo": "./rmemo/index.js",
|
|
98
98
|
"./set": "./set/index.js",
|
|
99
99
|
"./sleep": "./sleep/index.js",
|
|
100
100
|
"./string": "./string/index.js",
|
|
@@ -129,21 +129,21 @@
|
|
|
129
129
|
"import": {
|
|
130
130
|
"./be": "{ be_ }"
|
|
131
131
|
},
|
|
132
|
-
"limit": "
|
|
132
|
+
"limit": "465 B"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
|
-
"name": "
|
|
135
|
+
"name": "rmemo",
|
|
136
136
|
"import": {
|
|
137
|
-
"./
|
|
137
|
+
"./rmemo": "{ rmemo_ }"
|
|
138
138
|
},
|
|
139
|
-
"limit": "
|
|
139
|
+
"limit": "351 B"
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
|
-
"name": "
|
|
142
|
+
"name": "rmemo signal",
|
|
143
143
|
"import": {
|
|
144
|
-
"./
|
|
144
|
+
"./rmemo": "{ rsig_ }"
|
|
145
145
|
},
|
|
146
|
-
"limit": "
|
|
146
|
+
"limit": "377 B"
|
|
147
147
|
}
|
|
148
148
|
],
|
|
149
149
|
"scripts": {
|
package/rmemo/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../all/rmemo/index.js'
|
package/rmemo/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../all/rmemo/index.js'
|
package/all/rememo/index.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
package/all/rememo/index.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
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
|
-
}
|
package/rememo/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../all/rememo/index.js'
|
package/rememo/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../all/rememo/index.js'
|