@zeix/cause-effect 0.17.2 → 0.17.3
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/.ai-context.md +11 -5
- package/.github/copilot-instructions.md +1 -1
- package/.zed/settings.json +3 -0
- package/CLAUDE.md +18 -79
- package/README.md +23 -37
- package/archive/benchmark.ts +0 -5
- package/archive/collection.ts +5 -62
- package/archive/composite.ts +85 -0
- package/archive/computed.ts +17 -20
- package/archive/list.ts +6 -67
- package/archive/memo.ts +13 -14
- package/archive/store.ts +7 -66
- package/archive/task.ts +18 -20
- package/index.dev.js +438 -614
- package/index.js +1 -1
- package/index.ts +8 -19
- package/package.json +6 -6
- package/src/classes/collection.ts +59 -112
- package/src/classes/computed.ts +146 -189
- package/src/classes/list.ts +138 -105
- package/src/classes/ref.ts +16 -42
- package/src/classes/state.ts +16 -45
- package/src/classes/store.ts +107 -72
- package/src/effect.ts +9 -12
- package/src/errors.ts +12 -8
- package/src/signal.ts +3 -1
- package/src/system.ts +136 -154
- package/test/batch.test.ts +4 -11
- package/test/benchmark.test.ts +4 -2
- package/test/collection.test.ts +46 -306
- package/test/computed.test.ts +205 -223
- package/test/list.test.ts +35 -303
- package/test/ref.test.ts +38 -66
- package/test/state.test.ts +6 -12
- package/test/store.test.ts +37 -489
- package/test/util/dependency-graph.ts +2 -2
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +5 -7
- package/types/index.d.ts +2 -2
- package/types/src/classes/collection.d.ts +4 -6
- package/types/src/classes/computed.d.ts +17 -37
- package/types/src/classes/list.d.ts +8 -6
- package/types/src/classes/ref.d.ts +7 -20
- package/types/src/classes/state.d.ts +5 -17
- package/types/src/classes/store.d.ts +12 -11
- package/types/src/errors.d.ts +2 -4
- package/types/src/signal.d.ts +3 -2
- package/types/src/system.d.ts +41 -44
- package/src/classes/composite.ts +0 -171
- package/types/src/classes/composite.d.ts +0 -15
package/src/system.ts
CHANGED
|
@@ -1,36 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { assert, type Guard } from './errors'
|
|
2
|
+
import type { UnknownSignal } from './signal'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
import { isFunction } from './util'
|
|
4
|
+
/* === Types === */
|
|
5
5
|
|
|
6
6
|
type Cleanup = () => void
|
|
7
7
|
|
|
8
8
|
// biome-ignore lint/suspicious/noConfusingVoidType: optional Cleanup return type
|
|
9
9
|
type MaybeCleanup = Cleanup | undefined | void
|
|
10
10
|
|
|
11
|
-
type Hook = 'add' | 'change' | 'cleanup' | 'remove' | 'sort' | 'watch'
|
|
12
|
-
type CleanupHook = 'cleanup'
|
|
13
|
-
type WatchHook = 'watch'
|
|
14
|
-
|
|
15
|
-
type HookCallback = (payload?: readonly string[]) => MaybeCleanup
|
|
16
|
-
|
|
17
|
-
type HookCallbacks = {
|
|
18
|
-
[K in Hook]?: Set<HookCallback>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
11
|
type Watcher = {
|
|
22
12
|
(): void
|
|
23
|
-
|
|
13
|
+
run(): void
|
|
14
|
+
onCleanup(cleanup: Cleanup): void
|
|
24
15
|
stop(): void
|
|
25
16
|
}
|
|
26
17
|
|
|
18
|
+
type SignalOptions<T extends unknown & {}> = {
|
|
19
|
+
guard?: Guard<T>
|
|
20
|
+
watched?: () => void
|
|
21
|
+
unwatched?: () => void
|
|
22
|
+
}
|
|
23
|
+
|
|
27
24
|
/* === Internal === */
|
|
28
25
|
|
|
29
26
|
// Currently active watcher
|
|
30
27
|
let activeWatcher: Watcher | undefined
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
const
|
|
29
|
+
const watchersMap = new WeakMap<UnknownSignal, Set<Watcher>>()
|
|
30
|
+
const watchedCallbackMap = new WeakMap<object, () => void>()
|
|
31
|
+
const unwatchedCallbackMap = new WeakMap<object, () => void>()
|
|
34
32
|
|
|
35
33
|
// Queue of pending watcher reactions for batched change notifications
|
|
36
34
|
const pendingReactions = new Set<() => void>()
|
|
@@ -41,30 +39,32 @@ let batchDepth = 0
|
|
|
41
39
|
// biome-ignore lint/suspicious/noExplicitAny: Deliberately using any to be used as a placeholder value in any signal
|
|
42
40
|
const UNSET: any = Symbol()
|
|
43
41
|
|
|
44
|
-
const HOOK_ADD = 'add'
|
|
45
|
-
const HOOK_CHANGE = 'change'
|
|
46
|
-
const HOOK_CLEANUP = 'cleanup'
|
|
47
|
-
const HOOK_REMOVE = 'remove'
|
|
48
|
-
const HOOK_SORT = 'sort'
|
|
49
|
-
const HOOK_WATCH = 'watch'
|
|
50
|
-
|
|
51
42
|
/* === Functions === */
|
|
52
43
|
|
|
53
44
|
/**
|
|
54
|
-
* Create a watcher to observe changes
|
|
45
|
+
* Create a watcher to observe changes in signals.
|
|
55
46
|
*
|
|
56
|
-
* A watcher
|
|
47
|
+
* A watcher combines push and pull reaction functions with onCleanup and stop methods
|
|
57
48
|
*
|
|
58
|
-
* @since 0.
|
|
59
|
-
* @param {() => void}
|
|
49
|
+
* @since 0.17.3
|
|
50
|
+
* @param {() => void} push - Function to be called when the state changes (push)
|
|
51
|
+
* @param {() => void} pull - Function to be called on demand from consumers (pull)
|
|
60
52
|
* @returns {Watcher} - Watcher object with off and cleanup methods
|
|
61
53
|
*/
|
|
62
|
-
const createWatcher = (
|
|
54
|
+
const createWatcher = (push: () => void, pull: () => void): Watcher => {
|
|
63
55
|
const cleanups = new Set<Cleanup>()
|
|
64
|
-
const watcher =
|
|
65
|
-
watcher.
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
const watcher = push as Partial<Watcher>
|
|
57
|
+
watcher.run = () => {
|
|
58
|
+
const prev = activeWatcher
|
|
59
|
+
activeWatcher = watcher as Watcher
|
|
60
|
+
try {
|
|
61
|
+
pull()
|
|
62
|
+
} finally {
|
|
63
|
+
activeWatcher = prev
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
watcher.onCleanup = (cleanup: Cleanup) => {
|
|
67
|
+
cleanups.add(cleanup)
|
|
68
68
|
}
|
|
69
69
|
watcher.stop = () => {
|
|
70
70
|
try {
|
|
@@ -77,62 +77,113 @@ const createWatcher = (react: () => void): Watcher => {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* Run a function with signal reads in a non-tracking context.
|
|
81
81
|
*
|
|
82
|
-
* @param {
|
|
83
|
-
* @param {Set<HookCallback>} watchHookCallbacks - HOOK_WATCH callbacks of the signal
|
|
82
|
+
* @param {() => void} callback - Callback
|
|
84
83
|
*/
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (unwatch) {
|
|
93
|
-
const unwatchCallbacks =
|
|
94
|
-
unwatchMap.get(watchers) ?? new Set<Cleanup>()
|
|
95
|
-
unwatchCallbacks.add(unwatch)
|
|
96
|
-
if (!unwatchMap.has(watchers))
|
|
97
|
-
unwatchMap.set(watchers, unwatchCallbacks)
|
|
98
|
-
}
|
|
84
|
+
const untrack = (callback: () => void): void => {
|
|
85
|
+
const prev = activeWatcher
|
|
86
|
+
activeWatcher = undefined
|
|
87
|
+
try {
|
|
88
|
+
callback()
|
|
89
|
+
} finally {
|
|
90
|
+
activeWatcher = prev
|
|
99
91
|
}
|
|
92
|
+
}
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
const registerWatchCallbacks = (
|
|
95
|
+
signal: UnknownSignal,
|
|
96
|
+
watched: () => void,
|
|
97
|
+
unwatched?: () => void,
|
|
98
|
+
) => {
|
|
99
|
+
watchedCallbackMap.set(signal, watched)
|
|
100
|
+
if (unwatched) unwatchedCallbackMap.set(signal, unwatched)
|
|
101
|
+
}
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe active watcher to a signal.
|
|
105
|
+
*
|
|
106
|
+
* @param {UnknownSignal} signal - Signal to subscribe to
|
|
107
|
+
* @returns {boolean} - true if the active watcher was subscribed,
|
|
108
|
+
* false if the watcher was already subscribed or there was no active watcher
|
|
109
|
+
*/
|
|
110
|
+
const subscribeTo = (signal: UnknownSignal): boolean => {
|
|
111
|
+
if (!activeWatcher || watchersMap.get(signal)?.has(activeWatcher))
|
|
112
|
+
return false
|
|
113
|
+
|
|
114
|
+
const watcher = activeWatcher
|
|
115
|
+
if (!watchersMap.has(signal)) watchersMap.set(signal, new Set<Watcher>())
|
|
116
|
+
|
|
117
|
+
const watchers = watchersMap.get(signal)
|
|
118
|
+
assert(watchers)
|
|
119
|
+
if (!watchers.size) {
|
|
120
|
+
const watchedCallback = watchedCallbackMap.get(signal)
|
|
121
|
+
if (watchedCallback) untrack(watchedCallback)
|
|
122
|
+
}
|
|
123
|
+
watchers.add(watcher)
|
|
124
|
+
watcher.onCleanup(() => {
|
|
125
|
+
watchers.delete(watcher)
|
|
126
|
+
if (!watchers.size) {
|
|
127
|
+
const unwatchedCallback = unwatchedCallbackMap.get(signal)
|
|
128
|
+
if (unwatchedCallback) untrack(unwatchedCallback)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
return true
|
|
132
|
+
}
|
|
108
133
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const unwatchCallbacks = unwatchMap.get(watchers)
|
|
112
|
-
if (unwatchCallbacks) {
|
|
113
|
-
try {
|
|
114
|
-
for (const unwatch of unwatchCallbacks) unwatch()
|
|
115
|
-
} finally {
|
|
116
|
-
unwatchCallbacks.clear()
|
|
117
|
-
unwatchMap.delete(watchers)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
})
|
|
134
|
+
const subscribeActiveWatcher = (watchers: Set<Watcher>) => {
|
|
135
|
+
if (!activeWatcher || watchers.has(activeWatcher)) return false
|
|
122
136
|
|
|
123
|
-
|
|
124
|
-
|
|
137
|
+
const watcher = activeWatcher
|
|
138
|
+
watchers.add(watcher)
|
|
139
|
+
if (!watchers.size) {
|
|
140
|
+
const watchedCallback = watchedCallbackMap.get(watchers)
|
|
141
|
+
if (watchedCallback) untrack(watchedCallback)
|
|
125
142
|
}
|
|
143
|
+
watcher.onCleanup(() => {
|
|
144
|
+
watchers.delete(watcher)
|
|
145
|
+
if (!watchers.size) {
|
|
146
|
+
const unwatchedCallback = unwatchedCallbackMap.get(watchers)
|
|
147
|
+
if (unwatchedCallback) untrack(unwatchedCallback)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
return true
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Unsubscribe all watchers from a signal so it can be garbage collected.
|
|
155
|
+
*
|
|
156
|
+
* @param {UnknownSignal} signal - Signal to unsubscribe from
|
|
157
|
+
* @returns {void}
|
|
158
|
+
*/
|
|
159
|
+
const unsubscribeAllFrom = (signal: UnknownSignal): void => {
|
|
160
|
+
const watchers = watchersMap.get(signal)
|
|
161
|
+
if (!watchers) return
|
|
162
|
+
|
|
163
|
+
for (const watcher of watchers) watcher.stop()
|
|
164
|
+
watchers.clear()
|
|
126
165
|
}
|
|
127
166
|
|
|
128
167
|
/**
|
|
129
168
|
* Notify watchers of a signal change.
|
|
130
169
|
*
|
|
131
|
-
* @param {
|
|
170
|
+
* @param {UnknownSignal} signal - Signal to notify watchers of
|
|
132
171
|
* @returns {boolean} - Whether any watchers were notified
|
|
133
172
|
*/
|
|
173
|
+
const notifyOf = (signal: UnknownSignal): boolean => {
|
|
174
|
+
const watchers = watchersMap.get(signal)
|
|
175
|
+
if (!watchers?.size) return false
|
|
176
|
+
|
|
177
|
+
for (const react of watchers) {
|
|
178
|
+
if (batchDepth) pendingReactions.add(react)
|
|
179
|
+
else react()
|
|
180
|
+
}
|
|
181
|
+
return true
|
|
182
|
+
}
|
|
183
|
+
|
|
134
184
|
const notifyWatchers = (watchers: Set<Watcher>): boolean => {
|
|
135
185
|
if (!watchers.size) return false
|
|
186
|
+
|
|
136
187
|
for (const react of watchers) {
|
|
137
188
|
if (batchDepth) pendingReactions.add(react)
|
|
138
189
|
else react()
|
|
@@ -143,11 +194,11 @@ const notifyWatchers = (watchers: Set<Watcher>): boolean => {
|
|
|
143
194
|
/**
|
|
144
195
|
* Flush all pending reactions of enqueued watchers.
|
|
145
196
|
*/
|
|
146
|
-
const
|
|
197
|
+
const flush = () => {
|
|
147
198
|
while (pendingReactions.size) {
|
|
148
199
|
const watchers = Array.from(pendingReactions)
|
|
149
200
|
pendingReactions.clear()
|
|
150
|
-
for (const
|
|
201
|
+
for (const react of watchers) react()
|
|
151
202
|
}
|
|
152
203
|
}
|
|
153
204
|
|
|
@@ -156,12 +207,12 @@ const flushPendingReactions = () => {
|
|
|
156
207
|
*
|
|
157
208
|
* @param {() => void} callback - Function with multiple signal writes to be batched
|
|
158
209
|
*/
|
|
159
|
-
const
|
|
210
|
+
const batch = (callback: () => void) => {
|
|
160
211
|
batchDepth++
|
|
161
212
|
try {
|
|
162
213
|
callback()
|
|
163
214
|
} finally {
|
|
164
|
-
|
|
215
|
+
flush()
|
|
165
216
|
batchDepth--
|
|
166
217
|
}
|
|
167
218
|
}
|
|
@@ -174,7 +225,7 @@ const batchSignalWrites = (callback: () => void) => {
|
|
|
174
225
|
* that might read signals (e.g., Web Components)
|
|
175
226
|
* @param {() => void} run - Function to run the computation or effect
|
|
176
227
|
*/
|
|
177
|
-
const
|
|
228
|
+
const track = (watcher: Watcher | false, run: () => void): void => {
|
|
178
229
|
const prev = activeWatcher
|
|
179
230
|
activeWatcher = watcher || undefined
|
|
180
231
|
try {
|
|
@@ -184,92 +235,23 @@ const trackSignalReads = (watcher: Watcher | false, run: () => void): void => {
|
|
|
184
235
|
}
|
|
185
236
|
}
|
|
186
237
|
|
|
187
|
-
/**
|
|
188
|
-
* Trigger a hook.
|
|
189
|
-
*
|
|
190
|
-
* @param {Set<HookCallback> | undefined} callbacks - Callbacks to be called when the hook is triggered
|
|
191
|
-
* @param {readonly string[] | undefined} payload - Payload to be sent to listeners
|
|
192
|
-
* @return {Cleanup | undefined} Cleanup function to be called when the hook is unmounted
|
|
193
|
-
*/
|
|
194
|
-
const triggerHook = (
|
|
195
|
-
callbacks: Set<HookCallback> | undefined,
|
|
196
|
-
payload?: readonly string[],
|
|
197
|
-
): Cleanup | undefined => {
|
|
198
|
-
if (!callbacks) return
|
|
199
|
-
|
|
200
|
-
const cleanups: Cleanup[] = []
|
|
201
|
-
const errors: Error[] = []
|
|
202
|
-
|
|
203
|
-
const throwError = (inCleanup?: boolean) => {
|
|
204
|
-
if (errors.length) {
|
|
205
|
-
if (errors.length === 1) throw errors[0]
|
|
206
|
-
throw new AggregateError(
|
|
207
|
-
errors,
|
|
208
|
-
`Errors in hook ${inCleanup ? 'cleanup' : 'callback'}:`,
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
for (const callback of callbacks) {
|
|
214
|
-
try {
|
|
215
|
-
const cleanup = callback(payload)
|
|
216
|
-
if (isFunction(cleanup)) cleanups.push(cleanup)
|
|
217
|
-
} catch (error) {
|
|
218
|
-
errors.push(createError(error))
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
throwError()
|
|
222
|
-
|
|
223
|
-
if (!cleanups.length) return
|
|
224
|
-
if (cleanups.length === 1) return cleanups[0]
|
|
225
|
-
return () => {
|
|
226
|
-
for (const cleanup of cleanups) {
|
|
227
|
-
try {
|
|
228
|
-
cleanup()
|
|
229
|
-
} catch (error) {
|
|
230
|
-
errors.push(createError(error))
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
throwError(true)
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Check whether a hook type is handled in a signal.
|
|
239
|
-
*
|
|
240
|
-
* @param {Hook} type - Type of hook to check
|
|
241
|
-
* @param {T} handled - List of handled hook types
|
|
242
|
-
* @returns {type is T[number]} - Whether the hook type is handled
|
|
243
|
-
*/
|
|
244
|
-
const isHandledHook = <T extends readonly Hook[]>(
|
|
245
|
-
type: Hook,
|
|
246
|
-
handled: T,
|
|
247
|
-
): type is T[number] => handled.includes(type)
|
|
248
|
-
|
|
249
238
|
/* === Exports === */
|
|
250
239
|
|
|
251
240
|
export {
|
|
252
241
|
type Cleanup,
|
|
253
242
|
type MaybeCleanup,
|
|
254
243
|
type Watcher,
|
|
255
|
-
type
|
|
256
|
-
type CleanupHook,
|
|
257
|
-
type WatchHook,
|
|
258
|
-
type HookCallback,
|
|
259
|
-
type HookCallbacks,
|
|
260
|
-
HOOK_ADD,
|
|
261
|
-
HOOK_CHANGE,
|
|
262
|
-
HOOK_CLEANUP,
|
|
263
|
-
HOOK_REMOVE,
|
|
264
|
-
HOOK_SORT,
|
|
265
|
-
HOOK_WATCH,
|
|
244
|
+
type SignalOptions,
|
|
266
245
|
UNSET,
|
|
267
246
|
createWatcher,
|
|
247
|
+
registerWatchCallbacks,
|
|
248
|
+
subscribeTo,
|
|
268
249
|
subscribeActiveWatcher,
|
|
250
|
+
unsubscribeAllFrom,
|
|
251
|
+
notifyOf,
|
|
269
252
|
notifyWatchers,
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
isHandledHook,
|
|
253
|
+
flush,
|
|
254
|
+
batch,
|
|
255
|
+
track,
|
|
256
|
+
untrack,
|
|
275
257
|
}
|
package/test/batch.test.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
3
|
-
batchSignalWrites,
|
|
4
|
-
createEffect,
|
|
5
|
-
Memo,
|
|
6
|
-
match,
|
|
7
|
-
resolve,
|
|
8
|
-
State,
|
|
9
|
-
} from '../index.ts'
|
|
2
|
+
import { batch, createEffect, Memo, match, resolve, State } from '../index.ts'
|
|
10
3
|
|
|
11
4
|
/* === Tests === */
|
|
12
5
|
|
|
@@ -19,7 +12,7 @@ describe('Batch', () => {
|
|
|
19
12
|
result = cause.get()
|
|
20
13
|
count++
|
|
21
14
|
})
|
|
22
|
-
|
|
15
|
+
batch(() => {
|
|
23
16
|
for (let i = 1; i <= 10; i++) cause.set(i)
|
|
24
17
|
})
|
|
25
18
|
expect(result).toBe(10)
|
|
@@ -43,7 +36,7 @@ describe('Batch', () => {
|
|
|
43
36
|
err: () => {},
|
|
44
37
|
})
|
|
45
38
|
})
|
|
46
|
-
|
|
39
|
+
batch(() => {
|
|
47
40
|
a.set(6)
|
|
48
41
|
b.set(8)
|
|
49
42
|
c.set(10)
|
|
@@ -87,7 +80,7 @@ describe('Batch', () => {
|
|
|
87
80
|
expect(result).toBe(10)
|
|
88
81
|
|
|
89
82
|
// Batch: apply changes to all signals in a single transaction
|
|
90
|
-
|
|
83
|
+
batch(() => {
|
|
91
84
|
signals.forEach(signal => signal.update(v => v * 2))
|
|
92
85
|
})
|
|
93
86
|
|
package/test/benchmark.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { batch, createEffect, Memo, State } from '../index.ts'
|
|
3
3
|
import { Counter, makeGraph, runGraph } from './util/dependency-graph'
|
|
4
4
|
import type { Computed, ReactiveFramework } from './util/reactive-framework'
|
|
5
5
|
|
|
@@ -28,7 +28,7 @@ const framework = {
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
effect: (fn: () => undefined) => createEffect(fn),
|
|
31
|
-
withBatch: (fn: () => undefined) =>
|
|
31
|
+
withBatch: (fn: () => undefined) => batch(fn),
|
|
32
32
|
withBuild: <T>(fn: () => T) => fn(),
|
|
33
33
|
}
|
|
34
34
|
const testPullCounts = true
|
|
@@ -449,6 +449,7 @@ describe('$mol_wire tests', () => {
|
|
|
449
449
|
const name = framework.name
|
|
450
450
|
|
|
451
451
|
test(`${name} | $mol_wire benchmark`, () => {
|
|
452
|
+
// @ts-expect-error test
|
|
452
453
|
const fib = (n: number) => {
|
|
453
454
|
if (n < 2) return 1
|
|
454
455
|
return fib(n - 1) + fib(n - 2)
|
|
@@ -618,6 +619,7 @@ describe('CellX tests', () => {
|
|
|
618
619
|
for (const layers in expected) {
|
|
619
620
|
// @ts-expect-error - Framework object has incompatible type constraints with ReactiveFramework
|
|
620
621
|
const [before, after] = cellx(framework, layers)
|
|
622
|
+
// @ts-expect-error - Framework object has incompatible type constraints with ReactiveFramework
|
|
621
623
|
const [expectedBefore, expectedAfter] = expected[layers]
|
|
622
624
|
expect(before.toString()).toBe(expectedBefore.toString())
|
|
623
625
|
expect(after.toString()).toBe(expectedAfter.toString())
|