@mic-rexjs/usecases-react 2.0.2 → 2.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.
Files changed (102) hide show
  1. package/dist/index.min.js +1 -1
  2. package/es/components/UseCaseFragment/index.d.ts +2 -2
  3. package/es/components/UseCaseFragment/types.d.ts +3 -3
  4. package/es/configs/defaultUseCaseContext/index.d.ts +2 -3
  5. package/es/configs/defaultUseCaseContext/types.d.ts +13 -12
  6. package/es/configs/useCaseContextReferenceMap/types.d.ts +5 -5
  7. package/es/enums/UseCaseArgumentTypes/index.d.ts +5 -0
  8. package/es/enums/UseCaseArgumentTypes/index.js +6 -0
  9. package/es/enums/UseCaseStatuses/index.d.ts +10 -0
  10. package/es/enums/UseCaseStatuses/index.js +18 -0
  11. package/es/hooks/useArgumentTypes/index.d.ts +3 -0
  12. package/es/hooks/useArgumentTypes/index.js +19 -0
  13. package/es/hooks/useContextualItem/index.d.ts +3 -0
  14. package/es/hooks/useContextualItem/index.js +13 -0
  15. package/es/hooks/useContextualItem/types.d.ts +3 -0
  16. package/es/hooks/useEntity/index.d.ts +4 -0
  17. package/es/hooks/useEntity/index.js +49 -0
  18. package/es/hooks/useGlobalUseCase/index.js +3 -8
  19. package/es/hooks/useGlobalUseCase/index.test.js +10 -30
  20. package/es/hooks/useGlobalUseCase/types.d.ts +7 -10
  21. package/es/hooks/useMemoizedCall/index.d.ts +2 -0
  22. package/es/hooks/useMemoizedCall/index.js +15 -0
  23. package/es/hooks/useProvider/index.d.ts +4 -4
  24. package/es/hooks/useProvider/index.js +22 -15
  25. package/es/hooks/useStatelessUseCase/index.js +2 -5
  26. package/es/hooks/useStatelessUseCase/index.test.js +4 -42
  27. package/es/hooks/useStatelessUseCase/types.d.ts +2 -4
  28. package/es/hooks/useUseCase/index.js +44 -74
  29. package/es/hooks/useUseCase/index.test.js +26 -1
  30. package/es/hooks/useUseCase/types.d.ts +32 -45
  31. package/es/hooks/useUseCaseContext/index.d.ts +5 -3
  32. package/es/hooks/useUseCaseContext/index.js +10 -3
  33. package/es/hooks/useUseCaseContext/index.test.js +39 -12
  34. package/es/hooks/useUseCaseStatuses/index.d.ts +6 -0
  35. package/es/hooks/useUseCaseStatuses/index.js +29 -0
  36. package/es/index.d.ts +1 -1
  37. package/es/methods/cacheCall/index.d.ts +2 -0
  38. package/es/methods/cacheCall/index.js +26 -0
  39. package/es/methods/cacheCall/types.d.ts +13 -0
  40. package/es/methods/cacheCalls/index.d.ts +2 -0
  41. package/es/methods/cacheCalls/index.js +8 -0
  42. package/es/methods/fillArguments/index.d.ts +5 -0
  43. package/es/methods/fillArguments/index.js +41 -0
  44. package/es/methods/fillArguments/types.d.ts +10 -0
  45. package/es/methods/fillArguments/types.js +1 -0
  46. package/es/methods/getRenderingEntity/index.d.ts +3 -0
  47. package/es/methods/getRenderingEntity/index.js +13 -0
  48. package/es/methods/initEntityReducers/index.d.ts +2 -3
  49. package/es/methods/initEntityReducers/index.js +2 -3
  50. package/es/methods/transformGlobalArguments/index.d.ts +3 -0
  51. package/es/methods/transformGlobalArguments/index.js +8 -0
  52. package/es/methods/transformGlobalArguments/types.d.ts +2 -0
  53. package/es/methods/transformGlobalArguments/types.js +1 -0
  54. package/es/methods/triggerCallbacks/index.d.ts +1 -1
  55. package/es/methods/triggerCallbacks/index.js +3 -3
  56. package/lib/enums/UseCaseArgumentTypes/index.js +13 -0
  57. package/lib/enums/UseCaseStatuses/index.js +25 -0
  58. package/lib/hooks/useArgumentTypes/index.js +31 -0
  59. package/lib/hooks/useContextualItem/index.js +21 -0
  60. package/lib/hooks/useEntity/index.js +63 -0
  61. package/lib/hooks/useGlobalUseCase/index.js +3 -10
  62. package/lib/hooks/useGlobalUseCase/index.test.js +8 -35
  63. package/lib/hooks/useMemoizedCall/index.js +22 -0
  64. package/lib/hooks/useProvider/index.js +24 -15
  65. package/lib/hooks/useStatelessUseCase/index.js +2 -12
  66. package/lib/hooks/useStatelessUseCase/index.test.js +2 -43
  67. package/lib/hooks/useUseCase/index.js +55 -82
  68. package/lib/hooks/useUseCase/index.test.js +56 -25
  69. package/lib/hooks/useUseCaseContext/index.js +12 -3
  70. package/lib/hooks/useUseCaseContext/index.test.js +45 -19
  71. package/lib/hooks/useUseCaseStatuses/index.js +36 -0
  72. package/lib/methods/cacheCall/index.js +42 -0
  73. package/lib/methods/cacheCalls/index.js +20 -0
  74. package/lib/methods/fillArguments/index.js +31 -0
  75. package/lib/methods/fillArguments/types.js +5 -0
  76. package/lib/methods/getRenderingEntity/index.js +20 -0
  77. package/lib/methods/initEntityReducers/index.js +2 -3
  78. package/lib/methods/transformGlobalArguments/index.js +21 -0
  79. package/lib/methods/transformGlobalArguments/types.js +5 -0
  80. package/lib/methods/triggerCallbacks/index.js +3 -3
  81. package/package.json +3 -3
  82. package/es/hooks/useChangeCallbackCollection/index.d.ts +0 -3
  83. package/es/hooks/useChangeCallbackCollection/index.js +0 -29
  84. package/es/methods/cacheReducerCalls/index.d.ts +0 -3
  85. package/es/methods/cacheReducerCalls/index.js +0 -26
  86. package/es/methods/cacheReducerCalls/types.d.ts +0 -11
  87. package/es/methods/getRootEntity/index.d.ts +0 -3
  88. package/es/methods/getRootEntity/index.js +0 -10
  89. package/es/methods/initEntityReducers/types.d.ts +0 -3
  90. package/es/methods/removeItem/index.d.ts +0 -1
  91. package/es/methods/removeItem/index.js +0 -7
  92. package/es/methods/toMaxArguments/index.d.ts +0 -3
  93. package/es/methods/toMaxArguments/index.js +0 -28
  94. package/lib/hooks/useChangeCallbackCollection/index.js +0 -37
  95. package/lib/methods/cacheReducerCalls/index.js +0 -45
  96. package/lib/methods/getRootEntity/index.js +0 -17
  97. package/lib/methods/removeItem/index.js +0 -14
  98. package/lib/methods/toMaxArguments/index.js +0 -25
  99. /package/es/{methods/cacheReducerCalls → hooks/useContextualItem}/types.js +0 -0
  100. /package/es/methods/{initEntityReducers → cacheCall}/types.js +0 -0
  101. /package/lib/{methods/cacheReducerCalls → hooks/useContextualItem}/types.js +0 -0
  102. /package/lib/methods/{initEntityReducers → cacheCall}/types.js +0 -0
@@ -1,88 +1,58 @@
1
- import { useCreation, useMemoizedFn } from 'ahooks';
2
- import { useContext, useState } from 'react';
1
+ import { useCreation } from 'ahooks';
2
+ import { useContext } from 'react';
3
3
  import { useConstant } from '../useConstant';
4
4
  import { useConstantFn } from '../useConstantFn';
5
5
  import { useProvider } from '../useProvider';
6
- import { useCompareDeps } from '../useCompareDeps';
7
6
  import { initEntityReducers } from '../../methods/initEntityReducers';
8
- import { triggerCallbacks } from '../../methods/triggerCallbacks';
9
- import { getRootEntity } from '../../methods/getRootEntity';
10
7
  import { useUseCaseContext } from '../useUseCaseContext';
11
- import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
12
8
  import { useIsRenderingRef } from '../useIsRenderingRef';
13
- import { cacheReducerCalls } from '../../methods/cacheReducerCalls';
14
- import { UseCaseModes } from '../../enums/UseCaseModes';
15
- import { toMaxArguments } from '../../methods/toMaxArguments';
16
- import { useChangeCallbackCollection } from '../useChangeCallbackCollection';
9
+ import { fillArguments } from '../../methods/fillArguments';
10
+ import { useArgumentTypes } from '../useArgumentTypes';
11
+ import { useUseCaseStatuses } from '../useUseCaseStatuses';
12
+ import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
13
+ import { useEntity } from '../useEntity';
14
+ import { useContextualItem } from '../useContextualItem';
15
+ import { cacheCalls } from '../../methods/cacheCalls';
17
16
  export const useUseCase = ((...args) => {
18
- const [unsafeEntity, unsafeUsecase, unsafeMode, options, deps] = toMaxArguments(args);
19
- const [entityState, setEntityState] = useState(unsafeEntity);
20
- const usecase = useConstantFn(unsafeUsecase);
21
- const entityUseCase = usecase;
22
- const mode = useConstant(unsafeMode);
23
- const depsKey = useCompareDeps(deps);
17
+ const argumentTypes = useArgumentTypes(args);
18
+ const fullArguments = fillArguments(args, argumentTypes);
19
+ const [unsafeEntity, unsafeUsecase, unsafeMode, options, deps] = fullArguments;
20
+ const unkownUsecase = useConstantFn(unsafeUsecase);
21
+ const usecase = unkownUsecase;
22
+ const entityUseCase = unkownUsecase;
24
23
  const isRenderingRef = useIsRenderingRef();
25
- const isContextRoot = useConstant(typeof args[1] === 'function');
26
- const defaultContext = defaultUseCaseContext;
27
- const context = useUseCaseContext(entityUseCase, isContextRoot ? null : defaultContext);
28
- const getContextValue = useContext(context);
29
- const hasContextValueGetter = getContextValue !== null;
30
- const { entity: contextEntity, reducers: contextEntityReducers = null, changeCallbackCollection: contextChangeCallbackCollection = null, } = getContextValue?.() || {};
31
- // 是否需要初始化根 `redurcers`
32
- const isRoot = isContextRoot || !hasContextValueGetter;
33
- // 是否为上下文模式
34
- const isContextMode = isContextRoot || hasContextValueGetter;
35
- const changeCallbackCollection = useChangeCallbackCollection(isRoot, contextChangeCallbackCollection, options);
36
- const entity = useCreation(() => {
37
- if (!isContextRoot) {
38
- return contextEntity;
39
- }
40
- return getRootEntity(entityState, unsafeEntity, mode);
41
- }, [isContextRoot, contextEntity, mode, entityState, unsafeEntity]);
42
- const onEntityChange = useMemoizedFn((newEntity, oldEntity) => {
43
- if ((mode & UseCaseModes.Stateless) !== UseCaseModes.Stateless) {
44
- setEntityState(newEntity);
24
+ const mode = useConstant(unsafeMode);
25
+ const context = useUseCaseContext(unkownUsecase, argumentTypes, mode);
26
+ const contextValue = useContext(context)?.() || null;
27
+ const entityContextValue = contextValue;
28
+ const statuses = useUseCaseStatuses(argumentTypes, mode, contextValue);
29
+ const { reducers: contextReducers = null } = contextValue || {};
30
+ const { store: contextStore = null } = entityContextValue || {};
31
+ const [entity, store] = useEntity(statuses, unsafeEntity, contextStore, options);
32
+ const reducers = useContextualItem(statuses, contextReducers, () => {
33
+ if ((statuses & UseCaseStatuses.EntityEnabled) !== UseCaseStatuses.EntityEnabled) {
34
+ return usecase(options);
45
35
  }
46
- triggerCallbacks(changeCallbackCollection, newEntity, oldEntity);
47
- });
48
- const createRootEntityReducers = useMemoizedFn(() => {
49
- const initOptions = options;
50
- return initEntityReducers(entity, entityUseCase, initOptions, onEntityChange);
51
- });
52
- const createReducers = useMemoizedFn(() => {
53
- return usecase(options);
54
- });
55
- const rootEntityReducers = useCreation(() => {
56
- void depsKey;
57
- if (!isContextRoot) {
58
- return null;
36
+ const hookOptions = options;
37
+ return initEntityReducers(entityUseCase, store, hookOptions);
38
+ }, deps);
39
+ const Provider = useProvider(statuses, context, store, reducers);
40
+ return useCreation(() => {
41
+ if ((statuses & UseCaseStatuses.ContextEnabled) !== UseCaseStatuses.ContextEnabled) {
42
+ return reducers;
59
43
  }
60
- return createRootEntityReducers();
61
- }, [isContextRoot, depsKey, createRootEntityReducers]);
62
- const entityReducers = useCreation(() => {
63
- return rootEntityReducers || contextEntityReducers || {};
64
- }, [rootEntityReducers, contextEntityReducers]);
65
- const reducers = useCreation(() => {
66
- void depsKey;
67
- if (isContextMode) {
68
- return {};
44
+ const rootEnabled = (statuses & UseCaseStatuses.RootEnabled) === UseCaseStatuses.RootEnabled;
45
+ if ((statuses & UseCaseStatuses.EntityEnabled) !== UseCaseStatuses.EntityEnabled) {
46
+ return rootEnabled ? [reducers, Provider] : reducers;
69
47
  }
70
- return createReducers();
71
- }, [isContextMode, depsKey, createReducers]);
72
- const Provider = useProvider(context, mode, entity, entityReducers, changeCallbackCollection);
73
- const createCoreCollection = useMemoizedFn((coreEntity, coreReducers) => {
74
- return [
75
- coreEntity,
76
- cacheReducerCalls(coreReducers, () => {
48
+ const cachedReducers = cacheCalls(reducers, {
49
+ onShouldCache() {
77
50
  return isRenderingRef.current;
78
- }),
79
- isContextRoot ? Provider : null,
80
- ];
81
- });
82
- return useCreation(() => {
83
- if (isContextMode) {
84
- return createCoreCollection(entity, entityReducers);
51
+ },
52
+ });
53
+ if (rootEnabled) {
54
+ return [entity, cachedReducers, Provider];
85
55
  }
86
- return reducers;
87
- }, [isContextMode, entity, entityReducers, reducers, createCoreCollection]);
56
+ return [entity, cachedReducers];
57
+ }, [statuses, entity, reducers, Provider, isRenderingRef]);
88
58
  });
@@ -86,7 +86,7 @@ const Child = ({ textPrefix = '', onUpdate, onPathChange, onUndefinedEntity }) =
86
86
  useUpdateEffect(pathChange, [path, pathChange]);
87
87
  return (_jsxs("div", { children: [_jsxs("main", { children: ["child path: ", path, _jsx("br", {}), "child ext: ", ext] }), _jsx("footer", { children: _jsx("button", { onClick: onClick, children: textPrefix + CHILD_BUTTON_TEXT }) })] }));
88
88
  };
89
- const Parent = ({ children, mode, onUpdate, onSetPath }) => {
89
+ const Parent = ({ children, mode = UseCaseModes.Normal, onUpdate, onSetPath }) => {
90
90
  const [{ path, ext }, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, mode);
91
91
  const onClick = () => {
92
92
  setPath(onSetPath?.() || '');
@@ -1403,6 +1403,31 @@ describe('useUseCase', () => {
1403
1403
  expect(onChangeC).toHaveReturnedWith(3);
1404
1404
  });
1405
1405
  });
1406
+ describe('`useUseCase` should work the same as `usePseudoCoreCollection`', () => {
1407
+ test('the return value should be `PseudoCoreCollection`', () => {
1408
+ const { result } = renderHook(() => {
1409
+ return useUseCase(mathUseCase, UseCaseModes.Global);
1410
+ });
1411
+ const { current } = result;
1412
+ expect(current).toEqual([expect.any(Object), expect.any(Function)]);
1413
+ });
1414
+ test('the return value should be `reducers` object at child component', () => {
1415
+ const onMountA = jest.fn();
1416
+ const A = () => {
1417
+ const reducers = useUseCase(mathUseCase);
1418
+ useMount(() => {
1419
+ onMountA(reducers);
1420
+ });
1421
+ return null;
1422
+ };
1423
+ const B = () => {
1424
+ const [, Provider] = useUseCase(mathUseCase, UseCaseModes.Global);
1425
+ return (_jsx(Provider, { children: _jsx(A, {}) }));
1426
+ };
1427
+ render(_jsx(B, {}));
1428
+ expect(onMountA).toHaveBeenCalledWith(expect.any(Object));
1429
+ });
1430
+ });
1406
1431
  describe('`useUseCase` should work the same as `useReducers`', () => {
1407
1432
  test('`entity` should equal `defaultFile`', () => {
1408
1433
  const { result } = renderHook(() => {
@@ -1,8 +1,21 @@
1
- import { ContextualEntityReducers } from '../../configs/defaultUseCaseContext/types';
2
- import { EntityReducers, EntityUseCase, Reducers, UseCase } from '@mic-rexjs/usecases';
1
+ import { EntityReducerMap, EntityReducers, EntityUseCase, ReducerMap, Reducers, UseCase } from '@mic-rexjs/usecases';
3
2
  import { UseCaseProvider } from '../useProvider/types';
4
3
  import { UseCaseModes } from '../../enums/UseCaseModes';
5
- export type CoreCollection<T, TEntityReducers extends EntityReducers<T>, TProvider extends UseCaseProvider | null = UseCaseProvider> = [entity: T, reducers: ContextualEntityReducers<T, TEntityReducers>, Provider: TProvider];
4
+ import { ContextualEntityReducers } from '../../configs/defaultUseCaseContext/types';
5
+ export type RootCoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = [
6
+ entity: T,
7
+ reducers: ContextualEntityReducers<T, TEntityReducers>,
8
+ Provider: UseCaseProvider
9
+ ];
10
+ export type ContextualCoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = [
11
+ entity: T,
12
+ reducers: ContextualEntityReducers<T, TEntityReducers>
13
+ ];
14
+ export type CoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = RootCoreCollection<T, TEntityReducers> | ContextualCoreCollection<T, TEntityReducers>;
15
+ export type PseudoCoreCollection<T extends ReducerMap, TProvider extends UseCaseProvider | null = UseCaseProvider> = [
16
+ reducers: T,
17
+ Provider: TProvider
18
+ ];
6
19
  export interface EntityGetter<T> {
7
20
  (): T;
8
21
  }
@@ -32,67 +45,41 @@ export interface UseCaseHookOwnOptions<T, TUseCaseOptions extends object> extend
32
45
  options?: TUseCaseOptions;
33
46
  }
34
47
  export type UseCaseHookOptions<T, TUseCaseOptions extends object = object> = TUseCaseOptions & UseCaseHookOwnOptions<T, TUseCaseOptions>;
35
- export type ContextualCoreCollectionHookParameters<T, TEntityReducers extends EntityReducers<T>> = [
36
- usecase: EntityUseCase<T, TEntityReducers> &
48
+ export interface ContextualCoreCollectionHook {
49
+ <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
37
50
  /**
38
51
  * 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
39
52
  * 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
40
53
  * 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
41
54
  */
42
- UseCase<EntityReducers<T>>,
43
- options?: UseCaseHookContextualOptions<T>
44
- ];
45
- export interface ContextualCoreCollectionHook {
46
- <T, TEntityReducers extends EntityReducers<T>>(...args: ContextualCoreCollectionHookParameters<T, TEntityReducers>): CoreCollection<T, TEntityReducers, null>;
55
+ UseCase<EntityReducerMap<T>, TUseCaseOptions>, options?: UseCaseHookContextualOptions<T>): ContextualCoreCollection<T, TEntityReducers>;
47
56
  }
48
- export type RootCoreCollectionHookParameters<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object> = [
49
- entity: T | EntityGetter<T>,
50
- usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
57
+ export interface RootCoreCollectionHook {
58
+ <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(entity: T | EntityGetter<T>, usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
51
59
  /**
52
60
  * 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
53
61
  * 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
54
62
  * 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
55
63
  */
56
- UseCase<EntityReducers<T>, TUseCaseOptions>,
57
- options?: UseCaseHookOptions<T, TUseCaseOptions>,
58
- deps?: unknown[]
59
- ];
60
- export interface RootCoreCollectionHook {
61
- <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(...args: RootCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions>): CoreCollection<T, TEntityReducers>;
64
+ UseCase<EntityReducerMap<T>, TUseCaseOptions>, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?: unknown[]): RootCoreCollection<T, TEntityReducers>;
62
65
  }
63
- export type ModeCoreCollectionHookParameters<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object> = [
64
- entity: T | EntityGetter<T>,
65
- usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
66
+ export interface ModeCoreCollectionHook {
67
+ <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(entity: T | EntityGetter<T>, usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
66
68
  /**
67
69
  * 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
68
70
  * 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
69
71
  * 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
70
72
  */
71
- UseCase<EntityReducers<T>, TUseCaseOptions>,
72
- mode?: UseCaseModes,
73
- options?: UseCaseHookOptions<T, TUseCaseOptions>,
74
- deps?: unknown[]
75
- ];
76
- export interface ModeCoreCollectionHook {
77
- <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(...args: ModeCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions>): CoreCollection<T, TEntityReducers>;
73
+ UseCase<EntityReducerMap<T>, TUseCaseOptions>, mode: UseCaseModes, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?: unknown[]): RootCoreCollection<T, TEntityReducers>;
78
74
  }
79
- export interface CoreCollectionHook extends ContextualCoreCollectionHook, RootCoreCollectionHook, ModeCoreCollectionHook {
75
+ export interface PseudoCoreCollectionHook {
76
+ <T extends Reducers, TUseCaseOptions extends object = object>(usecase: UseCase<T, TUseCaseOptions>, mode: UseCaseModes, options?: TUseCaseOptions, deps?: unknown[]): PseudoCoreCollection<T>;
80
77
  }
81
- export type ReducersHookParameters<T extends Reducers, TUseCaseOptions extends object = object> = [
82
- usecase: UseCase<T, TUseCaseOptions>,
83
- options?: TUseCaseOptions,
84
- deps?: unknown[]
85
- ];
86
78
  export interface ReducersHook {
87
- <T extends Reducers, TUseCaseOptions extends object = object>(...args: ReducersHookParameters<T, TUseCaseOptions>): T;
79
+ <T extends Reducers, TUseCaseOptions extends object = object>(usecase: UseCase<T, TUseCaseOptions>, options?: TUseCaseOptions, deps?: unknown[]): T;
88
80
  }
89
- export type UseCaseHookParameters<T, TReducers extends Reducers, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object> = ContextualCoreCollectionHookParameters<T, TEntityReducers> | RootCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions> | ModeCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions> | ReducersHookParameters<TReducers, TUseCaseOptions>;
90
- export type UseCaseHookMaxParameters<T, TReducers extends Reducers, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object> = [
91
- entity: T | EntityGetter<T> | null,
92
- usecase: UseCase<TReducers, TUseCaseOptions> | EntityUseCase<T, TEntityReducers, TUseCaseOptions>,
93
- mode: UseCaseModes,
94
- options: TUseCaseOptions | UseCaseHookOptions<T, TUseCaseOptions> | UseCaseHookContextualOptions<T>,
95
- deps: unknown[]
96
- ];
97
- export interface UseCaseHook extends CoreCollectionHook, ReducersHook {
81
+ export interface CoreCollectionHook extends ContextualCoreCollectionHook, RootCoreCollectionHook, ModeCoreCollectionHook {
82
+ }
83
+ export type UseCaseHookParameters = Parameters<ContextualCoreCollectionHook> | Parameters<RootCoreCollectionHook> | Parameters<ModeCoreCollectionHook> | Parameters<PseudoCoreCollectionHook> | Parameters<ReducersHook>;
84
+ export interface UseCaseHook extends CoreCollectionHook, PseudoCoreCollectionHook, ReducersHook {
98
85
  }
@@ -1,3 +1,5 @@
1
- import { EntityReducers, EntityUseCase, UseCase } from '@mic-rexjs/usecases';
2
- import { UseCaseContext } from '../../configs/defaultUseCaseContext/types';
3
- export declare const useUseCaseContext: <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object, TContext extends UseCaseContext<T, TEntityReducers> = UseCaseContext<T, TEntityReducers>>(usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> & UseCase<EntityReducers<T>, TUseCaseOptions>, defaultContext?: (TContext & UseCaseContext<T, TEntityReducers>) | null | undefined) => TContext;
1
+ import { ReducerMap, UseCase } from '@mic-rexjs/usecases';
2
+ import { UseCaseContext, UseCaseContextValue } from '../../configs/defaultUseCaseContext/types';
3
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
4
+ import { UseCaseModes } from '../../enums/UseCaseModes';
5
+ export declare const useUseCaseContext: <T extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>, TUseCaseOptions extends object, TContext extends UseCaseContext<UseCaseContextValue<T>>>(usecase: UseCase<T, TUseCaseOptions>, argumentTypes?: UseCaseArgumentTypes, mode?: UseCaseModes) => TContext;
@@ -2,7 +2,10 @@ import { useConstant } from '../useConstant';
2
2
  import { usecaseContextReferenceMap } from '../../configs/useCaseContextReferenceMap';
3
3
  import { createContext } from 'react';
4
4
  import { useUnmount } from 'ahooks';
5
- export const useUseCaseContext = (usecase, defaultContext) => {
5
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
6
+ import { UseCaseModes } from '../../enums/UseCaseModes';
7
+ import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
8
+ export const useUseCaseContext = (usecase, argumentTypes = UseCaseArgumentTypes.None, mode = UseCaseModes.Normal) => {
6
9
  const map = usecaseContextReferenceMap;
7
10
  const context = useConstant(() => {
8
11
  if (map.has(usecase)) {
@@ -14,8 +17,12 @@ export const useUseCaseContext = (usecase, defaultContext) => {
14
17
  });
15
18
  return value;
16
19
  }
17
- if (defaultContext) {
18
- return defaultContext;
20
+ switch (true) {
21
+ case (mode & UseCaseModes.Global) === UseCaseModes.Global:
22
+ case (argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity:
23
+ break;
24
+ default:
25
+ return defaultUseCaseContext;
19
26
  }
20
27
  const ctx = createContext(null);
21
28
  map.set(usecase, {
@@ -1,41 +1,68 @@
1
1
  import { describe, expect, test } from '@jest/globals';
2
2
  import { renderHook } from '@testing-library/react';
3
3
  import { useUseCaseContext } from '.';
4
- import { objectUseCase } from '@mic-rexjs/usecases';
5
4
  import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
6
5
  import { usecaseContextReferenceMap } from '../../configs/useCaseContextReferenceMap';
6
+ import { UseCaseModes } from '../../enums/UseCaseModes';
7
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
7
8
  const testUseCase = () => {
8
- return objectUseCase();
9
+ return {};
9
10
  };
10
11
  describe('useUseCaseContext', () => {
11
- test('should return the default context if map has not save a usecase and provide a default context', () => {
12
- const defaultContext = defaultUseCaseContext;
12
+ test('should return the default context if map has not saved a usecase with default args', () => {
13
13
  const { result } = renderHook(() => {
14
- return useUseCaseContext(testUseCase, defaultContext);
14
+ return useUseCaseContext(testUseCase);
15
15
  });
16
16
  const { current } = result;
17
17
  expect(current).toBe(defaultUseCaseContext);
18
18
  });
19
- test('should return a new context if map has not save a usecase and does not provide a default context', () => {
19
+ test('should return the default context if map has not saved a usecase with `UseCaseArgumentTypes.None` & `UseCaseModes.Normal`', () => {
20
20
  const { result } = renderHook(() => {
21
- return useUseCaseContext(testUseCase, null);
21
+ return useUseCaseContext(testUseCase, UseCaseArgumentTypes.None, UseCaseModes.Normal);
22
+ });
23
+ const { current } = result;
24
+ expect(current).toBe(defaultUseCaseContext);
25
+ });
26
+ test('should return a new context if map has not saved a usecase with `UseCaseArgumentTypes.Entity` & `UseCaseModes.Normal`', () => {
27
+ const { result } = renderHook(() => {
28
+ return useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity, UseCaseModes.Normal);
29
+ });
30
+ const { current } = result;
31
+ expect(typeof current).toBe('object');
32
+ });
33
+ test('should return a new context if map has not saved a usecase with `UseCaseArgumentTypes.None` & `UseCaseModes.Global`', () => {
34
+ const { result } = renderHook(() => {
35
+ return useUseCaseContext(testUseCase, UseCaseArgumentTypes.None, UseCaseModes.Global);
22
36
  });
23
37
  const { current } = result;
24
38
  expect(typeof current).toBe('object');
25
39
  });
26
- test.each([void 0, null, defaultUseCaseContext])('should return the existing context if map has save a usecase already', (defaultContext) => {
40
+ test.each([
41
+ {
42
+ type: UseCaseArgumentTypes.Entity,
43
+ mode: UseCaseModes.Normal,
44
+ },
45
+ {
46
+ type: UseCaseArgumentTypes.None,
47
+ mode: UseCaseModes.Global,
48
+ },
49
+ {
50
+ type: UseCaseArgumentTypes.Entity,
51
+ mode: UseCaseModes.Global,
52
+ },
53
+ ])('should return the existing context if map has save a usecase already', ({ type, mode }) => {
27
54
  const { result } = renderHook(() => {
28
- return useUseCaseContext(testUseCase) === useUseCaseContext(testUseCase, defaultContext);
55
+ return useUseCaseContext(testUseCase, type, mode) === useUseCaseContext(testUseCase);
29
56
  });
30
57
  const { current: isSame } = result;
31
58
  expect(isSame).toBe(true);
32
59
  });
33
60
  test('check context reference times when mount/unmount a usecase', () => {
34
61
  const { unmount: unmount1 } = renderHook(() => {
35
- useUseCaseContext(testUseCase);
62
+ useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity);
36
63
  });
37
64
  const { times: times1 } = usecaseContextReferenceMap.get(testUseCase);
38
- const { unmount: unmount2, rerender: rerender2 } = renderHook(() => {
65
+ const { unmount: unmount2 } = renderHook(() => {
39
66
  useUseCaseContext(testUseCase);
40
67
  useUseCaseContext(testUseCase);
41
68
  });
@@ -51,7 +78,7 @@ describe('useUseCaseContext', () => {
51
78
  });
52
79
  test('context reference times should not change when rerender hooks', () => {
53
80
  const { rerender } = renderHook(() => {
54
- useUseCaseContext(testUseCase);
81
+ useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity);
55
82
  });
56
83
  rerender();
57
84
  const { times } = usecaseContextReferenceMap.get(testUseCase);
@@ -0,0 +1,6 @@
1
+ import { UseCaseContextValue } from '../../configs/defaultUseCaseContext/types';
2
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
3
+ import { UseCaseModes } from '../../enums/UseCaseModes';
4
+ import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
5
+ import { ReducerMap } from '@mic-rexjs/usecases';
6
+ export declare const useUseCaseStatuses: <T, TReducers extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>>(argumentTypes: UseCaseArgumentTypes, mode: UseCaseModes, contextValue: UseCaseContextValue<TReducers> | null) => UseCaseStatuses;
@@ -0,0 +1,29 @@
1
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
2
+ import { UseCaseModes } from '../../enums/UseCaseModes';
3
+ import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
4
+ import { useCreation } from 'ahooks';
5
+ export const useUseCaseStatuses = (argumentTypes, mode, contextValue) => {
6
+ return useCreation(() => {
7
+ let statuses = UseCaseStatuses.None;
8
+ const { store } = (contextValue || {});
9
+ if ((argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity) {
10
+ statuses |= UseCaseStatuses.EntityRootEnabled;
11
+ }
12
+ if (contextValue === null) {
13
+ statuses |= UseCaseStatuses.RootEnabled;
14
+ }
15
+ else {
16
+ statuses |= UseCaseStatuses.ContextEnabled;
17
+ }
18
+ if (store) {
19
+ statuses |= UseCaseStatuses.EntityEnabled;
20
+ }
21
+ if ((mode & UseCaseModes.Stateless) === UseCaseModes.Stateless) {
22
+ statuses |= UseCaseStatuses.StatelessEnabled;
23
+ }
24
+ if ((mode & UseCaseModes.Global) === UseCaseModes.Global) {
25
+ statuses |= UseCaseStatuses.GlobalEnabled;
26
+ }
27
+ return statuses;
28
+ }, [argumentTypes, contextValue, mode]);
29
+ };
package/es/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { UseCaseFragment } from './components/UseCaseFragment';
2
2
  export { useUseCase } from './hooks/useUseCase';
3
3
  export { useGlobalUseCase } from './hooks/useGlobalUseCase';
4
4
  export { useStatelessUseCase } from './hooks/useStatelessUseCase';
5
- export type { CoreCollection } from './hooks/useUseCase/types';
5
+ export type { RootCoreCollection, ContextualCoreCollection, CoreCollection, PseudoCoreCollection, } from './hooks/useUseCase/types';
6
6
  export type { UseCaseHookOptions } from './hooks/useUseCase/types';
7
7
  export type { UseCaseProvider } from './hooks/useProvider/types';
8
8
  export type { UseCaseFragmentProps } from './components/UseCaseFragment/types';
@@ -0,0 +1,2 @@
1
+ import { CacheableFactory, CacheCallOptions } from './types';
2
+ export declare const cacheCall: <T extends CacheableFactory>(factory: T, options?: CacheCallOptions) => T;
@@ -0,0 +1,26 @@
1
+ import { isSameArray } from '../isSameArray';
2
+ export const cacheCall = (factory, options) => {
3
+ let cache;
4
+ const { onShouldCache = () => {
5
+ return true;
6
+ }, onCompare = (newArgs, oldArgs) => {
7
+ return isSameArray(newArgs, oldArgs);
8
+ }, } = options || {};
9
+ return ((...args) => {
10
+ const cacheable = onShouldCache();
11
+ if (cache && cacheable) {
12
+ const { parameters, returnValue } = cache;
13
+ if (onCompare(parameters, args)) {
14
+ return returnValue;
15
+ }
16
+ }
17
+ const returnValue = factory(...args);
18
+ if (cacheable) {
19
+ cache = {
20
+ parameters: args,
21
+ returnValue,
22
+ };
23
+ }
24
+ return returnValue;
25
+ });
26
+ };
@@ -0,0 +1,13 @@
1
+ import { Reducer } from '@mic-rexjs/usecases';
2
+ import { RestArguments } from '@mic-rexjs/usecases/es/types';
3
+ export interface CacheableFactory {
4
+ (...args: RestArguments): unknown;
5
+ }
6
+ export interface CacheCallOptions {
7
+ onShouldCache?(): boolean;
8
+ onCompare?(newArgs: RestArguments, oldArgs: RestArguments): boolean;
9
+ }
10
+ export interface CallCache<T extends Reducer> {
11
+ parameters: Parameters<T>;
12
+ returnValue: ReturnType<T>;
13
+ }
@@ -0,0 +1,2 @@
1
+ import { CacheCallOptions, CacheableFactory } from '../cacheCall/types';
2
+ export declare const cacheCalls: <T extends Record<string, CacheableFactory>>(sourceFactories: T, options?: CacheCallOptions) => T;
@@ -0,0 +1,8 @@
1
+ import { cacheCall } from '../cacheCall';
2
+ export const cacheCalls = (sourceFactories, options) => {
3
+ const cachedFactories = {};
4
+ Object.entries(sourceFactories).forEach(([key, factory]) => {
5
+ cachedFactories[key] = cacheCall(factory, options);
6
+ });
7
+ return cachedFactories;
8
+ };
@@ -0,0 +1,5 @@
1
+ import { UseCaseHookParameters } from '../../hooks/useUseCase/types';
2
+ import { ReducerMap } from '@mic-rexjs/usecases';
3
+ import { UseCaseHookFullParameters } from './types';
4
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
5
+ export declare const fillArguments: <T, TReducers extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>, TUseCaseOptions extends object>(args: UseCaseHookParameters, argumentTypes: UseCaseArgumentTypes) => UseCaseHookFullParameters<T, TReducers, TUseCaseOptions>;
@@ -0,0 +1,41 @@
1
+ import { UseCaseModes } from '../../enums/UseCaseModes';
2
+ import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
3
+ export const fillArguments = (args, argumentTypes) => {
4
+ const [arg1, arg2, arg3, arg4, arg5] = args;
5
+ const hasEntity = (argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity;
6
+ const hasMode = (argumentTypes & UseCaseArgumentTypes.Mode) === UseCaseArgumentTypes.Mode;
7
+ if (hasEntity) {
8
+ if (hasMode) {
9
+ return [
10
+ arg1,
11
+ arg2,
12
+ arg3,
13
+ (arg4 || {}),
14
+ arg5 || [],
15
+ ];
16
+ }
17
+ return [
18
+ arg1,
19
+ arg2,
20
+ UseCaseModes.Normal,
21
+ (arg3 || {}),
22
+ (arg4 || []),
23
+ ];
24
+ }
25
+ if (hasMode) {
26
+ return [
27
+ null,
28
+ arg1,
29
+ arg2,
30
+ (arg3 || {}),
31
+ (arg4 || []),
32
+ ];
33
+ }
34
+ return [
35
+ null,
36
+ arg1,
37
+ UseCaseModes.Normal,
38
+ (arg2 || {}),
39
+ (arg3 || []),
40
+ ];
41
+ };
@@ -0,0 +1,10 @@
1
+ import { UseCaseModes } from '../../enums/UseCaseModes';
2
+ import { EntityGetter, UseCaseHookContextualOptions, UseCaseHookOptions } from '../../hooks/useUseCase/types';
3
+ import { EntityReducerMap, EntityUseCase, ReducerMap, UseCase } from '@mic-rexjs/usecases';
4
+ export type UseCaseHookFullParameters<T, TReducers extends ReducerMap, TUseCaseOptions extends object> = [
5
+ entity: T | EntityGetter<T>,
6
+ usecase: UseCase<TReducers, TUseCaseOptions> | EntityUseCase<T, TReducers & EntityReducerMap<T>, TUseCaseOptions>,
7
+ mode: UseCaseModes,
8
+ options: TUseCaseOptions | UseCaseHookOptions<T, TUseCaseOptions> | UseCaseHookContextualOptions<T>,
9
+ deps: unknown[]
10
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
2
+ import { EntityGetter } from '../../hooks/useUseCase/types';
3
+ export declare const getRenderingEntity: <T>(statuses: UseCaseStatuses, entityState: T, rootEntity: T | EntityGetter<T>, contextEntity: T) => T;
@@ -0,0 +1,13 @@
1
+ import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
2
+ export const getRenderingEntity = (statuses, entityState, rootEntity, contextEntity) => {
3
+ if ((statuses & UseCaseStatuses.EntityRootEnabled) !== UseCaseStatuses.EntityRootEnabled) {
4
+ return contextEntity;
5
+ }
6
+ if ((statuses & UseCaseStatuses.StatelessEnabled) !== UseCaseStatuses.StatelessEnabled) {
7
+ return entityState;
8
+ }
9
+ if (typeof rootEntity === 'function') {
10
+ return rootEntity();
11
+ }
12
+ return rootEntity;
13
+ };
@@ -1,5 +1,4 @@
1
- import { EntityReducers, EntityUseCase } from '@mic-rexjs/usecases';
1
+ import { EntityReducerMap, EntityStore, EntityUseCase } from '@mic-rexjs/usecases';
2
2
  import { UseCaseHookOptions } from '../../hooks/useUseCase/types';
3
3
  import { ContextualEntityReducers } from '../../configs/defaultUseCaseContext/types';
4
- import { EntityChangeEventHandler } from './types';
5
- export declare const initEntityReducers: <T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(entity: T, usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions>, options: UseCaseHookOptions<T, TUseCaseOptions>, onEntityChange: EntityChangeEventHandler<T>) => ContextualEntityReducers<T, TEntityReducers>;
4
+ export declare const initEntityReducers: <T, TEntityReducers extends EntityReducerMap<T>, TUseCaseOptions extends object = object>(usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions>, store: EntityStore<T>, options: UseCaseHookOptions<T, TUseCaseOptions>) => ContextualEntityReducers<T, TEntityReducers>;
@@ -1,10 +1,9 @@
1
1
  import { createEntityReducers } from '@mic-rexjs/usecases';
2
- export const initEntityReducers = (entity, usecase, options, onEntityChange) => {
2
+ export const initEntityReducers = (usecase, store, options) => {
3
3
  const { watch, onChange, options: usecaseOptions, ...restUseCaseOptions } = options;
4
- return createEntityReducers(entity, usecase, {
4
+ return createEntityReducers(store, usecase, {
5
5
  ...restUseCaseOptions,
6
6
  ...usecaseOptions,
7
- onChange: onEntityChange,
8
7
  onGenerate(newEntity, result) {
9
8
  return result;
10
9
  },