@zeix/cause-effect 0.17.3 → 0.18.1

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.
Files changed (94) hide show
  1. package/.ai-context.md +169 -227
  2. package/.cursorrules +41 -35
  3. package/.github/copilot-instructions.md +176 -116
  4. package/ARCHITECTURE.md +276 -0
  5. package/CHANGELOG.md +29 -0
  6. package/CLAUDE.md +201 -143
  7. package/GUIDE.md +298 -0
  8. package/README.md +246 -193
  9. package/REQUIREMENTS.md +100 -0
  10. package/bench/reactivity.bench.ts +577 -0
  11. package/context7.json +4 -0
  12. package/examples/events-sensor.ts +187 -0
  13. package/examples/selector-sensor.ts +173 -0
  14. package/index.dev.js +1390 -1008
  15. package/index.js +1 -1
  16. package/index.ts +60 -74
  17. package/package.json +5 -2
  18. package/skills/changelog-keeper/SKILL.md +59 -0
  19. package/skills/changelog-keeper/agents/openai.yaml +4 -0
  20. package/src/errors.ts +118 -74
  21. package/src/graph.ts +612 -0
  22. package/src/nodes/collection.ts +512 -0
  23. package/src/nodes/effect.ts +149 -0
  24. package/src/nodes/list.ts +589 -0
  25. package/src/nodes/memo.ts +148 -0
  26. package/src/nodes/sensor.ts +149 -0
  27. package/src/nodes/state.ts +135 -0
  28. package/src/nodes/store.ts +378 -0
  29. package/src/nodes/task.ts +174 -0
  30. package/src/signal.ts +112 -66
  31. package/src/util.ts +26 -57
  32. package/test/batch.test.ts +96 -62
  33. package/test/benchmark.test.ts +473 -487
  34. package/test/collection.test.ts +456 -707
  35. package/test/effect.test.ts +293 -696
  36. package/test/list.test.ts +335 -592
  37. package/test/memo.test.ts +574 -0
  38. package/test/regression.test.ts +156 -0
  39. package/test/scope.test.ts +191 -0
  40. package/test/sensor.test.ts +454 -0
  41. package/test/signal.test.ts +220 -213
  42. package/test/state.test.ts +217 -265
  43. package/test/store.test.ts +346 -446
  44. package/test/task.test.ts +529 -0
  45. package/test/untrack.test.ts +167 -0
  46. package/types/index.d.ts +13 -15
  47. package/types/src/errors.d.ts +73 -17
  48. package/types/src/graph.d.ts +218 -0
  49. package/types/src/nodes/collection.d.ts +69 -0
  50. package/types/src/nodes/effect.d.ts +48 -0
  51. package/types/src/nodes/list.d.ts +66 -0
  52. package/types/src/nodes/memo.d.ts +63 -0
  53. package/types/src/nodes/sensor.d.ts +81 -0
  54. package/types/src/nodes/state.d.ts +78 -0
  55. package/types/src/nodes/store.d.ts +51 -0
  56. package/types/src/nodes/task.d.ts +79 -0
  57. package/types/src/signal.d.ts +43 -29
  58. package/types/src/util.d.ts +9 -16
  59. package/archive/benchmark.ts +0 -683
  60. package/archive/collection.ts +0 -253
  61. package/archive/composite.ts +0 -85
  62. package/archive/computed.ts +0 -195
  63. package/archive/list.ts +0 -483
  64. package/archive/memo.ts +0 -139
  65. package/archive/state.ts +0 -90
  66. package/archive/store.ts +0 -298
  67. package/archive/task.ts +0 -189
  68. package/src/classes/collection.ts +0 -245
  69. package/src/classes/computed.ts +0 -349
  70. package/src/classes/list.ts +0 -343
  71. package/src/classes/ref.ts +0 -70
  72. package/src/classes/state.ts +0 -102
  73. package/src/classes/store.ts +0 -262
  74. package/src/diff.ts +0 -138
  75. package/src/effect.ts +0 -93
  76. package/src/match.ts +0 -45
  77. package/src/resolve.ts +0 -49
  78. package/src/system.ts +0 -257
  79. package/test/computed.test.ts +0 -1108
  80. package/test/diff.test.ts +0 -955
  81. package/test/match.test.ts +0 -388
  82. package/test/ref.test.ts +0 -353
  83. package/test/resolve.test.ts +0 -154
  84. package/types/src/classes/collection.d.ts +0 -45
  85. package/types/src/classes/computed.d.ts +0 -94
  86. package/types/src/classes/list.d.ts +0 -43
  87. package/types/src/classes/ref.d.ts +0 -35
  88. package/types/src/classes/state.d.ts +0 -49
  89. package/types/src/classes/store.d.ts +0 -52
  90. package/types/src/diff.d.ts +0 -28
  91. package/types/src/effect.d.ts +0 -15
  92. package/types/src/match.d.ts +0 -21
  93. package/types/src/resolve.d.ts +0 -29
  94. package/types/src/system.d.ts +0 -78
@@ -1,683 +0,0 @@
1
- import { List } from '../src/classes/list'
2
- import {
3
- BaseStore,
4
- createStore as createClassStore,
5
- } from '../src/classes/store'
6
- import { createList as createFactoryList } from './list'
7
- import { createStore as createFactoryStore } from './store'
8
-
9
- /* === Benchmark Configuration === */
10
-
11
- const ITERATIONS = 1000
12
- const METHOD_CALLS = 100
13
-
14
- /* === Test Data === */
15
-
16
- const testData = {
17
- user: {
18
- id: 42,
19
- name: 'Alice Johnson',
20
- email: 'alice@example.com',
21
- preferences: {
22
- theme: 'dark' as const,
23
- language: 'en',
24
- notifications: {
25
- email: true,
26
- push: false,
27
- desktop: true,
28
- },
29
- },
30
- },
31
- app: {
32
- version: '2.1.0',
33
- config: {
34
- api: {
35
- baseUrl: 'https://api.example.com',
36
- timeout: 5000,
37
- },
38
- },
39
- },
40
- }
41
-
42
- const testListData = [
43
- { id: 1, name: 'Item 1', value: 10 },
44
- { id: 2, name: 'Item 2', value: 20 },
45
- { id: 3, name: 'Item 3', value: 30 },
46
- { id: 4, name: 'Item 4', value: 40 },
47
- { id: 5, name: 'Item 5', value: 50 },
48
- ]
49
-
50
- /* === Benchmarking Utilities === */
51
-
52
- const measureTime = (label: string, fn: () => void): number => {
53
- const start = performance.now()
54
- fn()
55
- const end = performance.now()
56
- const duration = end - start
57
- console.log(`${label}: ${duration.toFixed(2)}ms`)
58
- return duration
59
- }
60
-
61
- // biome-ignore lint/suspicious/noExplicitAny: test
62
- const analyzeObjectStructure = (obj: any, label: string) => {
63
- const ownProps = Object.getOwnPropertyNames(obj)
64
- const ownMethods = ownProps.filter(prop => {
65
- const descriptor = Object.getOwnPropertyDescriptor(obj, prop)
66
- return descriptor && typeof descriptor.value === 'function'
67
- })
68
- const ownData = ownProps.filter(prop => {
69
- const descriptor = Object.getOwnPropertyDescriptor(obj, prop)
70
- return (
71
- descriptor &&
72
- (typeof descriptor.value !== 'function' ||
73
- descriptor.get ||
74
- descriptor.set)
75
- )
76
- })
77
-
78
- const prototype = Object.getPrototypeOf(obj)
79
- const prototypeProps = Object.getOwnPropertyNames(prototype)
80
- const prototypeMethods = prototypeProps.filter(prop => {
81
- if (prop === 'constructor') return false
82
- const descriptor = Object.getOwnPropertyDescriptor(prototype, prop)
83
- return descriptor && typeof descriptor.value === 'function'
84
- })
85
-
86
- console.log(`\n${label} Structure Analysis:`)
87
- console.log(
88
- ` Own Properties: ${ownProps.length} (${ownData.length} data, ${ownMethods.length} methods)`,
89
- )
90
- console.log(` Prototype Methods: ${prototypeMethods.length}`)
91
- console.log(` Own Methods: [${ownMethods.join(', ')}]`)
92
- console.log(
93
- ` Prototype Methods: [${prototypeMethods.slice(0, 5).join(', ')}${prototypeMethods.length > 5 ? '...' : ''}]`,
94
- )
95
-
96
- // Estimate more realistic memory usage
97
- let estimatedSize = 0
98
- estimatedSize += ownData.length * 32 // Property slots
99
- estimatedSize += ownMethods.length * 200 // Function objects (factories only)
100
- estimatedSize += prototypeMethods.length * 8 // Method references (shared)
101
- estimatedSize += 64 // Base object overhead
102
-
103
- return {
104
- ownMethods: ownMethods.length,
105
- prototypeMethods: prototypeMethods.length,
106
- ownData: ownData.length,
107
- estimatedSize,
108
- }
109
- }
110
-
111
- const measureMemory = async (
112
- label: string,
113
- // biome-ignore lint/suspicious/noExplicitAny: test
114
- fn: () => any[],
115
- // biome-ignore lint/suspicious/noExplicitAny: test
116
- ): Promise<any[]> => {
117
- // Force garbage collection multiple times to ensure clean baseline
118
- if ('gc' in globalThis && typeof globalThis.gc === 'function') {
119
- for (let i = 0; i < 3; i++) {
120
- globalThis.gc()
121
- await new Promise(resolve => setTimeout(resolve, 10))
122
- }
123
- }
124
-
125
- const memBefore = process.memoryUsage().heapUsed
126
- const result = fn()
127
-
128
- // Force another GC cycle and wait
129
- if ('gc' in globalThis && typeof globalThis.gc === 'function') {
130
- await new Promise(resolve => setTimeout(resolve, 50))
131
- globalThis.gc()
132
- await new Promise(resolve => setTimeout(resolve, 10))
133
- }
134
-
135
- const memAfter = process.memoryUsage().heapUsed
136
- const memDiff = memAfter - memBefore
137
-
138
- console.log(`${label} Memory: ${(memDiff / 1024 / 1024).toFixed(2)}MB`)
139
- return result
140
- }
141
-
142
- /* === Factory Approach Benchmark === */
143
-
144
- const benchmarkFactory = async () => {
145
- console.log('\n=== Factory Function Approach ===')
146
-
147
- // biome-ignore lint/suspicious/noExplicitAny: test
148
- let stores: any[] = []
149
-
150
- // Test instantiation performance
151
- measureTime('Factory Instantiation', () => {
152
- stores = []
153
- for (let i = 0; i < ITERATIONS; i++) {
154
- stores.push(createFactoryStore({ ...testData, id: i }))
155
- }
156
- })
157
-
158
- // Test memory usage
159
- const memoryStores = await measureMemory('Factory Memory Usage', () => {
160
- const tempStores = []
161
- for (let i = 0; i < ITERATIONS; i++)
162
- tempStores.push(createFactoryStore({ ...testData, id: i }))
163
- return tempStores
164
- })
165
-
166
- // Analyze object structure
167
- const sampleFactoryStore = createFactoryStore(testData)
168
- const factoryAnalysis = analyzeObjectStructure(
169
- sampleFactoryStore,
170
- 'Factory Store',
171
- )
172
- console.log(
173
- `Factory Estimated Size: ${(factoryAnalysis.estimatedSize / 1024).toFixed(2)}KB per store`,
174
- )
175
- console.log(
176
- `Factory Method Overhead: ${factoryAnalysis.ownMethods} own methods × ${ITERATIONS} stores = ${factoryAnalysis.ownMethods * ITERATIONS} method instances`,
177
- )
178
-
179
- // Test method call performance
180
- measureTime('Factory Method Calls', () => {
181
- for (let i = 0; i < METHOD_CALLS; i++) {
182
- memoryStores.forEach(store => {
183
- store.get()
184
- const _name = store.user.name
185
- const _emailNotification =
186
- store.user.preferences.notifications.email
187
- store.set({ ...testData, updated: true })
188
- })
189
- }
190
- })
191
-
192
- // Test method identity (should be different instances)
193
- const store1 = createFactoryStore(testData)
194
- const store2 = createFactoryStore(testData)
195
- console.log('Factory Methods Shared:', store1.get === store2.get) // Should be false
196
-
197
- return memoryStores
198
- }
199
-
200
- /* === Factory List Approach Benchmark === */
201
-
202
- const benchmarkFactoryList = async () => {
203
- console.log('\n=== Factory List Function Approach ===')
204
-
205
- // biome-ignore lint/suspicious/noExplicitAny: test
206
- let lists: any[] = []
207
-
208
- // Test instantiation performance
209
- measureTime('Factory List Instantiation', () => {
210
- lists = []
211
- for (let i = 0; i < ITERATIONS; i++) {
212
- lists.push(
213
- createFactoryList([
214
- ...testListData.map(item => ({
215
- ...item,
216
- id: item.id + i * 1000,
217
- })),
218
- ]),
219
- )
220
- }
221
- })
222
-
223
- // Test memory usage
224
- const memoryLists = await measureMemory('Factory List Memory Usage', () => {
225
- const tempLists = []
226
- for (let i = 0; i < ITERATIONS; i++) {
227
- tempLists.push(
228
- createFactoryList([
229
- ...testListData.map(item => ({
230
- ...item,
231
- id: item.id + i * 1000,
232
- })),
233
- ]),
234
- )
235
- }
236
- return tempLists
237
- })
238
-
239
- // Analyze object structure
240
- const sampleFactoryList = createFactoryList(testListData)
241
- const factoryAnalysis = analyzeObjectStructure(
242
- sampleFactoryList,
243
- 'Factory List',
244
- )
245
- console.log(
246
- `Factory List Estimated Size: ${(factoryAnalysis.estimatedSize / 1024).toFixed(2)}KB per list`,
247
- )
248
- console.log(
249
- `Factory List Method Overhead: ${factoryAnalysis.ownMethods} own methods × ${ITERATIONS} lists = ${factoryAnalysis.ownMethods * ITERATIONS} method instances`,
250
- )
251
-
252
- // Test method call performance
253
- measureTime('Factory List Method Calls', () => {
254
- for (let i = 0; i < METHOD_CALLS; i++) {
255
- memoryLists.forEach(list => {
256
- list.get()
257
- const _0 = list[0]
258
- const _length = list.length
259
- list.set([
260
- ...testListData,
261
- { id: 999, name: 'New', value: 999 },
262
- ])
263
- list.sort()
264
- })
265
- }
266
- })
267
-
268
- // Test method identity (should be different instances)
269
- const list1 = createFactoryList(testListData)
270
- const list2 = createFactoryList(testListData)
271
- console.log('Factory List Methods Shared:', list1.get === list2.get) // Should be false
272
-
273
- return memoryLists
274
- }
275
-
276
- /* === Direct Class List Approach Benchmark (No Proxy) === */
277
-
278
- const benchmarkDirectClassList = async () => {
279
- console.log('\n=== Direct Class-Based List Approach (No Proxy) ===')
280
-
281
- // biome-ignore lint/suspicious/noExplicitAny: test
282
- let lists: any[] = []
283
-
284
- // Test instantiation performance
285
- measureTime('Direct Class List Instantiation', () => {
286
- lists = []
287
- for (let i = 0; i < ITERATIONS; i++) {
288
- lists.push(
289
- new List([
290
- ...testListData.map(item => ({
291
- ...item,
292
- id: item.id + i * 1000,
293
- })),
294
- ]),
295
- )
296
- }
297
- })
298
-
299
- // Test memory usage
300
- const memoryLists = await measureMemory(
301
- 'Direct Class List Memory Usage',
302
- () => {
303
- const tempLists = []
304
- for (let i = 0; i < ITERATIONS; i++) {
305
- tempLists.push(
306
- new List([
307
- ...testListData.map(item => ({
308
- ...item,
309
- id: item.id + i * 1000,
310
- })),
311
- ]),
312
- )
313
- }
314
- return tempLists
315
- },
316
- )
317
-
318
- // Analyze object structure
319
- const sampleDirectClassList = new List(testListData)
320
- const classAnalysis = analyzeObjectStructure(
321
- sampleDirectClassList,
322
- 'Direct Class List',
323
- )
324
- console.log(
325
- `Direct Class List Estimated Size: ${(classAnalysis.estimatedSize / 1024).toFixed(2)}KB per list`,
326
- )
327
- console.log(
328
- `Direct Class List Method Overhead: ${classAnalysis.prototypeMethods} shared methods × ${ITERATIONS} lists = ${classAnalysis.prototypeMethods} method instances (shared)`,
329
- )
330
-
331
- // Test method call performance
332
- measureTime('Direct Class List Method Calls', () => {
333
- for (let i = 0; i < METHOD_CALLS; i++) {
334
- memoryLists.forEach(list => {
335
- list.get()
336
- const _0 = list.at(0)
337
- const _length = list.length
338
- list.set([
339
- ...testListData,
340
- { id: 999, name: 'New', value: 999 },
341
- ])
342
- list.sort()
343
- })
344
- }
345
- })
346
-
347
- // Test method identity (should be same instances - shared prototype)
348
- const list1 = new List(testListData)
349
- const list2 = new List(testListData)
350
- console.log('Direct Class List Methods Shared:', list1.get === list2.get) // Should be true
351
-
352
- return memoryLists
353
- }
354
-
355
- /* === Class Approach Benchmark === */
356
-
357
- const benchmarkClass = async () => {
358
- console.log('\n=== Class-Based Approach ===')
359
-
360
- // biome-ignore lint/suspicious/noExplicitAny: test
361
- let stores: any[] = []
362
-
363
- // Test instantiation performance
364
- measureTime('Class Instantiation', () => {
365
- stores = []
366
- for (let i = 0; i < ITERATIONS; i++) {
367
- stores.push(createClassStore({ ...testData, id: i }))
368
- }
369
- })
370
-
371
- // Test memory usage
372
- const memoryStores = await measureMemory('Class Memory Usage', () => {
373
- const tempStores = []
374
- for (let i = 0; i < ITERATIONS; i++)
375
- tempStores.push(createClassStore({ ...testData, id: i }))
376
- return tempStores
377
- })
378
-
379
- // Analyze object structure
380
- const sampleClassStore = createClassStore(testData)
381
- const classAnalysis = analyzeObjectStructure(
382
- sampleClassStore,
383
- 'Class Store',
384
- )
385
- console.log(
386
- `Class Estimated Size: ${(classAnalysis.estimatedSize / 1024).toFixed(2)}KB per store`,
387
- )
388
- console.log(
389
- `Class Method Overhead: ${classAnalysis.prototypeMethods} shared methods × ${ITERATIONS} stores = ${classAnalysis.prototypeMethods} method instances (shared)`,
390
- )
391
-
392
- // Test method call performance
393
- measureTime('Class Method Calls', () => {
394
- for (let i = 0; i < METHOD_CALLS; i++) {
395
- memoryStores.forEach(store => {
396
- store.get()
397
- const _name = store.user.name
398
- const _emailNotification =
399
- store.user.preferences.notifications.email
400
- store.set({ ...testData, updated: true })
401
- })
402
- }
403
- })
404
-
405
- // Test method identity (should be same instances - shared prototype)
406
- const store1 = createClassStore(testData)
407
- const store2 = createClassStore(testData)
408
- console.log('Class Methods Shared:', store1.get === store2.get) // Should be true
409
-
410
- return memoryStores
411
- }
412
-
413
- /* === Direct Class Approach Benchmark (No Proxy) === */
414
-
415
- const benchmarkDirectClass = async () => {
416
- console.log('\n=== Direct Class-Based Approach (No Proxy) ===')
417
-
418
- // biome-ignore lint/suspicious/noExplicitAny: test
419
- let stores: any[] = []
420
-
421
- // Test instantiation performance
422
- measureTime('Direct Class Instantiation', () => {
423
- stores = []
424
- for (let i = 0; i < ITERATIONS; i++) {
425
- stores.push(new BaseStore({ ...testData, id: i }))
426
- }
427
- })
428
-
429
- // Test memory usage
430
- const memoryStores = await measureMemory(
431
- 'Direct Class Memory Usage',
432
- () => {
433
- const tempStores = []
434
- for (let i = 0; i < ITERATIONS; i++)
435
- tempStores.push(new BaseStore({ ...testData, id: i }))
436
- return tempStores
437
- },
438
- )
439
-
440
- // Analyze object structure
441
- const sampleDirectClassStore = new BaseStore(testData)
442
- const classAnalysis = analyzeObjectStructure(
443
- sampleDirectClassStore,
444
- 'Direct Class Store',
445
- )
446
- console.log(
447
- `Direct Class Estimated Size: ${(classAnalysis.estimatedSize / 1024).toFixed(2)}KB per store`,
448
- )
449
- console.log(
450
- `Direct Class Method Overhead: ${classAnalysis.prototypeMethods} shared methods × ${ITERATIONS} stores = ${classAnalysis.prototypeMethods} method instances (shared)`,
451
- )
452
-
453
- // Test method call performance
454
- measureTime('Direct Class Method Calls', () => {
455
- for (let i = 0; i < METHOD_CALLS; i++) {
456
- memoryStores.forEach(store => {
457
- store.get()
458
- const _name = store.byKey('user').byKey('name')
459
- const _emailNotification = store
460
- .byKey('user')
461
- .byKey('preferences')
462
- .byKey('notifications')
463
- .byKey('email')
464
- store.set({ ...testData, updated: true })
465
- })
466
- }
467
- })
468
-
469
- // Test method identity (should be same instances - shared prototype)
470
- const store1 = new BaseStore(testData)
471
- const store2 = new BaseStore(testData)
472
- console.log('Direct Class Methods Shared:', store1.get === store2.get) // Should be true
473
-
474
- return memoryStores
475
- }
476
-
477
- /* === List Functionality Test === */
478
-
479
- const testListFunctionality = () => {
480
- console.log('\n=== List Functionality Comparison ===')
481
-
482
- console.log('\n--- Factory List ---')
483
- const factoryList = createFactoryList([
484
- { id: 1, name: 'A' },
485
- { id: 2, name: 'B' },
486
- ])
487
- console.log('Initial:', factoryList.get())
488
- console.log('Length:', factoryList.length)
489
- factoryList.add({ id: 3, name: 'C' })
490
- console.log('After add:', factoryList.get())
491
- console.log('Length:', factoryList.length)
492
- factoryList.splice(1, 1, { id: 4, name: 'D' })
493
- console.log('After splice:', factoryList.get())
494
-
495
- console.log('\n--- Class List ---')
496
- const classList = new List([
497
- { id: 1, name: 'A' },
498
- { id: 2, name: 'B' },
499
- ])
500
- console.log('Initial:', classList.get())
501
- console.log('Length:', classList.length)
502
- classList.add({ id: 3, name: 'C' })
503
- console.log('After add:', classList.get())
504
- console.log('Length:', classList.length)
505
- classList.splice(1, 1, { id: 4, name: 'D' })
506
- console.log('After splice:', classList.get())
507
-
508
- // Test that both approaches produce equivalent results (after same operations)
509
- const factoryList2 = createFactoryList([{ id: 1, name: 'Test' }])
510
- const classList2 = new List([{ id: 1, name: 'Test' }])
511
- factoryList2.add({ id: 2, name: 'Test2' })
512
- classList2.add({ id: 2, name: 'Test2' })
513
-
514
- const factoryResult = JSON.stringify(factoryList2.get())
515
- const classResult = JSON.stringify(classList2.get())
516
- console.log(
517
- '\nList Functionally Equivalent:',
518
- factoryResult === classResult,
519
- )
520
- }
521
-
522
- /* === Store Functionality Test === */
523
-
524
- const testStoreFunctionality = () => {
525
- console.log('\n=== Functionality Comparison ===')
526
-
527
- console.log('\n--- Factory Store ---')
528
- const factoryStore = createFactoryStore<{
529
- a: number
530
- b: number
531
- c?: number
532
- }>({ a: 1, b: 2 })
533
- console.log('Initial:', factoryStore.get())
534
- factoryStore.set({ a: 10, b: 20, c: 30 })
535
- console.log('After set:', factoryStore.get())
536
- console.log(
537
- 'Keys:',
538
- Array.from(factoryStore).map(([key]) => key),
539
- )
540
-
541
- console.log('\n--- Class Store ---')
542
- const classStore = createClassStore<{
543
- a: number
544
- b: number
545
- c?: number
546
- }>({ a: 1, b: 2 })
547
- console.log('Initial:', classStore.get())
548
- classStore.set({ a: 10, b: 20, c: 30 })
549
- console.log('After set:', classStore.get())
550
- console.log(
551
- 'Keys:',
552
- Array.from(classStore).map(([key]) => key),
553
- )
554
-
555
- // Test that both approaches produce equivalent results
556
- const factoryResult = JSON.stringify(factoryStore.get())
557
- const classResult = JSON.stringify(classStore.get())
558
- console.log(
559
- '\nStore Functionally Equivalent:',
560
- factoryResult === classResult,
561
- )
562
- }
563
-
564
- /* === Comparative Analysis === */
565
-
566
- const runComparison = async () => {
567
- console.log(`\n${'='.repeat(60)}`)
568
- console.log('STORE & LIST IMPLEMENTATION BENCHMARK')
569
- console.log(`Iterations: ${ITERATIONS} | Method Calls: ${METHOD_CALLS}`)
570
- console.log(`${'='.repeat(60)}`)
571
-
572
- // Test functionality first
573
- testStoreFunctionality()
574
- testListFunctionality()
575
-
576
- // Run Store benchmarks
577
- console.log(`\n${'='.repeat(40)}`)
578
- console.log('STORE BENCHMARKS')
579
- console.log(`${'='.repeat(40)}`)
580
- const factoryStores = await benchmarkFactory()
581
- const classStores = await benchmarkClass()
582
- const directClassStores = await benchmarkDirectClass()
583
-
584
- // Run List benchmarks
585
- console.log(`\n${'='.repeat(40)}`)
586
- console.log('LIST BENCHMARKS')
587
- console.log(`${'='.repeat(40)}`)
588
- const factoryLists = await benchmarkFactoryList()
589
- const directClassLists = await benchmarkDirectClassList()
590
-
591
- // Detailed memory analysis for both Store and List
592
- const sampleFactory = createFactoryStore(testData)
593
- const sampleClass = createClassStore(testData)
594
- const sampleFactoryList = createFactoryList(testListData)
595
- const sampleClassList = new List(testListData)
596
-
597
- const factoryStoreAnalysis = analyzeObjectStructure(
598
- sampleFactory,
599
- 'Final Factory Store Analysis',
600
- )
601
- const classStoreAnalysis = analyzeObjectStructure(
602
- sampleClass,
603
- 'Final Class Store Analysis',
604
- )
605
- const factoryListAnalysis = analyzeObjectStructure(
606
- sampleFactoryList,
607
- 'Final Factory List Analysis',
608
- )
609
- const classListAnalysis = analyzeObjectStructure(
610
- sampleClassList,
611
- 'Final Class List Analysis',
612
- )
613
-
614
- console.log('\n=== Memory Analysis Summary ===')
615
-
616
- // Store Memory Analysis
617
- console.log('\n--- Store Memory Analysis ---')
618
- console.log(
619
- `Store Factory Method Duplication: ${factoryStoreAnalysis.ownMethods * ITERATIONS} function instances`,
620
- )
621
- console.log(
622
- `Store Class Method Sharing: ${classStoreAnalysis.prototypeMethods} shared function instances`,
623
- )
624
-
625
- const storeMethodMemorySaving =
626
- ((factoryStoreAnalysis.ownMethods * ITERATIONS -
627
- classStoreAnalysis.prototypeMethods) *
628
- 200) /
629
- 1024 /
630
- 1024
631
- console.log(
632
- `Store Estimated Method Memory Savings: ${storeMethodMemorySaving.toFixed(2)}MB`,
633
- )
634
-
635
- // List Memory Analysis
636
- console.log('\n--- List Memory Analysis ---')
637
- console.log(
638
- `List Factory Method Duplication: ${factoryListAnalysis.ownMethods * ITERATIONS} function instances`,
639
- )
640
- console.log(
641
- `List Class Method Sharing: ${classListAnalysis.prototypeMethods} shared function instances`,
642
- )
643
-
644
- const listMethodMemorySaving =
645
- ((factoryListAnalysis.ownMethods * ITERATIONS -
646
- classListAnalysis.prototypeMethods) *
647
- 200) /
648
- 1024 /
649
- 1024
650
- console.log(
651
- `List Estimated Method Memory Savings: ${listMethodMemorySaving.toFixed(2)}MB`,
652
- )
653
-
654
- const totalMethodMemorySaving =
655
- storeMethodMemorySaving + listMethodMemorySaving
656
- console.log(
657
- `Total Estimated Method Memory Savings: ${totalMethodMemorySaving.toFixed(2)}MB`,
658
- )
659
-
660
- console.log('\n=== Performance Comparison Summary ===')
661
- console.log('Direct Class (No Proxy) vs Proxy Class vs Factory approaches:')
662
- console.log('- Direct Class should have fastest method calls')
663
- console.log('- Proxy Class has convenience but method call overhead')
664
- console.log('- Factory has per-instance method overhead')
665
-
666
- // Keep references to prevent GC during measurement
667
- return {
668
- factoryStores,
669
- classStores,
670
- directClassStores,
671
- factoryLists,
672
- directClassLists,
673
- }
674
- }
675
-
676
- /* === Export === */
677
-
678
- export { runComparison }
679
-
680
- // Auto-run if this file is executed directly
681
- if (import.meta.url === `file://${process.argv[1]}`) {
682
- runComparison().catch(console.error)
683
- }