@mic-rexjs/usecases-react 2.10.2 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.LICENSE.txt +4 -2
- package/es/components/SafeUseCaseFragment/index.js +1 -1
- package/es/components/UseCaseFragment/index.js +2 -2
- package/es/components/UseCaseFragment/types.d.ts +1 -1
- package/es/entities/matchPropertyFailedResult/types.d.ts +7 -0
- package/es/hooks/useArgumentTypes/index.d.ts +1 -1
- package/es/hooks/useArgumentTypes/index.js +3 -4
- package/es/hooks/useConstantEntityReducers/index.d.ts +3 -0
- package/es/hooks/useConstantEntityReducers/index.js +7 -0
- package/es/hooks/useConstantReducers/index.d.ts +3 -0
- package/es/hooks/useConstantReducers/index.js +6 -0
- package/es/hooks/useContext/index.d.ts +2 -2
- package/es/hooks/useContext/index.test.js +2 -2
- package/es/hooks/useContextualItem/index.d.ts +3 -2
- package/es/hooks/useContextualItem/index.js +18 -8
- package/es/hooks/useDepsKey/index.d.ts +2 -0
- package/es/hooks/useDepsKey/index.js +7 -0
- package/es/hooks/useEntity/index.d.ts +3 -2
- package/es/hooks/useEntity/index.js +17 -9
- package/es/hooks/useFullArguments/index.d.ts +3 -3
- package/es/hooks/useFullArguments/types.d.ts +5 -4
- package/es/hooks/useIsRenderingRef/index.js +3 -3
- package/es/hooks/useProvider/index.d.ts +3 -3
- package/es/hooks/useProvider/index.js +3 -3
- package/es/hooks/useProvider/types.d.ts +0 -1
- package/es/hooks/useRuntimeEntity/index.d.ts +3 -2
- package/es/hooks/useRuntimeEntity/index.js +8 -6
- package/es/hooks/useStatuses/index.d.ts +2 -2
- package/es/hooks/useStatuses/index.js +1 -1
- package/es/hooks/useUseCase/index.js +22 -16
- package/es/hooks/useUseCase/index.test.js +70 -6
- package/es/hooks/useUseCase/types.d.ts +13 -16
- package/es/methods/triggerWatchers/index.js +4 -9
- package/es/types.d.ts +3 -0
- package/es/usecases/contextUseCase/index.js +1 -1
- package/es/usecases/contextUseCase/types.d.ts +2 -3
- package/es/usecases/methodUseCase/index.d.ts +2 -0
- package/es/usecases/methodUseCase/index.js +55 -0
- package/es/usecases/methodUseCase/types.d.ts +21 -0
- package/es/usecases/valueUseCase/index.d.ts +2 -0
- package/es/usecases/valueUseCase/index.js +172 -0
- package/es/usecases/valueUseCase/types.d.ts +20 -0
- package/es/usecases/valueUseCase/types.js +1 -0
- package/lib/components/SafeUseCaseFragment/index.js +1 -1
- package/lib/components/UseCaseFragment/index.js +2 -2
- package/lib/hooks/useArgumentTypes/index.js +3 -4
- package/lib/hooks/useConstantEntityReducers/index.js +13 -0
- package/lib/hooks/useConstantReducers/index.js +12 -0
- package/lib/hooks/useContext/index.test.js +2 -2
- package/lib/hooks/useContextualItem/index.js +18 -7
- package/lib/hooks/useDepsKey/index.js +18 -0
- package/lib/hooks/useEntity/index.js +21 -10
- package/lib/hooks/useIsRenderingRef/index.js +2 -2
- package/lib/hooks/useProvider/index.js +4 -6
- package/lib/hooks/useRuntimeEntity/index.js +10 -6
- package/lib/hooks/useStatuses/index.js +1 -1
- package/lib/hooks/useUseCase/index.js +30 -19
- package/lib/hooks/useUseCase/index.test.js +242 -158
- package/lib/methods/triggerWatchers/index.js +5 -9
- package/lib/usecases/contextUseCase/index.js +1 -1
- package/lib/usecases/methodUseCase/index.js +79 -0
- package/lib/usecases/valueUseCase/index.js +246 -0
- package/lib/usecases/valueUseCase/types.js +5 -0
- package/package.json +45 -40
- package/es/hooks/useCompareDeps/index.d.ts +0 -1
- package/es/hooks/useCompareDeps/index.js +0 -11
- package/es/methods/cacheCall/index.d.ts +0 -2
- package/es/methods/cacheCall/index.js +0 -26
- package/es/methods/cacheCall/types.d.ts +0 -13
- package/es/methods/cacheCalls/index.d.ts +0 -2
- package/es/methods/cacheCalls/index.js +0 -8
- package/es/methods/captureCalls/index.d.ts +0 -2
- package/es/methods/captureCalls/index.js +0 -14
- package/es/methods/captureCalls/types.d.ts +0 -4
- package/es/methods/compareProperty/index.d.ts +0 -2
- package/es/methods/compareProperty/index.js +0 -34
- package/es/methods/compareProperty/types.d.ts +0 -3
- package/es/methods/hasField/index.d.ts +0 -1
- package/es/methods/hasField/index.js +0 -6
- package/es/methods/initEntityReducers/index.d.ts +0 -5
- package/es/methods/initEntityReducers/index.js +0 -11
- package/es/methods/isSameArray/index.d.ts +0 -1
- package/es/methods/isSameArray/index.js +0 -14
- package/lib/hooks/useCompareDeps/index.js +0 -17
- package/lib/methods/cacheCall/index.js +0 -41
- package/lib/methods/cacheCalls/index.js +0 -19
- package/lib/methods/captureCalls/index.js +0 -23
- package/lib/methods/compareProperty/index.js +0 -49
- package/lib/methods/hasField/index.js +0 -14
- package/lib/methods/initEntityReducers/index.js +0 -24
- package/lib/methods/isSameArray/index.js +0 -20
- /package/es/{methods/cacheCall → entities/matchPropertyFailedResult}/types.js +0 -0
- /package/es/{methods/captureCalls/types.js → types.js} +0 -0
- /package/es/{methods/compareProperty → usecases/methodUseCase}/types.js +0 -0
- /package/lib/{methods/cacheCall → entities/matchPropertyFailedResult}/types.js +0 -0
- /package/lib/{methods/captureCalls/types.js → types.js} +0 -0
- /package/lib/{methods/compareProperty → usecases/methodUseCase}/types.js +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { objectUseCase, entityUseCase, } from '@mic-rexjs/usecases';
|
|
3
|
-
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
|
4
|
-
import { renderHook, act, render, fireEvent, screen } from '@testing-library/react';
|
|
5
2
|
import { useUseCase } from '.';
|
|
3
|
+
import { useDepsKey } from '../useDepsKey';
|
|
4
|
+
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
|
5
|
+
import { entityUseCase, objectUseCase, } from '@mic-rexjs/usecases';
|
|
6
|
+
import { fireEvent, screen } from '@testing-library/dom';
|
|
7
|
+
import { act, render, renderHook } from '@testing-library/react';
|
|
6
8
|
import { useDeepCompareEffect, useMemoizedFn, useMount, useUpdate, useUpdateEffect } from 'ahooks';
|
|
7
9
|
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
10
|
const EXT_1 = '.png';
|
|
@@ -110,17 +112,19 @@ const MathParent = ({ extraValue = 0, onUpdate }) => {
|
|
|
110
112
|
};
|
|
111
113
|
const useDeepCompareUpdate = (callback, deps) => {
|
|
112
114
|
const isFirstRef = useRef(true);
|
|
115
|
+
const memoizedCallback = useMemoizedFn(callback);
|
|
116
|
+
const depsKey = useDepsKey(deps);
|
|
113
117
|
useEffect(() => {
|
|
114
118
|
return () => {
|
|
115
119
|
isFirstRef.current = false;
|
|
116
120
|
};
|
|
117
121
|
});
|
|
118
|
-
useDeepCompareEffect
|
|
122
|
+
useDeepCompareEffect(() => {
|
|
119
123
|
if (isFirstRef.current) {
|
|
120
124
|
return;
|
|
121
125
|
}
|
|
122
|
-
|
|
123
|
-
},
|
|
126
|
+
memoizedCallback();
|
|
127
|
+
}, [depsKey, memoizedCallback]);
|
|
124
128
|
};
|
|
125
129
|
beforeEach(() => {
|
|
126
130
|
subtractionReducer.mockClear();
|
|
@@ -189,6 +193,66 @@ describe('useUseCase', () => {
|
|
|
189
193
|
const { current: [currentFile], } = result;
|
|
190
194
|
expect(currentFile).toEqual(file);
|
|
191
195
|
});
|
|
196
|
+
test('Entity getter should provide the current entity', () => {
|
|
197
|
+
let updateIndex = 0;
|
|
198
|
+
const file = defaultFile;
|
|
199
|
+
const onFile = jest.fn();
|
|
200
|
+
const { result } = renderHook(() => {
|
|
201
|
+
return useUseCase((currentFile) => {
|
|
202
|
+
onFile(currentFile);
|
|
203
|
+
return currentFile ?? file;
|
|
204
|
+
}, fileUseCase, {}, [updateIndex++]);
|
|
205
|
+
});
|
|
206
|
+
const { current: [, { setPath: setPath1 }], } = result;
|
|
207
|
+
expect(onFile).toHaveBeenCalledTimes(1);
|
|
208
|
+
expect(onFile).toHaveBeenCalledWith(void 0);
|
|
209
|
+
act(() => {
|
|
210
|
+
setPath1(PATH_1);
|
|
211
|
+
});
|
|
212
|
+
const { current: [, { setPath: setPath2 }], } = result;
|
|
213
|
+
expect(onFile).toHaveBeenCalledTimes(2);
|
|
214
|
+
expect(onFile).toHaveBeenCalledWith({ ...file, ext: EXT_1, path: PATH_1 });
|
|
215
|
+
act(() => {
|
|
216
|
+
setPath2(PATH_2);
|
|
217
|
+
});
|
|
218
|
+
expect(onFile).toHaveBeenCalledTimes(3);
|
|
219
|
+
expect(onFile).toHaveBeenCalledWith({ ...file, ext: EXT_2, path: PATH_2 });
|
|
220
|
+
});
|
|
221
|
+
test('Entity getter should provide the changed deps', () => {
|
|
222
|
+
let updateIndex = 0;
|
|
223
|
+
const file = defaultFile;
|
|
224
|
+
const symbol = Symbol('changedDep');
|
|
225
|
+
const onChangedDeps = jest.fn();
|
|
226
|
+
const { result } = renderHook(() => {
|
|
227
|
+
return useUseCase((currentFile = file, changedDeps) => {
|
|
228
|
+
// 验证参数类型
|
|
229
|
+
const [index1, num1, index2, string1, index3, boolean1] = changedDeps;
|
|
230
|
+
const a = index1;
|
|
231
|
+
const b = num1;
|
|
232
|
+
const c = index2;
|
|
233
|
+
const d = string1;
|
|
234
|
+
const e = index3;
|
|
235
|
+
const f = boolean1;
|
|
236
|
+
void a;
|
|
237
|
+
void b;
|
|
238
|
+
void c;
|
|
239
|
+
void d;
|
|
240
|
+
void e;
|
|
241
|
+
void f;
|
|
242
|
+
// 先 `fill` 填充,再合并,以 `symbol` 代替虚无项去匹配
|
|
243
|
+
onChangedDeps(Object.assign([...changedDeps].fill(symbol), changedDeps));
|
|
244
|
+
return currentFile;
|
|
245
|
+
}, fileUseCase, {}, [updateIndex++, 0, updateIndex++, 'xyz', updateIndex++, false]);
|
|
246
|
+
});
|
|
247
|
+
const { current: [, { setPath: setPath }], } = result;
|
|
248
|
+
expect(onChangedDeps).toHaveBeenCalledTimes(1);
|
|
249
|
+
expect(onChangedDeps).toHaveBeenCalledWith([symbol, symbol, symbol, symbol, symbol, symbol]);
|
|
250
|
+
act(() => {
|
|
251
|
+
setPath(PATH_1);
|
|
252
|
+
});
|
|
253
|
+
expect(onChangedDeps).toHaveBeenCalledTimes(2);
|
|
254
|
+
expect(onChangedDeps).toHaveBeenCalledWith([3, symbol, 4, symbol, 5, symbol]);
|
|
255
|
+
});
|
|
192
256
|
test('Entity property getter should always return the same object if nothing changed after component update', () => {
|
|
193
257
|
let updateTimes = 0;
|
|
194
258
|
const data = {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { UseCase } from '@mic-rexjs/usecases';
|
|
2
1
|
import { UseCaseProvider } from '../useProvider/types';
|
|
2
|
+
import { UseCase } from '@mic-rexjs/usecases';
|
|
3
|
+
import { EntityReducerMap, EntityReducers, InferableEntityUseCase, ReducerMap, RestArguments, SymbolSet, SymbolSetTarget } from '@mic-rexjs/usecases/es/types';
|
|
4
|
+
import { MatchPropertyFailedResult } from '../../entities/matchPropertyFailedResult/types';
|
|
5
|
+
import { Dependencies } from '../../types';
|
|
3
6
|
import { ContextualEntityReducers } from '../../usecases/contextUseCase/types';
|
|
4
|
-
import { EntityReducerMap, EntityReducers, InferableEntityUseCase, ReducerMap, SymbolSet, SymbolSetTarget } from '@mic-rexjs/usecases/es/types';
|
|
5
7
|
export interface NonEntitySymbolSet extends SymbolSet {
|
|
6
8
|
entity?: never;
|
|
7
9
|
}
|
|
@@ -15,15 +17,10 @@ export type ContextualCoreCollection<T, TEntityReducers extends EntityReducerMap
|
|
|
15
17
|
reducers: ContextualEntityReducers<T, TEntityReducers>
|
|
16
18
|
];
|
|
17
19
|
export type CoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = RootCoreCollection<T, TEntityReducers> | ContextualCoreCollection<T, TEntityReducers>;
|
|
18
|
-
export interface EntityGetter<T> {
|
|
19
|
-
(entity
|
|
20
|
+
export interface EntityGetter<T, TDependencies extends Dependencies = Dependencies> {
|
|
21
|
+
(entity: T | undefined, changedDeps: TDependencies): T;
|
|
20
22
|
}
|
|
21
|
-
export interface EntityWatchEvent<T, TValue = unknown> {
|
|
22
|
-
fieldPaths: string[];
|
|
23
|
-
newEntity: T;
|
|
24
|
-
newValue: TValue;
|
|
25
|
-
oldEntity: T;
|
|
26
|
-
oldValue: TValue;
|
|
23
|
+
export interface EntityWatchEvent<T, TValue = unknown> extends MatchPropertyFailedResult<T, TValue> {
|
|
27
24
|
}
|
|
28
25
|
export interface EntityWatcher<T, TValue = unknown> {
|
|
29
26
|
(event: EntityWatchEvent<T, TValue>): void;
|
|
@@ -31,9 +28,9 @@ export interface EntityWatcher<T, TValue = unknown> {
|
|
|
31
28
|
export type PathTemplate = '1.2.3';
|
|
32
29
|
export type NextPathTemplate<T extends string> = T extends `${string}.${infer U}` ? U : T;
|
|
33
30
|
export type PropertyPath<T, TTemplate extends string, K extends keyof T = keyof T & string> = TTemplate extends `${string}.${string}` ? K extends infer TKey ? `${TKey & (string | number)}${'' | DotAccessorFieldPath<T[TKey & keyof T], TTemplate>}` : never : never;
|
|
34
|
-
export type DotAccessorFieldPath<T, TTemplate extends string> = TTemplate extends `${string}.${string}` ? T extends
|
|
35
|
-
export type FieldPath<T, TTemplate extends string = PathTemplate> = TTemplate extends `${string}.${string}` ? T extends
|
|
36
|
-
export type ExtractPropertyType<T, TPath> = TPath extends `${infer TKey}.${infer TSubPath}` ? T extends
|
|
31
|
+
export type DotAccessorFieldPath<T, TTemplate extends string> = TTemplate extends `${string}.${string}` ? T extends RestArguments ? '.length' | `${'' | `.${number}`}${DotAccessorFieldPath<T[number], NextPathTemplate<TTemplate>>}` : T extends object ? `.${PropertyPath<T, NextPathTemplate<TTemplate>>}` : '' : '';
|
|
32
|
+
export type FieldPath<T, TTemplate extends string = PathTemplate> = TTemplate extends `${string}.${string}` ? T extends RestArguments ? FieldPath<T[number], NextPathTemplate<TTemplate>> | 'length' : T extends object ? PropertyPath<T, TTemplate> : never : never;
|
|
33
|
+
export type ExtractPropertyType<T, TPath> = TPath extends `${infer TKey}.${infer TSubPath}` ? T extends RestArguments ? ExtractPropertyType<T[number], TKey extends `${number}` ? TSubPath : TPath> : ExtractPropertyType<T[TKey & keyof T], TSubPath> : T extends RestArguments ? TPath extends 'length' ? T[TPath] : TPath extends `${number}` ? T[number] : ExtractPropertyType<T[number], TPath> : T[TPath & keyof T];
|
|
37
34
|
export type ExtractFieldType<T, TPath> = TPath extends `${infer TKey}.${infer TSubProperty}` ? ExtractPropertyType<T[TKey & keyof T], TSubProperty> : T[TPath & keyof T];
|
|
38
35
|
export type EntityWatchMap<T> = {
|
|
39
36
|
[K in FieldPath<T>]?: EntityWatcher<T, ExtractFieldType<T, K>>;
|
|
@@ -51,13 +48,13 @@ export type UnextendOptionTypes<T> = {
|
|
|
51
48
|
};
|
|
52
49
|
export type UseCaseHookOptions<T, TUseCaseOptions extends object = object> = UnextendOptionTypes<TUseCaseOptions> & UseCaseHookOwnOptions<T, TUseCaseOptions>;
|
|
53
50
|
export interface ReducersHook {
|
|
54
|
-
<T extends ReducerMap, TUseCaseOptions extends object = object>(usecase: UseCase<T & SymbolSetTarget<NonEntitySymbolSet>, TUseCaseOptions>, options?: TUseCaseOptions, deps?:
|
|
51
|
+
<T extends ReducerMap, TUseCaseOptions extends object = object>(usecase: UseCase<T & SymbolSetTarget<NonEntitySymbolSet>, TUseCaseOptions>, options?: TUseCaseOptions, deps?: Dependencies): T;
|
|
55
52
|
}
|
|
56
53
|
export interface ContextualCoreCollectionHook {
|
|
57
|
-
<T, TEntityReducers extends EntityReducerMap<T>>(usecase: InferableEntityUseCase<T, TEntityReducers>, options?: UseCaseHookContextualOptions<T>, deps?:
|
|
54
|
+
<T, TEntityReducers extends EntityReducerMap<T>>(usecase: InferableEntityUseCase<T, TEntityReducers>, options?: UseCaseHookContextualOptions<T>, deps?: Dependencies): ContextualCoreCollection<T, TEntityReducers>;
|
|
58
55
|
}
|
|
59
56
|
export interface RootCoreCollectionHook {
|
|
60
|
-
<T, TEntityReducers extends EntityReducerMap<T>, TUseCaseOptions extends object = object>(entity: T | EntityGetter<T>, usecase: InferableEntityUseCase<T, TEntityReducers & EntityReducers<T>, TUseCaseOptions>, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?:
|
|
57
|
+
<T, TEntityReducers extends EntityReducerMap<T>, TUseCaseOptions extends object = object, TDependencies extends Dependencies = Dependencies>(entity: T | EntityGetter<T, TDependencies>, usecase: InferableEntityUseCase<T, TEntityReducers & EntityReducers<T>, TUseCaseOptions>, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?: TDependencies): RootCoreCollection<T, EntityReducers<T, TEntityReducers>>;
|
|
61
58
|
}
|
|
62
59
|
export interface CoreCollectionHook extends ContextualCoreCollectionHook, RootCoreCollectionHook {
|
|
63
60
|
}
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { valueUseCase } from '../../usecases/valueUseCase';
|
|
2
2
|
export const triggerWatchers = (watch, newEntity, oldEntity) => {
|
|
3
|
+
const { matchProperty } = valueUseCase();
|
|
3
4
|
for (const [fieldPath, watcher] of Object.entries(watch)) {
|
|
4
|
-
|
|
5
|
-
watcher(
|
|
6
|
-
fieldPaths,
|
|
7
|
-
newEntity,
|
|
8
|
-
oldEntity,
|
|
9
|
-
newValue,
|
|
10
|
-
oldValue,
|
|
11
|
-
});
|
|
5
|
+
matchProperty(oldEntity, newEntity, fieldPath, (result) => {
|
|
6
|
+
watcher(result);
|
|
12
7
|
});
|
|
13
8
|
}
|
|
14
9
|
};
|
package/es/types.d.ts
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createUseCase } from '@mic-rexjs/usecases';
|
|
2
|
-
import { ArgumentTypes } from '../../enums/ArgumentTypes';
|
|
3
2
|
import { createContext } from 'react';
|
|
3
|
+
import { ArgumentTypes } from '../../enums/ArgumentTypes';
|
|
4
4
|
import { Statuses } from '../../enums/Statuses';
|
|
5
5
|
export const contextUseCase = createUseCase(() => {
|
|
6
6
|
const referenceMap = new Map();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import { ArgumentTypes } from '../../enums/ArgumentTypes';
|
|
3
|
-
import { Statuses } from '../../enums/Statuses';
|
|
4
1
|
import { AsyncEntityGenerator, EntityGenerator, EntityReducer, EntityStore, ReducerKeys, Reducers } from '@mic-rexjs/usecases';
|
|
5
2
|
import { EntityReducerMap, InferableUseCase, ReducerMap } from '@mic-rexjs/usecases/es/types';
|
|
3
|
+
import { ArgumentTypes } from '../../enums/ArgumentTypes';
|
|
4
|
+
import { Statuses } from '../../enums/Statuses';
|
|
6
5
|
export type ContextualEntityReducer<T, TEntityReducer extends EntityReducer<T>> = TEntityReducer extends (entity: infer TEntity, ...args: infer TArgs) => infer TReturn ? (...args: TArgs) => TReturn extends AsyncEntityGenerator<TEntity, infer TResult> ? Promise<TResult> : TReturn extends EntityGenerator<TEntity, infer TResult> ? TResult : TReturn : never;
|
|
7
6
|
export type ContextualEntityReducers<T, TEntityReducers extends EntityReducerMap<T>> = {
|
|
8
7
|
[K in ReducerKeys<TEntityReducers>]: ContextualEntityReducer<T, TEntityReducers[K]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { valueUseCase } from '../valueUseCase';
|
|
2
|
+
export const methodUseCase = () => {
|
|
3
|
+
const { isValueMatched } = valueUseCase();
|
|
4
|
+
const cacheCall = (factory, options) => {
|
|
5
|
+
let cache;
|
|
6
|
+
const { onShouldCache = () => {
|
|
7
|
+
return true;
|
|
8
|
+
}, onCompare = (newArgs, oldArgs) => {
|
|
9
|
+
return isValueMatched(newArgs, oldArgs);
|
|
10
|
+
}, } = options || {};
|
|
11
|
+
return ((...args) => {
|
|
12
|
+
const cacheable = onShouldCache();
|
|
13
|
+
if (cache && cacheable) {
|
|
14
|
+
const { parameters, returnValue } = cache;
|
|
15
|
+
if (onCompare(parameters, args)) {
|
|
16
|
+
return returnValue;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const returnValue = factory(...args);
|
|
20
|
+
if (cacheable) {
|
|
21
|
+
cache = {
|
|
22
|
+
parameters: args,
|
|
23
|
+
returnValue,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return returnValue;
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const cacheCalls = (sourceFactories, options) => {
|
|
30
|
+
const cachedFactories = {};
|
|
31
|
+
Object.entries(sourceFactories).forEach(([key, factory]) => {
|
|
32
|
+
cachedFactories[key] = cacheCall(factory, options);
|
|
33
|
+
});
|
|
34
|
+
return cachedFactories;
|
|
35
|
+
};
|
|
36
|
+
const captureCalls = (obj, callback) => {
|
|
37
|
+
const newObj = {};
|
|
38
|
+
Object.keys(obj).forEach((key) => {
|
|
39
|
+
const value = obj[key];
|
|
40
|
+
if (typeof value === 'function') {
|
|
41
|
+
newObj[key] = ((...args) => {
|
|
42
|
+
return callback(key, args);
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
newObj[key] = value;
|
|
47
|
+
});
|
|
48
|
+
return newObj;
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
cacheCall,
|
|
52
|
+
cacheCalls,
|
|
53
|
+
captureCalls,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Reducers } 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 CacheableFactory> {
|
|
11
|
+
parameters: Parameters<T>;
|
|
12
|
+
returnValue: ReturnType<T>;
|
|
13
|
+
}
|
|
14
|
+
export interface CaptureCallFactory {
|
|
15
|
+
<T>(key: string, args: RestArguments): T;
|
|
16
|
+
}
|
|
17
|
+
export type MethodReducers = Reducers<{
|
|
18
|
+
cacheCall<T extends CacheableFactory>(factory: T, options?: CacheCallOptions): T;
|
|
19
|
+
cacheCalls<T extends Record<string, CacheableFactory>>(sourceFactories: T, options?: CacheCallOptions): T;
|
|
20
|
+
captureCalls<T extends object>(obj: T, callback: CaptureCallFactory): T;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { createUseCase, entityUseCase } from '@mic-rexjs/usecases';
|
|
2
|
+
export const valueUseCase = createUseCase(() => {
|
|
3
|
+
let keyIndex = 0;
|
|
4
|
+
return () => {
|
|
5
|
+
let prevKeyIndex = keyIndex++;
|
|
6
|
+
const entityReducers = entityUseCase();
|
|
7
|
+
const hasField = (entity, field) => {
|
|
8
|
+
if (typeof entity !== 'object' || entity === null) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return Object.hasOwn(entity, field);
|
|
12
|
+
};
|
|
13
|
+
const isValueChanged = (entity, value) => {
|
|
14
|
+
return entity !== value;
|
|
15
|
+
};
|
|
16
|
+
const isValueMatched = (entity, value, onMatchFailed) => {
|
|
17
|
+
if (entity === value) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const isObject1 = typeof entity === 'object' && entity !== null;
|
|
21
|
+
const isObject2 = typeof value === 'object' && value !== null;
|
|
22
|
+
if (!isObject1 || !isObject2) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
let allMatched = true;
|
|
26
|
+
const keys1 = Object.keys(entity);
|
|
27
|
+
const keys2 = Object.keys(value);
|
|
28
|
+
const { length: length1 } = keys1;
|
|
29
|
+
const keys = [...keys1, ...keys2];
|
|
30
|
+
const hasCallback = typeof onMatchFailed === 'function';
|
|
31
|
+
for (let i = 0, { length } = keys; i < length; i++) {
|
|
32
|
+
const key = keys[i];
|
|
33
|
+
const isFromKeys2 = i >= length1;
|
|
34
|
+
const isInKey1 = keys1.includes(key);
|
|
35
|
+
const isUsed = isFromKeys2 && isInKey1;
|
|
36
|
+
if (isUsed) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const hasField1 = Object.hasOwn(entity, key);
|
|
40
|
+
const hasField2 = Object.hasOwn(value, key);
|
|
41
|
+
const onlyHasField1 = hasField1 && !hasField2;
|
|
42
|
+
const onlyHasField2 = !hasField1 && hasField2;
|
|
43
|
+
const onlyHasOneField = onlyHasField1 || onlyHasField2;
|
|
44
|
+
const value1 = entity[key];
|
|
45
|
+
const value2 = value[key];
|
|
46
|
+
const matched = value1 === value2;
|
|
47
|
+
if (!onlyHasOneField && matched) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
allMatched = false;
|
|
51
|
+
if (hasCallback) {
|
|
52
|
+
onMatchFailed(key, value2, value1);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return allMatched;
|
|
58
|
+
};
|
|
59
|
+
const matchProperty = (entity, value, fieldPath, onFailed) => {
|
|
60
|
+
let allMatched = true;
|
|
61
|
+
let currentFieldPath = fieldPath;
|
|
62
|
+
const list = [
|
|
63
|
+
{
|
|
64
|
+
fieldPaths: [],
|
|
65
|
+
newEntity: value,
|
|
66
|
+
newValue: value,
|
|
67
|
+
oldEntity: entity,
|
|
68
|
+
oldValue: entity,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
do {
|
|
72
|
+
const { oldValue, newValue, fieldPaths } = list.shift();
|
|
73
|
+
const [, key = currentFieldPath, subFieldPath = ''] = currentFieldPath.match(/^([^.]+)\.(.+)$/) || [];
|
|
74
|
+
const hasOldField = hasField(oldValue, key);
|
|
75
|
+
const hasNewField = hasField(newValue, key);
|
|
76
|
+
if (hasOldField || hasNewField) {
|
|
77
|
+
const subOldValue = hasOldField ? oldValue[key] : void 0;
|
|
78
|
+
const subNewValue = hasNewField ? newValue[key] : void 0;
|
|
79
|
+
const result = {
|
|
80
|
+
fieldPaths: [...fieldPaths, key],
|
|
81
|
+
newEntity: value,
|
|
82
|
+
newValue: subNewValue,
|
|
83
|
+
oldEntity: entity,
|
|
84
|
+
oldValue: subOldValue,
|
|
85
|
+
};
|
|
86
|
+
if (subFieldPath) {
|
|
87
|
+
currentFieldPath = subFieldPath;
|
|
88
|
+
list.push(result);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (subOldValue === subNewValue) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
allMatched = false;
|
|
95
|
+
onFailed?.(result);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (/^\d+^/.test(key)) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const oldArray = Array.isArray(oldValue) ? oldValue : [];
|
|
102
|
+
const newArray = Array.isArray(newValue) ? newValue : [];
|
|
103
|
+
const { length: oldLength } = oldArray;
|
|
104
|
+
const { length: newLength } = newArray;
|
|
105
|
+
const length = Math.max(oldLength, newLength);
|
|
106
|
+
for (let i = 0; i < length; i++) {
|
|
107
|
+
list.push({
|
|
108
|
+
fieldPaths: [...fieldPaths, `${i}`],
|
|
109
|
+
newEntity: value,
|
|
110
|
+
newValue: newArray[i],
|
|
111
|
+
oldEntity: entity,
|
|
112
|
+
oldValue: oldArray[i],
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
} while (list.length > 0);
|
|
116
|
+
return allMatched;
|
|
117
|
+
};
|
|
118
|
+
const recordValue = function* (entity, value) {
|
|
119
|
+
const changed = isValueChanged(entity, value);
|
|
120
|
+
if (!changed) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
yield value;
|
|
124
|
+
return true;
|
|
125
|
+
};
|
|
126
|
+
const recordValueDiff = function* (entity, value) {
|
|
127
|
+
const isArray1 = Array.isArray(entity);
|
|
128
|
+
const isArray2 = Array.isArray(value);
|
|
129
|
+
const isArray = isArray1 && isArray2;
|
|
130
|
+
const result = (isArray ? [] : {});
|
|
131
|
+
if (isArray) {
|
|
132
|
+
const { length: length1 } = entity;
|
|
133
|
+
const { length: length2 } = value;
|
|
134
|
+
result.length = Math.max(length1, length2);
|
|
135
|
+
}
|
|
136
|
+
const matched = isValueMatched(entity, value, (key, newValue) => {
|
|
137
|
+
result[key] = newValue;
|
|
138
|
+
});
|
|
139
|
+
if (!matched) {
|
|
140
|
+
yield value;
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
};
|
|
144
|
+
const recordValueMatch = function* (entity, value) {
|
|
145
|
+
const matched = isValueMatched(entity, value);
|
|
146
|
+
if (matched) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
yield value;
|
|
150
|
+
return false;
|
|
151
|
+
};
|
|
152
|
+
const recordValueMatchWith = function* (entity, value, key = keyIndex + 1) {
|
|
153
|
+
const matched = yield* recordValueMatch(entity, value);
|
|
154
|
+
if (!matched) {
|
|
155
|
+
// 不管是不是使用 `keyIndex` 生成的 `key`,都自增一次,如果是,则可以保持一致
|
|
156
|
+
keyIndex++;
|
|
157
|
+
prevKeyIndex = key;
|
|
158
|
+
}
|
|
159
|
+
return prevKeyIndex;
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
...entityReducers,
|
|
163
|
+
isValueChanged,
|
|
164
|
+
isValueMatched,
|
|
165
|
+
matchProperty,
|
|
166
|
+
recordValue,
|
|
167
|
+
recordValueDiff,
|
|
168
|
+
recordValueMatch,
|
|
169
|
+
recordValueMatchWith,
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EntityGenerator, EntityReducers } from '@mic-rexjs/usecases';
|
|
2
|
+
import { MatchPropertyFailedResult } from '../../entities/matchPropertyFailedResult/types';
|
|
3
|
+
export interface MatchPropertyFailedCallback<T> {
|
|
4
|
+
(result: MatchPropertyFailedResult<T>): void;
|
|
5
|
+
}
|
|
6
|
+
export interface MatchValueFailedCallback<T> {
|
|
7
|
+
<K extends keyof T>(key: K, newValue: T[K], oldValue: T[K]): void;
|
|
8
|
+
}
|
|
9
|
+
export type ValueReducers<T> = EntityReducers<T, {
|
|
10
|
+
isValueChanged<S extends T>(entity: S, value: S): boolean;
|
|
11
|
+
isValueMatched<S extends T>(entity: S, value: S, onMatchFailed?: MatchValueFailedCallback<S>): boolean;
|
|
12
|
+
matchProperty<S extends T>(entity: S, value: S, fieldPath: string, onFailed?: MatchPropertyFailedCallback<S>): boolean;
|
|
13
|
+
recordValue<S extends T>(entity: S, value: S): EntityGenerator<S, boolean>;
|
|
14
|
+
recordValueDiff<S extends T>(entity: S, value: S): EntityGenerator<S, Partial<S>>;
|
|
15
|
+
recordValueMatch<S extends T>(entity: S, value: S): EntityGenerator<S, boolean>;
|
|
16
|
+
recordValueMatchWith<S extends T>(entity: S, value: S, key?: number): EntityGenerator<S, number>;
|
|
17
|
+
}>;
|
|
18
|
+
export interface ValueUseCase {
|
|
19
|
+
<T>(): ValueReducers<T>;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -7,9 +7,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.SafeUseCaseFragment = void 0;
|
|
8
8
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
9
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
-
var _react = require("react");
|
|
11
10
|
var _useUseCase3 = require("../../hooks/useUseCase");
|
|
12
11
|
var _ahooks = require("ahooks");
|
|
12
|
+
var _react = require("react");
|
|
13
13
|
var SafeUseCaseFragment = exports.SafeUseCaseFragment = function SafeUseCaseFragment(_ref) {
|
|
14
14
|
var usecase = _ref.usecase,
|
|
15
15
|
watch = _ref.watch,
|
|
@@ -8,10 +8,10 @@ exports.UseCaseFragment = void 0;
|
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
10
10
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
-
var _react = require("react");
|
|
12
11
|
var _useUseCase2 = require("../../hooks/useUseCase");
|
|
13
|
-
var _contextUseCase = require("../../usecases/contextUseCase");
|
|
14
12
|
var _SafeUseCaseFragment = require("../SafeUseCaseFragment");
|
|
13
|
+
var _react = require("react");
|
|
14
|
+
var _contextUseCase = require("../../usecases/contextUseCase");
|
|
15
15
|
var _excluded = ["usecase"];
|
|
16
16
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
17
17
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -7,17 +7,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.useArgumentTypes = void 0;
|
|
8
8
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
9
9
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
-
var _ArgumentTypes = require("../../enums/ArgumentTypes");
|
|
11
10
|
var _useConstant = require("../useConstant");
|
|
11
|
+
var _ArgumentTypes = require("../../enums/ArgumentTypes");
|
|
12
12
|
var useArgumentTypes = exports.useArgumentTypes = function useArgumentTypes(args) {
|
|
13
13
|
return (0, _useConstant.useConstant)(function () {
|
|
14
|
-
var types = _ArgumentTypes.ArgumentTypes.None;
|
|
15
14
|
var _args = (0, _slicedToArray2["default"])(args, 2),
|
|
16
15
|
arg2 = _args[1];
|
|
17
16
|
var type2 = (0, _typeof2["default"])(arg2);
|
|
18
17
|
if (type2 === 'function') {
|
|
19
|
-
|
|
18
|
+
return _ArgumentTypes.ArgumentTypes.Entity;
|
|
20
19
|
}
|
|
21
|
-
return
|
|
20
|
+
return _ArgumentTypes.ArgumentTypes.None;
|
|
22
21
|
});
|
|
23
22
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useConstantEntityReducers = void 0;
|
|
7
|
+
var _useConstant = require("../useConstant");
|
|
8
|
+
var _usecases = require("@mic-rexjs/usecases");
|
|
9
|
+
var useConstantEntityReducers = exports.useConstantEntityReducers = function useConstantEntityReducers(initailEntity, usecase, options) {
|
|
10
|
+
return (0, _useConstant.useConstant)(function () {
|
|
11
|
+
return (0, _usecases.createEntityReducers)(initailEntity, usecase, options);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useConstantReducers = void 0;
|
|
7
|
+
var _useConstant = require("../useConstant");
|
|
8
|
+
var useConstantReducers = exports.useConstantReducers = function useConstantReducers(usecase, options) {
|
|
9
|
+
return (0, _useConstant.useConstant)(function () {
|
|
10
|
+
return usecase(options);
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
4
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
5
|
+
var _ = require(".");
|
|
5
6
|
var _globals = require("@jest/globals");
|
|
6
7
|
var _react = require("@testing-library/react");
|
|
7
|
-
var _ = require(".");
|
|
8
|
-
var _ArgumentTypes = require("../../enums/ArgumentTypes");
|
|
9
8
|
var _react2 = require("react");
|
|
9
|
+
var _ArgumentTypes = require("../../enums/ArgumentTypes");
|
|
10
10
|
var testUseCase = function testUseCase() {
|
|
11
11
|
return {};
|
|
12
12
|
};
|
|
@@ -4,25 +4,36 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.useContextualItem = void 0;
|
|
7
|
+
var _useConstantReducers2 = require("../useConstantReducers");
|
|
8
|
+
var _useDepsKey = require("../useDepsKey");
|
|
7
9
|
var _ahooks = require("ahooks");
|
|
8
10
|
var _Statuses = require("../../enums/Statuses");
|
|
9
|
-
var
|
|
11
|
+
var _methodUseCase = require("../../usecases/methodUseCase");
|
|
10
12
|
var useContextualItem = exports.useContextualItem = function useContextualItem(contextItem, statuses, createFactory) {
|
|
11
|
-
var
|
|
13
|
+
var deps = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
|
|
14
|
+
var depsKey = (0, _useDepsKey.useDepsKey)(deps);
|
|
12
15
|
var factoryRef = (0, _ahooks.useLatest)(createFactory);
|
|
13
|
-
var
|
|
16
|
+
var _useConstantReducers = (0, _useConstantReducers2.useConstantReducers)(_methodUseCase.methodUseCase),
|
|
17
|
+
cacheCall = _useConstantReducers.cacheCall;
|
|
18
|
+
var onCache = (0, _ahooks.useMemoizedFn)(function () {
|
|
19
|
+
var currentFactory = factoryRef.current;
|
|
14
20
|
void depsKey;
|
|
15
|
-
|
|
21
|
+
// 防止在以下 `onCreate()` 多次调用实际 `factory`
|
|
22
|
+
return cacheCall(currentFactory, {
|
|
16
23
|
onCompare: function onCompare() {
|
|
17
24
|
return true;
|
|
18
25
|
}
|
|
19
26
|
});
|
|
20
|
-
}
|
|
27
|
+
});
|
|
28
|
+
var onCreate = (0, _ahooks.useCreation)(function () {
|
|
29
|
+
void depsKey;
|
|
30
|
+
return onCache();
|
|
31
|
+
}, [depsKey, onCache]);
|
|
21
32
|
return (0, _ahooks.useCreation)(function () {
|
|
22
33
|
var rootEnabled = (statuses & _Statuses.Statuses.RootEnabled) === _Statuses.Statuses.RootEnabled;
|
|
23
34
|
if (!rootEnabled && contextItem) {
|
|
24
35
|
return contextItem;
|
|
25
36
|
}
|
|
26
|
-
return
|
|
27
|
-
}, [statuses, contextItem,
|
|
37
|
+
return onCreate();
|
|
38
|
+
}, [statuses, contextItem, onCreate]);
|
|
28
39
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useDepsKey = void 0;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _useConstantEntityReducers = require("../useConstantEntityReducers");
|
|
10
|
+
var _valueUseCase = require("../../usecases/valueUseCase");
|
|
11
|
+
var useDepsKey = exports.useDepsKey = function useDepsKey(deps) {
|
|
12
|
+
var _useConstantEntityRed = (0, _useConstantEntityReducers.useConstantEntityReducers)(deps, _valueUseCase.valueUseCase),
|
|
13
|
+
recordValueMatchWith = _useConstantEntityRed.recordValueMatchWith;
|
|
14
|
+
var _recordValueMatchWith = recordValueMatchWith(deps),
|
|
15
|
+
_recordValueMatchWith2 = (0, _slicedToArray2["default"])(_recordValueMatchWith, 2),
|
|
16
|
+
depsKey = _recordValueMatchWith2[1];
|
|
17
|
+
return depsKey;
|
|
18
|
+
};
|