-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy pathderiveds.js
124 lines (109 loc) · 2.75 KB
/
deriveds.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { CLEAN, DERIVED, DESTROYED, DIRTY, MAYBE_DIRTY, UNOWNED } from '../constants.js';
import {
current_reaction,
current_effect,
remove_reactions,
set_signal_status,
mark_reactions,
current_skip_reaction,
execute_reaction_fn,
destroy_effect_children,
increment_version
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
export let updating_derived = false;
/**
* @template V
* @param {() => V} fn
* @returns {import('#client').Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived(fn) {
let flags = DERIVED | DIRTY;
if (current_effect === null) flags |= UNOWNED;
/** @type {import('#client').Derived<V>} */
const signal = {
deps: null,
deriveds: null,
equals,
f: flags,
first: null,
fn,
last: null,
reactions: null,
v: /** @type {V} */ (null),
version: 0
};
if (current_reaction !== null && (current_reaction.f & DERIVED) !== 0) {
var current_derived = /** @type {import('#client').Derived<V>} */ (current_reaction);
if (current_derived.deriveds === null) {
current_derived.deriveds = [signal];
} else {
current_derived.deriveds.push(signal);
}
}
return signal;
}
/**
* @template V
* @param {() => V} fn
* @returns {import('#client').Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived_safe_equal(fn) {
const signal = derived(fn);
signal.equals = safe_equals;
return signal;
}
/**
* @param {import('#client').Derived} signal
* @returns {void}
*/
function destroy_derived_children(signal) {
destroy_effect_children(signal);
var deriveds = signal.deriveds;
if (deriveds !== null) {
signal.deriveds = null;
for (var i = 0; i < deriveds.length; i += 1) {
destroy_derived(deriveds[i]);
}
}
}
/**
* @param {import('#client').Derived} derived
* @returns {void}
*/
export function update_derived(derived) {
var previous_updating_derived = updating_derived;
updating_derived = true;
destroy_derived_children(derived);
var value = execute_reaction_fn(derived);
updating_derived = previous_updating_derived;
var status =
(current_skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null
? MAYBE_DIRTY
: CLEAN;
set_signal_status(derived, status);
if (!derived.equals(value)) {
derived.v = value;
derived.version = increment_version();
mark_reactions(derived, DIRTY, false);
}
}
/**
* @param {import('#client').Derived} signal
* @returns {void}
*/
export function destroy_derived(signal) {
destroy_derived_children(signal);
remove_reactions(signal, 0);
set_signal_status(signal, DESTROYED);
// TODO we need to ensure we remove the derived from any parent derives
signal.first =
signal.last =
signal.deps =
signal.reactions =
// @ts-expect-error `signal.fn` cannot be `null` while the signal is alive
signal.fn =
null;
}