@ngrx/signals 19.0.0 → 19.1.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.
- package/entities/src/helpers.d.ts +4 -4
- package/entities/src/index.d.ts +4 -0
- package/entities/src/updaters/prepend-entities.d.ts +17 -0
- package/entities/src/updaters/prepend-entity.d.ts +17 -0
- package/entities/src/updaters/upsert-entities.d.ts +17 -0
- package/entities/src/updaters/upsert-entity.d.ts +17 -0
- package/fesm2022/ngrx-signals-entities.mjs +68 -10
- package/fesm2022/ngrx-signals-entities.mjs.map +1 -1
- package/fesm2022/ngrx-signals-rxjs-interop.mjs +9 -2
- package/fesm2022/ngrx-signals-rxjs-interop.mjs.map +1 -1
- package/fesm2022/ngrx-signals-testing.mjs +15 -0
- package/fesm2022/ngrx-signals-testing.mjs.map +1 -0
- package/fesm2022/ngrx-signals.mjs +74 -52
- package/fesm2022/ngrx-signals.mjs.map +1 -1
- package/package.json +6 -1
- package/rxjs-interop/src/index.d.ts +1 -1
- package/rxjs-interop/src/rx-method.d.ts +1 -1
- package/schematics-core/utility/libs-version.js +1 -1
- package/schematics-core/utility/libs-version.js.map +1 -1
- package/src/index.d.ts +3 -2
- package/src/signal-method.d.ts +1 -2
- package/src/signal-store-assertions.d.ts +1 -1
- package/src/state-source.d.ts +1 -0
- package/src/with-feature.d.ts +25 -0
- package/testing/index.d.ts +1 -0
- package/testing/src/index.d.ts +1 -0
- package/testing/src/unprotected.d.ts +4 -0
- package/src/deep-freeze.d.ts +0 -2
|
@@ -64,13 +64,25 @@ function signalMethod(processingFn, config) {
|
|
|
64
64
|
const sourceInjector = config?.injector ?? inject(Injector);
|
|
65
65
|
const signalMethodFn = (input, config) => {
|
|
66
66
|
if (isSignal(input)) {
|
|
67
|
-
const
|
|
68
|
-
|
|
67
|
+
const callerInjector = getCallerInjector();
|
|
68
|
+
if (typeof ngDevMode !== 'undefined' &&
|
|
69
|
+
ngDevMode &&
|
|
70
|
+
config?.injector === undefined &&
|
|
71
|
+
callerInjector === undefined) {
|
|
72
|
+
console.warn('@ngrx/signals: The function returned by signalMethod was called', 'outside the injection context with a signal. This may lead to', 'a memory leak. Make sure to call it within the injection context', '(e.g. in a constructor or field initializer) or pass an injector', 'explicitly via the config parameter.\n\nFor more information, see:', 'https://ngrx.io/guide/signals/signal-method#automatic-cleanup');
|
|
73
|
+
}
|
|
74
|
+
const instanceInjector = config?.injector ?? callerInjector ?? sourceInjector;
|
|
75
|
+
const watcher = effect(() => {
|
|
69
76
|
const value = input();
|
|
70
77
|
untracked(() => processingFn(value));
|
|
71
|
-
onCleanup(() => watchers.splice(watchers.indexOf(watcher), 1));
|
|
72
78
|
}, { injector: instanceInjector });
|
|
73
79
|
watchers.push(watcher);
|
|
80
|
+
instanceInjector.get(DestroyRef).onDestroy(() => {
|
|
81
|
+
const ix = watchers.indexOf(watcher);
|
|
82
|
+
if (ix !== -1) {
|
|
83
|
+
watchers.splice(ix, 1);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
74
86
|
return watcher;
|
|
75
87
|
}
|
|
76
88
|
else {
|
|
@@ -86,47 +98,20 @@ function getCallerInjector() {
|
|
|
86
98
|
return inject(Injector);
|
|
87
99
|
}
|
|
88
100
|
catch {
|
|
89
|
-
return
|
|
101
|
+
return undefined;
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
104
|
|
|
93
|
-
function deepFreeze(target) {
|
|
94
|
-
Object.freeze(target);
|
|
95
|
-
const targetIsFunction = typeof target === 'function';
|
|
96
|
-
Object.getOwnPropertyNames(target).forEach((prop) => {
|
|
97
|
-
// Ignore Ivy properties, ref: https://github.com/ngrx/platform/issues/2109#issuecomment-582689060
|
|
98
|
-
if (prop.startsWith('ɵ')) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (hasOwnProperty(target, prop) &&
|
|
102
|
-
(targetIsFunction
|
|
103
|
-
? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments'
|
|
104
|
-
: true)) {
|
|
105
|
-
const propValue = target[prop];
|
|
106
|
-
if ((isObjectLike(propValue) || typeof propValue === 'function') &&
|
|
107
|
-
!Object.isFrozen(propValue)) {
|
|
108
|
-
deepFreeze(propValue);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
return target;
|
|
113
|
-
}
|
|
114
|
-
function freezeInDevMode(target) {
|
|
115
|
-
return ngDevMode ? deepFreeze(target) : target;
|
|
116
|
-
}
|
|
117
|
-
function hasOwnProperty(target, propertyName) {
|
|
118
|
-
return isObjectLike(target)
|
|
119
|
-
? Object.prototype.hasOwnProperty.call(target, propertyName)
|
|
120
|
-
: false;
|
|
121
|
-
}
|
|
122
|
-
function isObjectLike(target) {
|
|
123
|
-
return typeof target === 'object' && target !== null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
105
|
const STATE_WATCHERS = new WeakMap();
|
|
127
106
|
const STATE_SOURCE = Symbol('STATE_SOURCE');
|
|
107
|
+
function isWritableStateSource(stateSource) {
|
|
108
|
+
return ('set' in stateSource[STATE_SOURCE] &&
|
|
109
|
+
'update' in stateSource[STATE_SOURCE] &&
|
|
110
|
+
typeof stateSource[STATE_SOURCE].set === 'function' &&
|
|
111
|
+
typeof stateSource[STATE_SOURCE].update === 'function');
|
|
112
|
+
}
|
|
128
113
|
function patchState(stateSource, ...updaters) {
|
|
129
|
-
stateSource[STATE_SOURCE].update((currentState) => updaters.reduce((nextState, updater) =>
|
|
114
|
+
stateSource[STATE_SOURCE].update((currentState) => updaters.reduce((nextState, updater) => ({
|
|
130
115
|
...nextState,
|
|
131
116
|
...(typeof updater === 'function' ? updater(nextState) : updater),
|
|
132
117
|
}), currentState));
|
|
@@ -167,7 +152,7 @@ function removeWatcher(stateSource, watcher) {
|
|
|
167
152
|
}
|
|
168
153
|
|
|
169
154
|
function signalState(initialState) {
|
|
170
|
-
const stateSource = signal(
|
|
155
|
+
const stateSource = signal(initialState);
|
|
171
156
|
const signalState = toDeepSignal(stateSource.asReadonly());
|
|
172
157
|
Object.defineProperty(signalState, STATE_SOURCE, {
|
|
173
158
|
value: stateSource,
|
|
@@ -185,9 +170,13 @@ function signalStore(...args) {
|
|
|
185
170
|
constructor() {
|
|
186
171
|
const innerStore = features.reduce((store, feature) => feature(store), getInitialInnerStore());
|
|
187
172
|
const { stateSignals, props, methods, hooks } = innerStore;
|
|
188
|
-
const storeMembers = {
|
|
173
|
+
const storeMembers = {
|
|
174
|
+
...stateSignals,
|
|
175
|
+
...props,
|
|
176
|
+
...methods,
|
|
177
|
+
};
|
|
189
178
|
this[STATE_SOURCE] = innerStore[STATE_SOURCE];
|
|
190
|
-
for (const key
|
|
179
|
+
for (const key of Reflect.ownKeys(storeMembers)) {
|
|
191
180
|
this[key] = storeMembers[key];
|
|
192
181
|
}
|
|
193
182
|
const { onInit, onDestroy } = hooks;
|
|
@@ -198,10 +187,10 @@ function signalStore(...args) {
|
|
|
198
187
|
inject(DestroyRef).onDestroy(onDestroy);
|
|
199
188
|
}
|
|
200
189
|
}
|
|
201
|
-
/** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.
|
|
202
|
-
/** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.
|
|
190
|
+
/** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: SignalStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
191
|
+
/** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: SignalStore, providedIn: config.providedIn || null });
|
|
203
192
|
}
|
|
204
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.
|
|
193
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: SignalStore, decorators: [{
|
|
205
194
|
type: Injectable,
|
|
206
195
|
args: [{ providedIn: config.providedIn || null }]
|
|
207
196
|
}], ctorParameters: () => [] });
|
|
@@ -228,7 +217,7 @@ function type() {
|
|
|
228
217
|
}
|
|
229
218
|
|
|
230
219
|
function assertUniqueStoreMembers(store, newMemberKeys) {
|
|
231
|
-
if (!ngDevMode) {
|
|
220
|
+
if (typeof ngDevMode === 'undefined' || !ngDevMode) {
|
|
232
221
|
return;
|
|
233
222
|
}
|
|
234
223
|
const storeMembers = {
|
|
@@ -236,9 +225,9 @@ function assertUniqueStoreMembers(store, newMemberKeys) {
|
|
|
236
225
|
...store.props,
|
|
237
226
|
...store.methods,
|
|
238
227
|
};
|
|
239
|
-
const overriddenKeys =
|
|
228
|
+
const overriddenKeys = Reflect.ownKeys(storeMembers).filter((memberKey) => newMemberKeys.includes(memberKey));
|
|
240
229
|
if (overriddenKeys.length > 0) {
|
|
241
|
-
console.warn('@ngrx/signals: SignalStore members cannot be overridden.', 'Trying to override:', overriddenKeys.join(', '));
|
|
230
|
+
console.warn('@ngrx/signals: SignalStore members cannot be overridden.', 'Trying to override:', overriddenKeys.map((key) => String(key)).join(', '));
|
|
242
231
|
}
|
|
243
232
|
}
|
|
244
233
|
|
|
@@ -250,7 +239,7 @@ function withProps(propsFactory) {
|
|
|
250
239
|
...store.props,
|
|
251
240
|
...store.methods,
|
|
252
241
|
});
|
|
253
|
-
assertUniqueStoreMembers(store,
|
|
242
|
+
assertUniqueStoreMembers(store, Reflect.ownKeys(props));
|
|
254
243
|
return {
|
|
255
244
|
...store,
|
|
256
245
|
props: { ...store.props, ...props },
|
|
@@ -262,6 +251,39 @@ function withComputed(signalsFactory) {
|
|
|
262
251
|
return withProps(signalsFactory);
|
|
263
252
|
}
|
|
264
253
|
|
|
254
|
+
/**
|
|
255
|
+
* @description
|
|
256
|
+
* Allows passing properties, methods, or signals from a SignalStore
|
|
257
|
+
* to a feature.
|
|
258
|
+
*
|
|
259
|
+
* @usageNotes
|
|
260
|
+
* ```typescript
|
|
261
|
+
* signalStore(
|
|
262
|
+
* withMethods((store) => ({
|
|
263
|
+
* load(id: number): Observable<Entity> {
|
|
264
|
+
* return of({ id, name: 'John' });
|
|
265
|
+
* },
|
|
266
|
+
* })),
|
|
267
|
+
* withFeature(
|
|
268
|
+
* // 👇 has full access to the store
|
|
269
|
+
* (store) => withEntityLoader((id) => firstValueFrom(store.load(id)))
|
|
270
|
+
* )
|
|
271
|
+
* );
|
|
272
|
+
* ```
|
|
273
|
+
*
|
|
274
|
+
* @param featureFactory function returning the actual feature
|
|
275
|
+
*/
|
|
276
|
+
function withFeature(featureFactory) {
|
|
277
|
+
return (store) => {
|
|
278
|
+
const storeForFactory = {
|
|
279
|
+
...store['stateSignals'],
|
|
280
|
+
...store['props'],
|
|
281
|
+
...store['methods'],
|
|
282
|
+
};
|
|
283
|
+
return featureFactory(storeForFactory)(store);
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
265
287
|
function withHooks(hooksOrFactory) {
|
|
266
288
|
return (store) => {
|
|
267
289
|
const storeMembers = {
|
|
@@ -303,7 +325,7 @@ function withMethods(methodsFactory) {
|
|
|
303
325
|
...store.props,
|
|
304
326
|
...store.methods,
|
|
305
327
|
});
|
|
306
|
-
assertUniqueStoreMembers(store,
|
|
328
|
+
assertUniqueStoreMembers(store, Reflect.ownKeys(methods));
|
|
307
329
|
return {
|
|
308
330
|
...store,
|
|
309
331
|
methods: { ...store.methods, ...methods },
|
|
@@ -314,9 +336,9 @@ function withMethods(methodsFactory) {
|
|
|
314
336
|
function withState(stateOrFactory) {
|
|
315
337
|
return (store) => {
|
|
316
338
|
const state = typeof stateOrFactory === 'function' ? stateOrFactory() : stateOrFactory;
|
|
317
|
-
const stateKeys =
|
|
339
|
+
const stateKeys = Reflect.ownKeys(state);
|
|
318
340
|
assertUniqueStoreMembers(store, stateKeys);
|
|
319
|
-
store[STATE_SOURCE].update((currentState) =>
|
|
341
|
+
store[STATE_SOURCE].update((currentState) => ({
|
|
320
342
|
...currentState,
|
|
321
343
|
...state,
|
|
322
344
|
}));
|
|
@@ -335,5 +357,5 @@ function withState(stateOrFactory) {
|
|
|
335
357
|
* Generated bundle index. Do not edit.
|
|
336
358
|
*/
|
|
337
359
|
|
|
338
|
-
export { deepComputed, getState, patchState, signalMethod, signalState, signalStore, signalStoreFeature, type, watchState, withComputed, withHooks, withMethods, withProps, withState };
|
|
360
|
+
export { deepComputed, getState, isWritableStateSource, patchState, signalMethod, signalState, signalStore, signalStoreFeature, type, watchState, withComputed, withFeature, withHooks, withMethods, withProps, withState };
|
|
339
361
|
//# sourceMappingURL=ngrx-signals.mjs.map
|