UNPKG

47 kBJavaScriptView Raw
1import * as ngCore from '@angular/core';
2import { Injectable, InjectionToken, Inject, isDevMode, NgModule, Optional, SkipSelf, Injector } from '@angular/core';
3import { BehaviorSubject, Observable, Subject, queueScheduler } from 'rxjs';
4import { observeOn, withLatestFrom, scan, pluck, map, distinctUntilChanged } from 'rxjs/operators';
5
6const REGISTERED_ACTION_TYPES = {};
7function resetRegisteredActionTypes() {
8 for (const key of Object.keys(REGISTERED_ACTION_TYPES)) {
9 delete REGISTERED_ACTION_TYPES[key];
10 }
11}
12
13/**
14 * @description
15 * Creates a configured `Creator` function that, when called, returns an object in the shape of the `Action` interface.
16 *
17 * Action creators reduce the explicitness of class-based action creators.
18 *
19 * @param type Describes the action that will be dispatched
20 * @param config Additional metadata needed for the handling of the action. See {@link createAction#usage-notes Usage Notes}.
21 *
22 * @usageNotes
23 *
24 * **Declaring an action creator**
25 *
26 * Without additional metadata:
27 * ```ts
28 * export const increment = createAction('[Counter] Increment');
29 * ```
30 * With additional metadata:
31 * ```ts
32 * export const loginSuccess = createAction(
33 * '[Auth/API] Login Success',
34 * props<{ user: User }>()
35 * );
36 * ```
37 * With a function:
38 * ```ts
39 * export const loginSuccess = createAction(
40 * '[Auth/API] Login Success',
41 * (response: Response) => response.user
42 * );
43 * ```
44 *
45 * **Dispatching an action**
46 *
47 * Without additional metadata:
48 * ```ts
49 * store.dispatch(increment());
50 * ```
51 * With additional metadata:
52 * ```ts
53 * store.dispatch(loginSuccess({ user: newUser }));
54 * ```
55 *
56 * **Referencing an action in a reducer**
57 *
58 * Using a switch statement:
59 * ```ts
60 * switch (action.type) {
61 * // ...
62 * case AuthApiActions.loginSuccess.type: {
63 * return {
64 * ...state,
65 * user: action.user
66 * };
67 * }
68 * }
69 * ```
70 * Using a reducer creator:
71 * ```ts
72 * on(AuthApiActions.loginSuccess, (state, { user }) => ({ ...state, user }))
73 * ```
74 *
75 * **Referencing an action in an effect**
76 * ```ts
77 * effectName$ = createEffect(
78 * () => this.actions$.pipe(
79 * ofType(AuthApiActions.loginSuccess),
80 * // ...
81 * )
82 * );
83 * ```
84 */
85function createAction(type, config) {
86 REGISTERED_ACTION_TYPES[type] = (REGISTERED_ACTION_TYPES[type] || 0) + 1;
87 if (typeof config === 'function') {
88 return defineType(type, (...args) => (Object.assign(Object.assign({}, config(...args)), { type })));
89 }
90 const as = config ? config._as : 'empty';
91 switch (as) {
92 case 'empty':
93 return defineType(type, () => ({ type }));
94 case 'props':
95 return defineType(type, (props) => (Object.assign(Object.assign({}, props), { type })));
96 default:
97 throw new Error('Unexpected config.');
98 }
99}
100function props() {
101 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/naming-convention
102 return { _as: 'props', _p: undefined };
103}
104function union(creators) {
105 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
106 return undefined;
107}
108function defineType(type, creator) {
109 return Object.defineProperty(creator, 'type', {
110 value: type,
111 writable: false,
112 });
113}
114
115const INIT = '@ngrx/store/init';
116class ActionsSubject extends BehaviorSubject {
117 constructor() {
118 super({ type: INIT });
119 }
120 next(action) {
121 if (typeof action === 'function') {
122 throw new TypeError(`
123 Dispatch expected an object, instead it received a function.
124 If you're using the createAction function, make sure to invoke the function
125 before dispatching the action. For example, someAction should be someAction().`);
126 }
127 else if (typeof action === 'undefined') {
128 throw new TypeError(`Actions must be objects`);
129 }
130 else if (typeof action.type === 'undefined') {
131 throw new TypeError(`Actions must have a type property`);
132 }
133 super.next(action);
134 }
135 complete() {
136 /* noop */
137 }
138 ngOnDestroy() {
139 super.complete();
140 }
141}
142ActionsSubject.decorators = [
143 { type: Injectable }
144];
145/** @nocollapse */
146ActionsSubject.ctorParameters = () => [];
147const ACTIONS_SUBJECT_PROVIDERS = [ActionsSubject];
148
149const _ROOT_STORE_GUARD = new InjectionToken('@ngrx/store Internal Root Guard');
150const _INITIAL_STATE = new InjectionToken('@ngrx/store Internal Initial State');
151const INITIAL_STATE = new InjectionToken('@ngrx/store Initial State');
152const REDUCER_FACTORY = new InjectionToken('@ngrx/store Reducer Factory');
153const _REDUCER_FACTORY = new InjectionToken('@ngrx/store Internal Reducer Factory Provider');
154const INITIAL_REDUCERS = new InjectionToken('@ngrx/store Initial Reducers');
155const _INITIAL_REDUCERS = new InjectionToken('@ngrx/store Internal Initial Reducers');
156const STORE_FEATURES = new InjectionToken('@ngrx/store Store Features');
157const _STORE_REDUCERS = new InjectionToken('@ngrx/store Internal Store Reducers');
158const _FEATURE_REDUCERS = new InjectionToken('@ngrx/store Internal Feature Reducers');
159const _FEATURE_CONFIGS = new InjectionToken('@ngrx/store Internal Feature Configs');
160const _STORE_FEATURES = new InjectionToken('@ngrx/store Internal Store Features');
161const _FEATURE_REDUCERS_TOKEN = new InjectionToken('@ngrx/store Internal Feature Reducers Token');
162const FEATURE_REDUCERS = new InjectionToken('@ngrx/store Feature Reducers');
163/**
164 * User-defined meta reducers from StoreModule.forRoot()
165 */
166const USER_PROVIDED_META_REDUCERS = new InjectionToken('@ngrx/store User Provided Meta Reducers');
167/**
168 * Meta reducers defined either internally by @ngrx/store or by library authors
169 */
170const META_REDUCERS = new InjectionToken('@ngrx/store Meta Reducers');
171/**
172 * Concats the user provided meta reducers and the meta reducers provided on the multi
173 * injection token
174 */
175const _RESOLVED_META_REDUCERS = new InjectionToken('@ngrx/store Internal Resolved Meta Reducers');
176/**
177 * Runtime checks defined by the user via an InjectionToken
178 * Defaults to `_USER_RUNTIME_CHECKS`
179 */
180const USER_RUNTIME_CHECKS = new InjectionToken('@ngrx/store User Runtime Checks Config');
181/**
182 * Runtime checks defined by the user via forRoot()
183 */
184const _USER_RUNTIME_CHECKS = new InjectionToken('@ngrx/store Internal User Runtime Checks Config');
185/**
186 * Runtime checks currently in use
187 */
188const ACTIVE_RUNTIME_CHECKS = new InjectionToken('@ngrx/store Internal Runtime Checks');
189const _ACTION_TYPE_UNIQUENESS_CHECK = new InjectionToken('@ngrx/store Check if Action types are unique');
190
191/**
192 * @description
193 * Combines reducers for individual features into a single reducer.
194 *
195 * You can use this function to delegate handling of state transitions to multiple reducers, each acting on their
196 * own sub-state within the root state.
197 *
198 * @param reducers An object mapping keys of the root state to their corresponding feature reducer.
199 * @param initialState Provides a state value if the current state is `undefined`, as it is initially.
200 * @returns A reducer function.
201 *
202 * @usageNotes
203 *
204 * **Example combining two feature reducers into one "root" reducer**
205 *
206 * ```ts
207 * export const reducer = combineReducers({
208 * featureA: featureAReducer,
209 * featureB: featureBReducer
210 * });
211 * ```
212 *
213 * You can also override the initial states of the sub-features:
214 * ```ts
215 * export const reducer = combineReducers({
216 * featureA: featureAReducer,
217 * featureB: featureBReducer
218 * }, {
219 * featureA: { counterA: 13 },
220 * featureB: { counterB: 37 }
221 * });
222 * ```
223 */
224function combineReducers(reducers, initialState = {}) {
225 const reducerKeys = Object.keys(reducers);
226 const finalReducers = {};
227 for (let i = 0; i < reducerKeys.length; i++) {
228 const key = reducerKeys[i];
229 if (typeof reducers[key] === 'function') {
230 finalReducers[key] = reducers[key];
231 }
232 }
233 const finalReducerKeys = Object.keys(finalReducers);
234 return function combination(state, action) {
235 state = state === undefined ? initialState : state;
236 let hasChanged = false;
237 const nextState = {};
238 for (let i = 0; i < finalReducerKeys.length; i++) {
239 const key = finalReducerKeys[i];
240 const reducer = finalReducers[key];
241 const previousStateForKey = state[key];
242 const nextStateForKey = reducer(previousStateForKey, action);
243 nextState[key] = nextStateForKey;
244 hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
245 }
246 return hasChanged ? nextState : state;
247 };
248}
249function omit(object, keyToRemove) {
250 return Object.keys(object)
251 .filter((key) => key !== keyToRemove)
252 .reduce((result, key) => Object.assign(result, { [key]: object[key] }), {});
253}
254function compose(...functions) {
255 return function (arg) {
256 if (functions.length === 0) {
257 return arg;
258 }
259 const last = functions[functions.length - 1];
260 const rest = functions.slice(0, -1);
261 return rest.reduceRight((composed, fn) => fn(composed), last(arg));
262 };
263}
264function createReducerFactory(reducerFactory, metaReducers) {
265 if (Array.isArray(metaReducers) && metaReducers.length > 0) {
266 reducerFactory = compose.apply(null, [
267 ...metaReducers,
268 reducerFactory,
269 ]);
270 }
271 return (reducers, initialState) => {
272 const reducer = reducerFactory(reducers);
273 return (state, action) => {
274 state = state === undefined ? initialState : state;
275 return reducer(state, action);
276 };
277 };
278}
279function createFeatureReducerFactory(metaReducers) {
280 const reducerFactory = Array.isArray(metaReducers) && metaReducers.length > 0
281 ? compose(...metaReducers)
282 : (r) => r;
283 return (reducer, initialState) => {
284 reducer = reducerFactory(reducer);
285 return (state, action) => {
286 state = state === undefined ? initialState : state;
287 return reducer(state, action);
288 };
289 };
290}
291
292class ReducerObservable extends Observable {
293}
294class ReducerManagerDispatcher extends ActionsSubject {
295}
296const UPDATE = '@ngrx/store/update-reducers';
297class ReducerManager extends BehaviorSubject {
298 constructor(dispatcher, initialState, reducers, reducerFactory) {
299 super(reducerFactory(reducers, initialState));
300 this.dispatcher = dispatcher;
301 this.initialState = initialState;
302 this.reducers = reducers;
303 this.reducerFactory = reducerFactory;
304 }
305 get currentReducers() {
306 return this.reducers;
307 }
308 addFeature(feature) {
309 this.addFeatures([feature]);
310 }
311 addFeatures(features) {
312 const reducers = features.reduce((reducerDict, { reducers, reducerFactory, metaReducers, initialState, key }) => {
313 const reducer = typeof reducers === 'function'
314 ? createFeatureReducerFactory(metaReducers)(reducers, initialState)
315 : createReducerFactory(reducerFactory, metaReducers)(reducers, initialState);
316 reducerDict[key] = reducer;
317 return reducerDict;
318 }, {});
319 this.addReducers(reducers);
320 }
321 removeFeature(feature) {
322 this.removeFeatures([feature]);
323 }
324 removeFeatures(features) {
325 this.removeReducers(features.map((p) => p.key));
326 }
327 addReducer(key, reducer) {
328 this.addReducers({ [key]: reducer });
329 }
330 addReducers(reducers) {
331 this.reducers = Object.assign(Object.assign({}, this.reducers), reducers);
332 this.updateReducers(Object.keys(reducers));
333 }
334 removeReducer(featureKey) {
335 this.removeReducers([featureKey]);
336 }
337 removeReducers(featureKeys) {
338 featureKeys.forEach((key) => {
339 this.reducers = omit(this.reducers, key) /*TODO(#823)*/;
340 });
341 this.updateReducers(featureKeys);
342 }
343 updateReducers(featureKeys) {
344 this.next(this.reducerFactory(this.reducers, this.initialState));
345 this.dispatcher.next({
346 type: UPDATE,
347 features: featureKeys,
348 });
349 }
350 ngOnDestroy() {
351 this.complete();
352 }
353}
354ReducerManager.decorators = [
355 { type: Injectable }
356];
357/** @nocollapse */
358ReducerManager.ctorParameters = () => [
359 { type: ReducerManagerDispatcher },
360 { type: undefined, decorators: [{ type: Inject, args: [INITIAL_STATE,] }] },
361 { type: undefined, decorators: [{ type: Inject, args: [INITIAL_REDUCERS,] }] },
362 { type: undefined, decorators: [{ type: Inject, args: [REDUCER_FACTORY,] }] }
363];
364const REDUCER_MANAGER_PROVIDERS = [
365 ReducerManager,
366 { provide: ReducerObservable, useExisting: ReducerManager },
367 { provide: ReducerManagerDispatcher, useExisting: ActionsSubject },
368];
369
370class ScannedActionsSubject extends Subject {
371 ngOnDestroy() {
372 this.complete();
373 }
374}
375ScannedActionsSubject.decorators = [
376 { type: Injectable }
377];
378const SCANNED_ACTIONS_SUBJECT_PROVIDERS = [
379 ScannedActionsSubject,
380];
381
382class StateObservable extends Observable {
383}
384class State extends BehaviorSubject {
385 constructor(actions$, reducer$, scannedActions, initialState) {
386 super(initialState);
387 const actionsOnQueue$ = actions$.pipe(observeOn(queueScheduler));
388 const withLatestReducer$ = actionsOnQueue$.pipe(withLatestFrom(reducer$));
389 const seed = { state: initialState };
390 const stateAndAction$ = withLatestReducer$.pipe(scan(reduceState, seed));
391 this.stateSubscription = stateAndAction$.subscribe(({ state, action }) => {
392 this.next(state);
393 scannedActions.next(action);
394 });
395 }
396 ngOnDestroy() {
397 this.stateSubscription.unsubscribe();
398 this.complete();
399 }
400}
401State.INIT = INIT;
402State.decorators = [
403 { type: Injectable }
404];
405/** @nocollapse */
406State.ctorParameters = () => [
407 { type: ActionsSubject },
408 { type: ReducerObservable },
409 { type: ScannedActionsSubject },
410 { type: undefined, decorators: [{ type: Inject, args: [INITIAL_STATE,] }] }
411];
412function reduceState(stateActionPair = { state: undefined }, [action, reducer]) {
413 const { state } = stateActionPair;
414 return { state: reducer(state, action), action };
415}
416const STATE_PROVIDERS = [
417 State,
418 { provide: StateObservable, useExisting: State },
419];
420
421/* eslint-disable @typescript-eslint/naming-convention */
422class Store extends Observable {
423 constructor(state$, actionsObserver, reducerManager) {
424 super();
425 this.actionsObserver = actionsObserver;
426 this.reducerManager = reducerManager;
427 this.source = state$;
428 }
429 select(pathOrMapFn, ...paths) {
430 return select.call(null, pathOrMapFn, ...paths)(this);
431 }
432 lift(operator) {
433 const store = new Store(this, this.actionsObserver, this.reducerManager);
434 store.operator = operator;
435 return store;
436 }
437 dispatch(action) {
438 this.actionsObserver.next(action);
439 }
440 next(action) {
441 this.actionsObserver.next(action);
442 }
443 error(err) {
444 this.actionsObserver.error(err);
445 }
446 complete() {
447 this.actionsObserver.complete();
448 }
449 addReducer(key, reducer) {
450 this.reducerManager.addReducer(key, reducer);
451 }
452 removeReducer(key) {
453 this.reducerManager.removeReducer(key);
454 }
455}
456Store.decorators = [
457 { type: Injectable }
458];
459/** @nocollapse */
460Store.ctorParameters = () => [
461 { type: StateObservable },
462 { type: ActionsSubject },
463 { type: ReducerManager }
464];
465const STORE_PROVIDERS = [Store];
466function select(pathOrMapFn, propsOrPath, ...paths) {
467 return function selectOperator(source$) {
468 let mapped$;
469 if (typeof pathOrMapFn === 'string') {
470 const pathSlices = [propsOrPath, ...paths].filter(Boolean);
471 mapped$ = source$.pipe(pluck(pathOrMapFn, ...pathSlices));
472 }
473 else if (typeof pathOrMapFn === 'function') {
474 mapped$ = source$.pipe(map((source) => pathOrMapFn(source, propsOrPath)));
475 }
476 else {
477 throw new TypeError(`Unexpected type '${typeof pathOrMapFn}' in select operator,` +
478 ` expected 'string' or 'function'`);
479 }
480 return mapped$.pipe(distinctUntilChanged());
481 };
482}
483
484function capitalize(text) {
485 return (text.charAt(0).toUpperCase() + text.substr(1));
486}
487
488const RUNTIME_CHECK_URL = 'https://ngrx.io/guide/store/configuration/runtime-checks';
489function isUndefined(target) {
490 return target === undefined;
491}
492function isNull(target) {
493 return target === null;
494}
495function isArray(target) {
496 return Array.isArray(target);
497}
498function isString(target) {
499 return typeof target === 'string';
500}
501function isBoolean(target) {
502 return typeof target === 'boolean';
503}
504function isNumber(target) {
505 return typeof target === 'number';
506}
507function isObjectLike(target) {
508 return typeof target === 'object' && target !== null;
509}
510function isObject(target) {
511 return isObjectLike(target) && !isArray(target);
512}
513function isPlainObject(target) {
514 if (!isObject(target)) {
515 return false;
516 }
517 const targetPrototype = Object.getPrototypeOf(target);
518 return targetPrototype === Object.prototype || targetPrototype === null;
519}
520function isFunction(target) {
521 return typeof target === 'function';
522}
523function isComponent(target) {
524 return isFunction(target) && target.hasOwnProperty('ɵcmp');
525}
526function hasOwnProperty(target, propertyName) {
527 return Object.prototype.hasOwnProperty.call(target, propertyName);
528}
529
530let _ngrxMockEnvironment = false;
531function setNgrxMockEnvironment(value) {
532 _ngrxMockEnvironment = value;
533}
534function isNgrxMockEnvironment() {
535 return _ngrxMockEnvironment;
536}
537
538function isEqualCheck(a, b) {
539 return a === b;
540}
541function isArgumentsChanged(args, lastArguments, comparator) {
542 for (let i = 0; i < args.length; i++) {
543 if (!comparator(args[i], lastArguments[i])) {
544 return true;
545 }
546 }
547 return false;
548}
549function resultMemoize(projectionFn, isResultEqual) {
550 return defaultMemoize(projectionFn, isEqualCheck, isResultEqual);
551}
552function defaultMemoize(projectionFn, isArgumentsEqual = isEqualCheck, isResultEqual = isEqualCheck) {
553 let lastArguments = null;
554 // eslint-disable-next-line @typescript-eslint/no-explicit-any, , , , ,
555 let lastResult = null;
556 let overrideResult;
557 function reset() {
558 lastArguments = null;
559 lastResult = null;
560 }
561 function setResult(result = undefined) {
562 overrideResult = { result };
563 }
564 function clearResult() {
565 overrideResult = undefined;
566 }
567 /* eslint-disable prefer-rest-params, prefer-spread */
568 // disabled because of the use of `arguments`
569 function memoized() {
570 if (overrideResult !== undefined) {
571 return overrideResult.result;
572 }
573 if (!lastArguments) {
574 lastResult = projectionFn.apply(null, arguments);
575 lastArguments = arguments;
576 return lastResult;
577 }
578 if (!isArgumentsChanged(arguments, lastArguments, isArgumentsEqual)) {
579 return lastResult;
580 }
581 const newResult = projectionFn.apply(null, arguments);
582 lastArguments = arguments;
583 if (isResultEqual(lastResult, newResult)) {
584 return lastResult;
585 }
586 lastResult = newResult;
587 return newResult;
588 }
589 return { memoized, reset, setResult, clearResult };
590}
591function createSelector(...input) {
592 return createSelectorFactory(defaultMemoize)(...input);
593}
594function defaultStateFn(state, selectors, props, memoizedProjector) {
595 if (props === undefined) {
596 const args = selectors.map((fn) => fn(state));
597 return memoizedProjector.memoized.apply(null, args);
598 }
599 const args = selectors.map((fn) => fn(state, props));
600 return memoizedProjector.memoized.apply(null, [...args, props]);
601}
602/**
603 *
604 * @param memoize The function used to memoize selectors
605 * @param options Config Object that may include a `stateFn` function defining how to return the selector's value, given the entire `Store`'s state, parent `Selector`s, `Props`, and a `MemoizedProjection`
606 *
607 * @usageNotes
608 *
609 * **Creating a Selector Factory Where Array Order Does Not Matter**
610 *
611 * ```ts
612 * function removeMatch(arr: string[], target: string): string[] {
613 * const matchIndex = arr.indexOf(target);
614 * return [...arr.slice(0, matchIndex), ...arr.slice(matchIndex + 1)];
615 * }
616 *
617 * function orderDoesNotMatterComparer(a: any, b: any): boolean {
618 * if (!Array.isArray(a) || !Array.isArray(b)) {
619 * return a === b;
620 * }
621 * if (a.length !== b.length) {
622 * return false;
623 * }
624 * let tempB = [...b];
625 * function reduceToDetermineIfArraysContainSameContents(
626 * previousCallResult: boolean,
627 * arrayMember: any
628 * ): boolean {
629 * if (previousCallResult === false) {
630 * return false;
631 * }
632 * if (tempB.includes(arrayMember)) {
633 * tempB = removeMatch(tempB, arrayMember);
634 * return true;
635 * }
636 * return false;
637 * }
638 * return a.reduce(reduceToDetermineIfArraysContainSameContents, true);
639 * }
640 *
641 * export const creactOrderDoesNotMatterSelector = createSelectorFactory(
642 * (projectionFun) => defaultMemoize(
643 * projectionFun,
644 * orderDoesNotMatterComparer,
645 * orderDoesNotMatterComparer
646 * )
647 * );
648 * ```
649 *
650 * **Creating an Alternative Memoization Strategy**
651 *
652 * ```ts
653 * function serialize(x: any): string {
654 * return JSON.stringify(x);
655 * }
656 *
657 * export const createFullHistorySelector = createSelectorFactory(
658 * (projectionFunction) => {
659 * const cache = {};
660 *
661 * function memoized() {
662 * const serializedArguments = serialize(...arguments);
663 * if (cache[serializedArguments] != null) {
664 * cache[serializedArguments] = projectionFunction.apply(null, arguments);
665 * }
666 * return cache[serializedArguments];
667 * }
668 * return {
669 * memoized,
670 * reset: () => {},
671 * setResult: () => {},
672 * clearResult: () => {},
673 * };
674 * }
675 * );
676 * ```
677 *
678 *
679 */
680function createSelectorFactory(memoize, options = {
681 stateFn: defaultStateFn,
682}) {
683 return function (...input) {
684 let args = input;
685 if (Array.isArray(args[0])) {
686 const [head, ...tail] = args;
687 args = [...head, ...tail];
688 }
689 const selectors = args.slice(0, args.length - 1);
690 const projector = args[args.length - 1];
691 const memoizedSelectors = selectors.filter((selector) => selector.release && typeof selector.release === 'function');
692 const memoizedProjector = memoize(function (...selectors) {
693 return projector.apply(null, selectors);
694 });
695 const memoizedState = defaultMemoize(function (state, props) {
696 return options.stateFn.apply(null, [
697 state,
698 selectors,
699 props,
700 memoizedProjector,
701 ]);
702 });
703 function release() {
704 memoizedState.reset();
705 memoizedProjector.reset();
706 memoizedSelectors.forEach((selector) => selector.release());
707 }
708 return Object.assign(memoizedState.memoized, {
709 release,
710 projector: memoizedProjector.memoized,
711 setResult: memoizedState.setResult,
712 clearResult: memoizedState.clearResult,
713 });
714 };
715}
716function createFeatureSelector(featureName) {
717 return createSelector((state) => {
718 const featureState = state[featureName];
719 if (!isNgrxMockEnvironment() && isDevMode() && !(featureName in state)) {
720 console.warn(`@ngrx/store: The feature name "${featureName}" does ` +
721 'not exist in the state, therefore createFeatureSelector ' +
722 'cannot access it. Be sure it is imported in a loaded module ' +
723 `using StoreModule.forRoot('${featureName}', ...) or ` +
724 `StoreModule.forFeature('${featureName}', ...). If the default ` +
725 'state is intended to be undefined, as is the case with router ' +
726 'state, this development-only warning message can be ignored.');
727 }
728 return featureState;
729 }, (featureState) => featureState);
730}
731
732/**
733 * @description
734 * A function that accepts a feature name and a feature reducer, and creates
735 * a feature selector and a selector for each feature state property.
736 *
737 * @param featureConfig An object that contains a feature name and a feature reducer.
738 * @returns An object that contains a feature name, a feature reducer,
739 * a feature selector, a the selector for each feature state property.
740 *
741 * @usageNotes
742 *
743 * **With Application State**
744 *
745 * ```ts
746 * interface AppState {
747 * products: ProductsState;
748 * }
749 *
750 * interface ProductsState {
751 * products: Product[];
752 * selectedId: string | null;
753 * }
754 *
755 * const initialState: ProductsState = {
756 * products: [],
757 * selectedId: null,
758 * };
759 *
760 * // AppState is passed as a generic argument
761 * const productsFeature = createFeature<AppState>({
762 * name: 'products',
763 * reducer: createReducer(
764 * initialState,
765 * on(ProductsApiActions.loadSuccess(state, { products }) => ({
766 * ...state,
767 * products,
768 * }),
769 * ),
770 * });
771 *
772 * const {
773 * selectProductsState, // type: MemoizedSelector<AppState, ProductsState>
774 * selectProducts, // type: MemoizedSelector<AppState, Product[]>
775 * selectSelectedId, // type: MemoizedSelector<AppState, string | null>
776 * } = productsFeature;
777 * ```
778 *
779 * **Without Application State**
780 *
781 * ```ts
782 * const productsFeature = createFeature({
783 * name: 'products',
784 * reducer: createReducer(initialState),
785 * });
786 *
787 * const {
788 * selectProductsState, // type: MemoizedSelector<Record<string, any>, ProductsState>
789 * selectProducts, // type: MemoizedSelector<Record<string, any>, Product[]>
790 * selectSelectedId, // type: MemoizedSelector<Record<string, any, string | null>
791 * } = productsFeature;
792 * ```
793 */
794function createFeature(featureConfig) {
795 const { name, reducer } = featureConfig;
796 const featureSelector = createFeatureSelector(name);
797 const nestedSelectors = createNestedSelectors(featureSelector, reducer);
798 return Object.assign({ name,
799 reducer, [`select${capitalize(name)}State`]: featureSelector }, nestedSelectors);
800}
801function createNestedSelectors(featureSelector, reducer) {
802 const initialState = getInitialState(reducer);
803 const nestedKeys = (isPlainObject(initialState)
804 ? Object.keys(initialState)
805 : []);
806 return nestedKeys.reduce((nestedSelectors, nestedKey) => (Object.assign(Object.assign({}, nestedSelectors), { [`select${capitalize(nestedKey)}`]: createSelector(featureSelector, (parentState) => parentState === null || parentState === void 0 ? void 0 : parentState[nestedKey]) })), {});
807}
808function getInitialState(reducer) {
809 return reducer(undefined, { type: '@ngrx/feature/init' });
810}
811
812function immutabilityCheckMetaReducer(reducer, checks) {
813 return function (state, action) {
814 const act = checks.action(action) ? freeze(action) : action;
815 const nextState = reducer(state, act);
816 return checks.state() ? freeze(nextState) : nextState;
817 };
818}
819function freeze(target) {
820 Object.freeze(target);
821 const targetIsFunction = isFunction(target);
822 Object.getOwnPropertyNames(target).forEach((prop) => {
823 // Ignore Ivy properties, ref: https://github.com/ngrx/platform/issues/2109#issuecomment-582689060
824 if (prop.startsWith('ɵ')) {
825 return;
826 }
827 if (hasOwnProperty(target, prop) &&
828 (targetIsFunction
829 ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments'
830 : true)) {
831 const propValue = target[prop];
832 if ((isObjectLike(propValue) || isFunction(propValue)) &&
833 !Object.isFrozen(propValue)) {
834 freeze(propValue);
835 }
836 }
837 });
838 return target;
839}
840
841function serializationCheckMetaReducer(reducer, checks) {
842 return function (state, action) {
843 if (checks.action(action)) {
844 const unserializableAction = getUnserializable(action);
845 throwIfUnserializable(unserializableAction, 'action');
846 }
847 const nextState = reducer(state, action);
848 if (checks.state()) {
849 const unserializableState = getUnserializable(nextState);
850 throwIfUnserializable(unserializableState, 'state');
851 }
852 return nextState;
853 };
854}
855function getUnserializable(target, path = []) {
856 // Guard against undefined and null, e.g. a reducer that returns undefined
857 if ((isUndefined(target) || isNull(target)) && path.length === 0) {
858 return {
859 path: ['root'],
860 value: target,
861 };
862 }
863 const keys = Object.keys(target);
864 return keys.reduce((result, key) => {
865 if (result) {
866 return result;
867 }
868 const value = target[key];
869 // Ignore Ivy components
870 if (isComponent(value)) {
871 return result;
872 }
873 if (isUndefined(value) ||
874 isNull(value) ||
875 isNumber(value) ||
876 isBoolean(value) ||
877 isString(value) ||
878 isArray(value)) {
879 return false;
880 }
881 if (isPlainObject(value)) {
882 return getUnserializable(value, [...path, key]);
883 }
884 return {
885 path: [...path, key],
886 value,
887 };
888 }, false);
889}
890function throwIfUnserializable(unserializable, context) {
891 if (unserializable === false) {
892 return;
893 }
894 const unserializablePath = unserializable.path.join('.');
895 const error = new Error(`Detected unserializable ${context} at "${unserializablePath}". ${RUNTIME_CHECK_URL}#strict${context}serializability`);
896 error.value = unserializable.value;
897 error.unserializablePath = unserializablePath;
898 throw error;
899}
900
901function inNgZoneAssertMetaReducer(reducer, checks) {
902 return function (state, action) {
903 if (checks.action(action) && !ngCore.NgZone.isInAngularZone()) {
904 throw new Error(`Action '${action.type}' running outside NgZone. ${RUNTIME_CHECK_URL}#strictactionwithinngzone`);
905 }
906 return reducer(state, action);
907 };
908}
909
910function createActiveRuntimeChecks(runtimeChecks) {
911 if (isDevMode()) {
912 return Object.assign({ strictStateSerializability: false, strictActionSerializability: false, strictStateImmutability: true, strictActionImmutability: true, strictActionWithinNgZone: false, strictActionTypeUniqueness: false }, runtimeChecks);
913 }
914 return {
915 strictStateSerializability: false,
916 strictActionSerializability: false,
917 strictStateImmutability: false,
918 strictActionImmutability: false,
919 strictActionWithinNgZone: false,
920 strictActionTypeUniqueness: false,
921 };
922}
923function createSerializationCheckMetaReducer({ strictActionSerializability, strictStateSerializability, }) {
924 return (reducer) => strictActionSerializability || strictStateSerializability
925 ? serializationCheckMetaReducer(reducer, {
926 action: (action) => strictActionSerializability && !ignoreNgrxAction(action),
927 state: () => strictStateSerializability,
928 })
929 : reducer;
930}
931function createImmutabilityCheckMetaReducer({ strictActionImmutability, strictStateImmutability, }) {
932 return (reducer) => strictActionImmutability || strictStateImmutability
933 ? immutabilityCheckMetaReducer(reducer, {
934 action: (action) => strictActionImmutability && !ignoreNgrxAction(action),
935 state: () => strictStateImmutability,
936 })
937 : reducer;
938}
939function ignoreNgrxAction(action) {
940 return action.type.startsWith('@ngrx');
941}
942function createInNgZoneCheckMetaReducer({ strictActionWithinNgZone, }) {
943 return (reducer) => strictActionWithinNgZone
944 ? inNgZoneAssertMetaReducer(reducer, {
945 action: (action) => strictActionWithinNgZone && !ignoreNgrxAction(action),
946 })
947 : reducer;
948}
949function provideRuntimeChecks(runtimeChecks) {
950 return [
951 {
952 provide: _USER_RUNTIME_CHECKS,
953 useValue: runtimeChecks,
954 },
955 {
956 provide: USER_RUNTIME_CHECKS,
957 useFactory: _runtimeChecksFactory,
958 deps: [_USER_RUNTIME_CHECKS],
959 },
960 {
961 provide: ACTIVE_RUNTIME_CHECKS,
962 deps: [USER_RUNTIME_CHECKS],
963 useFactory: createActiveRuntimeChecks,
964 },
965 {
966 provide: META_REDUCERS,
967 multi: true,
968 deps: [ACTIVE_RUNTIME_CHECKS],
969 useFactory: createImmutabilityCheckMetaReducer,
970 },
971 {
972 provide: META_REDUCERS,
973 multi: true,
974 deps: [ACTIVE_RUNTIME_CHECKS],
975 useFactory: createSerializationCheckMetaReducer,
976 },
977 {
978 provide: META_REDUCERS,
979 multi: true,
980 deps: [ACTIVE_RUNTIME_CHECKS],
981 useFactory: createInNgZoneCheckMetaReducer,
982 },
983 ];
984}
985function checkForActionTypeUniqueness() {
986 return [
987 {
988 provide: _ACTION_TYPE_UNIQUENESS_CHECK,
989 multi: true,
990 deps: [ACTIVE_RUNTIME_CHECKS],
991 useFactory: _actionTypeUniquenessCheck,
992 },
993 ];
994}
995function _runtimeChecksFactory(runtimeChecks) {
996 return runtimeChecks;
997}
998function _actionTypeUniquenessCheck(config) {
999 if (!config.strictActionTypeUniqueness) {
1000 return;
1001 }
1002 const duplicates = Object.entries(REGISTERED_ACTION_TYPES)
1003 .filter(([, registrations]) => registrations > 1)
1004 .map(([type]) => type);
1005 if (duplicates.length) {
1006 throw new Error(`Action types are registered more than once, ${duplicates
1007 .map((type) => `"${type}"`)
1008 .join(', ')}. ${RUNTIME_CHECK_URL}#strictactiontypeuniqueness`);
1009 }
1010}
1011
1012class StoreRootModule {
1013 constructor(actions$, reducer$, scannedActions$, store, guard, actionCheck) { }
1014}
1015StoreRootModule.decorators = [
1016 { type: NgModule, args: [{},] }
1017];
1018/** @nocollapse */
1019StoreRootModule.ctorParameters = () => [
1020 { type: ActionsSubject },
1021 { type: ReducerObservable },
1022 { type: ScannedActionsSubject },
1023 { type: Store },
1024 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [_ROOT_STORE_GUARD,] }] },
1025 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [_ACTION_TYPE_UNIQUENESS_CHECK,] }] }
1026];
1027class StoreFeatureModule {
1028 constructor(features, featureReducers, reducerManager, root, actionCheck) {
1029 this.features = features;
1030 this.featureReducers = featureReducers;
1031 this.reducerManager = reducerManager;
1032 const feats = features.map((feature, index) => {
1033 const featureReducerCollection = featureReducers.shift();
1034 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1035 const reducers = featureReducerCollection /*TODO(#823)*/[index];
1036 return Object.assign(Object.assign({}, feature), { reducers, initialState: _initialStateFactory(feature.initialState) });
1037 });
1038 reducerManager.addFeatures(feats);
1039 }
1040 // eslint-disable-next-line @angular-eslint/contextual-lifecycle
1041 ngOnDestroy() {
1042 this.reducerManager.removeFeatures(this.features);
1043 }
1044}
1045StoreFeatureModule.decorators = [
1046 { type: NgModule, args: [{},] }
1047];
1048/** @nocollapse */
1049StoreFeatureModule.ctorParameters = () => [
1050 { type: Array, decorators: [{ type: Inject, args: [_STORE_FEATURES,] }] },
1051 { type: Array, decorators: [{ type: Inject, args: [FEATURE_REDUCERS,] }] },
1052 { type: ReducerManager },
1053 { type: StoreRootModule },
1054 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [_ACTION_TYPE_UNIQUENESS_CHECK,] }] }
1055];
1056class StoreModule {
1057 static forRoot(reducers, config = {}) {
1058 return {
1059 ngModule: StoreRootModule,
1060 providers: [
1061 {
1062 provide: _ROOT_STORE_GUARD,
1063 useFactory: _provideForRootGuard,
1064 deps: [[Store, new Optional(), new SkipSelf()]],
1065 },
1066 { provide: _INITIAL_STATE, useValue: config.initialState },
1067 {
1068 provide: INITIAL_STATE,
1069 useFactory: _initialStateFactory,
1070 deps: [_INITIAL_STATE],
1071 },
1072 { provide: _INITIAL_REDUCERS, useValue: reducers },
1073 {
1074 provide: _STORE_REDUCERS,
1075 useExisting: reducers instanceof InjectionToken ? reducers : _INITIAL_REDUCERS,
1076 },
1077 {
1078 provide: INITIAL_REDUCERS,
1079 deps: [Injector, _INITIAL_REDUCERS, [new Inject(_STORE_REDUCERS)]],
1080 useFactory: _createStoreReducers,
1081 },
1082 {
1083 provide: USER_PROVIDED_META_REDUCERS,
1084 useValue: config.metaReducers ? config.metaReducers : [],
1085 },
1086 {
1087 provide: _RESOLVED_META_REDUCERS,
1088 deps: [META_REDUCERS, USER_PROVIDED_META_REDUCERS],
1089 useFactory: _concatMetaReducers,
1090 },
1091 {
1092 provide: _REDUCER_FACTORY,
1093 useValue: config.reducerFactory
1094 ? config.reducerFactory
1095 : combineReducers,
1096 },
1097 {
1098 provide: REDUCER_FACTORY,
1099 deps: [_REDUCER_FACTORY, _RESOLVED_META_REDUCERS],
1100 useFactory: createReducerFactory,
1101 },
1102 ACTIONS_SUBJECT_PROVIDERS,
1103 REDUCER_MANAGER_PROVIDERS,
1104 SCANNED_ACTIONS_SUBJECT_PROVIDERS,
1105 STATE_PROVIDERS,
1106 STORE_PROVIDERS,
1107 provideRuntimeChecks(config.runtimeChecks),
1108 checkForActionTypeUniqueness(),
1109 ],
1110 };
1111 }
1112 static forFeature(featureNameOrSlice, reducersOrConfig, config = {}) {
1113 return {
1114 ngModule: StoreFeatureModule,
1115 providers: [
1116 {
1117 provide: _FEATURE_CONFIGS,
1118 multi: true,
1119 useValue: featureNameOrSlice instanceof Object ? {} : config,
1120 },
1121 {
1122 provide: STORE_FEATURES,
1123 multi: true,
1124 useValue: {
1125 key: featureNameOrSlice instanceof Object
1126 ? featureNameOrSlice.name
1127 : featureNameOrSlice,
1128 reducerFactory: !(config instanceof InjectionToken) && config.reducerFactory
1129 ? config.reducerFactory
1130 : combineReducers,
1131 metaReducers: !(config instanceof InjectionToken) && config.metaReducers
1132 ? config.metaReducers
1133 : [],
1134 initialState: !(config instanceof InjectionToken) && config.initialState
1135 ? config.initialState
1136 : undefined,
1137 },
1138 },
1139 {
1140 provide: _STORE_FEATURES,
1141 deps: [Injector, _FEATURE_CONFIGS, STORE_FEATURES],
1142 useFactory: _createFeatureStore,
1143 },
1144 {
1145 provide: _FEATURE_REDUCERS,
1146 multi: true,
1147 useValue: featureNameOrSlice instanceof Object
1148 ? featureNameOrSlice.reducer
1149 : reducersOrConfig,
1150 },
1151 {
1152 provide: _FEATURE_REDUCERS_TOKEN,
1153 multi: true,
1154 useExisting: reducersOrConfig instanceof InjectionToken
1155 ? reducersOrConfig
1156 : _FEATURE_REDUCERS,
1157 },
1158 {
1159 provide: FEATURE_REDUCERS,
1160 multi: true,
1161 deps: [
1162 Injector,
1163 _FEATURE_REDUCERS,
1164 [new Inject(_FEATURE_REDUCERS_TOKEN)],
1165 ],
1166 useFactory: _createFeatureReducers,
1167 },
1168 checkForActionTypeUniqueness(),
1169 ],
1170 };
1171 }
1172}
1173StoreModule.decorators = [
1174 { type: NgModule, args: [{},] }
1175];
1176function _createStoreReducers(injector, reducers) {
1177 return reducers instanceof InjectionToken ? injector.get(reducers) : reducers;
1178}
1179function _createFeatureStore(injector, configs, featureStores) {
1180 return featureStores.map((feat, index) => {
1181 if (configs[index] instanceof InjectionToken) {
1182 const conf = injector.get(configs[index]);
1183 return {
1184 key: feat.key,
1185 reducerFactory: conf.reducerFactory
1186 ? conf.reducerFactory
1187 : combineReducers,
1188 metaReducers: conf.metaReducers ? conf.metaReducers : [],
1189 initialState: conf.initialState,
1190 };
1191 }
1192 return feat;
1193 });
1194}
1195function _createFeatureReducers(injector, reducerCollection) {
1196 const reducers = reducerCollection.map((reducer) => {
1197 return reducer instanceof InjectionToken ? injector.get(reducer) : reducer;
1198 });
1199 return reducers;
1200}
1201function _initialStateFactory(initialState) {
1202 if (typeof initialState === 'function') {
1203 return initialState();
1204 }
1205 return initialState;
1206}
1207function _concatMetaReducers(metaReducers, userProvidedMetaReducers) {
1208 return metaReducers.concat(userProvidedMetaReducers);
1209}
1210function _provideForRootGuard(store) {
1211 if (store) {
1212 throw new TypeError(`StoreModule.forRoot() called twice. Feature modules should use StoreModule.forFeature() instead.`);
1213 }
1214 return 'guarded';
1215}
1216
1217/**
1218 * @description
1219 * Associates actions with a given state change function.
1220 * A state change function must be provided as the last parameter.
1221 *
1222 * @param args `ActionCreator`'s followed by a state change function.
1223 *
1224 * @returns an association of action types with a state change function.
1225 *
1226 * @usageNotes
1227 * ```ts
1228 * on(AuthApiActions.loginSuccess, (state, { user }) => ({ ...state, user }))
1229 * ```
1230 */
1231function on(...args) {
1232 // This could be refactored when TS releases the version with this fix:
1233 // https://github.com/microsoft/TypeScript/pull/41544
1234 const reducer = args.pop();
1235 const types = args.map((creator) => creator.type);
1236 return { reducer, types };
1237}
1238/**
1239 * @description
1240 * Creates a reducer function to handle state transitions.
1241 *
1242 * Reducer creators reduce the explicitness of reducer functions with switch statements.
1243 *
1244 * @param initialState Provides a state value if the current state is `undefined`, as it is initially.
1245 * @param ons Associations between actions and state changes.
1246 * @returns A reducer function.
1247 *
1248 * @usageNotes
1249 *
1250 * - Must be used with `ActionCreator`'s (returned by `createAction`). Cannot be used with class-based action creators.
1251 * - The returned `ActionReducer` should additionally be wrapped with another function, if you are using View Engine AOT.
1252 * In case you are using Ivy (or only JIT View Engine) the extra wrapper function is not required.
1253 *
1254 * **Declaring a reducer creator**
1255 *
1256 * ```ts
1257 * export const reducer = createReducer(
1258 * initialState,
1259 * on(
1260 * featureActions.actionOne,
1261 * featureActions.actionTwo,
1262 * (state, { updatedValue }) => ({ ...state, prop: updatedValue })
1263 * ),
1264 * on(featureActions.actionThree, () => initialState);
1265 * );
1266 * ```
1267 *
1268 * **Declaring a reducer creator using a wrapper function (Only needed if using View Engine AOT)**
1269 *
1270 * ```ts
1271 * const featureReducer = createReducer(
1272 * initialState,
1273 * on(
1274 * featureActions.actionOne,
1275 * featureActions.actionTwo,
1276 * (state, { updatedValue }) => ({ ...state, prop: updatedValue })
1277 * ),
1278 * on(featureActions.actionThree, () => initialState);
1279 * );
1280 *
1281 * export function reducer(state: State | undefined, action: Action) {
1282 * return featureReducer(state, action);
1283 * }
1284 * ```
1285 */
1286function createReducer(initialState, ...ons) {
1287 const map = new Map();
1288 for (const on of ons) {
1289 for (const type of on.types) {
1290 const existingReducer = map.get(type);
1291 if (existingReducer) {
1292 const newReducer = (state, action) => on.reducer(existingReducer(state, action), action);
1293 map.set(type, newReducer);
1294 }
1295 else {
1296 map.set(type, on.reducer);
1297 }
1298 }
1299 }
1300 return function (state = initialState, action) {
1301 const reducer = map.get(action.type);
1302 return reducer ? reducer(state, action) : state;
1303 };
1304}
1305
1306/**
1307 * DO NOT EDIT
1308 *
1309 * This file is automatically generated at build
1310 */
1311
1312/**
1313 * Generated bundle index. Do not edit.
1314 */
1315
1316export { ACTIVE_RUNTIME_CHECKS, ActionsSubject, FEATURE_REDUCERS, INIT, INITIAL_REDUCERS, INITIAL_STATE, META_REDUCERS, REDUCER_FACTORY, ReducerManager, ReducerManagerDispatcher, ReducerObservable, STORE_FEATURES, ScannedActionsSubject, State, StateObservable, Store, StoreFeatureModule, StoreModule, StoreRootModule, UPDATE, USER_PROVIDED_META_REDUCERS, USER_RUNTIME_CHECKS, combineReducers, compose, createAction, createFeature, createFeatureSelector, createReducer, createReducerFactory, createSelector, createSelectorFactory, defaultMemoize, defaultStateFn, isNgrxMockEnvironment, on, props, reduceState, resultMemoize, select, setNgrxMockEnvironment, union, STORE_PROVIDERS as ɵb, createSerializationCheckMetaReducer as ɵba, createImmutabilityCheckMetaReducer as ɵbb, createInNgZoneCheckMetaReducer as ɵbc, provideRuntimeChecks as ɵbd, checkForActionTypeUniqueness as ɵbe, _runtimeChecksFactory as ɵbf, _actionTypeUniquenessCheck as ɵbg, ACTIONS_SUBJECT_PROVIDERS as ɵc, REDUCER_MANAGER_PROVIDERS as ɵd, SCANNED_ACTIONS_SUBJECT_PROVIDERS as ɵe, isEqualCheck as ɵf, STATE_PROVIDERS as ɵg, _ROOT_STORE_GUARD as ɵh, _INITIAL_STATE as ɵi, _REDUCER_FACTORY as ɵj, _INITIAL_REDUCERS as ɵk, _STORE_REDUCERS as ɵl, _FEATURE_REDUCERS as ɵm, _FEATURE_CONFIGS as ɵn, _STORE_FEATURES as ɵo, _FEATURE_REDUCERS_TOKEN as ɵp, _RESOLVED_META_REDUCERS as ɵq, _USER_RUNTIME_CHECKS as ɵr, _ACTION_TYPE_UNIQUENESS_CHECK as ɵs, _createStoreReducers as ɵt, _createFeatureStore as ɵu, _createFeatureReducers as ɵv, _initialStateFactory as ɵw, _concatMetaReducers as ɵx, _provideForRootGuard as ɵy, createActiveRuntimeChecks as ɵz };
1317//# sourceMappingURL=ngrx-store.js.map