@angular/core 21.0.0-next.9 → 21.0.0-rc.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/fesm2022/_attribute-chunk.mjs +2 -14
- package/fesm2022/_attribute-chunk.mjs.map +1 -1
- package/fesm2022/_debug_node-chunk.mjs +15265 -28386
- package/fesm2022/_debug_node-chunk.mjs.map +1 -1
- package/fesm2022/_effect-chunk.mjs +322 -504
- package/fesm2022/_effect-chunk.mjs.map +1 -1
- package/fesm2022/_effect-chunk2.mjs +2200 -4068
- package/fesm2022/_effect-chunk2.mjs.map +1 -1
- package/fesm2022/_not_found-chunk.mjs +18 -35
- package/fesm2022/_not_found-chunk.mjs.map +1 -1
- package/fesm2022/_resource-chunk.mjs +312 -391
- package/fesm2022/_resource-chunk.mjs.map +1 -1
- package/fesm2022/_untracked-chunk.mjs +75 -96
- package/fesm2022/_untracked-chunk.mjs.map +1 -1
- package/fesm2022/_weak_ref-chunk.mjs +2 -4
- package/fesm2022/_weak_ref-chunk.mjs.map +1 -1
- package/fesm2022/core.mjs +2463 -4307
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives-di.mjs +9 -9
- package/fesm2022/primitives-di.mjs.map +1 -1
- package/fesm2022/primitives-event-dispatch.mjs +626 -1460
- package/fesm2022/primitives-event-dispatch.mjs.map +1 -1
- package/fesm2022/primitives-signals.mjs +154 -188
- package/fesm2022/primitives-signals.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +204 -304
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +2303 -3162
- package/fesm2022/testing.mjs.map +1 -1
- package/package.json +8 -2
- package/resources/best-practices.md +56 -0
- package/schematics/bundles/add-bootstrap-context-to-server-main.cjs +7 -25
- package/schematics/bundles/application-config-core.cjs +8 -19
- package/schematics/bundles/{apply_import_manager-CoeTX_Ob.cjs → apply_import_manager-1Zs_gpB6.cjs} +4 -5
- package/schematics/bundles/bootstrap-options-migration.cjs +93 -132
- package/schematics/bundles/cleanup-unused-imports.cjs +9 -13
- package/schematics/bundles/common-to-standalone-migration.cjs +12 -16
- package/schematics/bundles/{compiler_host-emLDwK2U.cjs → compiler_host-DBwYMlTo.cjs} +10 -11
- package/schematics/bundles/control-flow-migration.cjs +29 -31
- package/schematics/bundles/{imports-DwPXlGFl.cjs → imports-DP72APSx.cjs} +1 -23
- package/schematics/bundles/{index-CLxYZ09c.cjs → index-B7I9sIUx.cjs} +36 -37
- package/schematics/bundles/inject-migration.cjs +9 -26
- package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
- package/schematics/bundles/{migrate_ts_type_references-CpM5FPGa.cjs → migrate_ts_type_references-UGIUl7En.cjs} +458 -24
- package/schematics/bundles/{ng_component_template-BRbBIAUX.cjs → ng_component_template-Dsuq1Lw7.cjs} +4 -5
- package/schematics/bundles/{ng_decorators-BI0uV7KI.cjs → ng_decorators-DSFlWYQY.cjs} +2 -2
- package/schematics/bundles/ngclass-to-class-migration.cjs +16 -19
- package/schematics/bundles/ngstyle-to-style-migration.cjs +15 -18
- package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
- package/schematics/bundles/output-migration.cjs +16 -19
- package/schematics/bundles/{parse_html-CPWfkfhR.cjs → parse_html-8VLCL37B.cjs} +5 -5
- package/schematics/bundles/{project_paths-C8H7KDJ3.cjs → project_paths-DvD50ouC.cjs} +14 -247
- package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs +90 -0
- package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
- package/schematics/bundles/route-lazy-loading.cjs +9 -25
- package/schematics/bundles/router-current-navigation.cjs +6 -17
- package/schematics/bundles/router-last-successful-navigation.cjs +6 -17
- package/schematics/bundles/router-testing-module-migration.cjs +7 -18
- package/schematics/bundles/self-closing-tags-migration.cjs +14 -17
- package/schematics/bundles/signal-input-migration.cjs +23 -26
- package/schematics/bundles/signal-queries-migration.cjs +22 -25
- package/schematics/bundles/signals.cjs +10 -13
- package/schematics/bundles/standalone-migration.cjs +22 -56
- package/schematics/bundles/symbol-BObKoqes.cjs +1 -1
- package/types/_api-chunk.d.ts +1 -1
- package/types/_chrome_dev_tools_performance-chunk.d.ts +34 -28
- package/types/_discovery-chunk.d.ts +26 -15
- package/types/_effect-chunk.d.ts +1 -1
- package/types/_event_dispatcher-chunk.d.ts +1 -1
- package/types/_formatter-chunk.d.ts +1 -1
- package/types/_weak_ref-chunk.d.ts +1 -1
- package/types/core.d.ts +18 -88
- package/types/primitives-di.d.ts +1 -1
- package/types/primitives-event-dispatch.d.ts +1 -1
- package/types/primitives-signals.d.ts +1 -1
- package/types/rxjs-interop.d.ts +1 -1
- package/types/testing.d.ts +1 -1
- package/schematics/bundles/index-Dvqnp6JS.cjs +0 -22419
- package/schematics/bundles/project_tsconfig_paths-CiBzGSIa.cjs +0 -51591
|
@@ -1,604 +1,422 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v21.0.0-
|
|
2
|
+
* @license Angular v21.0.0-rc.1
|
|
3
3
|
* (c) 2010-2025 Google LLC. https://angular.dev/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* The currently active consumer `ReactiveNode`, if running code in a reactive context.
|
|
9
|
-
*
|
|
10
|
-
* Change this via `setActiveConsumer`.
|
|
11
|
-
*/
|
|
12
7
|
let activeConsumer = null;
|
|
13
8
|
let inNotificationPhase = false;
|
|
14
|
-
/**
|
|
15
|
-
* Global epoch counter. Incremented whenever a source signal is set.
|
|
16
|
-
*/
|
|
17
9
|
let epoch = 1;
|
|
18
|
-
/**
|
|
19
|
-
* If set, called after a producer `ReactiveNode` is created.
|
|
20
|
-
*/
|
|
21
10
|
let postProducerCreatedFn = null;
|
|
22
|
-
|
|
23
|
-
* Symbol used to tell `Signal`s apart from other functions.
|
|
24
|
-
*
|
|
25
|
-
* This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values.
|
|
26
|
-
*/
|
|
27
|
-
const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL');
|
|
11
|
+
const SIGNAL = /* @__PURE__ */Symbol('SIGNAL');
|
|
28
12
|
function setActiveConsumer(consumer) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
13
|
+
const prev = activeConsumer;
|
|
14
|
+
activeConsumer = consumer;
|
|
15
|
+
return prev;
|
|
32
16
|
}
|
|
33
17
|
function getActiveConsumer() {
|
|
34
|
-
|
|
18
|
+
return activeConsumer;
|
|
35
19
|
}
|
|
36
20
|
function isInNotificationPhase() {
|
|
37
|
-
|
|
21
|
+
return inNotificationPhase;
|
|
38
22
|
}
|
|
39
23
|
function isReactive(value) {
|
|
40
|
-
|
|
24
|
+
return value[SIGNAL] !== undefined;
|
|
41
25
|
}
|
|
42
26
|
const REACTIVE_NODE = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
27
|
+
version: 0,
|
|
28
|
+
lastCleanEpoch: 0,
|
|
29
|
+
dirty: false,
|
|
30
|
+
producers: undefined,
|
|
31
|
+
producersTail: undefined,
|
|
32
|
+
consumers: undefined,
|
|
33
|
+
consumersTail: undefined,
|
|
34
|
+
recomputing: false,
|
|
35
|
+
consumerAllowSignalWrites: false,
|
|
36
|
+
consumerIsAlwaysLive: false,
|
|
37
|
+
kind: 'unknown',
|
|
38
|
+
producerMustRecompute: () => false,
|
|
39
|
+
producerRecomputeValue: () => {},
|
|
40
|
+
consumerMarkedDirty: () => {},
|
|
41
|
+
consumerOnSignalRead: () => {}
|
|
58
42
|
};
|
|
59
|
-
/**
|
|
60
|
-
* Called by implementations when a producer's signal is read.
|
|
61
|
-
*/
|
|
62
43
|
function producerAccessed(node) {
|
|
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
|
-
// If we got here, it means that we need to create a new link between the producer and the consumer.
|
|
107
|
-
const isLive = consumerIsLive(activeConsumer);
|
|
108
|
-
const newLink = {
|
|
109
|
-
producer: node,
|
|
110
|
-
consumer: activeConsumer,
|
|
111
|
-
// instead of eagerly destroying the previous link, we delay until we've finished recomputing
|
|
112
|
-
// the producers list, so that we can destroy all of the old links at once.
|
|
113
|
-
nextProducer: nextProducerLink,
|
|
114
|
-
prevConsumer: prevConsumerLink,
|
|
115
|
-
lastReadVersion: node.version,
|
|
116
|
-
nextConsumer: undefined,
|
|
117
|
-
};
|
|
118
|
-
activeConsumer.producersTail = newLink;
|
|
119
|
-
if (prevProducerLink !== undefined) {
|
|
120
|
-
prevProducerLink.nextProducer = newLink;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
activeConsumer.producers = newLink;
|
|
124
|
-
}
|
|
125
|
-
if (isLive) {
|
|
126
|
-
producerAddLiveConsumer(node, newLink);
|
|
127
|
-
}
|
|
44
|
+
if (inNotificationPhase) {
|
|
45
|
+
throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? `Assertion error: signal read during notification phase` : '');
|
|
46
|
+
}
|
|
47
|
+
if (activeConsumer === null) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
activeConsumer.consumerOnSignalRead(node);
|
|
51
|
+
const prevProducerLink = activeConsumer.producersTail;
|
|
52
|
+
if (prevProducerLink !== undefined && prevProducerLink.producer === node) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
let nextProducerLink = undefined;
|
|
56
|
+
const isRecomputing = activeConsumer.recomputing;
|
|
57
|
+
if (isRecomputing) {
|
|
58
|
+
nextProducerLink = prevProducerLink !== undefined ? prevProducerLink.nextProducer : activeConsumer.producers;
|
|
59
|
+
if (nextProducerLink !== undefined && nextProducerLink.producer === node) {
|
|
60
|
+
activeConsumer.producersTail = nextProducerLink;
|
|
61
|
+
nextProducerLink.lastReadVersion = node.version;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const prevConsumerLink = node.consumersTail;
|
|
66
|
+
if (prevConsumerLink !== undefined && prevConsumerLink.consumer === activeConsumer && (!isRecomputing || isValidLink(prevConsumerLink, activeConsumer))) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const isLive = consumerIsLive(activeConsumer);
|
|
70
|
+
const newLink = {
|
|
71
|
+
producer: node,
|
|
72
|
+
consumer: activeConsumer,
|
|
73
|
+
nextProducer: nextProducerLink,
|
|
74
|
+
prevConsumer: prevConsumerLink,
|
|
75
|
+
lastReadVersion: node.version,
|
|
76
|
+
nextConsumer: undefined
|
|
77
|
+
};
|
|
78
|
+
activeConsumer.producersTail = newLink;
|
|
79
|
+
if (prevProducerLink !== undefined) {
|
|
80
|
+
prevProducerLink.nextProducer = newLink;
|
|
81
|
+
} else {
|
|
82
|
+
activeConsumer.producers = newLink;
|
|
83
|
+
}
|
|
84
|
+
if (isLive) {
|
|
85
|
+
producerAddLiveConsumer(node, newLink);
|
|
86
|
+
}
|
|
128
87
|
}
|
|
129
|
-
/**
|
|
130
|
-
* Increment the global epoch counter.
|
|
131
|
-
*
|
|
132
|
-
* Called by source producers (that is, not computeds) whenever their values change.
|
|
133
|
-
*/
|
|
134
88
|
function producerIncrementEpoch() {
|
|
135
|
-
|
|
89
|
+
epoch++;
|
|
136
90
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Ensure this producer's `version` is up-to-date.
|
|
139
|
-
*/
|
|
140
91
|
function producerUpdateValueVersion(node) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// the current epoch, since their dependencies could not possibly have changed (such a change
|
|
149
|
-
// would've increased the epoch).
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
|
|
153
|
-
// None of our producers report a change since the last time they were read, so no
|
|
154
|
-
// recomputation of our value is necessary, and we can consider ourselves clean.
|
|
155
|
-
producerMarkClean(node);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
node.producerRecomputeValue(node);
|
|
159
|
-
// After recomputing the value, we're no longer dirty.
|
|
92
|
+
if (consumerIsLive(node) && !node.dirty) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!node.dirty && node.lastCleanEpoch === epoch) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
|
|
160
99
|
producerMarkClean(node);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
node.producerRecomputeValue(node);
|
|
103
|
+
producerMarkClean(node);
|
|
161
104
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Propagate a dirty notification to live consumers of this producer.
|
|
164
|
-
*/
|
|
165
105
|
function producerNotifyConsumers(node) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
inNotificationPhase = prev;
|
|
182
|
-
}
|
|
106
|
+
if (node.consumers === undefined) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const prev = inNotificationPhase;
|
|
110
|
+
inNotificationPhase = true;
|
|
111
|
+
try {
|
|
112
|
+
for (let link = node.consumers; link !== undefined; link = link.nextConsumer) {
|
|
113
|
+
const consumer = link.consumer;
|
|
114
|
+
if (!consumer.dirty) {
|
|
115
|
+
consumerMarkDirty(consumer);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} finally {
|
|
119
|
+
inNotificationPhase = prev;
|
|
120
|
+
}
|
|
183
121
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
|
|
186
|
-
* based on the current consumer context.
|
|
187
|
-
*/
|
|
188
122
|
function producerUpdatesAllowed() {
|
|
189
|
-
|
|
123
|
+
return activeConsumer?.consumerAllowSignalWrites !== false;
|
|
190
124
|
}
|
|
191
125
|
function consumerMarkDirty(node) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
126
|
+
node.dirty = true;
|
|
127
|
+
producerNotifyConsumers(node);
|
|
128
|
+
node.consumerMarkedDirty?.(node);
|
|
195
129
|
}
|
|
196
130
|
function producerMarkClean(node) {
|
|
197
|
-
|
|
198
|
-
|
|
131
|
+
node.dirty = false;
|
|
132
|
+
node.lastCleanEpoch = epoch;
|
|
199
133
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Prepare this consumer to run a computation in its reactive context and set
|
|
202
|
-
* it as the active consumer.
|
|
203
|
-
*
|
|
204
|
-
* Must be called by subclasses which represent reactive computations, before those computations
|
|
205
|
-
* begin.
|
|
206
|
-
*/
|
|
207
134
|
function consumerBeforeComputation(node) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return setActiveConsumer(node);
|
|
135
|
+
if (node) resetConsumerBeforeComputation(node);
|
|
136
|
+
return setActiveConsumer(node);
|
|
211
137
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Prepare this consumer to run a computation in its reactive context.
|
|
214
|
-
*
|
|
215
|
-
* We expose this mainly for code where we manually batch effects into a single
|
|
216
|
-
* consumer. In those cases we may wish to "reopen" a consumer multiple times
|
|
217
|
-
* in initial render before finalizing it. Most code should just call
|
|
218
|
-
* `consumerBeforeComputation` instead of calling this directly.
|
|
219
|
-
*/
|
|
220
138
|
function resetConsumerBeforeComputation(node) {
|
|
221
|
-
|
|
222
|
-
|
|
139
|
+
node.producersTail = undefined;
|
|
140
|
+
node.recomputing = true;
|
|
223
141
|
}
|
|
224
|
-
/**
|
|
225
|
-
* Finalize this consumer's state and set previous consumer as the active consumer after a
|
|
226
|
-
* reactive computation has run.
|
|
227
|
-
*
|
|
228
|
-
* Must be called by subclasses which represent reactive computations, after those computations
|
|
229
|
-
* have finished.
|
|
230
|
-
*/
|
|
231
142
|
function consumerAfterComputation(node, prevConsumer) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
finalizeConsumerAfterComputation(node);
|
|
143
|
+
setActiveConsumer(prevConsumer);
|
|
144
|
+
if (node) finalizeConsumerAfterComputation(node);
|
|
235
145
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Finalize this consumer's state after a reactive computation has run.
|
|
238
|
-
*
|
|
239
|
-
* We expose this mainly for code where we manually batch effects into a single
|
|
240
|
-
* consumer. In those cases we may wish to "reopen" a consumer multiple times
|
|
241
|
-
* in initial render before finalizing it. Most code should just call
|
|
242
|
-
* `consumerAfterComputation` instead of calling this directly.
|
|
243
|
-
*/
|
|
244
146
|
function finalizeConsumerAfterComputation(node) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
do {
|
|
254
|
-
toRemove = producerRemoveLiveConsumerLink(toRemove);
|
|
255
|
-
} while (toRemove !== undefined);
|
|
256
|
-
}
|
|
257
|
-
// Now, we can truncate the producers list to remove all stale links.
|
|
258
|
-
if (producersTail !== undefined) {
|
|
259
|
-
producersTail.nextProducer = undefined;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
node.producers = undefined;
|
|
263
|
-
}
|
|
147
|
+
node.recomputing = false;
|
|
148
|
+
const producersTail = node.producersTail;
|
|
149
|
+
let toRemove = producersTail !== undefined ? producersTail.nextProducer : node.producers;
|
|
150
|
+
if (toRemove !== undefined) {
|
|
151
|
+
if (consumerIsLive(node)) {
|
|
152
|
+
do {
|
|
153
|
+
toRemove = producerRemoveLiveConsumerLink(toRemove);
|
|
154
|
+
} while (toRemove !== undefined);
|
|
264
155
|
}
|
|
156
|
+
if (producersTail !== undefined) {
|
|
157
|
+
producersTail.nextProducer = undefined;
|
|
158
|
+
} else {
|
|
159
|
+
node.producers = undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
265
162
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Determine whether this consumer has any dependencies which have changed since the last time
|
|
268
|
-
* they were read.
|
|
269
|
-
*/
|
|
270
163
|
function consumerPollProducersForChange(node) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
// changed since the last time we read it.
|
|
277
|
-
if (seenVersion !== producer.version) {
|
|
278
|
-
return true;
|
|
279
|
-
}
|
|
280
|
-
// The producer's version is the same as the last time we read it, but it might itself be
|
|
281
|
-
// stale. Force the producer to recompute its version (calculating a new value if necessary).
|
|
282
|
-
producerUpdateValueVersion(producer);
|
|
283
|
-
// Now when we do this check, `producer.version` is guaranteed to be up to date, so if the
|
|
284
|
-
// versions still match then it has not changed since the last time we read it.
|
|
285
|
-
if (seenVersion !== producer.version) {
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
164
|
+
for (let link = node.producers; link !== undefined; link = link.nextProducer) {
|
|
165
|
+
const producer = link.producer;
|
|
166
|
+
const seenVersion = link.lastReadVersion;
|
|
167
|
+
if (seenVersion !== producer.version) {
|
|
168
|
+
return true;
|
|
288
169
|
}
|
|
289
|
-
|
|
170
|
+
producerUpdateValueVersion(producer);
|
|
171
|
+
if (seenVersion !== producer.version) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
290
176
|
}
|
|
291
|
-
/**
|
|
292
|
-
* Disconnect this consumer from the graph.
|
|
293
|
-
*/
|
|
294
177
|
function consumerDestroy(node) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
link = producerRemoveLiveConsumerLink(link);
|
|
300
|
-
}
|
|
178
|
+
if (consumerIsLive(node)) {
|
|
179
|
+
let link = node.producers;
|
|
180
|
+
while (link !== undefined) {
|
|
181
|
+
link = producerRemoveLiveConsumerLink(link);
|
|
301
182
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
183
|
+
}
|
|
184
|
+
node.producers = undefined;
|
|
185
|
+
node.producersTail = undefined;
|
|
186
|
+
node.consumers = undefined;
|
|
187
|
+
node.consumersTail = undefined;
|
|
307
188
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Add `consumer` as a live consumer of this node.
|
|
310
|
-
*
|
|
311
|
-
* Note that this operation is potentially transitive. If this node becomes live, then it becomes
|
|
312
|
-
* a live consumer of all of its current producers.
|
|
313
|
-
*/
|
|
314
189
|
function producerAddLiveConsumer(node, link) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
producerAddLiveConsumer(link.producer, link);
|
|
330
|
-
}
|
|
190
|
+
const consumersTail = node.consumersTail;
|
|
191
|
+
const wasLive = consumerIsLive(node);
|
|
192
|
+
if (consumersTail !== undefined) {
|
|
193
|
+
link.nextConsumer = consumersTail.nextConsumer;
|
|
194
|
+
consumersTail.nextConsumer = link;
|
|
195
|
+
} else {
|
|
196
|
+
link.nextConsumer = undefined;
|
|
197
|
+
node.consumers = link;
|
|
198
|
+
}
|
|
199
|
+
link.prevConsumer = consumersTail;
|
|
200
|
+
node.consumersTail = link;
|
|
201
|
+
if (!wasLive) {
|
|
202
|
+
for (let link = node.producers; link !== undefined; link = link.nextProducer) {
|
|
203
|
+
producerAddLiveConsumer(link.producer, link);
|
|
331
204
|
}
|
|
205
|
+
}
|
|
332
206
|
}
|
|
333
207
|
function producerRemoveLiveConsumerLink(link) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
return nextProducer;
|
|
208
|
+
const producer = link.producer;
|
|
209
|
+
const nextProducer = link.nextProducer;
|
|
210
|
+
const nextConsumer = link.nextConsumer;
|
|
211
|
+
const prevConsumer = link.prevConsumer;
|
|
212
|
+
link.nextConsumer = undefined;
|
|
213
|
+
link.prevConsumer = undefined;
|
|
214
|
+
if (nextConsumer !== undefined) {
|
|
215
|
+
nextConsumer.prevConsumer = prevConsumer;
|
|
216
|
+
} else {
|
|
217
|
+
producer.consumersTail = prevConsumer;
|
|
218
|
+
}
|
|
219
|
+
if (prevConsumer !== undefined) {
|
|
220
|
+
prevConsumer.nextConsumer = nextConsumer;
|
|
221
|
+
} else {
|
|
222
|
+
producer.consumers = nextConsumer;
|
|
223
|
+
if (!consumerIsLive(producer)) {
|
|
224
|
+
let producerLink = producer.producers;
|
|
225
|
+
while (producerLink !== undefined) {
|
|
226
|
+
producerLink = producerRemoveLiveConsumerLink(producerLink);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return nextProducer;
|
|
359
231
|
}
|
|
360
232
|
function consumerIsLive(node) {
|
|
361
|
-
|
|
233
|
+
return node.consumerIsAlwaysLive || node.consumers !== undefined;
|
|
362
234
|
}
|
|
363
235
|
function runPostProducerCreatedFn(node) {
|
|
364
|
-
|
|
236
|
+
postProducerCreatedFn?.(node);
|
|
365
237
|
}
|
|
366
238
|
function setPostProducerCreatedFn(fn) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
239
|
+
const prev = postProducerCreatedFn;
|
|
240
|
+
postProducerCreatedFn = fn;
|
|
241
|
+
return prev;
|
|
370
242
|
}
|
|
371
|
-
// While a ReactiveNode is recomputing, it may not have destroyed previous links
|
|
372
|
-
// This allows us to check if a given link will be destroyed by a reactivenode if it were to finish running immediately without accesing any more producers
|
|
373
243
|
function isValidLink(checkLink, consumer) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
244
|
+
const producersTail = consumer.producersTail;
|
|
245
|
+
if (producersTail !== undefined) {
|
|
246
|
+
let link = consumer.producers;
|
|
247
|
+
do {
|
|
248
|
+
if (link === checkLink) {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
if (link === producersTail) {
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
link = link.nextProducer;
|
|
255
|
+
} while (link !== undefined);
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
388
258
|
}
|
|
389
259
|
|
|
390
|
-
/**
|
|
391
|
-
* The default equality function used for `signal` and `computed`, which uses referential equality.
|
|
392
|
-
*/
|
|
393
260
|
function defaultEquals(a, b) {
|
|
394
|
-
|
|
261
|
+
return Object.is(a, b);
|
|
395
262
|
}
|
|
396
263
|
|
|
397
|
-
/**
|
|
398
|
-
* Create a computed signal which derives a reactive value from an expression.
|
|
399
|
-
*/
|
|
400
264
|
function createComputed(computation, equal) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
265
|
+
const node = Object.create(COMPUTED_NODE);
|
|
266
|
+
node.computation = computation;
|
|
267
|
+
if (equal !== undefined) {
|
|
268
|
+
node.equal = equal;
|
|
269
|
+
}
|
|
270
|
+
const computed = () => {
|
|
271
|
+
producerUpdateValueVersion(node);
|
|
272
|
+
producerAccessed(node);
|
|
273
|
+
if (node.value === ERRORED) {
|
|
274
|
+
throw node.error;
|
|
405
275
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
276
|
+
return node.value;
|
|
277
|
+
};
|
|
278
|
+
computed[SIGNAL] = node;
|
|
279
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
280
|
+
const debugName = node.debugName ? ' (' + node.debugName + ')' : '';
|
|
281
|
+
computed.toString = () => `[Computed${debugName}: ${node.value}]`;
|
|
282
|
+
}
|
|
283
|
+
runPostProducerCreatedFn(node);
|
|
284
|
+
return computed;
|
|
285
|
+
}
|
|
286
|
+
const UNSET = /* @__PURE__ */Symbol('UNSET');
|
|
287
|
+
const COMPUTING = /* @__PURE__ */Symbol('COMPUTING');
|
|
288
|
+
const ERRORED = /* @__PURE__ */Symbol('ERRORED');
|
|
289
|
+
const COMPUTED_NODE = /* @__PURE__ */(() => {
|
|
290
|
+
return {
|
|
291
|
+
...REACTIVE_NODE,
|
|
292
|
+
value: UNSET,
|
|
293
|
+
dirty: true,
|
|
294
|
+
error: null,
|
|
295
|
+
equal: defaultEquals,
|
|
296
|
+
kind: 'computed',
|
|
297
|
+
producerMustRecompute(node) {
|
|
298
|
+
return node.value === UNSET || node.value === COMPUTING;
|
|
299
|
+
},
|
|
300
|
+
producerRecomputeValue(node) {
|
|
301
|
+
if (node.value === COMPUTING) {
|
|
302
|
+
throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : '');
|
|
303
|
+
}
|
|
304
|
+
const oldValue = node.value;
|
|
305
|
+
node.value = COMPUTING;
|
|
306
|
+
const prevConsumer = consumerBeforeComputation(node);
|
|
307
|
+
let newValue;
|
|
308
|
+
let wasEqual = false;
|
|
309
|
+
try {
|
|
310
|
+
newValue = node.computation();
|
|
311
|
+
setActiveConsumer(null);
|
|
312
|
+
wasEqual = oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED && node.equal(oldValue, newValue);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
newValue = ERRORED;
|
|
315
|
+
node.error = err;
|
|
316
|
+
} finally {
|
|
317
|
+
consumerAfterComputation(node, prevConsumer);
|
|
318
|
+
}
|
|
319
|
+
if (wasEqual) {
|
|
320
|
+
node.value = oldValue;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
node.value = newValue;
|
|
324
|
+
node.version++;
|
|
420
325
|
}
|
|
421
|
-
|
|
422
|
-
return computed;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* A dedicated symbol used before a computed value has been calculated for the first time.
|
|
426
|
-
* Explicitly typed as `any` so we can use it as signal's value.
|
|
427
|
-
*/
|
|
428
|
-
const UNSET = /* @__PURE__ */ Symbol('UNSET');
|
|
429
|
-
/**
|
|
430
|
-
* A dedicated symbol used in place of a computed signal value to indicate that a given computation
|
|
431
|
-
* is in progress. Used to detect cycles in computation chains.
|
|
432
|
-
* Explicitly typed as `any` so we can use it as signal's value.
|
|
433
|
-
*/
|
|
434
|
-
const COMPUTING = /* @__PURE__ */ Symbol('COMPUTING');
|
|
435
|
-
/**
|
|
436
|
-
* A dedicated symbol used in place of a computed signal value to indicate that a given computation
|
|
437
|
-
* failed. The thrown error is cached until the computation gets dirty again.
|
|
438
|
-
* Explicitly typed as `any` so we can use it as signal's value.
|
|
439
|
-
*/
|
|
440
|
-
const ERRORED = /* @__PURE__ */ Symbol('ERRORED');
|
|
441
|
-
// Note: Using an IIFE here to ensure that the spread assignment is not considered
|
|
442
|
-
// a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
|
|
443
|
-
// TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
|
|
444
|
-
const COMPUTED_NODE = /* @__PURE__ */ (() => {
|
|
445
|
-
return {
|
|
446
|
-
...REACTIVE_NODE,
|
|
447
|
-
value: UNSET,
|
|
448
|
-
dirty: true,
|
|
449
|
-
error: null,
|
|
450
|
-
equal: defaultEquals,
|
|
451
|
-
kind: 'computed',
|
|
452
|
-
producerMustRecompute(node) {
|
|
453
|
-
// Force a recomputation if there's no current value, or if the current value is in the
|
|
454
|
-
// process of being calculated (which should throw an error).
|
|
455
|
-
return node.value === UNSET || node.value === COMPUTING;
|
|
456
|
-
},
|
|
457
|
-
producerRecomputeValue(node) {
|
|
458
|
-
if (node.value === COMPUTING) {
|
|
459
|
-
// Our computation somehow led to a cyclic read of itself.
|
|
460
|
-
throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : '');
|
|
461
|
-
}
|
|
462
|
-
const oldValue = node.value;
|
|
463
|
-
node.value = COMPUTING;
|
|
464
|
-
const prevConsumer = consumerBeforeComputation(node);
|
|
465
|
-
let newValue;
|
|
466
|
-
let wasEqual = false;
|
|
467
|
-
try {
|
|
468
|
-
newValue = node.computation();
|
|
469
|
-
// We want to mark this node as errored if calling `equal` throws; however, we don't want
|
|
470
|
-
// to track any reactive reads inside `equal`.
|
|
471
|
-
setActiveConsumer(null);
|
|
472
|
-
wasEqual =
|
|
473
|
-
oldValue !== UNSET &&
|
|
474
|
-
oldValue !== ERRORED &&
|
|
475
|
-
newValue !== ERRORED &&
|
|
476
|
-
node.equal(oldValue, newValue);
|
|
477
|
-
}
|
|
478
|
-
catch (err) {
|
|
479
|
-
newValue = ERRORED;
|
|
480
|
-
node.error = err;
|
|
481
|
-
}
|
|
482
|
-
finally {
|
|
483
|
-
consumerAfterComputation(node, prevConsumer);
|
|
484
|
-
}
|
|
485
|
-
if (wasEqual) {
|
|
486
|
-
// No change to `valueVersion` - old and new values are
|
|
487
|
-
// semantically equivalent.
|
|
488
|
-
node.value = oldValue;
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
node.value = newValue;
|
|
492
|
-
node.version++;
|
|
493
|
-
},
|
|
494
|
-
};
|
|
326
|
+
};
|
|
495
327
|
})();
|
|
496
328
|
|
|
497
329
|
function defaultThrowError() {
|
|
498
|
-
|
|
330
|
+
throw new Error();
|
|
499
331
|
}
|
|
500
332
|
let throwInvalidWriteToSignalErrorFn = defaultThrowError;
|
|
501
333
|
function throwInvalidWriteToSignalError(node) {
|
|
502
|
-
|
|
334
|
+
throwInvalidWriteToSignalErrorFn(node);
|
|
503
335
|
}
|
|
504
336
|
function setThrowInvalidWriteToSignalError(fn) {
|
|
505
|
-
|
|
337
|
+
throwInvalidWriteToSignalErrorFn = fn;
|
|
506
338
|
}
|
|
507
339
|
|
|
508
|
-
/**
|
|
509
|
-
* If set, called after `WritableSignal`s are updated.
|
|
510
|
-
*
|
|
511
|
-
* This hook can be used to achieve various effects, such as running effects synchronously as part
|
|
512
|
-
* of setting a signal.
|
|
513
|
-
*/
|
|
514
340
|
let postSignalSetFn = null;
|
|
515
|
-
/**
|
|
516
|
-
* Creates a `Signal` getter, setter, and updater function.
|
|
517
|
-
*/
|
|
518
341
|
function createSignal(initialValue, equal) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
342
|
+
const node = Object.create(SIGNAL_NODE);
|
|
343
|
+
node.value = initialValue;
|
|
344
|
+
if (equal !== undefined) {
|
|
345
|
+
node.equal = equal;
|
|
346
|
+
}
|
|
347
|
+
const getter = () => signalGetFn(node);
|
|
348
|
+
getter[SIGNAL] = node;
|
|
349
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
350
|
+
const debugName = node.debugName ? ' (' + node.debugName + ')' : '';
|
|
351
|
+
getter.toString = () => `[Signal${debugName}: ${node.value}]`;
|
|
352
|
+
}
|
|
353
|
+
runPostProducerCreatedFn(node);
|
|
354
|
+
const set = newValue => signalSetFn(node, newValue);
|
|
355
|
+
const update = updateFn => signalUpdateFn(node, updateFn);
|
|
356
|
+
return [getter, set, update];
|
|
534
357
|
}
|
|
535
358
|
function setPostSignalSetFn(fn) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
359
|
+
const prev = postSignalSetFn;
|
|
360
|
+
postSignalSetFn = fn;
|
|
361
|
+
return prev;
|
|
539
362
|
}
|
|
540
363
|
function signalGetFn(node) {
|
|
541
|
-
|
|
542
|
-
|
|
364
|
+
producerAccessed(node);
|
|
365
|
+
return node.value;
|
|
543
366
|
}
|
|
544
367
|
function signalSetFn(node, newValue) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
368
|
+
if (!producerUpdatesAllowed()) {
|
|
369
|
+
throwInvalidWriteToSignalError(node);
|
|
370
|
+
}
|
|
371
|
+
if (!node.equal(node.value, newValue)) {
|
|
372
|
+
node.value = newValue;
|
|
373
|
+
signalValueChanged(node);
|
|
374
|
+
}
|
|
552
375
|
}
|
|
553
376
|
function signalUpdateFn(node, updater) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
377
|
+
if (!producerUpdatesAllowed()) {
|
|
378
|
+
throwInvalidWriteToSignalError(node);
|
|
379
|
+
}
|
|
380
|
+
signalSetFn(node, updater(node.value));
|
|
558
381
|
}
|
|
559
382
|
function runPostSignalSetFn(node) {
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
value: undefined,
|
|
570
|
-
kind: 'signal',
|
|
571
|
-
};
|
|
383
|
+
postSignalSetFn?.(node);
|
|
384
|
+
}
|
|
385
|
+
const SIGNAL_NODE = /* @__PURE__ */(() => {
|
|
386
|
+
return {
|
|
387
|
+
...REACTIVE_NODE,
|
|
388
|
+
equal: defaultEquals,
|
|
389
|
+
value: undefined,
|
|
390
|
+
kind: 'signal'
|
|
391
|
+
};
|
|
572
392
|
})();
|
|
573
393
|
function signalValueChanged(node) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
394
|
+
node.version++;
|
|
395
|
+
producerIncrementEpoch();
|
|
396
|
+
producerNotifyConsumers(node);
|
|
397
|
+
postSignalSetFn?.(node);
|
|
578
398
|
}
|
|
579
399
|
|
|
580
|
-
const BASE_EFFECT_NODE =
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
kind: 'effect',
|
|
400
|
+
const BASE_EFFECT_NODE = /* @__PURE__ */(() => ({
|
|
401
|
+
...REACTIVE_NODE,
|
|
402
|
+
consumerIsAlwaysLive: true,
|
|
403
|
+
consumerAllowSignalWrites: true,
|
|
404
|
+
dirty: true,
|
|
405
|
+
kind: 'effect'
|
|
587
406
|
}))();
|
|
588
407
|
function runEffect(node) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
}
|
|
408
|
+
node.dirty = false;
|
|
409
|
+
if (node.version > 0 && !consumerPollProducersForChange(node)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
node.version++;
|
|
413
|
+
const prevNode = consumerBeforeComputation(node);
|
|
414
|
+
try {
|
|
415
|
+
node.cleanup();
|
|
416
|
+
node.fn();
|
|
417
|
+
} finally {
|
|
418
|
+
consumerAfterComputation(node, prevNode);
|
|
419
|
+
}
|
|
602
420
|
}
|
|
603
421
|
|
|
604
422
|
export { BASE_EFFECT_NODE, COMPUTING, ERRORED, REACTIVE_NODE, SIGNAL, SIGNAL_NODE, UNSET, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, createComputed, createSignal, defaultEquals, finalizeConsumerAfterComputation, getActiveConsumer, isInNotificationPhase, isReactive, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, resetConsumerBeforeComputation, runEffect, runPostProducerCreatedFn, runPostSignalSetFn, setActiveConsumer, setPostProducerCreatedFn, setPostSignalSetFn, setThrowInvalidWriteToSignalError, signalGetFn, signalSetFn, signalUpdateFn };
|