@tstdl/base 0.87.13 → 0.87.15
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/package.json +1 -1
- package/signals/implementation/api.d.ts +1 -18
- package/signals/implementation/api.js +1 -5
- package/signals/implementation/computed.js +35 -70
- package/signals/implementation/effect.d.ts +1 -1
- package/signals/implementation/effect.js +14 -14
- package/signals/implementation/graph.d.ts +118 -73
- package/signals/implementation/graph.js +162 -107
- package/signals/implementation/signal.js +55 -74
- package/signals/implementation/watch.d.ts +2 -18
- package/signals/implementation/watch.js +38 -47
- package/text/dynamic-text.model.js +2 -4
package/package.json
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
import type { ReactiveNode } from './graph.js';
|
|
9
8
|
/**
|
|
10
9
|
* Symbol used to tell `Signal`s apart from other functions.
|
|
11
10
|
*
|
|
12
11
|
* This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values.
|
|
13
12
|
*/
|
|
14
|
-
declare const SIGNAL: unique symbol;
|
|
13
|
+
export declare const SIGNAL: unique symbol;
|
|
15
14
|
/**
|
|
16
15
|
* A reactive value which notifies consumers of any changes.
|
|
17
16
|
*
|
|
@@ -28,21 +27,6 @@ export interface Signal<T> {
|
|
|
28
27
|
* Checks if the given `value` is a reactive `Signal`.
|
|
29
28
|
*/
|
|
30
29
|
export declare function isSignal(value: unknown): value is Signal<unknown>;
|
|
31
|
-
/**
|
|
32
|
-
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`).
|
|
33
|
-
*
|
|
34
|
-
* @param fn A zero-argument function which will be converted into a `Signal`.
|
|
35
|
-
*/
|
|
36
|
-
export declare function createSignalFromFunction<T>(node: ReactiveNode, fn: () => T): Signal<T>;
|
|
37
|
-
/**
|
|
38
|
-
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
|
|
39
|
-
* potentially add some set of extra properties (passed as an object record `extraApi`).
|
|
40
|
-
*
|
|
41
|
-
* @param fn A zero-argument function which will be converted into a `Signal`.
|
|
42
|
-
* @param extraApi An object whose properties will be copied onto `fn` in order to create a specific
|
|
43
|
-
* desired interface for the `Signal`.
|
|
44
|
-
*/
|
|
45
|
-
export declare function createSignalFromFunction<T, U extends Record<string, unknown>>(node: ReactiveNode, fn: () => T, extraApi: U): Signal<T> & U;
|
|
46
30
|
/**
|
|
47
31
|
* A comparison function which can determine if two values are equal.
|
|
48
32
|
*/
|
|
@@ -55,4 +39,3 @@ export type ValueEqualityFn<T> = (a: T, b: T) => boolean;
|
|
|
55
39
|
* propagate change notification upon explicit mutation without identity change.
|
|
56
40
|
*/
|
|
57
41
|
export declare function defaultEquals<T>(a: T, b: T): boolean;
|
|
58
|
-
export {};
|
|
@@ -18,7 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var api_exports = {};
|
|
20
20
|
__export(api_exports, {
|
|
21
|
-
|
|
21
|
+
SIGNAL: () => SIGNAL,
|
|
22
22
|
defaultEquals: () => defaultEquals,
|
|
23
23
|
isSignal: () => isSignal
|
|
24
24
|
});
|
|
@@ -34,10 +34,6 @@ const SIGNAL = Symbol("SIGNAL");
|
|
|
34
34
|
function isSignal(value) {
|
|
35
35
|
return typeof value === "function" && value[SIGNAL] !== void 0;
|
|
36
36
|
}
|
|
37
|
-
function createSignalFromFunction(node, fn, extraApi = {}) {
|
|
38
|
-
fn[SIGNAL] = node;
|
|
39
|
-
return Object.assign(fn, extraApi);
|
|
40
|
-
}
|
|
41
37
|
function defaultEquals(a, b) {
|
|
42
38
|
return (a === null || typeof a !== "object") && Object.is(a, b);
|
|
43
39
|
}
|
|
@@ -31,88 +31,53 @@ var import_graph = require("./graph.js");
|
|
|
31
31
|
* found in the LICENSE file at https://angular.io/license
|
|
32
32
|
*/
|
|
33
33
|
function computed(computation, options) {
|
|
34
|
-
const node =
|
|
35
|
-
|
|
34
|
+
const node = Object.create(COMPUTED_NODE);
|
|
35
|
+
node.computation = computation;
|
|
36
|
+
options?.equal && (node.equal = options.equal);
|
|
37
|
+
const computed2 = () => {
|
|
38
|
+
(0, import_graph.producerUpdateValueVersion)(node);
|
|
39
|
+
(0, import_graph.producerAccessed)(node);
|
|
40
|
+
if (node.value === ERRORED) {
|
|
41
|
+
throw node.error;
|
|
42
|
+
}
|
|
43
|
+
return node.value;
|
|
44
|
+
};
|
|
45
|
+
computed2[import_api.SIGNAL] = node;
|
|
46
|
+
return computed2;
|
|
36
47
|
}
|
|
37
48
|
const UNSET = Symbol("UNSET");
|
|
38
49
|
const COMPUTING = Symbol("COMPUTING");
|
|
39
50
|
const ERRORED = Symbol("ERRORED");
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* This can also be one of the special values `UNSET`, `COMPUTING`, or `ERRORED`.
|
|
52
|
-
*/
|
|
53
|
-
value = UNSET;
|
|
54
|
-
/**
|
|
55
|
-
* If `value` is `ERRORED`, the error caught from the last computation attempt which will
|
|
56
|
-
* be re-thrown.
|
|
57
|
-
*/
|
|
58
|
-
error = null;
|
|
59
|
-
/**
|
|
60
|
-
* Flag indicating that the computation is currently stale, meaning that one of the
|
|
61
|
-
* dependencies has notified of a potential change.
|
|
62
|
-
*
|
|
63
|
-
* It's possible that no dependency has _actually_ changed, in which case the `stale`
|
|
64
|
-
* state can be resolved without recomputing the value.
|
|
65
|
-
*/
|
|
66
|
-
stale = true;
|
|
67
|
-
consumerAllowSignalWrites = false;
|
|
68
|
-
onConsumerDependencyMayHaveChanged() {
|
|
69
|
-
if (this.stale) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
this.stale = true;
|
|
73
|
-
this.producerMayHaveChanged();
|
|
74
|
-
}
|
|
75
|
-
onProducerUpdateValueVersion() {
|
|
76
|
-
if (!this.stale) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (this.value !== UNSET && this.value !== COMPUTING && !this.consumerPollProducersForChange()) {
|
|
80
|
-
this.stale = false;
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
this.recomputeValue();
|
|
84
|
-
}
|
|
85
|
-
recomputeValue() {
|
|
86
|
-
if (this.value === COMPUTING) {
|
|
51
|
+
const COMPUTED_NODE = {
|
|
52
|
+
...import_graph.REACTIVE_NODE,
|
|
53
|
+
value: UNSET,
|
|
54
|
+
dirty: true,
|
|
55
|
+
error: null,
|
|
56
|
+
equal: import_api.defaultEquals,
|
|
57
|
+
producerMustRecompute(node) {
|
|
58
|
+
return node.value === UNSET || node.value === COMPUTING;
|
|
59
|
+
},
|
|
60
|
+
producerRecomputeValue(node) {
|
|
61
|
+
if (node.value === COMPUTING) {
|
|
87
62
|
throw new Error("Detected cycle in computations.");
|
|
88
63
|
}
|
|
89
|
-
const oldValue =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const prevConsumer = (0, import_graph.setActiveConsumer)(this);
|
|
64
|
+
const oldValue = node.value;
|
|
65
|
+
node.value = COMPUTING;
|
|
66
|
+
const prevConsumer = (0, import_graph.consumerBeforeComputation)(node);
|
|
93
67
|
let newValue;
|
|
94
68
|
try {
|
|
95
|
-
newValue =
|
|
69
|
+
newValue = node.computation();
|
|
96
70
|
} catch (err) {
|
|
97
71
|
newValue = ERRORED;
|
|
98
|
-
|
|
72
|
+
node.error = err;
|
|
99
73
|
} finally {
|
|
100
|
-
(0, import_graph.
|
|
74
|
+
(0, import_graph.consumerAfterComputation)(node, prevConsumer);
|
|
101
75
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.value = oldValue;
|
|
76
|
+
if (oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED && node.equal(oldValue, newValue)) {
|
|
77
|
+
node.value = oldValue;
|
|
105
78
|
return;
|
|
106
79
|
}
|
|
107
|
-
|
|
108
|
-
|
|
80
|
+
node.value = newValue;
|
|
81
|
+
node.version++;
|
|
109
82
|
}
|
|
110
|
-
|
|
111
|
-
this.onProducerUpdateValueVersion();
|
|
112
|
-
this.producerAccessed();
|
|
113
|
-
if (this.value === ERRORED) {
|
|
114
|
-
throw this.error;
|
|
115
|
-
}
|
|
116
|
-
return this.value;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
83
|
+
};
|
|
@@ -22,7 +22,7 @@ export declare class EffectManager {
|
|
|
22
22
|
private readonly all;
|
|
23
23
|
private readonly queue;
|
|
24
24
|
private pendingFlush;
|
|
25
|
-
create(effectFn: (onCleanup: (cleanupFn: EffectCleanupFn) => void) => void,
|
|
25
|
+
create(effectFn: (onCleanup: (cleanupFn: EffectCleanupFn) => void) => void, allowSignalWrites: boolean): EffectRef;
|
|
26
26
|
flush(): void;
|
|
27
27
|
get isQueueEmpty(): boolean;
|
|
28
28
|
}
|
|
@@ -34,12 +34,12 @@ class EffectManager {
|
|
|
34
34
|
all = /* @__PURE__ */ new Set();
|
|
35
35
|
queue = /* @__PURE__ */ new Set();
|
|
36
36
|
pendingFlush;
|
|
37
|
-
create(effectFn,
|
|
38
|
-
const
|
|
39
|
-
if (!this.all.has(
|
|
37
|
+
create(effectFn, allowSignalWrites) {
|
|
38
|
+
const w = (0, import_watch.watch)(effectFn, () => {
|
|
39
|
+
if (!this.all.has(w)) {
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
this.queue.add(
|
|
42
|
+
this.queue.add(w);
|
|
43
43
|
if (!this.pendingFlush) {
|
|
44
44
|
this.pendingFlush = true;
|
|
45
45
|
queueMicrotask(() => {
|
|
@@ -48,24 +48,24 @@ class EffectManager {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
}, allowSignalWrites);
|
|
51
|
-
this.all.add(
|
|
52
|
-
|
|
51
|
+
this.all.add(w);
|
|
52
|
+
w.notify();
|
|
53
53
|
const destroy = () => {
|
|
54
|
-
|
|
55
|
-
this.all.delete(
|
|
56
|
-
this.queue.delete(
|
|
54
|
+
w.cleanup();
|
|
55
|
+
this.all.delete(w);
|
|
56
|
+
this.queue.delete(w);
|
|
57
57
|
};
|
|
58
58
|
return {
|
|
59
59
|
destroy
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
flush() {
|
|
63
|
-
if (this.queue.size
|
|
63
|
+
if (this.queue.size === 0) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
|
-
for (const
|
|
67
|
-
this.queue.delete(
|
|
68
|
-
|
|
66
|
+
for (const w of this.queue) {
|
|
67
|
+
this.queue.delete(w);
|
|
68
|
+
w.run();
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
get isQueueEmpty() {
|
|
@@ -74,5 +74,5 @@ class EffectManager {
|
|
|
74
74
|
}
|
|
75
75
|
const effectManager = new EffectManager();
|
|
76
76
|
function effect(effectFn, options) {
|
|
77
|
-
return effectManager.create(effectFn, options);
|
|
77
|
+
return effectManager.create(effectFn, options?.allowSignalWrites ?? false);
|
|
78
78
|
}
|
|
@@ -5,104 +5,149 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
+
type Version = number & {
|
|
9
|
+
__brand: 'Version';
|
|
10
|
+
};
|
|
8
11
|
export declare function setActiveConsumer(consumer: ReactiveNode | null): ReactiveNode | null;
|
|
12
|
+
export declare const REACTIVE_NODE: {
|
|
13
|
+
version: Version;
|
|
14
|
+
dirty: boolean;
|
|
15
|
+
producerNode: undefined;
|
|
16
|
+
producerLastReadVersion: undefined;
|
|
17
|
+
producerIndexOfThis: undefined;
|
|
18
|
+
nextProducerIndex: number;
|
|
19
|
+
liveConsumerNode: undefined;
|
|
20
|
+
liveConsumerIndexOfThis: undefined;
|
|
21
|
+
consumerAllowSignalWrites: boolean;
|
|
22
|
+
consumerIsAlwaysLive: boolean;
|
|
23
|
+
producerMustRecompute: () => boolean;
|
|
24
|
+
producerRecomputeValue: () => void;
|
|
25
|
+
consumerMarkedDirty: () => void;
|
|
26
|
+
};
|
|
9
27
|
/**
|
|
10
|
-
* A
|
|
28
|
+
* A producer and/or consumer which participates in the reactive graph.
|
|
11
29
|
*
|
|
12
|
-
*
|
|
30
|
+
* Producer `ReactiveNode`s which are accessed when a consumer `ReactiveNode` is the
|
|
31
|
+
* `activeConsumer` are tracked as dependencies of that consumer.
|
|
13
32
|
*
|
|
14
|
-
*
|
|
33
|
+
* Certain consumers are also tracked as "live" consumers and create edges in the other direction,
|
|
34
|
+
* from producer to consumer. These edges are used to propagate change notifications when a
|
|
35
|
+
* producer's value is updated.
|
|
15
36
|
*
|
|
16
|
-
*
|
|
17
|
-
* version when their value semantically changes. Some producers may produce their values lazily and
|
|
18
|
-
* thus at times need to be polled for potential updates to their value (and by extension their
|
|
19
|
-
* `valueVersion`). This is accomplished via the `onProducerUpdateValueVersion` method for
|
|
20
|
-
* implemented by producers, which should perform whatever calculations are necessary to ensure
|
|
21
|
-
* `valueVersion` is up to date.
|
|
22
|
-
*
|
|
23
|
-
* Consumers are nodes that depend on the values of producers and are notified when those values
|
|
24
|
-
* might have changed.
|
|
25
|
-
*
|
|
26
|
-
* Consumers do not wrap the reads they consume themselves, but rather can be set as the active
|
|
27
|
-
* reader via `setActiveConsumer`. Reads of producers that happen while a consumer is active will
|
|
28
|
-
* result in those producers being added as dependencies of that consumer node.
|
|
29
|
-
*
|
|
30
|
-
* The set of dependencies of a consumer is dynamic. Implementers expose a monotonically increasing
|
|
31
|
-
* `trackingVersion` counter, which increments whenever the consumer is about to re-run any reactive
|
|
32
|
-
* reads it needs and establish a new set of dependencies as a result.
|
|
33
|
-
*
|
|
34
|
-
* Producers store the last `trackingVersion` they've seen from `Consumer`s which have read them.
|
|
35
|
-
* This allows a producer to identify whether its record of the dependency is current or stale, by
|
|
36
|
-
* comparing the consumer's `trackingVersion` to the version at which the dependency was
|
|
37
|
-
* last observed.
|
|
37
|
+
* A `ReactiveNode` may be both a producer and consumer.
|
|
38
38
|
*/
|
|
39
|
-
export
|
|
40
|
-
private readonly id;
|
|
41
|
-
/**
|
|
42
|
-
* A cached weak reference to this node, which will be used in `ReactiveEdge`s.
|
|
43
|
-
*/
|
|
44
|
-
private readonly ref;
|
|
45
|
-
/**
|
|
46
|
-
* Edges to producers on which this node depends (in its consumer capacity).
|
|
47
|
-
*/
|
|
48
|
-
private readonly producers;
|
|
49
|
-
/**
|
|
50
|
-
* Edges to consumers on which this node depends (in its producer capacity).
|
|
51
|
-
*/
|
|
52
|
-
private readonly consumers;
|
|
39
|
+
export interface ReactiveNode {
|
|
53
40
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Monotonically increasing counter which increases when the value of this `Producer`
|
|
60
|
-
* semantically changes.
|
|
41
|
+
* Version of the value that this node produces.
|
|
42
|
+
*
|
|
43
|
+
* This is incremented whenever a new value is produced by this node which is not equal to the
|
|
44
|
+
* previous value (by whatever definition of equality is in use).
|
|
61
45
|
*/
|
|
62
|
-
|
|
46
|
+
version: Version;
|
|
63
47
|
/**
|
|
64
|
-
* Whether
|
|
48
|
+
* Whether this node (in its consumer capacity) is dirty.
|
|
49
|
+
*
|
|
50
|
+
* Only live consumers become dirty, when receiving a change notification from a dependency
|
|
51
|
+
* producer.
|
|
65
52
|
*/
|
|
66
|
-
|
|
53
|
+
dirty: boolean;
|
|
67
54
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
55
|
+
* Producers which are dependencies of this consumer.
|
|
56
|
+
*
|
|
57
|
+
* Uses the same indices as the `producerLastReadVersion` and `producerIndexOfThis` arrays.
|
|
70
58
|
*/
|
|
71
|
-
|
|
59
|
+
producerNode: ReactiveNode[] | undefined;
|
|
72
60
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
61
|
+
* `Version` of the value last read by a given producer.
|
|
62
|
+
*
|
|
63
|
+
* Uses the same indices as the `producerNode` and `producerIndexOfThis` arrays.
|
|
75
64
|
*/
|
|
76
|
-
|
|
65
|
+
producerLastReadVersion: Version[] | undefined;
|
|
77
66
|
/**
|
|
78
|
-
*
|
|
67
|
+
* Index of `this` (consumer) in each producer's `liveConsumers` array.
|
|
68
|
+
*
|
|
69
|
+
* This value is only meaningful if this node is live (`liveConsumers.length > 0`). Otherwise
|
|
70
|
+
* these indices are stale.
|
|
79
71
|
*
|
|
80
|
-
*
|
|
81
|
-
* change, the values of its dependencies have not actually changed and the consumer should not
|
|
82
|
-
* rerun any reactions.
|
|
72
|
+
* Uses the same indices as the `producerNode` and `producerLastReadVersion` arrays.
|
|
83
73
|
*/
|
|
84
|
-
|
|
74
|
+
producerIndexOfThis: number[] | undefined;
|
|
85
75
|
/**
|
|
86
|
-
*
|
|
76
|
+
* Index into the producer arrays that the next dependency of this node as a consumer will use.
|
|
77
|
+
*
|
|
78
|
+
* This index is zeroed before this node as a consumer begins executing. When a producer is read,
|
|
79
|
+
* it gets inserted into the producers arrays at this index. There may be an existing dependency
|
|
80
|
+
* in this location which may or may not match the incoming producer, depending on whether the
|
|
81
|
+
* same producers were read in the same order as the last computation.
|
|
87
82
|
*/
|
|
88
|
-
|
|
83
|
+
nextProducerIndex: number;
|
|
89
84
|
/**
|
|
90
|
-
*
|
|
85
|
+
* Array of consumers of this producer that are "live" (they require push notifications).
|
|
86
|
+
*
|
|
87
|
+
* `liveConsumerNode.length` is effectively our reference count for this node.
|
|
91
88
|
*/
|
|
92
|
-
|
|
89
|
+
liveConsumerNode: ReactiveNode[] | undefined;
|
|
93
90
|
/**
|
|
94
|
-
*
|
|
91
|
+
* Index of `this` (producer) in each consumer's `producerNode` array.
|
|
92
|
+
*
|
|
93
|
+
* Uses the same indices as the `liveConsumerNode` array.
|
|
95
94
|
*/
|
|
96
|
-
|
|
95
|
+
liveConsumerIndexOfThis: number[] | undefined;
|
|
97
96
|
/**
|
|
98
|
-
* Whether
|
|
99
|
-
*
|
|
97
|
+
* Whether writes to signals are allowed when this consumer is the `activeConsumer`.
|
|
98
|
+
*
|
|
99
|
+
* This is used to enforce guardrails such as preventing writes to writable signals in the
|
|
100
|
+
* computation function of computed signals, which is supposed to be pure.
|
|
100
101
|
*/
|
|
101
|
-
|
|
102
|
+
consumerAllowSignalWrites: boolean;
|
|
103
|
+
readonly consumerIsAlwaysLive: boolean;
|
|
102
104
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* this `Producer`.
|
|
105
|
+
* Tracks whether producers need to recompute their value independently of the reactive graph (for
|
|
106
|
+
* example, if no initial value has been computed).
|
|
106
107
|
*/
|
|
107
|
-
|
|
108
|
+
producerMustRecompute(node: unknown): boolean;
|
|
109
|
+
producerRecomputeValue(node: unknown): void;
|
|
110
|
+
consumerMarkedDirty(node: unknown): void;
|
|
108
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Called by implementations when a producer's signal is read.
|
|
114
|
+
*/
|
|
115
|
+
export declare function producerAccessed(node: ReactiveNode): void;
|
|
116
|
+
/**
|
|
117
|
+
* Ensure this producer's `version` is up-to-date.
|
|
118
|
+
*/
|
|
119
|
+
export declare function producerUpdateValueVersion(node: ReactiveNode): void;
|
|
120
|
+
/**
|
|
121
|
+
* Propagate a dirty notification to live consumers of this producer.
|
|
122
|
+
*/
|
|
123
|
+
export declare function producerNotifyConsumers(node: ReactiveNode): void;
|
|
124
|
+
/**
|
|
125
|
+
* Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
|
|
126
|
+
* based on the current consumer context.
|
|
127
|
+
*/
|
|
128
|
+
export declare function producerUpdatesAllowed(): boolean;
|
|
129
|
+
export declare function consumerMarkDirty(node: ReactiveNode): void;
|
|
130
|
+
/**
|
|
131
|
+
* Prepare this consumer to run a computation in its reactive context.
|
|
132
|
+
*
|
|
133
|
+
* Must be called by subclasses which represent reactive computations, before those computations
|
|
134
|
+
* begin.
|
|
135
|
+
*/
|
|
136
|
+
export declare function consumerBeforeComputation(node: ReactiveNode | null): ReactiveNode | null;
|
|
137
|
+
/**
|
|
138
|
+
* Finalize this consumer's state after a reactive computation has run.
|
|
139
|
+
*
|
|
140
|
+
* Must be called by subclasses which represent reactive computations, after those computations
|
|
141
|
+
* have finished.
|
|
142
|
+
*/
|
|
143
|
+
export declare function consumerAfterComputation(node: ReactiveNode | null, prevConsumer: ReactiveNode | null): void;
|
|
144
|
+
/**
|
|
145
|
+
* Determine whether this consumer has any dependencies which have changed since the last time
|
|
146
|
+
* they were read.
|
|
147
|
+
*/
|
|
148
|
+
export declare function consumerPollProducersForChange(node: ReactiveNode): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Disconnect this consumer from the graph.
|
|
151
|
+
*/
|
|
152
|
+
export declare function consumerDestroy(node: ReactiveNode): void;
|
|
153
|
+
export {};
|
|
@@ -18,7 +18,16 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var graph_exports = {};
|
|
20
20
|
__export(graph_exports, {
|
|
21
|
-
|
|
21
|
+
REACTIVE_NODE: () => REACTIVE_NODE,
|
|
22
|
+
consumerAfterComputation: () => consumerAfterComputation,
|
|
23
|
+
consumerBeforeComputation: () => consumerBeforeComputation,
|
|
24
|
+
consumerDestroy: () => consumerDestroy,
|
|
25
|
+
consumerMarkDirty: () => consumerMarkDirty,
|
|
26
|
+
consumerPollProducersForChange: () => consumerPollProducersForChange,
|
|
27
|
+
producerAccessed: () => producerAccessed,
|
|
28
|
+
producerNotifyConsumers: () => producerNotifyConsumers,
|
|
29
|
+
producerUpdateValueVersion: () => producerUpdateValueVersion,
|
|
30
|
+
producerUpdatesAllowed: () => producerUpdatesAllowed,
|
|
22
31
|
setActiveConsumer: () => setActiveConsumer
|
|
23
32
|
});
|
|
24
33
|
module.exports = __toCommonJS(graph_exports);
|
|
@@ -29,7 +38,6 @@ module.exports = __toCommonJS(graph_exports);
|
|
|
29
38
|
* Use of this source code is governed by an MIT-style license that can be
|
|
30
39
|
* found in the LICENSE file at https://angular.io/license
|
|
31
40
|
*/
|
|
32
|
-
let _nextReactiveId = 0;
|
|
33
41
|
let activeConsumer = null;
|
|
34
42
|
let inNotificationPhase = false;
|
|
35
43
|
function setActiveConsumer(consumer) {
|
|
@@ -37,119 +45,166 @@ function setActiveConsumer(consumer) {
|
|
|
37
45
|
activeConsumer = consumer;
|
|
38
46
|
return prev;
|
|
39
47
|
}
|
|
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
|
-
consumerPollProducersForChange() {
|
|
72
|
-
for (const [producerId, edge] of this.producers) {
|
|
73
|
-
const producer = edge.producerNode.deref();
|
|
74
|
-
if (producer == null || edge.atTrackingVersion !== this.trackingVersion) {
|
|
75
|
-
this.producers.delete(producerId);
|
|
76
|
-
producer?.consumers.delete(this.id);
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
if (producer.producerPollStatus(edge.seenValueVersion)) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
48
|
+
const REACTIVE_NODE = {
|
|
49
|
+
version: 0,
|
|
50
|
+
dirty: false,
|
|
51
|
+
producerNode: void 0,
|
|
52
|
+
producerLastReadVersion: void 0,
|
|
53
|
+
producerIndexOfThis: void 0,
|
|
54
|
+
nextProducerIndex: 0,
|
|
55
|
+
liveConsumerNode: void 0,
|
|
56
|
+
liveConsumerIndexOfThis: void 0,
|
|
57
|
+
consumerAllowSignalWrites: false,
|
|
58
|
+
consumerIsAlwaysLive: false,
|
|
59
|
+
producerMustRecompute: () => false,
|
|
60
|
+
producerRecomputeValue: () => {
|
|
61
|
+
},
|
|
62
|
+
consumerMarkedDirty: () => {
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function producerAccessed(node) {
|
|
66
|
+
if (inNotificationPhase) {
|
|
67
|
+
throw new Error("Assertion error: signal read during notification phase");
|
|
68
|
+
}
|
|
69
|
+
if (activeConsumer === null) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const idx = activeConsumer.nextProducerIndex++;
|
|
73
|
+
assertConsumerNode(activeConsumer);
|
|
74
|
+
if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) {
|
|
75
|
+
if (consumerIsLive(activeConsumer)) {
|
|
76
|
+
const staleProducer = activeConsumer.producerNode[idx];
|
|
77
|
+
producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]);
|
|
82
78
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
79
|
+
}
|
|
80
|
+
if (activeConsumer.producerNode[idx] !== node) {
|
|
81
|
+
activeConsumer.producerNode[idx] = node;
|
|
82
|
+
activeConsumer.producerIndexOfThis[idx] = consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0;
|
|
83
|
+
}
|
|
84
|
+
activeConsumer.producerLastReadVersion[idx] = node.version;
|
|
85
|
+
}
|
|
86
|
+
function producerUpdateValueVersion(node) {
|
|
87
|
+
if (consumerIsLive(node) && !node.dirty) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
|
|
91
|
+
node.dirty = false;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
node.producerRecomputeValue(node);
|
|
95
|
+
node.dirty = false;
|
|
96
|
+
}
|
|
97
|
+
function producerNotifyConsumers(node) {
|
|
98
|
+
if (node.liveConsumerNode === void 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const prev = inNotificationPhase;
|
|
102
|
+
inNotificationPhase = true;
|
|
103
|
+
try {
|
|
104
|
+
for (const consumer of node.liveConsumerNode) {
|
|
105
|
+
if (!consumer.dirty) {
|
|
106
|
+
consumerMarkDirty(consumer);
|
|
100
107
|
}
|
|
101
|
-
} finally {
|
|
102
|
-
inNotificationPhase = prev;
|
|
103
108
|
}
|
|
109
|
+
} finally {
|
|
110
|
+
inNotificationPhase = prev;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function producerUpdatesAllowed() {
|
|
114
|
+
return activeConsumer?.consumerAllowSignalWrites !== false;
|
|
115
|
+
}
|
|
116
|
+
function consumerMarkDirty(node) {
|
|
117
|
+
node.dirty = true;
|
|
118
|
+
producerNotifyConsumers(node);
|
|
119
|
+
node.consumerMarkedDirty?.(node);
|
|
120
|
+
}
|
|
121
|
+
function consumerBeforeComputation(node) {
|
|
122
|
+
node && (node.nextProducerIndex = 0);
|
|
123
|
+
return setActiveConsumer(node);
|
|
124
|
+
}
|
|
125
|
+
function consumerAfterComputation(node, prevConsumer) {
|
|
126
|
+
setActiveConsumer(prevConsumer);
|
|
127
|
+
if (!node || node.producerNode === void 0 || node.producerIndexOfThis === void 0 || node.producerLastReadVersion === void 0) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (consumerIsLive(node)) {
|
|
131
|
+
for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
|
|
132
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
|
|
136
|
+
node.producerNode.pop();
|
|
137
|
+
node.producerLastReadVersion.pop();
|
|
138
|
+
node.producerIndexOfThis.pop();
|
|
104
139
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
140
|
+
}
|
|
141
|
+
function consumerPollProducersForChange(node) {
|
|
142
|
+
assertConsumerNode(node);
|
|
143
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
144
|
+
const producer = node.producerNode[i];
|
|
145
|
+
const seenVersion = node.producerLastReadVersion[i];
|
|
146
|
+
if (seenVersion !== producer.version) {
|
|
147
|
+
return true;
|
|
111
148
|
}
|
|
112
|
-
|
|
113
|
-
|
|
149
|
+
producerUpdateValueVersion(producer);
|
|
150
|
+
if (seenVersion !== producer.version) {
|
|
151
|
+
return true;
|
|
114
152
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
activeConsumer.producers.set(this.id, edge);
|
|
124
|
-
this.consumers.set(activeConsumer.id, edge);
|
|
125
|
-
} else {
|
|
126
|
-
edge.seenValueVersion = this.valueVersion;
|
|
127
|
-
edge.atTrackingVersion = activeConsumer.trackingVersion;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function consumerDestroy(node) {
|
|
157
|
+
assertConsumerNode(node);
|
|
158
|
+
if (consumerIsLive(node)) {
|
|
159
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
160
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
128
161
|
}
|
|
129
162
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
163
|
+
node.producerNode.length = node.producerLastReadVersion.length = node.producerIndexOfThis.length = 0;
|
|
164
|
+
if (node.liveConsumerNode) {
|
|
165
|
+
node.liveConsumerNode.length = node.liveConsumerIndexOfThis.length = 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function producerAddLiveConsumer(node, consumer, indexOfThis) {
|
|
169
|
+
assertProducerNode(node);
|
|
170
|
+
assertConsumerNode(node);
|
|
171
|
+
if (node.liveConsumerNode.length === 0) {
|
|
172
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
173
|
+
node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
node.liveConsumerIndexOfThis.push(indexOfThis);
|
|
177
|
+
return node.liveConsumerNode.push(consumer) - 1;
|
|
178
|
+
}
|
|
179
|
+
function producerRemoveLiveConsumerAtIndex(node, idx) {
|
|
180
|
+
assertProducerNode(node);
|
|
181
|
+
assertConsumerNode(node);
|
|
182
|
+
if (node.liveConsumerNode.length === 1) {
|
|
183
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
184
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
151
185
|
}
|
|
152
|
-
this.onProducerUpdateValueVersion();
|
|
153
|
-
return this.valueVersion !== lastSeenValueVersion;
|
|
154
186
|
}
|
|
187
|
+
const lastIdx = node.liveConsumerNode.length - 1;
|
|
188
|
+
node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx];
|
|
189
|
+
node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx];
|
|
190
|
+
node.liveConsumerNode.length--;
|
|
191
|
+
node.liveConsumerIndexOfThis.length--;
|
|
192
|
+
if (idx < node.liveConsumerNode.length) {
|
|
193
|
+
const idxProducer = node.liveConsumerIndexOfThis[idx];
|
|
194
|
+
const consumer = node.liveConsumerNode[idx];
|
|
195
|
+
assertConsumerNode(consumer);
|
|
196
|
+
consumer.producerIndexOfThis[idxProducer] = idx;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function consumerIsLive(node) {
|
|
200
|
+
return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0;
|
|
201
|
+
}
|
|
202
|
+
function assertConsumerNode(node) {
|
|
203
|
+
node.producerNode ??= [];
|
|
204
|
+
node.producerIndexOfThis ??= [];
|
|
205
|
+
node.producerLastReadVersion ??= [];
|
|
206
|
+
}
|
|
207
|
+
function assertProducerNode(node) {
|
|
208
|
+
node.liveConsumerNode ??= [];
|
|
209
|
+
node.liveConsumerIndexOfThis ??= [];
|
|
155
210
|
}
|
|
@@ -33,81 +33,19 @@ var import_graph = require("./graph.js");
|
|
|
33
33
|
* found in the LICENSE file at https://angular.io/license
|
|
34
34
|
*/
|
|
35
35
|
let postSignalSetFn = null;
|
|
36
|
-
class WritableSignalImpl extends import_graph.ReactiveNode {
|
|
37
|
-
value;
|
|
38
|
-
equal;
|
|
39
|
-
readonlySignal;
|
|
40
|
-
consumerAllowSignalWrites = false;
|
|
41
|
-
constructor(value, equal) {
|
|
42
|
-
super();
|
|
43
|
-
this.value = value;
|
|
44
|
-
this.equal = equal;
|
|
45
|
-
}
|
|
46
|
-
onConsumerDependencyMayHaveChanged() {
|
|
47
|
-
}
|
|
48
|
-
onProducerUpdateValueVersion() {
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Directly update the value of the signal to a new value, which may or may not be
|
|
52
|
-
* equal to the previous.
|
|
53
|
-
*
|
|
54
|
-
* In the event that `newValue` is semantically equal to the current value, `set` is
|
|
55
|
-
* a no-op.
|
|
56
|
-
*/
|
|
57
|
-
set(newValue) {
|
|
58
|
-
if (!this.producerUpdatesAllowed) {
|
|
59
|
-
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
60
|
-
}
|
|
61
|
-
if (!this.equal(this.value, newValue)) {
|
|
62
|
-
this.value = newValue;
|
|
63
|
-
this.valueVersion++;
|
|
64
|
-
this.producerMayHaveChanged();
|
|
65
|
-
postSignalSetFn?.();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Derive a new value for the signal from its current value using the `updater` function.
|
|
70
|
-
*
|
|
71
|
-
* This is equivalent to calling `set` on the result of running `updater` on the current
|
|
72
|
-
* value.
|
|
73
|
-
*/
|
|
74
|
-
update(updater) {
|
|
75
|
-
if (!this.producerUpdatesAllowed) {
|
|
76
|
-
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
77
|
-
}
|
|
78
|
-
this.set(updater(this.value));
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Calls `mutator` on the current value and assumes that it has been mutated.
|
|
82
|
-
*/
|
|
83
|
-
mutate(mutator) {
|
|
84
|
-
if (!this.producerUpdatesAllowed) {
|
|
85
|
-
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
86
|
-
}
|
|
87
|
-
mutator(this.value);
|
|
88
|
-
this.valueVersion++;
|
|
89
|
-
this.producerMayHaveChanged();
|
|
90
|
-
postSignalSetFn?.();
|
|
91
|
-
}
|
|
92
|
-
asReadonly() {
|
|
93
|
-
if (this.readonlySignal === void 0) {
|
|
94
|
-
this.readonlySignal = (0, import_api.createSignalFromFunction)(this, () => this.signal());
|
|
95
|
-
}
|
|
96
|
-
return this.readonlySignal;
|
|
97
|
-
}
|
|
98
|
-
signal() {
|
|
99
|
-
this.producerAccessed();
|
|
100
|
-
return this.value;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
36
|
function signal(initialValue, options) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
37
|
+
const node = Object.create(SIGNAL_NODE);
|
|
38
|
+
node.value = initialValue;
|
|
39
|
+
options?.equal && (node.equal = options.equal);
|
|
40
|
+
function signalFn() {
|
|
41
|
+
(0, import_graph.producerAccessed)(node);
|
|
42
|
+
return node.value;
|
|
43
|
+
}
|
|
44
|
+
signalFn.set = signalSetFn;
|
|
45
|
+
signalFn.update = signalUpdateFn;
|
|
46
|
+
signalFn.mutate = signalMutateFn;
|
|
47
|
+
signalFn.asReadonly = signalAsReadonlyFn;
|
|
48
|
+
signalFn[import_api.SIGNAL] = node;
|
|
111
49
|
return signalFn;
|
|
112
50
|
}
|
|
113
51
|
function setPostSignalSetFn(fn) {
|
|
@@ -115,3 +53,46 @@ function setPostSignalSetFn(fn) {
|
|
|
115
53
|
postSignalSetFn = fn;
|
|
116
54
|
return prev;
|
|
117
55
|
}
|
|
56
|
+
const SIGNAL_NODE = {
|
|
57
|
+
...import_graph.REACTIVE_NODE,
|
|
58
|
+
equal: import_api.defaultEquals,
|
|
59
|
+
readonlyFn: void 0
|
|
60
|
+
};
|
|
61
|
+
function signalValueChanged(node) {
|
|
62
|
+
node.version++;
|
|
63
|
+
(0, import_graph.producerNotifyConsumers)(node);
|
|
64
|
+
postSignalSetFn?.();
|
|
65
|
+
}
|
|
66
|
+
function signalSetFn(newValue) {
|
|
67
|
+
const node = this[import_api.SIGNAL];
|
|
68
|
+
if (!(0, import_graph.producerUpdatesAllowed)()) {
|
|
69
|
+
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
70
|
+
}
|
|
71
|
+
if (!node.equal(node.value, newValue)) {
|
|
72
|
+
node.value = newValue;
|
|
73
|
+
signalValueChanged(node);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function signalUpdateFn(updater) {
|
|
77
|
+
if (!(0, import_graph.producerUpdatesAllowed)()) {
|
|
78
|
+
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
79
|
+
}
|
|
80
|
+
signalSetFn.call(this, updater(this[import_api.SIGNAL].value));
|
|
81
|
+
}
|
|
82
|
+
function signalMutateFn(mutator) {
|
|
83
|
+
const node = this[import_api.SIGNAL];
|
|
84
|
+
if (!(0, import_graph.producerUpdatesAllowed)()) {
|
|
85
|
+
(0, import_errors.throwInvalidWriteToSignalError)();
|
|
86
|
+
}
|
|
87
|
+
mutator(node.value);
|
|
88
|
+
signalValueChanged(node);
|
|
89
|
+
}
|
|
90
|
+
function signalAsReadonlyFn() {
|
|
91
|
+
const node = this[import_api.SIGNAL];
|
|
92
|
+
if (node.readonlyFn === void 0) {
|
|
93
|
+
const readonlyFn = () => this();
|
|
94
|
+
readonlyFn[import_api.SIGNAL] = node;
|
|
95
|
+
node.readonlyFn = readonlyFn;
|
|
96
|
+
}
|
|
97
|
+
return node.readonlyFn;
|
|
98
|
+
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
import { ReactiveNode } from './graph.js';
|
|
9
8
|
/**
|
|
10
9
|
* A cleanup function that can be optionally registered from the watch logic. If registered, the
|
|
11
10
|
* cleanup logic runs before the next watch execution.
|
|
@@ -15,24 +14,8 @@ export type WatchCleanupFn = () => void;
|
|
|
15
14
|
* A callback passed to the watch function that makes it possible to register cleanup logic.
|
|
16
15
|
*/
|
|
17
16
|
export type WatchCleanupRegisterFn = (cleanupFn: WatchCleanupFn) => void;
|
|
18
|
-
|
|
19
|
-
* Watches a reactive expression and allows it to be scheduled to re-run
|
|
20
|
-
* when any dependencies notify of a change.
|
|
21
|
-
*
|
|
22
|
-
* `Watch` doesn't run reactive expressions itself, but relies on a consumer-
|
|
23
|
-
* provided scheduling operation to coordinate calling `Watch.run()`.
|
|
24
|
-
*/
|
|
25
|
-
export declare class Watch extends ReactiveNode {
|
|
26
|
-
private watch;
|
|
27
|
-
private schedule;
|
|
28
|
-
protected readonly consumerAllowSignalWrites: boolean;
|
|
29
|
-
private dirty;
|
|
30
|
-
private cleanupFn;
|
|
31
|
-
private registerOnCleanup;
|
|
32
|
-
constructor(watch: (onCleanup: WatchCleanupRegisterFn) => void, schedule: (watch: Watch) => void, allowSignalWrites: boolean);
|
|
17
|
+
export interface Watch {
|
|
33
18
|
notify(): void;
|
|
34
|
-
protected onConsumerDependencyMayHaveChanged(): void;
|
|
35
|
-
protected onProducerUpdateValueVersion(): void;
|
|
36
19
|
/**
|
|
37
20
|
* Execute the reactive expression in the context of this `Watch` consumer.
|
|
38
21
|
*
|
|
@@ -42,3 +25,4 @@ export declare class Watch extends ReactiveNode {
|
|
|
42
25
|
run(): void;
|
|
43
26
|
cleanup(): void;
|
|
44
27
|
}
|
|
28
|
+
export declare function watch(fn: (onCleanup: WatchCleanupRegisterFn) => void, schedule: (watch: Watch) => void, allowSignalWrites: boolean): Watch;
|
|
@@ -18,7 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var watch_exports = {};
|
|
20
20
|
__export(watch_exports, {
|
|
21
|
-
|
|
21
|
+
watch: () => watch
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(watch_exports);
|
|
24
24
|
var import_graph = require("./graph.js");
|
|
@@ -29,56 +29,47 @@ var import_graph = require("./graph.js");
|
|
|
29
29
|
* Use of this source code is governed by an MIT-style license that can be
|
|
30
30
|
* found in the LICENSE file at https://angular.io/license
|
|
31
31
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
schedule;
|
|
37
|
-
consumerAllowSignalWrites;
|
|
38
|
-
dirty = false;
|
|
39
|
-
cleanupFn = NOOP_CLEANUP_FN;
|
|
40
|
-
registerOnCleanup = (cleanupFn) => {
|
|
41
|
-
this.cleanupFn = cleanupFn;
|
|
42
|
-
};
|
|
43
|
-
constructor(watch, schedule, allowSignalWrites) {
|
|
44
|
-
super();
|
|
45
|
-
this.watch = watch;
|
|
46
|
-
this.schedule = schedule;
|
|
47
|
-
this.consumerAllowSignalWrites = allowSignalWrites;
|
|
48
|
-
}
|
|
49
|
-
notify() {
|
|
50
|
-
if (!this.dirty) {
|
|
51
|
-
this.schedule(this);
|
|
52
|
-
}
|
|
53
|
-
this.dirty = true;
|
|
54
|
-
}
|
|
55
|
-
onConsumerDependencyMayHaveChanged() {
|
|
56
|
-
this.notify();
|
|
32
|
+
function watch(fn, schedule, allowSignalWrites) {
|
|
33
|
+
const node = Object.create(WATCH_NODE);
|
|
34
|
+
if (allowSignalWrites) {
|
|
35
|
+
node.consumerAllowSignalWrites = true;
|
|
57
36
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
run() {
|
|
67
|
-
this.dirty = false;
|
|
68
|
-
if (this.trackingVersion !== 0 && !this.consumerPollProducersForChange()) {
|
|
37
|
+
node.fn = fn;
|
|
38
|
+
node.schedule = schedule;
|
|
39
|
+
const registerOnCleanup = (cleanupFn) => {
|
|
40
|
+
node.cleanupFn = cleanupFn;
|
|
41
|
+
};
|
|
42
|
+
const run = () => {
|
|
43
|
+
node.dirty = false;
|
|
44
|
+
if (node.hasRun && !(0, import_graph.consumerPollProducersForChange)(node)) {
|
|
69
45
|
return;
|
|
70
46
|
}
|
|
71
|
-
|
|
72
|
-
|
|
47
|
+
node.hasRun = true;
|
|
48
|
+
const prevConsumer = (0, import_graph.consumerBeforeComputation)(node);
|
|
73
49
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
node.cleanupFn();
|
|
51
|
+
node.cleanupFn = NOOP_CLEANUP_FN;
|
|
52
|
+
node.fn(registerOnCleanup);
|
|
77
53
|
} finally {
|
|
78
|
-
(0, import_graph.
|
|
54
|
+
(0, import_graph.consumerAfterComputation)(node, prevConsumer);
|
|
79
55
|
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
56
|
+
};
|
|
57
|
+
node.ref = {
|
|
58
|
+
notify: () => (0, import_graph.consumerMarkDirty)(node),
|
|
59
|
+
run,
|
|
60
|
+
cleanup: () => node.cleanupFn()
|
|
61
|
+
};
|
|
62
|
+
return node.ref;
|
|
84
63
|
}
|
|
64
|
+
const NOOP_CLEANUP_FN = () => {
|
|
65
|
+
};
|
|
66
|
+
const WATCH_NODE = {
|
|
67
|
+
...import_graph.REACTIVE_NODE,
|
|
68
|
+
consumerIsAlwaysLive: true,
|
|
69
|
+
consumerAllowSignalWrites: false,
|
|
70
|
+
consumerMarkedDirty: (node) => {
|
|
71
|
+
node.schedule(node.ref);
|
|
72
|
+
},
|
|
73
|
+
hasRun: false,
|
|
74
|
+
cleanupFn: NOOP_CLEANUP_FN
|
|
75
|
+
};
|
|
@@ -30,7 +30,6 @@ __export(dynamic_text_model_exports, {
|
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(dynamic_text_model_exports);
|
|
32
32
|
var import_rxjs = require("rxjs");
|
|
33
|
-
var import_core = require("../core.js");
|
|
34
33
|
var import_inject = require("../injector/inject.js");
|
|
35
34
|
var import_api = require("../signals/api.js");
|
|
36
35
|
var import_switch_map = require("../signals/switch-map.js");
|
|
@@ -38,12 +37,11 @@ var import_untracked_operator = require("../signals/untracked-operator.js");
|
|
|
38
37
|
var import_type_guards = require("../utils/type-guards.js");
|
|
39
38
|
var import_localization_service = require("./localization.service.js");
|
|
40
39
|
const missingLocalizationKeyText = "[MISSING LOCALIZATION KEY]";
|
|
41
|
-
function resolveDynamicText(text, localizationService) {
|
|
42
|
-
const resolvedLocalizationService = localizationService ?? ((0, import_inject.isInInjectionContext)() ? (0, import_inject.inject)(import_localization_service.LocalizationService) : (0, import_core.getGlobalInjector)().resolve(import_localization_service.LocalizationService));
|
|
40
|
+
function resolveDynamicText(text, localizationService = (0, import_inject.inject)(import_localization_service.LocalizationService)) {
|
|
43
41
|
const localizableTextSignal = (0, import_api.isSignal)(text) ? text : (0, import_rxjs.isObservable)(text) ? (0, import_api.toSignal)(text.pipe((0, import_untracked_operator.runInUntracked)()), { initialValue: missingLocalizationKeyText }) : (0, import_api.computed)(() => text);
|
|
44
42
|
return (0, import_switch_map.switchMap)(() => {
|
|
45
43
|
const localizableText = localizableTextSignal();
|
|
46
|
-
return (0, import_type_guards.isString)(localizableText) ? (0, import_api.computed)(() => localizableText) :
|
|
44
|
+
return (0, import_type_guards.isString)(localizableText) ? (0, import_api.computed)(() => localizableText) : localizationService.localize(localizableText);
|
|
47
45
|
});
|
|
48
46
|
}
|
|
49
47
|
function resolveDynamicText$(text, localizationService) {
|