@ngxs/store 18.1.1-dev.master-a8f62df → 18.1.1-dev.master-b178ff0
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/esm2022/internals/memoize.mjs +14 -3
- package/esm2022/src/actions/action-registry.mjs +34 -0
- package/esm2022/src/actions-stream.mjs +13 -5
- package/esm2022/src/internal/state-factory.mjs +68 -101
- package/fesm2022/ngxs-store-internals.mjs +13 -2
- package/fesm2022/ngxs-store-internals.mjs.map +1 -1
- package/fesm2022/ngxs-store.mjs +291 -279
- package/fesm2022/ngxs-store.mjs.map +1 -1
- package/package.json +7 -7
- package/src/actions/action-registry.d.ts +12 -0
- package/src/actions-stream.d.ts +3 -1
- package/src/internal/state-factory.d.ts +13 -25
package/fesm2022/ngxs-store.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, NgZone, PLATFORM_ID, Inject, InjectionToken, inject, INJECTOR, ErrorHandler, ɵisPromise as _isPromise,
|
|
3
|
-
import { Observable,
|
|
2
|
+
import { Injectable, NgZone, PLATFORM_ID, Inject, InjectionToken, inject, INJECTOR, ErrorHandler, Injector, ɵisPromise as _isPromise, computed, Optional, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule, APP_BOOTSTRAP_LISTENER } from '@angular/core';
|
|
3
|
+
import { Subject, filter, Observable, share, config, of, forkJoin, throwError, EMPTY, mergeMap, map as map$1, defaultIfEmpty, catchError, from, isObservable, takeUntil, shareReplay as shareReplay$1, distinctUntilChanged, take as take$1, ReplaySubject } from 'rxjs';
|
|
4
4
|
import * as i1 from '@ngxs/store/internals';
|
|
5
5
|
import { ɵwrapObserverCalls as _wrapObserverCalls, ɵOrderedSubject as _OrderedSubject, ɵmemoize as _memoize, ɵgetStoreMetadata as _getStoreMetadata, ɵgetSelectorMetadata as _getSelectorMetadata, ɵMETA_KEY as _META_KEY, ɵINITIAL_STATE_TOKEN as _INITIAL_STATE_TOKEN, ɵNgxsAppBootstrappedState as _NgxsAppBootstrappedState, ɵNGXS_STATE_CONTEXT_FACTORY as _NGXS_STATE_CONTEXT_FACTORY, ɵNGXS_STATE_FACTORY as _NGXS_STATE_FACTORY, ɵensureStoreMetadata as _ensureStoreMetadata, ɵMETA_OPTIONS_KEY as _META_OPTIONS_KEY, ɵensureSelectorMetadata as _ensureSelectorMetadata } from '@ngxs/store/internals';
|
|
6
6
|
export { StateToken } from '@ngxs/store/internals';
|
|
7
7
|
import { isPlatformServer } from '@angular/common';
|
|
8
|
-
import {
|
|
9
|
-
import { NGXS_PLUGINS, getActionTypeFromInstance,
|
|
8
|
+
import { map, shareReplay, filter as filter$1, take, exhaustMap, tap, mergeMap as mergeMap$1, takeUntil as takeUntil$1, startWith, pairwise } from 'rxjs/operators';
|
|
9
|
+
import { NGXS_PLUGINS, getActionTypeFromInstance, InitState, UpdateState, setValue, getValue } from '@ngxs/store/plugins';
|
|
10
10
|
export { InitState, NGXS_PLUGINS, UpdateState, actionMatcher, getActionTypeFromInstance, getValue, setValue } from '@ngxs/store/plugins';
|
|
11
11
|
import { isStateOperator } from '@ngxs/store/operators';
|
|
12
12
|
|
|
@@ -209,16 +209,25 @@ function leaveNgxs(ngxsExecutionStrategy) {
|
|
|
209
209
|
* Internal Action stream that is emitted anytime an action is dispatched.
|
|
210
210
|
*/
|
|
211
211
|
class InternalActions extends _OrderedSubject {
|
|
212
|
+
constructor() {
|
|
213
|
+
super();
|
|
214
|
+
// This subject will be the first to know about the dispatched action, its purpose is for
|
|
215
|
+
// any logic that must be executed before action handlers are invoked (i.e., cancelation).
|
|
216
|
+
this.dispatched$ = new Subject();
|
|
217
|
+
this.pipe(filter(ctx => ctx.status === "DISPATCHED" /* ActionStatus.Dispatched */)).subscribe(ctx => {
|
|
218
|
+
this.dispatched$.next(ctx);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
212
221
|
ngOnDestroy() {
|
|
213
222
|
this.complete();
|
|
214
223
|
}
|
|
215
|
-
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InternalActions, deps:
|
|
224
|
+
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InternalActions, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
216
225
|
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InternalActions, providedIn: 'root' }); }
|
|
217
226
|
}
|
|
218
227
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InternalActions, decorators: [{
|
|
219
228
|
type: Injectable,
|
|
220
229
|
args: [{ providedIn: 'root' }]
|
|
221
|
-
}] });
|
|
230
|
+
}], ctorParameters: () => [] });
|
|
222
231
|
/**
|
|
223
232
|
* Action stream that is emitted anytime an action is dispatched.
|
|
224
233
|
*
|
|
@@ -408,7 +417,7 @@ class InternalDispatcher {
|
|
|
408
417
|
])(prevState, action).pipe(shareReplay());
|
|
409
418
|
}
|
|
410
419
|
getActionResultStream(action) {
|
|
411
|
-
return this._actionResults.pipe(filter((ctx) => ctx.action === action && ctx.status !== "DISPATCHED" /* ActionStatus.Dispatched */), take(1), shareReplay());
|
|
420
|
+
return this._actionResults.pipe(filter$1((ctx) => ctx.action === action && ctx.status !== "DISPATCHED" /* ActionStatus.Dispatched */), take(1), shareReplay());
|
|
412
421
|
}
|
|
413
422
|
createDispatchObservable(actionResult$) {
|
|
414
423
|
return actionResult$
|
|
@@ -889,190 +898,37 @@ function topologicalSort(graph) {
|
|
|
889
898
|
return sorted.reverse();
|
|
890
899
|
}
|
|
891
900
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* RxJS operator for selecting out specific actions.
|
|
902
|
-
*
|
|
903
|
-
* This will ONLY grab actions that have just been dispatched
|
|
904
|
-
*/
|
|
905
|
-
function ofActionDispatched(...allowedTypes) {
|
|
906
|
-
return ofActionOperator(allowedTypes, ["DISPATCHED" /* ActionStatus.Dispatched */]);
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* RxJS operator for selecting out specific actions.
|
|
910
|
-
*
|
|
911
|
-
* This will ONLY grab actions that have just been successfully completed
|
|
912
|
-
*/
|
|
913
|
-
function ofActionSuccessful(...allowedTypes) {
|
|
914
|
-
return ofActionOperator(allowedTypes, ["SUCCESSFUL" /* ActionStatus.Successful */]);
|
|
915
|
-
}
|
|
916
|
-
/**
|
|
917
|
-
* RxJS operator for selecting out specific actions.
|
|
918
|
-
*
|
|
919
|
-
* This will ONLY grab actions that have just been canceled
|
|
920
|
-
*/
|
|
921
|
-
function ofActionCanceled(...allowedTypes) {
|
|
922
|
-
return ofActionOperator(allowedTypes, ["CANCELED" /* ActionStatus.Canceled */]);
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* RxJS operator for selecting out specific actions.
|
|
926
|
-
*
|
|
927
|
-
* This will ONLY grab actions that have just been completed
|
|
928
|
-
*/
|
|
929
|
-
function ofActionCompleted(...allowedTypes) {
|
|
930
|
-
const allowedStatuses = [
|
|
931
|
-
"SUCCESSFUL" /* ActionStatus.Successful */,
|
|
932
|
-
"CANCELED" /* ActionStatus.Canceled */,
|
|
933
|
-
"ERRORED" /* ActionStatus.Errored */
|
|
934
|
-
];
|
|
935
|
-
return ofActionOperator(allowedTypes, allowedStatuses, mapActionResult);
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* RxJS operator for selecting out specific actions.
|
|
939
|
-
*
|
|
940
|
-
* This will ONLY grab actions that have just thrown an error
|
|
941
|
-
*/
|
|
942
|
-
function ofActionErrored(...allowedTypes) {
|
|
943
|
-
return ofActionOperator(allowedTypes, ["ERRORED" /* ActionStatus.Errored */], mapActionResult);
|
|
944
|
-
}
|
|
945
|
-
function ofActionOperator(allowedTypes, statuses,
|
|
946
|
-
// This could have been written as
|
|
947
|
-
// `OperatorFunction<ActionContext, ActionCompletion | any>`, as it maps
|
|
948
|
-
// either to `ctx.action` or to `ActionCompletion`. However,
|
|
949
|
-
// `ActionCompletion | any` defaults to `any`, rendering the union
|
|
950
|
-
// type meaningless.
|
|
951
|
-
mapOperator = mapAction) {
|
|
952
|
-
const allowedMap = createAllowedActionTypesMap(allowedTypes);
|
|
953
|
-
const allowedStatusMap = statuses && createAllowedStatusesMap(statuses);
|
|
954
|
-
return function (o) {
|
|
955
|
-
return o.pipe(filterStatus(allowedMap, allowedStatusMap), mapOperator());
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
function filterStatus(allowedTypes, allowedStatuses) {
|
|
959
|
-
return filter((ctx) => {
|
|
960
|
-
const actionType = getActionTypeFromInstance(ctx.action);
|
|
961
|
-
const typeMatch = allowedTypes[actionType];
|
|
962
|
-
const statusMatch = allowedStatuses ? allowedStatuses[ctx.status] : true;
|
|
963
|
-
return typeMatch && statusMatch;
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
function mapActionResult() {
|
|
967
|
-
return map(({ action, status, error }) => {
|
|
968
|
-
return {
|
|
969
|
-
action,
|
|
970
|
-
result: {
|
|
971
|
-
successful: "SUCCESSFUL" /* ActionStatus.Successful */ === status,
|
|
972
|
-
canceled: "CANCELED" /* ActionStatus.Canceled */ === status,
|
|
973
|
-
error
|
|
974
|
-
}
|
|
975
|
-
};
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
function mapAction() {
|
|
979
|
-
return map((ctx) => ctx.action);
|
|
980
|
-
}
|
|
981
|
-
function createAllowedActionTypesMap(types) {
|
|
982
|
-
return types.reduce((filterMap, klass) => {
|
|
983
|
-
filterMap[getActionTypeFromInstance(klass)] = true;
|
|
984
|
-
return filterMap;
|
|
985
|
-
}, {});
|
|
986
|
-
}
|
|
987
|
-
function createAllowedStatusesMap(statuses) {
|
|
988
|
-
return statuses.reduce((filterMap, status) => {
|
|
989
|
-
filterMap[status] = true;
|
|
990
|
-
return filterMap;
|
|
991
|
-
}, {});
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
function simplePatch(value) {
|
|
995
|
-
return (existingState) => {
|
|
996
|
-
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
997
|
-
if (Array.isArray(value)) {
|
|
998
|
-
throwPatchingArrayError();
|
|
999
|
-
}
|
|
1000
|
-
else if (typeof value !== 'object') {
|
|
1001
|
-
throwPatchingPrimitiveError();
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
const newState = { ...existingState };
|
|
1005
|
-
for (const key in value) {
|
|
1006
|
-
// deep clone for patch compatibility
|
|
1007
|
-
newState[key] = value[key];
|
|
1008
|
-
}
|
|
1009
|
-
return newState;
|
|
1010
|
-
};
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
/**
|
|
1014
|
-
* State Context factory class
|
|
1015
|
-
* @ignore
|
|
1016
|
-
*/
|
|
1017
|
-
class StateContextFactory {
|
|
1018
|
-
constructor(_internalStateOperations) {
|
|
1019
|
-
this._internalStateOperations = _internalStateOperations;
|
|
901
|
+
class NgxsActionRegistry {
|
|
902
|
+
constructor() {
|
|
903
|
+
// Instead of going over the states list every time an action is dispatched,
|
|
904
|
+
// we are constructing a map of action types to lists of action metadata.
|
|
905
|
+
// If the `@@Init` action is handled in two different states, the action
|
|
906
|
+
// metadata list will contain two objects that have the state `instance` and
|
|
907
|
+
// method names to be used as action handlers (decorated with `@Action(InitState)`).
|
|
908
|
+
this._actionTypeToHandlersMap = new Map();
|
|
1020
909
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
setStateFromOperator(root, currentAppState, patchOperator, path);
|
|
1035
|
-
},
|
|
1036
|
-
setState(val) {
|
|
1037
|
-
const currentAppState = root.getState();
|
|
1038
|
-
if (isStateOperator(val)) {
|
|
1039
|
-
setStateFromOperator(root, currentAppState, val, path);
|
|
1040
|
-
}
|
|
1041
|
-
else {
|
|
1042
|
-
setStateValue(root, currentAppState, val, path);
|
|
1043
|
-
}
|
|
1044
|
-
},
|
|
1045
|
-
dispatch(actions) {
|
|
1046
|
-
return root.dispatch(actions);
|
|
1047
|
-
}
|
|
910
|
+
ngOnDestroy() {
|
|
911
|
+
this._actionTypeToHandlersMap.clear();
|
|
912
|
+
}
|
|
913
|
+
get(type) {
|
|
914
|
+
return this._actionTypeToHandlersMap.get(type);
|
|
915
|
+
}
|
|
916
|
+
register(type, handler) {
|
|
917
|
+
const handlers = this._actionTypeToHandlersMap.get(type) ?? new Set();
|
|
918
|
+
handlers.add(handler);
|
|
919
|
+
this._actionTypeToHandlersMap.set(type, handlers);
|
|
920
|
+
return () => {
|
|
921
|
+
const handlers = this._actionTypeToHandlersMap.get(type);
|
|
922
|
+
handlers.delete(handler);
|
|
1048
923
|
};
|
|
1049
924
|
}
|
|
1050
|
-
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type:
|
|
1051
|
-
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type:
|
|
925
|
+
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: NgxsActionRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
926
|
+
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: NgxsActionRegistry, providedIn: 'root' }); }
|
|
1052
927
|
}
|
|
1053
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type:
|
|
928
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: NgxsActionRegistry, decorators: [{
|
|
1054
929
|
type: Injectable,
|
|
1055
930
|
args: [{ providedIn: 'root' }]
|
|
1056
|
-
}]
|
|
1057
|
-
function setStateValue(root, currentAppState, newValue, path) {
|
|
1058
|
-
const newAppState = setValue(currentAppState, path, newValue);
|
|
1059
|
-
root.setState(newAppState);
|
|
1060
|
-
return newAppState;
|
|
1061
|
-
// In doing this refactoring I noticed that there is a 'bug' where the
|
|
1062
|
-
// application state is returned instead of this state slice.
|
|
1063
|
-
// This has worked this way since the beginning see:
|
|
1064
|
-
// https://github.com/ngxs/store/blame/324c667b4b7debd8eb979006c67ca0ae347d88cd/src/state-factory.ts
|
|
1065
|
-
// This needs to be fixed, but is a 'breaking' change.
|
|
1066
|
-
// I will do this fix in a subsequent PR and we can decide how to handle it.
|
|
1067
|
-
}
|
|
1068
|
-
function setStateFromOperator(root, currentAppState, stateOperator, path) {
|
|
1069
|
-
const local = getState(currentAppState, path);
|
|
1070
|
-
const newValue = stateOperator(local);
|
|
1071
|
-
return setStateValue(root, currentAppState, newValue, path);
|
|
1072
|
-
}
|
|
1073
|
-
function getState(currentAppState, path) {
|
|
1074
|
-
return getValue(currentAppState, path);
|
|
1075
|
-
}
|
|
931
|
+
}] });
|
|
1076
932
|
|
|
1077
933
|
const stateNameRegex = new RegExp('^[a-zA-Z0-9_]+$');
|
|
1078
934
|
function ensureStateNameIsValid(name) {
|
|
@@ -1195,6 +1051,191 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImpor
|
|
|
1195
1051
|
args: [{ providedIn: 'root' }]
|
|
1196
1052
|
}] });
|
|
1197
1053
|
|
|
1054
|
+
function simplePatch(value) {
|
|
1055
|
+
return (existingState) => {
|
|
1056
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
1057
|
+
if (Array.isArray(value)) {
|
|
1058
|
+
throwPatchingArrayError();
|
|
1059
|
+
}
|
|
1060
|
+
else if (typeof value !== 'object') {
|
|
1061
|
+
throwPatchingPrimitiveError();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
const newState = { ...existingState };
|
|
1065
|
+
for (const key in value) {
|
|
1066
|
+
// deep clone for patch compatibility
|
|
1067
|
+
newState[key] = value[key];
|
|
1068
|
+
}
|
|
1069
|
+
return newState;
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* State Context factory class
|
|
1075
|
+
* @ignore
|
|
1076
|
+
*/
|
|
1077
|
+
class StateContextFactory {
|
|
1078
|
+
constructor(_internalStateOperations) {
|
|
1079
|
+
this._internalStateOperations = _internalStateOperations;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Create the state context
|
|
1083
|
+
*/
|
|
1084
|
+
createStateContext(path) {
|
|
1085
|
+
const root = this._internalStateOperations.getRootStateOperations();
|
|
1086
|
+
return {
|
|
1087
|
+
getState() {
|
|
1088
|
+
const currentAppState = root.getState();
|
|
1089
|
+
return getState(currentAppState, path);
|
|
1090
|
+
},
|
|
1091
|
+
patchState(val) {
|
|
1092
|
+
const currentAppState = root.getState();
|
|
1093
|
+
const patchOperator = simplePatch(val);
|
|
1094
|
+
setStateFromOperator(root, currentAppState, patchOperator, path);
|
|
1095
|
+
},
|
|
1096
|
+
setState(val) {
|
|
1097
|
+
const currentAppState = root.getState();
|
|
1098
|
+
if (isStateOperator(val)) {
|
|
1099
|
+
setStateFromOperator(root, currentAppState, val, path);
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
setStateValue(root, currentAppState, val, path);
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
dispatch(actions) {
|
|
1106
|
+
return root.dispatch(actions);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateContextFactory, deps: [{ token: InternalStateOperations }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1111
|
+
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateContextFactory, providedIn: 'root' }); }
|
|
1112
|
+
}
|
|
1113
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateContextFactory, decorators: [{
|
|
1114
|
+
type: Injectable,
|
|
1115
|
+
args: [{ providedIn: 'root' }]
|
|
1116
|
+
}], ctorParameters: () => [{ type: InternalStateOperations }] });
|
|
1117
|
+
function setStateValue(root, currentAppState, newValue, path) {
|
|
1118
|
+
const newAppState = setValue(currentAppState, path, newValue);
|
|
1119
|
+
root.setState(newAppState);
|
|
1120
|
+
return newAppState;
|
|
1121
|
+
// In doing this refactoring I noticed that there is a 'bug' where the
|
|
1122
|
+
// application state is returned instead of this state slice.
|
|
1123
|
+
// This has worked this way since the beginning see:
|
|
1124
|
+
// https://github.com/ngxs/store/blame/324c667b4b7debd8eb979006c67ca0ae347d88cd/src/state-factory.ts
|
|
1125
|
+
// This needs to be fixed, but is a 'breaking' change.
|
|
1126
|
+
// I will do this fix in a subsequent PR and we can decide how to handle it.
|
|
1127
|
+
}
|
|
1128
|
+
function setStateFromOperator(root, currentAppState, stateOperator, path) {
|
|
1129
|
+
const local = getState(currentAppState, path);
|
|
1130
|
+
const newValue = stateOperator(local);
|
|
1131
|
+
return setStateValue(root, currentAppState, newValue, path);
|
|
1132
|
+
}
|
|
1133
|
+
function getState(currentAppState, path) {
|
|
1134
|
+
return getValue(currentAppState, path);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* RxJS operator for selecting out specific actions.
|
|
1139
|
+
*
|
|
1140
|
+
* This will grab actions that have just been dispatched as well as actions that have completed
|
|
1141
|
+
*/
|
|
1142
|
+
function ofAction(...allowedTypes) {
|
|
1143
|
+
return ofActionOperator(allowedTypes);
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* RxJS operator for selecting out specific actions.
|
|
1147
|
+
*
|
|
1148
|
+
* This will ONLY grab actions that have just been dispatched
|
|
1149
|
+
*/
|
|
1150
|
+
function ofActionDispatched(...allowedTypes) {
|
|
1151
|
+
return ofActionOperator(allowedTypes, ["DISPATCHED" /* ActionStatus.Dispatched */]);
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* RxJS operator for selecting out specific actions.
|
|
1155
|
+
*
|
|
1156
|
+
* This will ONLY grab actions that have just been successfully completed
|
|
1157
|
+
*/
|
|
1158
|
+
function ofActionSuccessful(...allowedTypes) {
|
|
1159
|
+
return ofActionOperator(allowedTypes, ["SUCCESSFUL" /* ActionStatus.Successful */]);
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* RxJS operator for selecting out specific actions.
|
|
1163
|
+
*
|
|
1164
|
+
* This will ONLY grab actions that have just been canceled
|
|
1165
|
+
*/
|
|
1166
|
+
function ofActionCanceled(...allowedTypes) {
|
|
1167
|
+
return ofActionOperator(allowedTypes, ["CANCELED" /* ActionStatus.Canceled */]);
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* RxJS operator for selecting out specific actions.
|
|
1171
|
+
*
|
|
1172
|
+
* This will ONLY grab actions that have just been completed
|
|
1173
|
+
*/
|
|
1174
|
+
function ofActionCompleted(...allowedTypes) {
|
|
1175
|
+
const allowedStatuses = [
|
|
1176
|
+
"SUCCESSFUL" /* ActionStatus.Successful */,
|
|
1177
|
+
"CANCELED" /* ActionStatus.Canceled */,
|
|
1178
|
+
"ERRORED" /* ActionStatus.Errored */
|
|
1179
|
+
];
|
|
1180
|
+
return ofActionOperator(allowedTypes, allowedStatuses, mapActionResult);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* RxJS operator for selecting out specific actions.
|
|
1184
|
+
*
|
|
1185
|
+
* This will ONLY grab actions that have just thrown an error
|
|
1186
|
+
*/
|
|
1187
|
+
function ofActionErrored(...allowedTypes) {
|
|
1188
|
+
return ofActionOperator(allowedTypes, ["ERRORED" /* ActionStatus.Errored */], mapActionResult);
|
|
1189
|
+
}
|
|
1190
|
+
function ofActionOperator(allowedTypes, statuses,
|
|
1191
|
+
// This could have been written as
|
|
1192
|
+
// `OperatorFunction<ActionContext, ActionCompletion | any>`, as it maps
|
|
1193
|
+
// either to `ctx.action` or to `ActionCompletion`. However,
|
|
1194
|
+
// `ActionCompletion | any` defaults to `any`, rendering the union
|
|
1195
|
+
// type meaningless.
|
|
1196
|
+
mapOperator = mapAction) {
|
|
1197
|
+
const allowedMap = createAllowedActionTypesMap(allowedTypes);
|
|
1198
|
+
const allowedStatusMap = statuses && createAllowedStatusesMap(statuses);
|
|
1199
|
+
return function (o) {
|
|
1200
|
+
return o.pipe(filterStatus(allowedMap, allowedStatusMap), mapOperator());
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
function filterStatus(allowedTypes, allowedStatuses) {
|
|
1204
|
+
return filter$1((ctx) => {
|
|
1205
|
+
const actionType = getActionTypeFromInstance(ctx.action);
|
|
1206
|
+
const typeMatch = allowedTypes[actionType];
|
|
1207
|
+
const statusMatch = allowedStatuses ? allowedStatuses[ctx.status] : true;
|
|
1208
|
+
return typeMatch && statusMatch;
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
function mapActionResult() {
|
|
1212
|
+
return map(({ action, status, error }) => {
|
|
1213
|
+
return {
|
|
1214
|
+
action,
|
|
1215
|
+
result: {
|
|
1216
|
+
successful: "SUCCESSFUL" /* ActionStatus.Successful */ === status,
|
|
1217
|
+
canceled: "CANCELED" /* ActionStatus.Canceled */ === status,
|
|
1218
|
+
error
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
function mapAction() {
|
|
1224
|
+
return map((ctx) => ctx.action);
|
|
1225
|
+
}
|
|
1226
|
+
function createAllowedActionTypesMap(types) {
|
|
1227
|
+
return types.reduce((filterMap, klass) => {
|
|
1228
|
+
filterMap[getActionTypeFromInstance(klass)] = true;
|
|
1229
|
+
return filterMap;
|
|
1230
|
+
}, {});
|
|
1231
|
+
}
|
|
1232
|
+
function createAllowedStatusesMap(statuses) {
|
|
1233
|
+
return statuses.reduce((filterMap, status) => {
|
|
1234
|
+
filterMap[status] = true;
|
|
1235
|
+
return filterMap;
|
|
1236
|
+
}, {});
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1198
1239
|
const NG_DEV_MODE$3 = typeof ngDevMode !== 'undefined' && ngDevMode;
|
|
1199
1240
|
function cloneDefaults(defaults) {
|
|
1200
1241
|
let value = defaults === undefined ? {} : defaults;
|
|
@@ -1222,23 +1263,18 @@ function cloneDefaults(defaults) {
|
|
|
1222
1263
|
* @ignore
|
|
1223
1264
|
*/
|
|
1224
1265
|
class StateFactory {
|
|
1225
|
-
constructor(
|
|
1226
|
-
this._injector =
|
|
1227
|
-
this._config =
|
|
1228
|
-
this._parentFactory =
|
|
1229
|
-
this.
|
|
1230
|
-
this.
|
|
1231
|
-
this.
|
|
1232
|
-
this._initialState =
|
|
1233
|
-
this.
|
|
1266
|
+
constructor() {
|
|
1267
|
+
this._injector = inject(Injector);
|
|
1268
|
+
this._config = inject(NgxsConfig);
|
|
1269
|
+
this._parentFactory = inject(StateFactory, { optional: true, skipSelf: true });
|
|
1270
|
+
this._stateContextFactory = inject(StateContextFactory);
|
|
1271
|
+
this._actions = inject(InternalActions);
|
|
1272
|
+
this._actionResults = inject(InternalDispatchedActionResults);
|
|
1273
|
+
this._initialState = inject(_INITIAL_STATE_TOKEN, { optional: true });
|
|
1274
|
+
this._actionRegistry = inject(NgxsActionRegistry);
|
|
1234
1275
|
this._propGetter = inject(ɵPROP_GETTER);
|
|
1276
|
+
this._actionsSubscription = null;
|
|
1235
1277
|
this._ngxsUnhandledErrorHandler = null;
|
|
1236
|
-
// Instead of going over the states list every time an action is dispatched,
|
|
1237
|
-
// we are constructing a map of action types to lists of action metadata.
|
|
1238
|
-
// If the `@@Init` action is handled in two different states, the action
|
|
1239
|
-
// metadata list will contain two objects that have the state `instance` and
|
|
1240
|
-
// method names to be used as action handlers (decorated with `@Action(InitState)`).
|
|
1241
|
-
this._actionTypeToMetasMap = new Map();
|
|
1242
1278
|
this._states = [];
|
|
1243
1279
|
this._statesByName = {};
|
|
1244
1280
|
this._statePaths = {};
|
|
@@ -1279,11 +1315,6 @@ class StateFactory {
|
|
|
1279
1315
|
return context;
|
|
1280
1316
|
});
|
|
1281
1317
|
}
|
|
1282
|
-
get actionTypeToMetasMap() {
|
|
1283
|
-
return this._parentFactory
|
|
1284
|
-
? this._parentFactory.actionTypeToMetasMap
|
|
1285
|
-
: this._actionTypeToMetasMap;
|
|
1286
|
-
}
|
|
1287
1318
|
get states() {
|
|
1288
1319
|
return this._parentFactory ? this._parentFactory.states : this._states;
|
|
1289
1320
|
}
|
|
@@ -1358,12 +1389,10 @@ class StateFactory {
|
|
|
1358
1389
|
if (this._parentFactory || this._actionsSubscription !== null) {
|
|
1359
1390
|
return;
|
|
1360
1391
|
}
|
|
1361
|
-
const dispatched$ = new Subject();
|
|
1362
1392
|
this._actionsSubscription = this._actions
|
|
1363
1393
|
.pipe(filter((ctx) => ctx.status === "DISPATCHED" /* ActionStatus.Dispatched */), mergeMap(ctx => {
|
|
1364
|
-
dispatched$.next(ctx);
|
|
1365
1394
|
const action = ctx.action;
|
|
1366
|
-
return this.invokeActions(
|
|
1395
|
+
return this.invokeActions(action).pipe(map$1(() => ({ action, status: "SUCCESSFUL" /* ActionStatus.Successful */ })), defaultIfEmpty({ action, status: "CANCELED" /* ActionStatus.Canceled */ }), catchError(error => {
|
|
1367
1396
|
const ngxsUnhandledErrorHandler = (this._ngxsUnhandledErrorHandler ||=
|
|
1368
1397
|
this._injector.get(NgxsUnhandledErrorHandler));
|
|
1369
1398
|
const handleableError = assignUnhandledCallback(error, () => ngxsUnhandledErrorHandler.handleError(error, { action }));
|
|
@@ -1379,53 +1408,18 @@ class StateFactory {
|
|
|
1379
1408
|
/**
|
|
1380
1409
|
* Invoke actions on the states.
|
|
1381
1410
|
*/
|
|
1382
|
-
invokeActions(
|
|
1411
|
+
invokeActions(action) {
|
|
1383
1412
|
const type = getActionTypeFromInstance(action);
|
|
1384
1413
|
const results = [];
|
|
1385
1414
|
// Determines whether the dispatched action has been handled, this is assigned
|
|
1386
1415
|
// to `true` within the below `for` loop if any `actionMetas` has been found.
|
|
1387
1416
|
let actionHasBeenHandled = false;
|
|
1388
|
-
const
|
|
1389
|
-
if (
|
|
1390
|
-
for (const
|
|
1391
|
-
const stateContext = this._stateContextFactory.createStateContext(actionMeta.path);
|
|
1417
|
+
const actionHandlers = this._actionRegistry.get(type);
|
|
1418
|
+
if (actionHandlers) {
|
|
1419
|
+
for (const actionHandler of actionHandlers) {
|
|
1392
1420
|
let result;
|
|
1393
1421
|
try {
|
|
1394
|
-
result =
|
|
1395
|
-
// We need to use `isPromise` instead of checking whether
|
|
1396
|
-
// `result instanceof Promise`. In zone.js patched environments, `global.Promise`
|
|
1397
|
-
// is the `ZoneAwarePromise`. Some APIs, which are likely not patched by zone.js
|
|
1398
|
-
// for certain reasons, might not work with `instanceof`. For instance, the dynamic
|
|
1399
|
-
// import returns a native promise (not a `ZoneAwarePromise`), causing this check to
|
|
1400
|
-
// be falsy.
|
|
1401
|
-
if (_isPromise(result)) {
|
|
1402
|
-
result = from(result);
|
|
1403
|
-
}
|
|
1404
|
-
if (isObservable(result)) {
|
|
1405
|
-
result = result.pipe(mergeMap((value) => {
|
|
1406
|
-
if (_isPromise(value)) {
|
|
1407
|
-
return from(value);
|
|
1408
|
-
}
|
|
1409
|
-
if (isObservable(value)) {
|
|
1410
|
-
return value;
|
|
1411
|
-
}
|
|
1412
|
-
return of(value);
|
|
1413
|
-
}),
|
|
1414
|
-
// If this observable has completed without emitting any values,
|
|
1415
|
-
// we wouldn't want to complete the entire chain of actions.
|
|
1416
|
-
// If any observable completes, then the action will be canceled.
|
|
1417
|
-
// For instance, if any action handler had a statement like
|
|
1418
|
-
// `handler(ctx) { return EMPTY; }`, then the action would be canceled.
|
|
1419
|
-
// See https://github.com/ngxs/store/issues/1568
|
|
1420
|
-
defaultIfEmpty({}));
|
|
1421
|
-
if (actionMeta.options.cancelUncompleted) {
|
|
1422
|
-
// todo: ofActionDispatched should be used with action class
|
|
1423
|
-
result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
else {
|
|
1427
|
-
result = of({}).pipe(shareReplay());
|
|
1428
|
-
}
|
|
1422
|
+
result = actionHandler(action);
|
|
1429
1423
|
}
|
|
1430
1424
|
catch (e) {
|
|
1431
1425
|
result = throwError(e);
|
|
@@ -1478,42 +1472,60 @@ class StateFactory {
|
|
|
1478
1472
|
return this.statesByName[name] && valueIsBootstrappedInInitialState;
|
|
1479
1473
|
}
|
|
1480
1474
|
hydrateActionMetasMap({ path, actions, instance }) {
|
|
1481
|
-
const
|
|
1475
|
+
const { dispatched$ } = this._actions;
|
|
1482
1476
|
for (const actionType of Object.keys(actions)) {
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1477
|
+
const actionHandlers = actions[actionType].map(actionMeta => {
|
|
1478
|
+
// action: Instance<ActionType>
|
|
1479
|
+
return (action) => {
|
|
1480
|
+
const stateContext = this._stateContextFactory.createStateContext(path);
|
|
1481
|
+
let result = instance[actionMeta.fn](stateContext, action);
|
|
1482
|
+
// We need to use `isPromise` instead of checking whether
|
|
1483
|
+
// `result instanceof Promise`. In zone.js patched environments, `global.Promise`
|
|
1484
|
+
// is the `ZoneAwarePromise`. Some APIs, which are likely not patched by zone.js
|
|
1485
|
+
// for certain reasons, might not work with `instanceof`. For instance, the dynamic
|
|
1486
|
+
// import returns a native promise (not a `ZoneAwarePromise`), causing this check to
|
|
1487
|
+
// be falsy.
|
|
1488
|
+
if (_isPromise(result)) {
|
|
1489
|
+
result = from(result);
|
|
1490
|
+
}
|
|
1491
|
+
if (isObservable(result)) {
|
|
1492
|
+
result = result.pipe(mergeMap((value) => {
|
|
1493
|
+
if (_isPromise(value)) {
|
|
1494
|
+
return from(value);
|
|
1495
|
+
}
|
|
1496
|
+
if (isObservable(value)) {
|
|
1497
|
+
return value;
|
|
1498
|
+
}
|
|
1499
|
+
return of(value);
|
|
1500
|
+
}),
|
|
1501
|
+
// If this observable has completed without emitting any values,
|
|
1502
|
+
// we wouldn't want to complete the entire chain of actions.
|
|
1503
|
+
// If any observable completes, then the action will be canceled.
|
|
1504
|
+
// For instance, if any action handler had a statement like
|
|
1505
|
+
// `handler(ctx) { return EMPTY; }`, then the action would be canceled.
|
|
1506
|
+
// See https://github.com/ngxs/store/issues/1568
|
|
1507
|
+
defaultIfEmpty({}));
|
|
1508
|
+
if (actionMeta.options.cancelUncompleted) {
|
|
1509
|
+
result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
else {
|
|
1513
|
+
result = of({}).pipe(shareReplay$1());
|
|
1514
|
+
}
|
|
1515
|
+
return result;
|
|
1516
|
+
};
|
|
1517
|
+
});
|
|
1518
|
+
for (const actionHandler of actionHandlers) {
|
|
1519
|
+
this._actionRegistry.register(actionType, actionHandler);
|
|
1488
1520
|
}
|
|
1489
|
-
const extendedActionMetas = actionTypeToMetasMap.get(actionType);
|
|
1490
|
-
extendedActionMetas.push(
|
|
1491
|
-
// This involves combining each individual action metadata with
|
|
1492
|
-
// the state instance and the path—essentially everything needed
|
|
1493
|
-
// to invoke an action. This eliminates the need to loop over states
|
|
1494
|
-
// every time an action is dispatched.
|
|
1495
|
-
...actions[actionType].map(actionMeta => ({
|
|
1496
|
-
...actionMeta,
|
|
1497
|
-
path,
|
|
1498
|
-
instance
|
|
1499
|
-
})));
|
|
1500
1521
|
}
|
|
1501
1522
|
}
|
|
1502
|
-
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory, deps: [
|
|
1523
|
+
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1503
1524
|
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory }); }
|
|
1504
1525
|
}
|
|
1505
1526
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory, decorators: [{
|
|
1506
1527
|
type: Injectable
|
|
1507
|
-
}]
|
|
1508
|
-
type: Optional
|
|
1509
|
-
}, {
|
|
1510
|
-
type: SkipSelf
|
|
1511
|
-
}] }, { type: InternalActions }, { type: InternalDispatchedActionResults }, { type: StateContextFactory }, { type: undefined, decorators: [{
|
|
1512
|
-
type: Optional
|
|
1513
|
-
}, {
|
|
1514
|
-
type: Inject,
|
|
1515
|
-
args: [_INITIAL_STATE_TOKEN]
|
|
1516
|
-
}] }] });
|
|
1528
|
+
}] });
|
|
1517
1529
|
|
|
1518
1530
|
class Store {
|
|
1519
1531
|
constructor(_stateStream, _internalStateOperations, _config, _internalExecutionStrategy, _stateFactory, initialStateValue) {
|
|
@@ -1541,7 +1553,7 @@ class Store {
|
|
|
1541
1553
|
*/
|
|
1542
1554
|
select(selector) {
|
|
1543
1555
|
const selectorFn = this.getStoreBoundSelectorFn(selector);
|
|
1544
|
-
return this._selectableStateStream.pipe(map$1(selectorFn), catchError
|
|
1556
|
+
return this._selectableStateStream.pipe(map$1(selectorFn), catchError((error) => {
|
|
1545
1557
|
// if error is TypeError we swallow it to prevent usual errors with property access
|
|
1546
1558
|
if (this._config.selectorOptions.suppressErrors && error instanceof TypeError) {
|
|
1547
1559
|
return of(undefined);
|
|
@@ -1701,7 +1713,7 @@ class LifecycleStateManager {
|
|
|
1701
1713
|
this._internalStateOperations
|
|
1702
1714
|
.getRootStateOperations()
|
|
1703
1715
|
.dispatch(action)
|
|
1704
|
-
.pipe(filter(() => !!results), tap(() => this._invokeInitOnStates(results.states)), mergeMap(() => this._appBootstrappedState), filter(appBootstrapped => !!appBootstrapped), takeUntil(this._destroy$))
|
|
1716
|
+
.pipe(filter$1(() => !!results), tap(() => this._invokeInitOnStates(results.states)), mergeMap$1(() => this._appBootstrappedState), filter$1(appBootstrapped => !!appBootstrapped), takeUntil$1(this._destroy$))
|
|
1705
1717
|
.subscribe(() => this._invokeBootstrapOnStates(results.states));
|
|
1706
1718
|
}
|
|
1707
1719
|
_invokeInitOnStates(mappedStores) {
|
|
@@ -1710,7 +1722,7 @@ class LifecycleStateManager {
|
|
|
1710
1722
|
if (instance.ngxsOnChanges) {
|
|
1711
1723
|
this._store
|
|
1712
1724
|
.select(state => getValue(state, mappedStore.path))
|
|
1713
|
-
.pipe(startWith(undefined), pairwise(), takeUntil(this._destroy$))
|
|
1725
|
+
.pipe(startWith(undefined), pairwise(), takeUntil$1(this._destroy$))
|
|
1714
1726
|
.subscribe(([previousValue, currentValue]) => {
|
|
1715
1727
|
const change = new NgxsSimpleChange(previousValue, currentValue, !mappedStore.isInitialised);
|
|
1716
1728
|
instance.ngxsOnChanges(change);
|