@montra-interactive/deepstate 0.1.1 → 0.2.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.
@@ -191,5 +191,44 @@ export declare function state<T extends object>(initialState: T, options?: State
191
191
  * store.user?.name.set("Charlie"); // After ?. on user, children are directly accessible
192
192
  */
193
193
  export declare function nullable<T extends object>(value: T | null): T | null;
194
+ /** Comparison mode for array distinct checking */
195
+ export type ArrayDistinct<T> = false | 'shallow' | 'deep' | ((a: T[], b: T[]) => boolean);
196
+ /** Options for the array() helper */
197
+ export interface ArrayOptions<T> {
198
+ /**
199
+ * How to compare arrays to prevent duplicate emissions.
200
+ * - false: No deduplication (default, always emits on set)
201
+ * - 'shallow': Reference equality per element (a[i] === b[i])
202
+ * - 'deep': JSON.stringify comparison (expensive for large arrays)
203
+ * - function: Custom comparator (a, b) => boolean
204
+ */
205
+ distinct?: ArrayDistinct<T>;
206
+ }
207
+ /**
208
+ * Marks an array with options for how it should behave in state.
209
+ * Use this to enable deduplication (prevent emissions when setting same values).
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * const store = state({
214
+ * // Default behavior - emits on every set
215
+ * items: [1, 2, 3],
216
+ *
217
+ * // Shallow comparison - only emits if elements differ by reference
218
+ * tags: array(['a', 'b'], { distinct: 'shallow' }),
219
+ *
220
+ * // Deep comparison - only emits if JSON representation differs
221
+ * settings: array([{ theme: 'dark' }], { distinct: 'deep' }),
222
+ *
223
+ * // Custom comparator - you define equality
224
+ * users: array([{ id: 1, name: 'Alice' }], {
225
+ * distinct: (a, b) =>
226
+ * a.length === b.length &&
227
+ * a.every((user, i) => user.id === b[i].id)
228
+ * }),
229
+ * });
230
+ * ```
231
+ */
232
+ export declare function array<T>(value: T[], options?: ArrayOptions<T>): T[];
194
233
  export {};
195
234
  //# sourceMappingURL=deepstate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,12 +4,13 @@
4
4
  * Core exports:
5
5
  * - state() - Create reactive state from plain objects
6
6
  * - nullable() - Mark a property as nullable (can transition between null and object)
7
+ * - array() - Mark an array with deduplication options
7
8
  * - RxState, Draft - Type exports
8
9
  *
9
10
  * Helper exports:
10
11
  * - select() - Combine multiple observables
11
12
  * - selectFromEach() - Select from each array item with precise change detection
12
13
  */
13
- export { state, nullable, type RxState, type Draft, type StateOptions } from "./deepstate";
14
+ export { state, nullable, array, type RxState, type Draft, type StateOptions, type ArrayOptions, type ArrayDistinct } from "./deepstate";
14
15
  export { select, selectFromEach } from "./helpers";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACzI,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -164,7 +164,7 @@ function createObjectNode(value) {
164
164
  }
165
165
  };
166
166
  }
167
- function createArrayNode(value) {
167
+ function createArrayNode(value, comparator) {
168
168
  const subject$ = new BehaviorSubject([...value]);
169
169
  const childCache = new Map;
170
170
  const createChildProjection = (index) => {
@@ -188,7 +188,8 @@ function createArrayNode(value) {
188
188
  };
189
189
  };
190
190
  const lock$ = new BehaviorSubject(true);
191
- const locked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr), map2(deepFreeze), shareReplay(1));
191
+ const baseLocked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr));
192
+ const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2(deepFreeze), shareReplay(1));
192
193
  locked$.subscribe();
193
194
  const length$ = locked$.pipe(map2((arr) => arr.length), distinctUntilChanged2(), shareReplay(1));
194
195
  length$.subscribe();
@@ -562,6 +563,12 @@ function createNodeForValue(value, maybeNullable = false) {
562
563
  return createLeafNode(value);
563
564
  }
564
565
  if (Array.isArray(value)) {
566
+ if (isArrayMarked(value)) {
567
+ const options = value[ARRAY_MARKER];
568
+ const comparator = getArrayComparator(options);
569
+ delete value[ARRAY_MARKER];
570
+ return createArrayNode(value, comparator);
571
+ }
565
572
  return createArrayNode(value);
566
573
  }
567
574
  return createObjectNode(value);
@@ -782,9 +789,30 @@ function nullable(value) {
782
789
  function isNullableMarked(value) {
783
790
  return value !== null && typeof value === "object" && NULLABLE_MARKER in value;
784
791
  }
792
+ var ARRAY_MARKER = Symbol("array");
793
+ function array(value, options = {}) {
794
+ const marked = [...value];
795
+ marked[ARRAY_MARKER] = options;
796
+ return marked;
797
+ }
798
+ function isArrayMarked(value) {
799
+ return Array.isArray(value) && ARRAY_MARKER in value;
800
+ }
801
+ function getArrayComparator(options) {
802
+ if (!options.distinct)
803
+ return;
804
+ if (options.distinct === "shallow") {
805
+ return (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
806
+ }
807
+ if (options.distinct === "deep") {
808
+ return (a, b) => JSON.stringify(a) === JSON.stringify(b);
809
+ }
810
+ return options.distinct;
811
+ }
785
812
  export {
786
813
  state,
787
814
  selectFromEach,
788
815
  select,
789
- nullable
816
+ nullable,
817
+ array
790
818
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@montra-interactive/deepstate",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Proxy-based reactive state management with RxJS. Deep nested state observation with full TypeScript support.",
5
5
  "keywords": [
6
6
  "state",
package/src/deepstate.ts CHANGED
@@ -424,7 +424,10 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
424
424
  };
425
425
  }
426
426
 
427
- function createArrayNode<T>(value: T[]): NodeCore<T[]> & {
427
+ function createArrayNode<T>(
428
+ value: T[],
429
+ comparator?: (a: T[], b: T[]) => boolean
430
+ ): NodeCore<T[]> & {
428
431
  at(index: number): NodeCore<T> | undefined;
429
432
  childCache: Map<number, NodeCore<T>>;
430
433
  length$: Observable<number> & { get(): number };
@@ -478,10 +481,17 @@ function createArrayNode<T>(value: T[]): NodeCore<T[]> & {
478
481
  // Lock for batching updates - when false, emissions are filtered out
479
482
  const lock$ = new BehaviorSubject<boolean>(true);
480
483
 
481
- // Create observable that respects lock
482
- const locked$ = combineLatest([subject$, lock$]).pipe(
484
+ // Create observable that respects lock, with optional distinct comparison
485
+ const baseLocked$ = combineLatest([subject$, lock$]).pipe(
483
486
  filter(([_, unlocked]) => unlocked),
484
487
  map(([arr, _]) => arr),
488
+ );
489
+
490
+ // Apply distinct comparison if provided
491
+ const locked$ = (comparator
492
+ ? baseLocked$.pipe(distinctUntilChanged(comparator))
493
+ : baseLocked$
494
+ ).pipe(
485
495
  map(deepFreeze),
486
496
  shareReplay(1)
487
497
  );
@@ -1079,6 +1089,14 @@ function createNodeForValue<T>(value: T, maybeNullable: boolean = false): NodeCo
1079
1089
  return createLeafNode(value as Primitive) as NodeCore<T>;
1080
1090
  }
1081
1091
  if (Array.isArray(value)) {
1092
+ // Check if array was marked with options via array() helper
1093
+ if (isArrayMarked(value)) {
1094
+ const options = value[ARRAY_MARKER];
1095
+ const comparator = getArrayComparator(options);
1096
+ // Remove the marker before creating the node
1097
+ delete (value as Record<symbol, unknown>)[ARRAY_MARKER];
1098
+ return createArrayNode(value, comparator) as unknown as NodeCore<T>;
1099
+ }
1082
1100
  return createArrayNode(value) as unknown as NodeCore<T>;
1083
1101
  }
1084
1102
  return createObjectNode(value as object) as unknown as NodeCore<T>;
@@ -1401,3 +1419,81 @@ export function nullable<T extends object>(value: T | null): T | null {
1401
1419
  function isNullableMarked<T>(value: T): boolean {
1402
1420
  return value !== null && typeof value === "object" && NULLABLE_MARKER in value;
1403
1421
  }
1422
+
1423
+ // Symbol to mark an array with distinct options
1424
+ const ARRAY_MARKER = Symbol("array");
1425
+
1426
+ /** Comparison mode for array distinct checking */
1427
+ export type ArrayDistinct<T> =
1428
+ | false // No deduplication (default)
1429
+ | 'shallow' // Reference equality per element
1430
+ | 'deep' // JSON.stringify comparison
1431
+ | ((a: T[], b: T[]) => boolean); // Custom comparator
1432
+
1433
+ /** Options for the array() helper */
1434
+ export interface ArrayOptions<T> {
1435
+ /**
1436
+ * How to compare arrays to prevent duplicate emissions.
1437
+ * - false: No deduplication (default, always emits on set)
1438
+ * - 'shallow': Reference equality per element (a[i] === b[i])
1439
+ * - 'deep': JSON.stringify comparison (expensive for large arrays)
1440
+ * - function: Custom comparator (a, b) => boolean
1441
+ */
1442
+ distinct?: ArrayDistinct<T>;
1443
+ }
1444
+
1445
+ interface MarkedArray<T> extends Array<T> {
1446
+ [ARRAY_MARKER]: ArrayOptions<T>;
1447
+ }
1448
+
1449
+ /**
1450
+ * Marks an array with options for how it should behave in state.
1451
+ * Use this to enable deduplication (prevent emissions when setting same values).
1452
+ *
1453
+ * @example
1454
+ * ```ts
1455
+ * const store = state({
1456
+ * // Default behavior - emits on every set
1457
+ * items: [1, 2, 3],
1458
+ *
1459
+ * // Shallow comparison - only emits if elements differ by reference
1460
+ * tags: array(['a', 'b'], { distinct: 'shallow' }),
1461
+ *
1462
+ * // Deep comparison - only emits if JSON representation differs
1463
+ * settings: array([{ theme: 'dark' }], { distinct: 'deep' }),
1464
+ *
1465
+ * // Custom comparator - you define equality
1466
+ * users: array([{ id: 1, name: 'Alice' }], {
1467
+ * distinct: (a, b) =>
1468
+ * a.length === b.length &&
1469
+ * a.every((user, i) => user.id === b[i].id)
1470
+ * }),
1471
+ * });
1472
+ * ```
1473
+ */
1474
+ export function array<T>(value: T[], options: ArrayOptions<T> = {}): T[] {
1475
+ const marked = [...value] as MarkedArray<T>;
1476
+ marked[ARRAY_MARKER] = options;
1477
+ return marked;
1478
+ }
1479
+
1480
+ // Check if an array was marked with options
1481
+ function isArrayMarked<T>(value: unknown): value is MarkedArray<T> {
1482
+ return Array.isArray(value) && ARRAY_MARKER in value;
1483
+ }
1484
+
1485
+ // Get the distinct comparator function from array options
1486
+ function getArrayComparator<T>(options: ArrayOptions<T>): ((a: T[], b: T[]) => boolean) | undefined {
1487
+ if (!options.distinct) return undefined;
1488
+
1489
+ if (options.distinct === 'shallow') {
1490
+ return (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
1491
+ }
1492
+
1493
+ if (options.distinct === 'deep') {
1494
+ return (a, b) => JSON.stringify(a) === JSON.stringify(b);
1495
+ }
1496
+
1497
+ // Custom function
1498
+ return options.distinct;
1499
+ }
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * Core exports:
5
5
  * - state() - Create reactive state from plain objects
6
6
  * - nullable() - Mark a property as nullable (can transition between null and object)
7
+ * - array() - Mark an array with deduplication options
7
8
  * - RxState, Draft - Type exports
8
9
  *
9
10
  * Helper exports:
@@ -11,5 +12,5 @@
11
12
  * - selectFromEach() - Select from each array item with precise change detection
12
13
  */
13
14
 
14
- export { state, nullable, type RxState, type Draft, type StateOptions } from "./deepstate";
15
+ export { state, nullable, array, type RxState, type Draft, type StateOptions, type ArrayOptions, type ArrayDistinct } from "./deepstate";
15
16
  export { select, selectFromEach } from "./helpers";