Skip to content

Commit 0812ac3

Browse files
meDavidNSkirjs
authored andcommitted
refactor(core): add debugName option to rxjs-interop toSignal
toSignal predates the debugName option for signals to name the signals in the Angular dev-tools This adds the debugName option to toSignal.
1 parent 80202bf commit 0812ac3

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

goldens/public-api/core/rxjs-interop/index.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export function toSignal<T, const U extends T>(source: Observable<T> | Subscriba
7171

7272
// @public
7373
export interface ToSignalOptions<T> {
74+
debugName?: string;
7475
equal?: ValueEqualityFn_2<T>;
7576
initialValue?: unknown;
7677
injector?: Injector;

packages/core/rxjs-interop/src/to_signal.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export interface ToSignalOptions<T> {
6868
* Equality comparisons are executed against the initial value if one is provided.
6969
*/
7070
equal?: ValueEqualityFn<T>;
71+
72+
/**
73+
* A debug name for the signal. Used in Angular DevTools to identify the signal.
74+
*/
75+
debugName?: string;
7176
}
7277

7378
// Base case: no options -> `undefined` in the result type.
@@ -149,12 +154,15 @@ export function toSignal<T, U = undefined>(
149154
let state: WritableSignal<State<T | U>>;
150155
if (options?.requireSync) {
151156
// Initially the signal is in a `NoValue` state.
152-
state = signal({kind: StateKind.NoValue}, {equal});
157+
state = signal(
158+
{kind: StateKind.NoValue},
159+
{equal, ...(ngDevMode ? createDebugNameObject(options?.debugName, 'state') : undefined)},
160+
);
153161
} else {
154162
// If an initial value was passed, use it. Otherwise, use `undefined` as the initial value.
155163
state = signal<State<T | U>>(
156164
{kind: StateKind.Value, value: options?.initialValue as U},
157-
{equal},
165+
{equal, ...(ngDevMode ? createDebugNameObject(options?.debugName, 'state') : undefined)},
158166
);
159167
}
160168

@@ -209,7 +217,10 @@ export function toSignal<T, U = undefined>(
209217
);
210218
}
211219
},
212-
{equal: options?.equal},
220+
{
221+
equal: options?.equal,
222+
...(ngDevMode ? createDebugNameObject(options?.debugName, 'source') : undefined),
223+
},
213224
);
214225
}
215226

@@ -220,6 +231,18 @@ function makeToSignalEqual<T>(
220231
a.kind === StateKind.Value && b.kind === StateKind.Value && userEquality(a.value, b.value);
221232
}
222233

234+
/**
235+
* Creates a debug name object for an internal toSignal signal.
236+
*/
237+
function createDebugNameObject(
238+
toSignalDebugName: string | undefined,
239+
internalSignalDebugName: string,
240+
): {debugName?: string} {
241+
return {
242+
debugName: `toSignal${toSignalDebugName ? '#' + toSignalDebugName : ''}.${internalSignalDebugName}`,
243+
};
244+
}
245+
223246
const enum StateKind {
224247
NoValue,
225248
Value,

packages/core/rxjs-interop/test/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ts_project(
77
deps = [
88
"//:node_modules/rxjs",
99
"//packages/core",
10+
"//packages/core/primitives/signals",
1011
"//packages/core/rxjs-interop",
1112
"//packages/core/testing",
1213
"//packages/private/testing",

packages/core/rxjs-interop/test/to_signal_spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
Subscribable,
2727
Unsubscribable,
2828
} from 'rxjs';
29+
import {ReactiveNode, SIGNAL} from '../../primitives/signals';
2930

3031
describe('toSignal()', () => {
3132
it(
@@ -42,6 +43,28 @@ describe('toSignal()', () => {
4243
}),
4344
);
4445

46+
it(
47+
'should set debugName when a debugName is provided',
48+
test(() => {
49+
const counter$ = new BehaviorSubject(0);
50+
const counter = toSignal(counter$, {debugName: 'counterSignal'});
51+
const node = counter[SIGNAL] as ReactiveNode;
52+
53+
expect(node.debugName).toBe('toSignal#counterSignal.source');
54+
}),
55+
);
56+
57+
it(
58+
'should set debugName when a debugName is provided together with requireSync',
59+
test(() => {
60+
const counter$ = new BehaviorSubject(0);
61+
const counter = toSignal(counter$, {debugName: 'counterSignal', requireSync: true});
62+
const node = counter[SIGNAL] as ReactiveNode;
63+
64+
expect(node.debugName).toBe('toSignal#counterSignal.source');
65+
}),
66+
);
67+
4568
it(
4669
'should notify when the last emitted value of an Observable changes',
4770
test(() => {

0 commit comments

Comments
 (0)