@angular/core 21.0.0-next.8 → 21.0.0-rc.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.
Files changed (84) hide show
  1. package/fesm2022/_attribute-chunk.mjs +2 -14
  2. package/fesm2022/_attribute-chunk.mjs.map +1 -1
  3. package/fesm2022/_debug_node-chunk.mjs +15214 -28375
  4. package/fesm2022/_debug_node-chunk.mjs.map +1 -1
  5. package/fesm2022/_effect-chunk.mjs +402 -120
  6. package/fesm2022/_effect-chunk.mjs.map +1 -1
  7. package/fesm2022/_effect-chunk2.mjs +2951 -0
  8. package/fesm2022/_effect-chunk2.mjs.map +1 -0
  9. package/fesm2022/_not_found-chunk.mjs +18 -35
  10. package/fesm2022/_not_found-chunk.mjs.map +1 -1
  11. package/fesm2022/_resource-chunk.mjs +316 -563
  12. package/fesm2022/_resource-chunk.mjs.map +1 -1
  13. package/fesm2022/_untracked-chunk.mjs +96 -0
  14. package/fesm2022/_untracked-chunk.mjs.map +1 -0
  15. package/fesm2022/_weak_ref-chunk.mjs +2 -4
  16. package/fesm2022/_weak_ref-chunk.mjs.map +1 -1
  17. package/fesm2022/core.mjs +2466 -4309
  18. package/fesm2022/core.mjs.map +1 -1
  19. package/fesm2022/primitives-di.mjs +9 -9
  20. package/fesm2022/primitives-di.mjs.map +1 -1
  21. package/fesm2022/primitives-event-dispatch.mjs +626 -1460
  22. package/fesm2022/primitives-event-dispatch.mjs.map +1 -1
  23. package/fesm2022/primitives-signals.mjs +157 -191
  24. package/fesm2022/primitives-signals.mjs.map +1 -1
  25. package/fesm2022/rxjs-interop.mjs +208 -308
  26. package/fesm2022/rxjs-interop.mjs.map +1 -1
  27. package/fesm2022/testing.mjs +2305 -3164
  28. package/fesm2022/testing.mjs.map +1 -1
  29. package/package.json +8 -2
  30. package/resources/best-practices.md +56 -0
  31. package/schematics/bundles/add-bootstrap-context-to-server-main.cjs +7 -25
  32. package/schematics/bundles/application-config-core.cjs +8 -19
  33. package/schematics/bundles/{apply_import_manager-CBLmogDD.cjs → apply_import_manager-1Zs_gpB6.cjs} +4 -5
  34. package/schematics/bundles/bootstrap-options-migration.cjs +93 -132
  35. package/schematics/bundles/cleanup-unused-imports.cjs +9 -13
  36. package/schematics/bundles/common-to-standalone-migration.cjs +381 -0
  37. package/schematics/bundles/{compiler_host-T6xncpiw.cjs → compiler_host-DBwYMlTo.cjs} +10 -11
  38. package/schematics/bundles/control-flow-migration.cjs +29 -31
  39. package/schematics/bundles/{imports-DwPXlGFl.cjs → imports-DP72APSx.cjs} +1 -23
  40. package/schematics/bundles/{index-DWSaRJdz.cjs → index-B7I9sIUx.cjs} +36 -37
  41. package/schematics/bundles/inject-migration.cjs +9 -26
  42. package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
  43. package/schematics/bundles/{migrate_ts_type_references-Cu-FR4L5.cjs → migrate_ts_type_references-UGIUl7En.cjs} +458 -24
  44. package/schematics/bundles/{ng_component_template-BkWiUuGG.cjs → ng_component_template-Dsuq1Lw7.cjs} +4 -5
  45. package/schematics/bundles/{ng_decorators-BI0uV7KI.cjs → ng_decorators-DSFlWYQY.cjs} +2 -2
  46. package/schematics/bundles/ngclass-to-class-migration.cjs +16 -19
  47. package/schematics/bundles/ngstyle-to-style-migration.cjs +15 -18
  48. package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
  49. package/schematics/bundles/output-migration.cjs +16 -19
  50. package/schematics/bundles/{parse_html-C97tKKp3.cjs → parse_html-8VLCL37B.cjs} +5 -5
  51. package/schematics/bundles/{project_paths-C6g3lqjX.cjs → project_paths-DvD50ouC.cjs} +14 -247
  52. package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs +90 -0
  53. package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
  54. package/schematics/bundles/route-lazy-loading.cjs +9 -25
  55. package/schematics/bundles/router-current-navigation.cjs +6 -17
  56. package/schematics/bundles/router-last-successful-navigation.cjs +6 -17
  57. package/schematics/bundles/router-testing-module-migration.cjs +7 -18
  58. package/schematics/bundles/self-closing-tags-migration.cjs +14 -17
  59. package/schematics/bundles/signal-input-migration.cjs +23 -26
  60. package/schematics/bundles/signal-queries-migration.cjs +22 -25
  61. package/schematics/bundles/signals.cjs +10 -13
  62. package/schematics/bundles/standalone-migration.cjs +22 -56
  63. package/schematics/bundles/symbol-BObKoqes.cjs +1 -1
  64. package/schematics/collection.json +6 -0
  65. package/schematics/migrations/common-to-standalone-migration/schema.json +14 -0
  66. package/types/_api-chunk.d.ts +1 -1
  67. package/types/_chrome_dev_tools_performance-chunk.d.ts +20 -12
  68. package/types/_discovery-chunk.d.ts +18 -14
  69. package/types/_effect-chunk.d.ts +1 -1
  70. package/types/_event_dispatcher-chunk.d.ts +1 -1
  71. package/types/_formatter-chunk.d.ts +4 -3
  72. package/types/_weak_ref-chunk.d.ts +1 -1
  73. package/types/core.d.ts +49 -100
  74. package/types/primitives-di.d.ts +1 -1
  75. package/types/primitives-event-dispatch.d.ts +1 -1
  76. package/types/primitives-signals.d.ts +2 -2
  77. package/types/rxjs-interop.d.ts +1 -1
  78. package/types/testing.d.ts +1 -1
  79. package/fesm2022/_root_effect_scheduler-chunk.mjs +0 -4630
  80. package/fesm2022/_root_effect_scheduler-chunk.mjs.map +0 -1
  81. package/fesm2022/_signal-chunk.mjs +0 -581
  82. package/fesm2022/_signal-chunk.mjs.map +0 -1
  83. package/schematics/bundles/index-BnmACOsq.cjs +0 -22319
  84. package/schematics/bundles/project_tsconfig_paths-CdhVNYMk.cjs +0 -51583
@@ -1,351 +1,251 @@
1
1
  /**
2
- * @license Angular v21.0.0-next.8
2
+ * @license Angular v21.0.0-rc.0
3
3
  * (c) 2010-2025 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import { Observable, ReplaySubject } from 'rxjs';
8
8
  import { takeUntil } from 'rxjs/operators';
9
- import { assertInInjectionContext, inject, DestroyRef, RuntimeError, Injector, assertNotInReactiveContext, signal, PendingTasks } from './_root_effect_scheduler-chunk.mjs';
10
- import { getOutputDestroyRef, effect, untracked, computed, resource, encapsulateResourceError } from './_resource-chunk.mjs';
11
- import './_signal-chunk.mjs';
9
+ import { assertInInjectionContext, inject, DestroyRef, RuntimeError, Injector, effect, assertNotInReactiveContext, signal, PendingTasks } from './_effect-chunk2.mjs';
10
+ import { getOutputDestroyRef, untracked, computed, resource, encapsulateResourceError } from './_resource-chunk.mjs';
11
+ import './_effect-chunk.mjs';
12
12
  import './_not_found-chunk.mjs';
13
13
  import '@angular/core/primitives/signals';
14
14
  import '@angular/core/primitives/di';
15
- import './_effect-chunk.mjs';
15
+ import './_untracked-chunk.mjs';
16
16
 
17
- /**
18
- * Operator which completes the Observable when the calling context (component, directive, service,
19
- * etc) is destroyed.
20
- *
21
- * @param destroyRef optionally, the `DestroyRef` representing the current context. This can be
22
- * passed explicitly to use `takeUntilDestroyed` outside of an [injection
23
- * context](guide/di/dependency-injection-context). Otherwise, the current `DestroyRef` is injected.
24
- *
25
- * @publicApi 19.0
26
- */
27
17
  function takeUntilDestroyed(destroyRef) {
28
- if (!destroyRef) {
29
- ngDevMode && assertInInjectionContext(takeUntilDestroyed);
30
- destroyRef = inject(DestroyRef);
18
+ if (!destroyRef) {
19
+ ngDevMode && assertInInjectionContext(takeUntilDestroyed);
20
+ destroyRef = inject(DestroyRef);
21
+ }
22
+ const destroyed$ = new Observable(subscriber => {
23
+ if (destroyRef.destroyed) {
24
+ subscriber.next();
25
+ return;
31
26
  }
32
- const destroyed$ = new Observable((subscriber) => {
33
- if (destroyRef.destroyed) {
34
- subscriber.next();
35
- return;
36
- }
37
- const unregisterFn = destroyRef.onDestroy(subscriber.next.bind(subscriber));
38
- return unregisterFn;
39
- });
40
- return (source) => {
41
- return source.pipe(takeUntil(destroyed$));
42
- };
27
+ const unregisterFn = destroyRef.onDestroy(subscriber.next.bind(subscriber));
28
+ return unregisterFn;
29
+ });
30
+ return source => {
31
+ return source.pipe(takeUntil(destroyed$));
32
+ };
43
33
  }
44
34
 
45
- /**
46
- * Implementation of `OutputRef` that emits values from
47
- * an RxJS observable source.
48
- *
49
- * @internal
50
- */
51
35
  class OutputFromObservableRef {
52
- source;
53
- destroyed = false;
54
- destroyRef = inject(DestroyRef);
55
- constructor(source) {
56
- this.source = source;
57
- this.destroyRef.onDestroy(() => {
58
- this.destroyed = true;
59
- });
60
- }
61
- subscribe(callbackFn) {
62
- if (this.destroyed) {
63
- throw new RuntimeError(953 /* ɵRuntimeErrorCode.OUTPUT_REF_DESTROYED */, ngDevMode &&
64
- 'Unexpected subscription to destroyed `OutputRef`. ' +
65
- 'The owning directive/component is destroyed.');
66
- }
67
- // Stop yielding more values when the directive/component is already destroyed.
68
- const subscription = this.source.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
69
- next: (value) => callbackFn(value),
70
- });
71
- return {
72
- unsubscribe: () => subscription.unsubscribe(),
73
- };
36
+ source;
37
+ destroyed = false;
38
+ destroyRef = inject(DestroyRef);
39
+ constructor(source) {
40
+ this.source = source;
41
+ this.destroyRef.onDestroy(() => {
42
+ this.destroyed = true;
43
+ });
44
+ }
45
+ subscribe(callbackFn) {
46
+ if (this.destroyed) {
47
+ throw new RuntimeError(953, ngDevMode && 'Unexpected subscription to destroyed `OutputRef`. ' + 'The owning directive/component is destroyed.');
74
48
  }
49
+ const subscription = this.source.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
50
+ next: value => callbackFn(value)
51
+ });
52
+ return {
53
+ unsubscribe: () => subscription.unsubscribe()
54
+ };
55
+ }
75
56
  }
76
- /**
77
- * Declares an Angular output that is using an RxJS observable as a source
78
- * for events dispatched to parent subscribers.
79
- *
80
- * The behavior for an observable as source is defined as followed:
81
- * 1. New values are forwarded to the Angular output (next notifications).
82
- * 2. Errors notifications are not handled by Angular. You need to handle these manually.
83
- * For example by using `catchError`.
84
- * 3. Completion notifications stop the output from emitting new values.
85
- *
86
- * @usageNotes
87
- * Initialize an output in your directive by declaring a
88
- * class field and initializing it with the `outputFromObservable()` function.
89
- *
90
- * ```ts
91
- * @Directive({..})
92
- * export class MyDir {
93
- * nameChange$ = <some-observable>;
94
- * nameChange = outputFromObservable(this.nameChange$);
95
- * }
96
- * ```
97
- *
98
- * @publicApi 19.0
99
- */
100
57
  function outputFromObservable(observable, opts) {
101
- ngDevMode && assertInInjectionContext(outputFromObservable);
102
- return new OutputFromObservableRef(observable);
58
+ ngDevMode && assertInInjectionContext(outputFromObservable);
59
+ return new OutputFromObservableRef(observable);
103
60
  }
104
61
 
105
- /**
106
- * Converts an Angular output declared via `output()` or `outputFromObservable()`
107
- * to an observable.
108
- * It creates an observable that represents the stream of "events firing" in an output.
109
- *
110
- * You can subscribe to the output via `Observable.subscribe` then.
111
- *
112
- * @publicApi 19.0
113
- */
114
62
  function outputToObservable(ref) {
115
- const destroyRef = getOutputDestroyRef(ref);
116
- return new Observable((observer) => {
117
- // Complete the observable upon directive/component destroy.
118
- // Note: May be `undefined` if an `EventEmitter` is declared outside
119
- // of an injection context.
120
- const unregisterOnDestroy = destroyRef?.onDestroy(() => observer.complete());
121
- const subscription = ref.subscribe((v) => observer.next(v));
122
- return () => {
123
- subscription.unsubscribe();
124
- unregisterOnDestroy?.();
125
- };
126
- });
63
+ const destroyRef = getOutputDestroyRef(ref);
64
+ return new Observable(observer => {
65
+ const unregisterOnDestroy = destroyRef?.onDestroy(() => observer.complete());
66
+ const subscription = ref.subscribe(v => observer.next(v));
67
+ return () => {
68
+ subscription.unsubscribe();
69
+ unregisterOnDestroy?.();
70
+ };
71
+ });
127
72
  }
128
73
 
129
- /**
130
- * Exposes the value of an Angular `Signal` as an RxJS `Observable`.
131
- * As it reflects a state, the observable will always emit the latest value upon subscription.
132
- *
133
- * The signal's value will be propagated into the `Observable`'s subscribers using an `effect`.
134
- *
135
- * `toObservable` must be called in an injection context unless an injector is provided via options.
136
- *
137
- * @publicApi 20.0
138
- */
139
74
  function toObservable(source, options) {
140
- if (ngDevMode && !options?.injector) {
141
- assertInInjectionContext(toObservable);
75
+ if (ngDevMode && !options?.injector) {
76
+ assertInInjectionContext(toObservable);
77
+ }
78
+ const injector = options?.injector ?? inject(Injector);
79
+ const subject = new ReplaySubject(1);
80
+ const watcher = effect(() => {
81
+ let value;
82
+ try {
83
+ value = source();
84
+ } catch (err) {
85
+ untracked(() => subject.error(err));
86
+ return;
142
87
  }
143
- const injector = options?.injector ?? inject(Injector);
144
- const subject = new ReplaySubject(1);
145
- const watcher = effect(() => {
146
- let value;
147
- try {
148
- value = source();
149
- }
150
- catch (err) {
151
- untracked(() => subject.error(err));
152
- return;
153
- }
154
- untracked(() => subject.next(value));
155
- }, { injector, manualCleanup: true });
156
- injector.get(DestroyRef).onDestroy(() => {
157
- watcher.destroy();
158
- subject.complete();
159
- });
160
- return subject.asObservable();
88
+ untracked(() => subject.next(value));
89
+ }, {
90
+ injector,
91
+ manualCleanup: true
92
+ });
93
+ injector.get(DestroyRef).onDestroy(() => {
94
+ watcher.destroy();
95
+ subject.complete();
96
+ });
97
+ return subject.asObservable();
161
98
  }
162
99
 
163
- /**
164
- * Get the current value of an `Observable` as a reactive `Signal`.
165
- *
166
- * `toSignal` returns a `Signal` which provides synchronous reactive access to values produced
167
- * by the given `Observable`, by subscribing to that `Observable`. The returned `Signal` will always
168
- * have the most recent value emitted by the subscription, and will throw an error if the
169
- * `Observable` errors.
170
- *
171
- * With `requireSync` set to `true`, `toSignal` will assert that the `Observable` produces a value
172
- * immediately upon subscription. No `initialValue` is needed in this case, and the returned signal
173
- * does not include an `undefined` type.
174
- *
175
- * By default, the subscription will be automatically cleaned up when the current [injection
176
- * context](guide/di/dependency-injection-context) is destroyed. For example, when `toSignal` is
177
- * called during the construction of a component, the subscription will be cleaned up when the
178
- * component is destroyed. If an injection context is not available, an explicit `Injector` can be
179
- * passed instead.
180
- *
181
- * If the subscription should persist until the `Observable` itself completes, the `manualCleanup`
182
- * option can be specified instead, which disables the automatic subscription teardown. No injection
183
- * context is needed in this configuration as well.
184
- */
185
100
  function toSignal(source, options) {
186
- typeof ngDevMode !== 'undefined' &&
187
- ngDevMode &&
188
- assertNotInReactiveContext(toSignal, 'Invoking `toSignal` causes new subscriptions every time. ' +
189
- 'Consider moving `toSignal` outside of the reactive context and read the signal value where needed.');
190
- const requiresCleanup = !options?.manualCleanup;
191
- if (ngDevMode && requiresCleanup && !options?.injector) {
192
- assertInInjectionContext(toSignal);
193
- }
194
- const cleanupRef = requiresCleanup
195
- ? (options?.injector?.get(DestroyRef) ?? inject(DestroyRef))
196
- : null;
197
- const equal = makeToSignalEqual(options?.equal);
198
- // Note: T is the Observable value type, and U is the initial value type. They don't have to be
199
- // the same - the returned signal gives values of type `T`.
200
- let state;
201
- if (options?.requireSync) {
202
- // Initially the signal is in a `NoValue` state.
203
- state = signal({ kind: 0 /* StateKind.NoValue */ }, { equal });
204
- }
205
- else {
206
- // If an initial value was passed, use it. Otherwise, use `undefined` as the initial value.
207
- state = signal({ kind: 1 /* StateKind.Value */, value: options?.initialValue }, { equal });
208
- }
209
- let destroyUnregisterFn;
210
- // Note: This code cannot run inside a reactive context (see assertion above). If we'd support
211
- // this, we would subscribe to the observable outside of the current reactive context, avoiding
212
- // that side-effect signal reads/writes are attribute to the current consumer. The current
213
- // consumer only needs to be notified when the `state` signal changes through the observable
214
- // subscription. Additional context (related to async pipe):
215
- // https://github.com/angular/angular/pull/50522.
216
- const sub = source.subscribe({
217
- next: (value) => state.set({ kind: 1 /* StateKind.Value */, value }),
218
- error: (error) => {
219
- state.set({ kind: 2 /* StateKind.Error */, error });
220
- destroyUnregisterFn?.();
221
- },
222
- complete: () => {
223
- destroyUnregisterFn?.();
224
- },
225
- // Completion of the Observable is meaningless to the signal. Signals don't have a concept of
226
- // "complete".
101
+ typeof ngDevMode !== 'undefined' && ngDevMode && assertNotInReactiveContext(toSignal, 'Invoking `toSignal` causes new subscriptions every time. ' + 'Consider moving `toSignal` outside of the reactive context and read the signal value where needed.');
102
+ const requiresCleanup = !options?.manualCleanup;
103
+ if (ngDevMode && requiresCleanup && !options?.injector) {
104
+ assertInInjectionContext(toSignal);
105
+ }
106
+ const cleanupRef = requiresCleanup ? options?.injector?.get(DestroyRef) ?? inject(DestroyRef) : null;
107
+ const equal = makeToSignalEqual(options?.equal);
108
+ let state;
109
+ if (options?.requireSync) {
110
+ state = signal({
111
+ kind: 0
112
+ }, {
113
+ equal
114
+ });
115
+ } else {
116
+ state = signal({
117
+ kind: 1,
118
+ value: options?.initialValue
119
+ }, {
120
+ equal
227
121
  });
228
- if (options?.requireSync && state().kind === 0 /* StateKind.NoValue */) {
229
- throw new RuntimeError(601 /* ɵRuntimeErrorCode.REQUIRE_SYNC_WITHOUT_SYNC_EMIT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
230
- '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.');
122
+ }
123
+ let destroyUnregisterFn;
124
+ const sub = source.subscribe({
125
+ next: value => state.set({
126
+ kind: 1,
127
+ value
128
+ }),
129
+ error: error => {
130
+ state.set({
131
+ kind: 2,
132
+ error
133
+ });
134
+ destroyUnregisterFn?.();
135
+ },
136
+ complete: () => {
137
+ destroyUnregisterFn?.();
231
138
  }
232
- // Unsubscribe when the current context is destroyed, if requested.
233
- destroyUnregisterFn = cleanupRef?.onDestroy(sub.unsubscribe.bind(sub));
234
- // The actual returned signal is a `computed` of the `State` signal, which maps the various states
235
- // to either values or errors.
236
- return computed(() => {
237
- const current = state();
238
- switch (current.kind) {
239
- case 1 /* StateKind.Value */:
240
- return current.value;
241
- case 2 /* StateKind.Error */:
242
- throw current.error;
243
- case 0 /* StateKind.NoValue */:
244
- // This shouldn't really happen because the error is thrown on creation.
245
- throw new RuntimeError(601 /* ɵRuntimeErrorCode.REQUIRE_SYNC_WITHOUT_SYNC_EMIT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
246
- '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.');
247
- }
248
- }, { equal: options?.equal });
139
+ });
140
+ if (options?.requireSync && state().kind === 0) {
141
+ throw new RuntimeError(601, (typeof ngDevMode === 'undefined' || ngDevMode) && '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.');
142
+ }
143
+ destroyUnregisterFn = cleanupRef?.onDestroy(sub.unsubscribe.bind(sub));
144
+ return computed(() => {
145
+ const current = state();
146
+ switch (current.kind) {
147
+ case 1:
148
+ return current.value;
149
+ case 2:
150
+ throw current.error;
151
+ case 0:
152
+ throw new RuntimeError(601, (typeof ngDevMode === 'undefined' || ngDevMode) && '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.');
153
+ }
154
+ }, {
155
+ equal: options?.equal
156
+ });
249
157
  }
250
158
  function makeToSignalEqual(userEquality = Object.is) {
251
- return (a, b) => a.kind === 1 /* StateKind.Value */ && b.kind === 1 /* StateKind.Value */ && userEquality(a.value, b.value);
159
+ return (a, b) => a.kind === 1 && b.kind === 1 && userEquality(a.value, b.value);
252
160
  }
253
161
 
254
- /**
255
- * Operator which makes the application unstable until the observable emits, completes, errors, or is unsubscribed.
256
- *
257
- * Use this operator in observables whose subscriptions are important for rendering and should be included in SSR serialization.
258
- *
259
- * @param injector The `Injector` to use during creation. If this is not provided, the current injection context will be used instead (via `inject`).
260
- *
261
- * @developerPreview 20.0
262
- */
263
162
  function pendingUntilEvent(injector) {
264
- if (injector === undefined) {
265
- ngDevMode && assertInInjectionContext(pendingUntilEvent);
266
- injector = inject(Injector);
267
- }
268
- const taskService = injector.get(PendingTasks);
269
- return (sourceObservable) => {
270
- return new Observable((originalSubscriber) => {
271
- // create a new task on subscription
272
- const removeTask = taskService.add();
273
- let cleanedUp = false;
274
- function cleanupTask() {
275
- if (cleanedUp) {
276
- return;
277
- }
278
- removeTask();
279
- cleanedUp = true;
280
- }
281
- const innerSubscription = sourceObservable.subscribe({
282
- next: (v) => {
283
- originalSubscriber.next(v);
284
- cleanupTask();
285
- },
286
- complete: () => {
287
- originalSubscriber.complete();
288
- cleanupTask();
289
- },
290
- error: (e) => {
291
- originalSubscriber.error(e);
292
- cleanupTask();
293
- },
294
- });
295
- innerSubscription.add(() => {
296
- originalSubscriber.unsubscribe();
297
- cleanupTask();
298
- });
299
- return innerSubscription;
300
- });
301
- };
163
+ if (injector === undefined) {
164
+ ngDevMode && assertInInjectionContext(pendingUntilEvent);
165
+ injector = inject(Injector);
166
+ }
167
+ const taskService = injector.get(PendingTasks);
168
+ return sourceObservable => {
169
+ return new Observable(originalSubscriber => {
170
+ const removeTask = taskService.add();
171
+ let cleanedUp = false;
172
+ function cleanupTask() {
173
+ if (cleanedUp) {
174
+ return;
175
+ }
176
+ removeTask();
177
+ cleanedUp = true;
178
+ }
179
+ const innerSubscription = sourceObservable.subscribe({
180
+ next: v => {
181
+ originalSubscriber.next(v);
182
+ cleanupTask();
183
+ },
184
+ complete: () => {
185
+ originalSubscriber.complete();
186
+ cleanupTask();
187
+ },
188
+ error: e => {
189
+ originalSubscriber.error(e);
190
+ cleanupTask();
191
+ }
192
+ });
193
+ innerSubscription.add(() => {
194
+ originalSubscriber.unsubscribe();
195
+ cleanupTask();
196
+ });
197
+ return innerSubscription;
198
+ });
199
+ };
302
200
  }
303
201
 
304
202
  function rxResource(opts) {
305
- if (ngDevMode && !opts?.injector) {
306
- assertInInjectionContext(rxResource);
307
- }
308
- return resource({
309
- ...opts,
310
- loader: undefined,
311
- stream: (params) => {
312
- let sub;
313
- // Track the abort listener so it can be removed if the Observable completes (as a memory
314
- // optimization).
315
- const onAbort = () => sub?.unsubscribe();
316
- params.abortSignal.addEventListener('abort', onAbort);
317
- // Start off stream as undefined.
318
- const stream = signal({ value: undefined });
319
- let resolve;
320
- const promise = new Promise((r) => (resolve = r));
321
- function send(value) {
322
- stream.set(value);
323
- resolve?.(stream);
324
- resolve = undefined;
325
- }
326
- // TODO(alxhub): remove after g3 updated to rename loader -> stream
327
- const streamFn = opts.stream ?? opts.loader;
328
- if (streamFn === undefined) {
329
- throw new RuntimeError(990 /* ɵRuntimeErrorCode.MUST_PROVIDE_STREAM_OPTION */, ngDevMode && `Must provide \`stream\` option.`);
330
- }
331
- sub = streamFn(params).subscribe({
332
- next: (value) => send({ value }),
333
- error: (error) => {
334
- send({ error: encapsulateResourceError(error) });
335
- params.abortSignal.removeEventListener('abort', onAbort);
336
- },
337
- complete: () => {
338
- if (resolve) {
339
- send({
340
- error: new RuntimeError(991 /* ɵRuntimeErrorCode.RESOURCE_COMPLETED_BEFORE_PRODUCING_VALUE */, ngDevMode && 'Resource completed before producing a value'),
341
- });
342
- }
343
- params.abortSignal.removeEventListener('abort', onAbort);
344
- },
345
- });
346
- return promise;
203
+ if (ngDevMode && !opts?.injector) {
204
+ assertInInjectionContext(rxResource);
205
+ }
206
+ return resource({
207
+ ...opts,
208
+ loader: undefined,
209
+ stream: params => {
210
+ let sub;
211
+ const onAbort = () => sub?.unsubscribe();
212
+ params.abortSignal.addEventListener('abort', onAbort);
213
+ const stream = signal({
214
+ value: undefined
215
+ });
216
+ let resolve;
217
+ const promise = new Promise(r => resolve = r);
218
+ function send(value) {
219
+ stream.set(value);
220
+ resolve?.(stream);
221
+ resolve = undefined;
222
+ }
223
+ const streamFn = opts.stream ?? opts.loader;
224
+ if (streamFn === undefined) {
225
+ throw new RuntimeError(990, ngDevMode && `Must provide \`stream\` option.`);
226
+ }
227
+ sub = streamFn(params).subscribe({
228
+ next: value => send({
229
+ value
230
+ }),
231
+ error: error => {
232
+ send({
233
+ error: encapsulateResourceError(error)
234
+ });
235
+ params.abortSignal.removeEventListener('abort', onAbort);
347
236
  },
348
- });
237
+ complete: () => {
238
+ if (resolve) {
239
+ send({
240
+ error: new RuntimeError(991, ngDevMode && 'Resource completed before producing a value')
241
+ });
242
+ }
243
+ params.abortSignal.removeEventListener('abort', onAbort);
244
+ }
245
+ });
246
+ return promise;
247
+ }
248
+ });
349
249
  }
350
250
 
351
251
  export { outputFromObservable, outputToObservable, pendingUntilEvent, rxResource, takeUntilDestroyed, toObservable, toSignal };