@adbl/cells 0.0.1 → 0.0.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/index.js CHANGED
@@ -1,3 +1,3 @@
1
- /// <reference types="./types/index.d.ts" />
1
+ // <reference types="./types/index.d.ts" />
2
2
 
3
3
  export * from './library/index.js';
@@ -326,7 +326,7 @@ export class Cell {
326
326
  update() {
327
327
  // Run watchers.
328
328
  for (const effect of this.__effects) {
329
- let watcher = effect.callback;
329
+ const watcher = effect.callback;
330
330
  if (watcher === undefined) continue;
331
331
 
332
332
  if (root.batchNestingLevel > 0) {
@@ -593,6 +593,8 @@ export class Cell {
593
593
 
594
594
  async function run(input = initialInput) {
595
595
  pending.value = true;
596
+ error.value = null;
597
+ data.value = null;
596
598
  try {
597
599
  initialInput = input;
598
600
  const result = await getter(/** @type {X} */ (input));
@@ -684,6 +686,9 @@ export class SourceCell extends Cell {
684
686
  /** @type {Partial<CellOptions<T>>} */
685
687
  options;
686
688
 
689
+ /** @type {object | undefined} */
690
+ #originalObject;
691
+
687
692
  /**
688
693
  * Creates a new Cell with the provided value.
689
694
  * @param {T} value
@@ -694,6 +699,32 @@ export class SourceCell extends Cell {
694
699
 
695
700
  this.setValue(options?.shallowProxied ? value : this.proxy(value));
696
701
  this.options = options ?? {};
702
+
703
+ if (typeof value === 'object' && value !== null) {
704
+ this.#originalObject = value;
705
+ }
706
+ }
707
+
708
+ /**
709
+ * For cells containing objects, returns the object itself.
710
+ * This can be useful in scenarios where unfettered access to the original object is needed,
711
+ * such as when using the object as a cache.
712
+ *
713
+ * @example
714
+ * const cell = new SourceCell({ a: 1, b: 2 });
715
+ * console.log(cell.originalObject); // { a: 1, b: 2 }
716
+ *
717
+ * cell.value = { a: 3, b: 4 };
718
+ * console.log(cell.originalObject); // { a: 3, b: 4 }
719
+ *
720
+ * @returns {T extends object ? T : never} The original object if T is an object, otherwise never.
721
+ */
722
+ deproxy() {
723
+ const originalObject = this.#originalObject;
724
+ if (typeof originalObject === 'object' && originalObject !== null) {
725
+ return /** @type {T extends object ? T : never} */ (originalObject);
726
+ }
727
+ throw new Error('Cannot deproxy a non-object cell.');
697
728
  }
698
729
 
699
730
  get value() {
@@ -713,7 +744,7 @@ export class SourceCell extends Cell {
713
744
 
714
745
  const isEqual = this.options.equals
715
746
  ? this.options.equals(oldValue, value)
716
- : oldValue === value;
747
+ : deepEqual(oldValue, value);
717
748
 
718
749
  if (isEqual) return;
719
750
 
@@ -728,7 +759,10 @@ export class SourceCell extends Cell {
728
759
  }
729
760
  }
730
761
 
731
- this.setValue(value);
762
+ this.setValue(this.options?.shallowProxied ? value : this.proxy(value));
763
+ if (typeof value === 'object' && value !== null) {
764
+ this.#originalObject = value;
765
+ }
732
766
  this.update();
733
767
  }
734
768
 
@@ -750,10 +784,53 @@ export class SourceCell extends Cell {
750
784
  return this.proxy(Reflect.get(target, prop));
751
785
  },
752
786
  set: (target, prop, value) => {
787
+ const formerValue = Reflect.get(target, prop);
753
788
  Reflect.set(target, prop, value);
754
- this.update();
789
+
790
+ const isEqual = deepEqual(formerValue, value);
791
+ if (!isEqual) this.update();
792
+
755
793
  return true;
756
794
  },
757
795
  });
758
796
  }
759
797
  }
798
+
799
+ /**
800
+ * Recursively compares two values for deep equality.
801
+ * @param {any} a - The first value to compare.
802
+ * @param {any} b - The second value to compare.
803
+ * @returns {boolean} - True if the values are deeply equal, false otherwise.
804
+ */
805
+ function deepEqual(a, b) {
806
+ if (a === b) return true;
807
+
808
+ if (
809
+ typeof a !== typeof b ||
810
+ typeof a !== 'object' ||
811
+ a === null ||
812
+ b === null
813
+ )
814
+ return false;
815
+
816
+ if (Array.isArray(a)) {
817
+ const aLength = a.length;
818
+ if (!Array.isArray(b) || aLength !== b.length) return false;
819
+
820
+ for (let i = 0; i < aLength; i++) {
821
+ if (!deepEqual(a[i], b[i])) return false;
822
+ }
823
+ } else {
824
+ const keysA = Object.keys(a);
825
+ const keysB = Object.keys(b);
826
+ const keysALength = keysA.length;
827
+ if (keysALength !== keysB.length) return false;
828
+
829
+ for (let i = 0; i < keysALength; i++) {
830
+ const key = keysA[i];
831
+ if (a === b) return true;
832
+ if (!(key in b) || !deepEqual(a[key], b[key])) return false;
833
+ }
834
+ }
835
+ return true;
836
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adbl/cells",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A simple implementation of reactive updates for JavaScript",
5
5
  "main": "index.js",
6
6
  "private": false,
@@ -147,10 +147,10 @@ export class Cell<T> {
147
147
  */
148
148
  protected __effects: Array<Effect<T>>;
149
149
  /**
150
- * @type {Array<WeakRef<[DerivedCell<any>, () => any]>>}
150
+ * @type {Array<[WeakRef<DerivedCell<any>>, () => any]>}
151
151
  * @protected
152
152
  */
153
- protected __derivedCells: Array<WeakRef<[DerivedCell<any>, () => any]>>;
153
+ protected __derivedCells: Array<[WeakRef<DerivedCell<any>>, () => any]>;
154
154
  /**
155
155
  * @readonly
156
156
  */
@@ -264,6 +264,21 @@ export class SourceCell<T> extends Cell<T> {
264
264
  constructor(value: T, options?: Partial<CellOptions<T>> | undefined);
265
265
  /** @type {Partial<CellOptions<T>>} */
266
266
  options: Partial<CellOptions<T>>;
267
+ /**
268
+ * For cells containing objects, returns the object itself.
269
+ * This can be useful in scenarios where unfettered access to the original object is needed,
270
+ * such as when using the object as a cache.
271
+ *
272
+ * @example
273
+ * const cell = new SourceCell({ a: 1, b: 2 });
274
+ * console.log(cell.originalObject); // { a: 1, b: 2 }
275
+ *
276
+ * cell.value = { a: 3, b: 4 };
277
+ * console.log(cell.originalObject); // { a: 3, b: 4 }
278
+ *
279
+ * @returns {T extends object ? T : never} The original object if T is an object, otherwise never.
280
+ */
281
+ deproxy(): T extends object ? T : never;
267
282
  /**
268
283
  * Sets the value stored in the Cell and triggers an update.
269
284
  * @param {T} value
@@ -278,6 +293,7 @@ export class SourceCell<T> extends Cell<T> {
278
293
  * @private
279
294
  */
280
295
  private proxy;
296
+ #private;
281
297
  }
282
298
  export type AsyncRequestAtoms<Input, Output> = {
283
299
  /**
Binary file