@zeix/cause-effect 0.18.0 → 0.18.2

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/index.dev.js CHANGED
@@ -415,14 +415,6 @@ function isState(value) {
415
415
  }
416
416
 
417
417
  // src/nodes/list.ts
418
- function keysEqual(a, b) {
419
- if (a.length !== b.length)
420
- return false;
421
- for (let i = 0;i < a.length; i++)
422
- if (a[i] !== b[i])
423
- return false;
424
- return true;
425
- }
426
418
  function isEqual(a, b, visited) {
427
419
  if (Object.is(a, b))
428
420
  return true;
@@ -445,10 +437,9 @@ function isEqual(a, b, visited) {
445
437
  const ba = b;
446
438
  if (aa.length !== ba.length)
447
439
  return false;
448
- for (let i = 0;i < aa.length; i++) {
440
+ for (let i = 0;i < aa.length; i++)
449
441
  if (!isEqual(aa[i], ba[i], visited))
450
442
  return false;
451
- }
452
443
  return true;
453
444
  }
454
445
  if (isRecord(a) && isRecord(b)) {
@@ -470,62 +461,72 @@ function isEqual(a, b, visited) {
470
461
  visited.delete(b);
471
462
  }
472
463
  }
473
- function diffArrays(oldArray, newArray, currentKeys, generateKey, contentBased) {
464
+ function keysEqual(a, b) {
465
+ if (a.length !== b.length)
466
+ return false;
467
+ for (let i = 0;i < a.length; i++)
468
+ if (a[i] !== b[i])
469
+ return false;
470
+ return true;
471
+ }
472
+ function getKeyGenerator(keyConfig) {
473
+ let keyCounter = 0;
474
+ const contentBased = typeof keyConfig === "function";
475
+ return [
476
+ typeof keyConfig === "string" ? () => `${keyConfig}${keyCounter++}` : contentBased ? (item) => keyConfig(item) || String(keyCounter++) : () => String(keyCounter++),
477
+ contentBased
478
+ ];
479
+ }
480
+ function diffArrays(prev, next, prevKeys, generateKey, contentBased) {
474
481
  const visited = new WeakSet;
475
482
  const add = {};
476
483
  const change = {};
477
484
  const remove = {};
478
- const newKeys = [];
485
+ const nextKeys = [];
479
486
  let changed = false;
480
- const oldByKey = new Map;
481
- for (let i = 0;i < oldArray.length; i++) {
482
- const key = currentKeys[i];
483
- if (key && oldArray[i])
484
- oldByKey.set(key, oldArray[i]);
487
+ const prevByKey = new Map;
488
+ for (let i = 0;i < prev.length; i++) {
489
+ const key = prevKeys[i];
490
+ if (key && prev[i])
491
+ prevByKey.set(key, prev[i]);
485
492
  }
486
493
  const seenKeys = new Set;
487
- for (let i = 0;i < newArray.length; i++) {
488
- const newValue = newArray[i];
489
- if (newValue === undefined)
494
+ for (let i = 0;i < next.length; i++) {
495
+ const val = next[i];
496
+ if (val === undefined)
490
497
  continue;
491
- const key = contentBased ? generateKey(newValue) : currentKeys[i] ?? generateKey(newValue);
498
+ const key = contentBased ? generateKey(val) : prevKeys[i] ?? generateKey(val);
492
499
  if (seenKeys.has(key))
493
- throw new DuplicateKeyError(TYPE_LIST, key, newValue);
494
- newKeys.push(key);
500
+ throw new DuplicateKeyError(TYPE_LIST, key, val);
501
+ nextKeys.push(key);
495
502
  seenKeys.add(key);
496
- if (!oldByKey.has(key)) {
497
- add[key] = newValue;
503
+ if (!prevByKey.has(key)) {
504
+ add[key] = val;
505
+ changed = true;
506
+ } else if (!isEqual(prevByKey.get(key), val, visited)) {
507
+ change[key] = val;
498
508
  changed = true;
499
- } else {
500
- const oldValue = oldByKey.get(key);
501
- if (!isEqual(oldValue, newValue, visited)) {
502
- change[key] = newValue;
503
- changed = true;
504
- }
505
509
  }
506
510
  }
507
- for (const [key] of oldByKey) {
511
+ for (const [key] of prevByKey) {
508
512
  if (!seenKeys.has(key)) {
509
513
  remove[key] = null;
510
514
  changed = true;
511
515
  }
512
516
  }
513
- if (!changed && !keysEqual(currentKeys, newKeys))
517
+ if (!changed && !keysEqual(prevKeys, nextKeys))
514
518
  changed = true;
515
- return { add, change, remove, newKeys, changed };
519
+ return { add, change, remove, newKeys: nextKeys, changed };
516
520
  }
517
- function createList(initialValue, options) {
518
- validateSignalValue(TYPE_LIST, initialValue, Array.isArray);
521
+ function createList(value, options) {
522
+ validateSignalValue(TYPE_LIST, value, Array.isArray);
519
523
  const signals = new Map;
520
524
  let keys = [];
521
- let keyCounter = 0;
522
- const keyConfig = options?.keyConfig;
523
- const contentBased = isFunction(keyConfig);
524
- const generateKey = typeof keyConfig === "string" ? () => `${keyConfig}${keyCounter++}` : contentBased ? (item) => keyConfig(item) : () => String(keyCounter++);
525
+ const [generateKey, contentBased] = getKeyGenerator(options?.keyConfig);
525
526
  const buildValue = () => keys.map((key) => signals.get(key)?.get()).filter((v) => v !== undefined);
526
527
  const node = {
527
528
  fn: buildValue,
528
- value: initialValue,
529
+ value,
529
530
  flags: FLAG_DIRTY,
530
531
  sources: null,
531
532
  sourcesTail: null,
@@ -537,34 +538,34 @@ function createList(initialValue, options) {
537
538
  const toRecord = (array) => {
538
539
  const record = {};
539
540
  for (let i = 0;i < array.length; i++) {
540
- const value = array[i];
541
- if (value === undefined)
541
+ const val = array[i];
542
+ if (val === undefined)
542
543
  continue;
543
544
  let key = keys[i];
544
545
  if (!key) {
545
- key = generateKey(value);
546
+ key = generateKey(val);
546
547
  keys[i] = key;
547
548
  }
548
- record[key] = value;
549
+ record[key] = val;
549
550
  }
550
551
  return record;
551
552
  };
552
553
  const applyChanges = (changes) => {
553
554
  let structural = false;
554
555
  for (const key in changes.add) {
555
- const value = changes.add[key];
556
- validateSignalValue(`${TYPE_LIST} item for key "${key}"`, value);
557
- signals.set(key, createState(value));
556
+ const val = changes.add[key];
557
+ validateSignalValue(`${TYPE_LIST} item for key "${key}"`, val);
558
+ signals.set(key, createState(val));
558
559
  structural = true;
559
560
  }
560
561
  if (Object.keys(changes.change).length) {
561
562
  batch(() => {
562
563
  for (const key in changes.change) {
563
- const value = changes.change[key];
564
- validateSignalValue(`${TYPE_LIST} item for key "${key}"`, value);
564
+ const val = changes.change[key];
565
+ validateSignalValue(`${TYPE_LIST} item for key "${key}"`, val);
565
566
  const signal = signals.get(key);
566
567
  if (signal)
567
- signal.set(value);
568
+ signal.set(val);
568
569
  }
569
570
  });
570
571
  }
@@ -581,13 +582,24 @@ function createList(initialValue, options) {
581
582
  }
582
583
  return changes.changed;
583
584
  };
584
- const initRecord = toRecord(initialValue);
585
+ const watched = options?.watched;
586
+ const subscribe = watched ? () => {
587
+ if (activeSink) {
588
+ if (!node.sinks)
589
+ node.stop = watched();
590
+ link(node, activeSink);
591
+ }
592
+ } : () => {
593
+ if (activeSink)
594
+ link(node, activeSink);
595
+ };
596
+ const initRecord = toRecord(value);
585
597
  for (const key in initRecord) {
586
- const value = initRecord[key];
587
- validateSignalValue(`${TYPE_LIST} item for key "${key}"`, value);
588
- signals.set(key, createState(value));
598
+ const val = initRecord[key];
599
+ validateSignalValue(`${TYPE_LIST} item for key "${key}"`, val);
600
+ signals.set(key, createState(val));
589
601
  }
590
- node.value = initialValue;
602
+ node.value = value;
591
603
  node.flags = 0;
592
604
  const list = {
593
605
  [Symbol.toStringTag]: TYPE_LIST,
@@ -600,19 +612,11 @@ function createList(initialValue, options) {
600
612
  }
601
613
  },
602
614
  get length() {
603
- if (activeSink) {
604
- if (!node.sinks && options?.watched)
605
- node.stop = options.watched();
606
- link(node, activeSink);
607
- }
615
+ subscribe();
608
616
  return keys.length;
609
617
  },
610
618
  get() {
611
- if (activeSink) {
612
- if (!node.sinks && options?.watched)
613
- node.stop = options.watched();
614
- link(node, activeSink);
615
- }
619
+ subscribe();
616
620
  if (node.sources) {
617
621
  if (node.flags) {
618
622
  node.value = untrack(buildValue);
@@ -625,14 +629,15 @@ function createList(initialValue, options) {
625
629
  }
626
630
  return node.value;
627
631
  },
628
- set(newValue) {
629
- const currentValue = node.flags & FLAG_DIRTY ? buildValue() : node.value;
630
- const changes = diffArrays(currentValue, newValue, keys, generateKey, contentBased);
632
+ set(next) {
633
+ const prev = node.flags & FLAG_DIRTY ? buildValue() : node.value;
634
+ const changes = diffArrays(prev, next, keys, generateKey, contentBased);
631
635
  if (changes.changed) {
632
636
  keys = changes.newKeys;
633
637
  applyChanges(changes);
634
- propagate(node);
635
638
  node.flags |= FLAG_DIRTY;
639
+ for (let e = node.sinks;e; e = e.nextSink)
640
+ propagate(e.sink);
636
641
  if (batchDepth === 0)
637
642
  flush();
638
643
  }
@@ -644,11 +649,7 @@ function createList(initialValue, options) {
644
649
  return signals.get(keys[index]);
645
650
  },
646
651
  keys() {
647
- if (activeSink) {
648
- if (!node.sinks && options?.watched)
649
- node.stop = options.watched();
650
- link(node, activeSink);
651
- }
652
+ subscribe();
652
653
  return keys.values();
653
654
  },
654
655
  byKey(key) {
@@ -660,18 +661,19 @@ function createList(initialValue, options) {
660
661
  indexOfKey(key) {
661
662
  return keys.indexOf(key);
662
663
  },
663
- add(value) {
664
- const key = generateKey(value);
664
+ add(value2) {
665
+ const key = generateKey(value2);
665
666
  if (signals.has(key))
666
- throw new DuplicateKeyError(TYPE_LIST, key, value);
667
+ throw new DuplicateKeyError(TYPE_LIST, key, value2);
667
668
  if (!keys.includes(key))
668
669
  keys.push(key);
669
- validateSignalValue(`${TYPE_LIST} item for key "${key}"`, value);
670
- signals.set(key, createState(value));
670
+ validateSignalValue(`${TYPE_LIST} item for key "${key}"`, value2);
671
+ signals.set(key, createState(value2));
671
672
  node.sources = null;
672
673
  node.sourcesTail = null;
673
- propagate(node);
674
674
  node.flags |= FLAG_DIRTY;
675
+ for (let e = node.sinks;e; e = e.nextSink)
676
+ propagate(e.sink);
675
677
  if (batchDepth === 0)
676
678
  flush();
677
679
  return key;
@@ -685,8 +687,9 @@ function createList(initialValue, options) {
685
687
  keys.splice(index, 1);
686
688
  node.sources = null;
687
689
  node.sourcesTail = null;
688
- propagate(node);
689
690
  node.flags |= FLAG_DIRTY;
691
+ for (let e = node.sinks;e; e = e.nextSink)
692
+ propagate(e.sink);
690
693
  if (batchDepth === 0)
691
694
  flush();
692
695
  }
@@ -696,8 +699,9 @@ function createList(initialValue, options) {
696
699
  const newOrder = entries.map(([key]) => key);
697
700
  if (!keysEqual(keys, newOrder)) {
698
701
  keys = newOrder;
699
- propagate(node);
700
702
  node.flags |= FLAG_DIRTY;
703
+ for (let e = node.sinks;e; e = e.nextSink)
704
+ propagate(e.sink);
701
705
  if (batchDepth === 0)
702
706
  flush();
703
707
  }
@@ -735,8 +739,9 @@ function createList(initialValue, options) {
735
739
  changed
736
740
  });
737
741
  keys = newOrder;
738
- propagate(node);
739
742
  node.flags |= FLAG_DIRTY;
743
+ for (let e = node.sinks;e; e = e.nextSink)
744
+ propagate(e.sink);
740
745
  if (batchDepth === 0)
741
746
  flush();
742
747
  }
@@ -766,13 +771,30 @@ function createMemo(fn, options) {
766
771
  sinks: null,
767
772
  sinksTail: null,
768
773
  equals: options?.equals ?? DEFAULT_EQUALITY,
769
- error: undefined
774
+ error: undefined,
775
+ stop: undefined
776
+ };
777
+ const watched = options?.watched;
778
+ const subscribe = watched ? () => {
779
+ if (activeSink) {
780
+ if (!node.sinks)
781
+ node.stop = watched(() => {
782
+ node.flags |= FLAG_DIRTY;
783
+ for (let e = node.sinks;e; e = e.nextSink)
784
+ propagate(e.sink);
785
+ if (batchDepth === 0)
786
+ flush();
787
+ });
788
+ link(node, activeSink);
789
+ }
790
+ } : () => {
791
+ if (activeSink)
792
+ link(node, activeSink);
770
793
  };
771
794
  return {
772
795
  [Symbol.toStringTag]: TYPE_MEMO,
773
796
  get() {
774
- if (activeSink)
775
- link(node, activeSink);
797
+ subscribe();
776
798
  refresh(node);
777
799
  if (node.error)
778
800
  throw node.error;
@@ -800,13 +822,30 @@ function createTask(fn, options) {
800
822
  flags: FLAG_DIRTY,
801
823
  equals: options?.equals ?? DEFAULT_EQUALITY,
802
824
  controller: undefined,
803
- error: undefined
825
+ error: undefined,
826
+ stop: undefined
827
+ };
828
+ const watched = options?.watched;
829
+ const subscribe = watched ? () => {
830
+ if (activeSink) {
831
+ if (!node.sinks)
832
+ node.stop = watched(() => {
833
+ node.flags |= FLAG_DIRTY;
834
+ for (let e = node.sinks;e; e = e.nextSink)
835
+ propagate(e.sink);
836
+ if (batchDepth === 0)
837
+ flush();
838
+ });
839
+ link(node, activeSink);
840
+ }
841
+ } : () => {
842
+ if (activeSink)
843
+ link(node, activeSink);
804
844
  };
805
845
  return {
806
846
  [Symbol.toStringTag]: TYPE_TASK,
807
847
  get() {
808
- if (activeSink)
809
- link(node, activeSink);
848
+ subscribe();
810
849
  refresh(node);
811
850
  if (node.error)
812
851
  throw node.error;
@@ -848,19 +887,19 @@ function deriveCollection(source, callback) {
848
887
  signals.set(key, signal);
849
888
  };
850
889
  function syncKeys() {
851
- const newKeys = Array.from(source.keys());
852
- const oldKeys = node.value;
853
- if (!keysEqual(oldKeys, newKeys)) {
854
- const oldKeySet = new Set(oldKeys);
855
- const newKeySet = new Set(newKeys);
856
- for (const key of oldKeys)
857
- if (!newKeySet.has(key))
890
+ const nextKeys = Array.from(source.keys());
891
+ const prevKeys = node.value;
892
+ if (!keysEqual(prevKeys, nextKeys)) {
893
+ const a = new Set(prevKeys);
894
+ const b = new Set(nextKeys);
895
+ for (const key of prevKeys)
896
+ if (!b.has(key))
858
897
  signals.delete(key);
859
- for (const key of newKeys)
860
- if (!oldKeySet.has(key))
898
+ for (const key of nextKeys)
899
+ if (!a.has(key))
861
900
  addSignal(key);
862
901
  }
863
- return newKeys;
902
+ return nextKeys;
864
903
  }
865
904
  const node = {
866
905
  fn: syncKeys,
@@ -945,17 +984,17 @@ function deriveCollection(source, callback) {
945
984
  };
946
985
  return collection;
947
986
  }
948
- function createCollection(start, options) {
949
- const initialValue = options?.value ?? [];
950
- if (initialValue.length)
951
- validateSignalValue(TYPE_COLLECTION, initialValue, Array.isArray);
952
- validateCallback(TYPE_COLLECTION, start);
987
+ function createCollection(watched, options) {
988
+ const value = options?.value ?? [];
989
+ if (value.length)
990
+ validateSignalValue(TYPE_COLLECTION, value, Array.isArray);
991
+ validateCallback(TYPE_COLLECTION, watched, isSyncFunction);
953
992
  const signals = new Map;
954
993
  const keys = [];
955
- let keyCounter = 0;
956
- const keyConfig = options?.keyConfig;
957
- const generateKey = typeof keyConfig === "string" ? () => `${keyConfig}${keyCounter++}` : isFunction(keyConfig) ? (item) => keyConfig(item) : () => String(keyCounter++);
958
- const itemFactory = options?.createItem ?? ((_key, value) => createState(value));
994
+ const itemToKey = new Map;
995
+ const [generateKey, contentBased] = getKeyGenerator(options?.keyConfig);
996
+ const resolveKey = (item) => itemToKey.get(item) ?? (contentBased ? generateKey(item) : undefined);
997
+ const itemFactory = options?.createItem ?? createState;
959
998
  function buildValue() {
960
999
  const result = [];
961
1000
  for (const key of keys) {
@@ -972,59 +1011,79 @@ function createCollection(start, options) {
972
1011
  }
973
1012
  const node = {
974
1013
  fn: buildValue,
975
- value: initialValue,
1014
+ value,
976
1015
  flags: FLAG_DIRTY,
977
1016
  sources: null,
978
1017
  sourcesTail: null,
979
1018
  sinks: null,
980
1019
  sinksTail: null,
981
- equals: () => false,
1020
+ equals: SKIP_EQUALITY,
982
1021
  error: undefined
983
1022
  };
984
- function applyChanges(changes) {
985
- if (!changes.changed)
986
- return;
987
- let structural = false;
988
- batch(() => {
989
- for (const key in changes.add) {
990
- const value = changes.add[key];
991
- signals.set(key, itemFactory(key, value));
992
- if (!keys.includes(key))
993
- keys.push(key);
994
- structural = true;
995
- }
996
- for (const key in changes.change) {
997
- const signal = signals.get(key);
998
- if (signal && isState(signal)) {
999
- signal.set(changes.change[key]);
1000
- }
1001
- }
1002
- for (const key in changes.remove) {
1003
- signals.delete(key);
1004
- const index = keys.indexOf(key);
1005
- if (index !== -1)
1006
- keys.splice(index, 1);
1007
- structural = true;
1008
- }
1009
- if (structural) {
1010
- node.sources = null;
1011
- node.sourcesTail = null;
1012
- }
1013
- node.flags = FLAG_CLEAN;
1014
- propagate(node);
1015
- node.flags |= FLAG_DIRTY;
1016
- });
1017
- }
1018
- for (const item of initialValue) {
1023
+ for (const item of value) {
1019
1024
  const key = generateKey(item);
1020
- signals.set(key, itemFactory(key, item));
1025
+ signals.set(key, itemFactory(item));
1026
+ itemToKey.set(item, key);
1021
1027
  keys.push(key);
1022
1028
  }
1023
- node.value = initialValue;
1029
+ node.value = value;
1024
1030
  node.flags = FLAG_DIRTY;
1025
- function startWatching() {
1026
- if (!node.sinks)
1027
- node.stop = start(applyChanges);
1031
+ function subscribe() {
1032
+ if (activeSink) {
1033
+ if (!node.sinks)
1034
+ node.stop = watched((changes) => {
1035
+ const { add, change, remove } = changes;
1036
+ if (!add?.length && !change?.length && !remove?.length)
1037
+ return;
1038
+ let structural = false;
1039
+ batch(() => {
1040
+ if (add) {
1041
+ for (const item of add) {
1042
+ const key = generateKey(item);
1043
+ signals.set(key, itemFactory(item));
1044
+ itemToKey.set(item, key);
1045
+ if (!keys.includes(key))
1046
+ keys.push(key);
1047
+ structural = true;
1048
+ }
1049
+ }
1050
+ if (change) {
1051
+ for (const item of change) {
1052
+ const key = resolveKey(item);
1053
+ if (!key)
1054
+ continue;
1055
+ const signal = signals.get(key);
1056
+ if (signal && isState(signal)) {
1057
+ itemToKey.delete(signal.get());
1058
+ signal.set(item);
1059
+ itemToKey.set(item, key);
1060
+ }
1061
+ }
1062
+ }
1063
+ if (remove) {
1064
+ for (const item of remove) {
1065
+ const key = resolveKey(item);
1066
+ if (!key)
1067
+ continue;
1068
+ itemToKey.delete(item);
1069
+ signals.delete(key);
1070
+ const index = keys.indexOf(key);
1071
+ if (index !== -1)
1072
+ keys.splice(index, 1);
1073
+ structural = true;
1074
+ }
1075
+ }
1076
+ if (structural) {
1077
+ node.sources = null;
1078
+ node.sourcesTail = null;
1079
+ }
1080
+ node.flags = FLAG_DIRTY;
1081
+ for (let e = node.sinks;e; e = e.nextSink)
1082
+ propagate(e.sink);
1083
+ });
1084
+ });
1085
+ link(node, activeSink);
1086
+ }
1028
1087
  }
1029
1088
  const collection = {
1030
1089
  [Symbol.toStringTag]: TYPE_COLLECTION,
@@ -1037,24 +1096,15 @@ function createCollection(start, options) {
1037
1096
  }
1038
1097
  },
1039
1098
  get length() {
1040
- if (activeSink) {
1041
- startWatching();
1042
- link(node, activeSink);
1043
- }
1099
+ subscribe();
1044
1100
  return keys.length;
1045
1101
  },
1046
1102
  keys() {
1047
- if (activeSink) {
1048
- startWatching();
1049
- link(node, activeSink);
1050
- }
1103
+ subscribe();
1051
1104
  return keys.values();
1052
1105
  },
1053
1106
  get() {
1054
- if (activeSink) {
1055
- startWatching();
1056
- link(node, activeSink);
1057
- }
1107
+ subscribe();
1058
1108
  if (node.sources) {
1059
1109
  if (node.flags) {
1060
1110
  node.value = untrack(buildValue);
@@ -1159,8 +1209,8 @@ function match(signals, handlers) {
1159
1209
  }
1160
1210
  }
1161
1211
  // src/nodes/sensor.ts
1162
- function createSensor(start, options) {
1163
- validateCallback(TYPE_SENSOR, start, isSyncFunction);
1212
+ function createSensor(watched, options) {
1213
+ validateCallback(TYPE_SENSOR, watched, isSyncFunction);
1164
1214
  if (options?.value !== undefined)
1165
1215
  validateSignalValue(TYPE_SENSOR, options.value, options?.guard);
1166
1216
  const node = {
@@ -1176,7 +1226,7 @@ function createSensor(start, options) {
1176
1226
  get() {
1177
1227
  if (activeSink) {
1178
1228
  if (!node.sinks)
1179
- node.stop = start((next) => {
1229
+ node.stop = watched((next) => {
1180
1230
  validateSignalValue(TYPE_SENSOR, next, node.guard);
1181
1231
  setState(node, next);
1182
1232
  });
@@ -1191,16 +1241,16 @@ function isSensor(value) {
1191
1241
  return isObjectOfType(value, TYPE_SENSOR);
1192
1242
  }
1193
1243
  // src/nodes/store.ts
1194
- function diffRecords(oldObj, newObj) {
1195
- const oldValid = isRecord(oldObj) || Array.isArray(oldObj);
1196
- const newValid = isRecord(newObj) || Array.isArray(newObj);
1197
- if (!oldValid || !newValid) {
1198
- const changed2 = !Object.is(oldObj, newObj);
1244
+ function diffRecords(prev, next) {
1245
+ const prevValid = isRecord(prev) || Array.isArray(prev);
1246
+ const nextValid = isRecord(next) || Array.isArray(next);
1247
+ if (!prevValid || !nextValid) {
1248
+ const changed2 = !Object.is(prev, next);
1199
1249
  return {
1200
1250
  changed: changed2,
1201
- add: changed2 && newValid ? newObj : {},
1251
+ add: changed2 && nextValid ? next : {},
1202
1252
  change: {},
1203
- remove: changed2 && oldValid ? oldObj : {}
1253
+ remove: changed2 && prevValid ? prev : {}
1204
1254
  };
1205
1255
  }
1206
1256
  const visited = new WeakSet;
@@ -1208,38 +1258,38 @@ function diffRecords(oldObj, newObj) {
1208
1258
  const change = {};
1209
1259
  const remove = {};
1210
1260
  let changed = false;
1211
- const oldKeys = Object.keys(oldObj);
1212
- const newKeys = Object.keys(newObj);
1213
- for (const key of newKeys) {
1214
- if (key in oldObj) {
1215
- if (!isEqual(oldObj[key], newObj[key], visited)) {
1216
- change[key] = newObj[key];
1261
+ const prevKeys = Object.keys(prev);
1262
+ const nextKeys = Object.keys(next);
1263
+ for (const key of nextKeys) {
1264
+ if (key in prev) {
1265
+ if (!isEqual(prev[key], next[key], visited)) {
1266
+ change[key] = next[key];
1217
1267
  changed = true;
1218
1268
  }
1219
1269
  } else {
1220
- add[key] = newObj[key];
1270
+ add[key] = next[key];
1221
1271
  changed = true;
1222
1272
  }
1223
1273
  }
1224
- for (const key of oldKeys) {
1225
- if (!(key in newObj)) {
1274
+ for (const key of prevKeys) {
1275
+ if (!(key in next)) {
1226
1276
  remove[key] = undefined;
1227
1277
  changed = true;
1228
1278
  }
1229
1279
  }
1230
1280
  return { add, change, remove, changed };
1231
1281
  }
1232
- function createStore(initialValue, options) {
1233
- validateSignalValue(TYPE_STORE, initialValue, isRecord);
1282
+ function createStore(value, options) {
1283
+ validateSignalValue(TYPE_STORE, value, isRecord);
1234
1284
  const signals = new Map;
1235
- const addSignal = (key, value) => {
1236
- validateSignalValue(`${TYPE_STORE} for key "${key}"`, value);
1237
- if (Array.isArray(value))
1238
- signals.set(key, createList(value));
1239
- else if (isRecord(value))
1240
- signals.set(key, createStore(value));
1285
+ const addSignal = (key, val) => {
1286
+ validateSignalValue(`${TYPE_STORE} for key "${key}"`, val);
1287
+ if (Array.isArray(val))
1288
+ signals.set(key, createList(val));
1289
+ else if (isRecord(val))
1290
+ signals.set(key, createStore(val));
1241
1291
  else
1242
- signals.set(key, createState(value));
1292
+ signals.set(key, createState(val));
1243
1293
  };
1244
1294
  const buildValue = () => {
1245
1295
  const record = {};
@@ -1250,7 +1300,7 @@ function createStore(initialValue, options) {
1250
1300
  };
1251
1301
  const node = {
1252
1302
  fn: buildValue,
1253
- value: initialValue,
1303
+ value,
1254
1304
  flags: FLAG_DIRTY,
1255
1305
  sources: null,
1256
1306
  sourcesTail: null,
@@ -1268,15 +1318,15 @@ function createStore(initialValue, options) {
1268
1318
  if (Object.keys(changes.change).length) {
1269
1319
  batch(() => {
1270
1320
  for (const key in changes.change) {
1271
- const value = changes.change[key];
1272
- validateSignalValue(`${TYPE_STORE} for key "${key}"`, value);
1321
+ const val = changes.change[key];
1322
+ validateSignalValue(`${TYPE_STORE} for key "${key}"`, val);
1273
1323
  const signal = signals.get(key);
1274
1324
  if (signal) {
1275
- if (isRecord(value) !== isStore(signal)) {
1276
- addSignal(key, value);
1325
+ if (isRecord(val) !== isStore(signal)) {
1326
+ addSignal(key, val);
1277
1327
  structural = true;
1278
1328
  } else
1279
- signal.set(value);
1329
+ signal.set(val);
1280
1330
  }
1281
1331
  }
1282
1332
  });
@@ -1291,8 +1341,19 @@ function createStore(initialValue, options) {
1291
1341
  }
1292
1342
  return changes.changed;
1293
1343
  };
1294
- for (const key of Object.keys(initialValue))
1295
- addSignal(key, initialValue[key]);
1344
+ const watched = options?.watched;
1345
+ const subscribe = watched ? () => {
1346
+ if (activeSink) {
1347
+ if (!node.sinks)
1348
+ node.stop = watched();
1349
+ link(node, activeSink);
1350
+ }
1351
+ } : () => {
1352
+ if (activeSink)
1353
+ link(node, activeSink);
1354
+ };
1355
+ for (const key of Object.keys(value))
1356
+ addSignal(key, value[key]);
1296
1357
  const store = {
1297
1358
  [Symbol.toStringTag]: TYPE_STORE,
1298
1359
  [Symbol.isConcatSpreadable]: false,
@@ -1304,22 +1365,14 @@ function createStore(initialValue, options) {
1304
1365
  }
1305
1366
  },
1306
1367
  keys() {
1307
- if (activeSink) {
1308
- if (!node.sinks && options?.watched)
1309
- node.stop = options.watched();
1310
- link(node, activeSink);
1311
- }
1368
+ subscribe();
1312
1369
  return signals.keys();
1313
1370
  },
1314
1371
  byKey(key) {
1315
1372
  return signals.get(key);
1316
1373
  },
1317
1374
  get() {
1318
- if (activeSink) {
1319
- if (!node.sinks && options?.watched)
1320
- node.stop = options.watched();
1321
- link(node, activeSink);
1322
- }
1375
+ subscribe();
1323
1376
  if (node.sources) {
1324
1377
  if (node.flags) {
1325
1378
  node.value = untrack(buildValue);
@@ -1332,12 +1385,13 @@ function createStore(initialValue, options) {
1332
1385
  }
1333
1386
  return node.value;
1334
1387
  },
1335
- set(newValue) {
1336
- const currentValue = node.flags & FLAG_DIRTY ? buildValue() : node.value;
1337
- const changes = diffRecords(currentValue, newValue);
1388
+ set(next) {
1389
+ const prev = node.flags & FLAG_DIRTY ? buildValue() : node.value;
1390
+ const changes = diffRecords(prev, next);
1338
1391
  if (applyChanges(changes)) {
1339
- propagate(node);
1340
1392
  node.flags |= FLAG_DIRTY;
1393
+ for (let e = node.sinks;e; e = e.nextSink)
1394
+ propagate(e.sink);
1341
1395
  if (batchDepth === 0)
1342
1396
  flush();
1343
1397
  }
@@ -1345,14 +1399,15 @@ function createStore(initialValue, options) {
1345
1399
  update(fn) {
1346
1400
  store.set(fn(store.get()));
1347
1401
  },
1348
- add(key, value) {
1402
+ add(key, value2) {
1349
1403
  if (signals.has(key))
1350
- throw new DuplicateKeyError(TYPE_STORE, key, value);
1351
- addSignal(key, value);
1404
+ throw new DuplicateKeyError(TYPE_STORE, key, value2);
1405
+ addSignal(key, value2);
1352
1406
  node.sources = null;
1353
1407
  node.sourcesTail = null;
1354
- propagate(node);
1355
1408
  node.flags |= FLAG_DIRTY;
1409
+ for (let e = node.sinks;e; e = e.nextSink)
1410
+ propagate(e.sink);
1356
1411
  if (batchDepth === 0)
1357
1412
  flush();
1358
1413
  return key;
@@ -1362,8 +1417,9 @@ function createStore(initialValue, options) {
1362
1417
  if (ok) {
1363
1418
  node.sources = null;
1364
1419
  node.sourcesTail = null;
1365
- propagate(node);
1366
1420
  node.flags |= FLAG_DIRTY;
1421
+ for (let e = node.sinks;e; e = e.nextSink)
1422
+ propagate(e.sink);
1367
1423
  if (batchDepth === 0)
1368
1424
  flush();
1369
1425
  }
@@ -1371,10 +1427,8 @@ function createStore(initialValue, options) {
1371
1427
  };
1372
1428
  return new Proxy(store, {
1373
1429
  get(target, prop) {
1374
- if (prop in target) {
1375
- const value = Reflect.get(target, prop);
1376
- return isFunction(value) ? value.bind(target) : value;
1377
- }
1430
+ if (prop in target)
1431
+ return Reflect.get(target, prop);
1378
1432
  if (typeof prop !== "symbol")
1379
1433
  return target.byKey(prop);
1380
1434
  },