@zeix/cause-effect 0.15.2 → 0.16.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.
package/src/state.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { isEqual } from './diff'
2
- import { NullishSignalValueError } from './errors'
3
- import { notify, subscribe, type Watcher } from './scheduler'
4
- import { isObjectOfType, UNSET } from './util'
2
+ import { InvalidCallbackError, NullishSignalValueError } from './errors'
3
+ import { notify, subscribe, type Watcher } from './system'
4
+ import { isFunction, isObjectOfType, UNSET, valueString } from './util'
5
5
 
6
6
  /* === Types === */
7
7
 
8
8
  type State<T extends {}> = {
9
- [Symbol.toStringTag]: 'State'
9
+ readonly [Symbol.toStringTag]: 'State'
10
10
  get(): T
11
- set(v: T): void
12
- update(fn: (v: T) => T): void
11
+ set(newValue: T): void
12
+ update(updater: (oldValue: T) => T): void
13
13
  }
14
14
 
15
15
  /* === Constants === */
@@ -25,54 +25,50 @@ const TYPE_STATE = 'State'
25
25
  * @param {T} initialValue - initial value of the state
26
26
  * @returns {State<T>} - new state signal
27
27
  */
28
- const state = /*#__PURE__*/ <T extends {}>(initialValue: T): State<T> => {
28
+ const createState = /*#__PURE__*/ <T extends {}>(initialValue: T): State<T> => {
29
+ if (initialValue == null) throw new NullishSignalValueError('state')
30
+
29
31
  const watchers: Set<Watcher> = new Set()
30
32
  let value: T = initialValue
31
33
 
32
- const s: State<T> = {
33
- [Symbol.toStringTag]: TYPE_STATE,
34
-
35
- /**
36
- * Get the current value of the state
37
- *
38
- * @since 0.9.0
39
- * @returns {T} - current value of the state
40
- */
41
- get: (): T => {
42
- subscribe(watchers)
43
- return value
44
- },
34
+ const setValue = (newValue: T) => {
35
+ if (newValue == null) throw new NullishSignalValueError('state')
36
+ if (isEqual(value, newValue)) return
37
+ value = newValue
38
+ notify(watchers)
45
39
 
46
- /**
47
- * Set a new value of the state
48
- *
49
- * @since 0.9.0
50
- * @param {T} v
51
- * @returns {void}
52
- */
53
- set: (v: T): void => {
54
- if (v == null) throw new NullishSignalValueError('state')
55
- if (isEqual(value, v)) return
56
- value = v
57
- notify(watchers)
40
+ // Setting to UNSET clears the watchers so the signal can be garbage collected
41
+ if (UNSET === value) watchers.clear()
42
+ }
58
43
 
59
- // Setting to UNSET clears the watchers so the signal can be garbage collected
60
- if (UNSET === value) watchers.clear()
44
+ const state: Record<PropertyKey, unknown> = {}
45
+ Object.defineProperties(state, {
46
+ [Symbol.toStringTag]: {
47
+ value: TYPE_STATE,
61
48
  },
62
-
63
- /**
64
- * Update the state with a new value using a function
65
- *
66
- * @since 0.10.0
67
- * @param {(v: T) => T} fn - function to update the state
68
- * @returns {void} - updates the state with the result of the function
69
- */
70
- update: (fn: (v: T) => T): void => {
71
- s.set(fn(value))
49
+ get: {
50
+ value: () => {
51
+ subscribe(watchers)
52
+ return value
53
+ },
72
54
  },
73
- }
74
-
75
- return s
55
+ set: {
56
+ value: (newValue: T) => {
57
+ setValue(newValue)
58
+ },
59
+ },
60
+ update: {
61
+ value: (updater: (oldValue: T) => T) => {
62
+ if (!isFunction(updater))
63
+ throw new InvalidCallbackError(
64
+ 'state update',
65
+ valueString(updater),
66
+ )
67
+ setValue(updater(value))
68
+ },
69
+ },
70
+ })
71
+ return state as State<T>
76
72
  }
77
73
 
78
74
  /**
@@ -88,4 +84,4 @@ const isState = /*#__PURE__*/ <T extends {}>(
88
84
 
89
85
  /* === Exports === */
90
86
 
91
- export { TYPE_STATE, isState, state, type State }
87
+ export { TYPE_STATE, isState, createState, type State }