@mic-rexjs/usecases-react 1.4.0 → 1.5.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 (40) hide show
  1. package/README.md +2 -2
  2. package/dist/index.min.js +1 -1
  3. package/es/components/UseCaseFragment/types.d.ts +1 -1
  4. package/es/hooks/useCompareDeps/index.js +3 -16
  5. package/es/hooks/useReducer/index.d.ts +2 -0
  6. package/es/hooks/useReducer/index.js +20 -0
  7. package/es/hooks/useUseCase/index.js +2 -2
  8. package/es/hooks/useUseCase/index.test.js +493 -41
  9. package/es/hooks/useUseCase/types.d.ts +18 -6
  10. package/es/index.d.ts +1 -0
  11. package/es/index.js +1 -0
  12. package/es/methods/compareProperty/index.d.ts +2 -0
  13. package/es/methods/compareProperty/index.js +34 -0
  14. package/es/methods/compareProperty/types.d.ts +3 -0
  15. package/es/methods/hasField/index.d.ts +1 -0
  16. package/es/methods/hasField/index.js +6 -0
  17. package/es/methods/initEntityReducers/types.d.ts +1 -1
  18. package/es/methods/isSameArray/index.d.ts +1 -0
  19. package/es/methods/isSameArray/index.js +14 -0
  20. package/es/methods/triggerCallbacks/index.d.ts +1 -1
  21. package/es/methods/triggerCallbacks/index.js +3 -3
  22. package/es/methods/triggerWatchers/index.d.ts +1 -1
  23. package/es/methods/triggerWatchers/index.js +12 -8
  24. package/lib/hooks/useCompareDeps/index.js +3 -16
  25. package/lib/hooks/useReducer/index.js +30 -0
  26. package/lib/hooks/useUseCase/index.js +2 -2
  27. package/lib/hooks/useUseCase/index.test.js +643 -91
  28. package/lib/index.js +7 -0
  29. package/lib/methods/compareProperty/index.js +50 -0
  30. package/lib/methods/hasField/index.js +15 -0
  31. package/lib/methods/isSameArray/index.js +21 -0
  32. package/lib/methods/triggerCallbacks/index.js +3 -3
  33. package/lib/methods/triggerWatchers/index.js +16 -9
  34. package/package.json +1 -1
  35. package/es/hooks/useScope/index.d.ts +0 -2
  36. package/es/hooks/useScope/index.js +0 -3
  37. package/es/hooks/useScope/types.d.ts +0 -3
  38. package/lib/hooks/useScope/index.js +0 -10
  39. /package/es/{hooks/useScope → methods/compareProperty}/types.js +0 -0
  40. /package/lib/{hooks/useScope → methods/compareProperty}/types.js +0 -0
@@ -5,15 +5,27 @@ export type CoreCollection<T, TEntityReducers extends EntityReducers<T>, TProvid
5
5
  export interface EntityGetter<T> {
6
6
  (): T;
7
7
  }
8
- export interface EntityWatcher<T> {
9
- (newEntity: T, prevEntity: T): void;
8
+ export interface EntityWatchEvent<T, TValue = unknown> {
9
+ fieldPaths: string[];
10
+ newEntity: T;
11
+ newValue: TValue;
12
+ oldEntity: T;
13
+ oldValue: TValue;
10
14
  }
11
- export type EntityWatchMap<T> = T extends unknown[] ? Record<number, EntityWatcher<T>> : T extends object ? {
12
- [K in keyof T]?: EntityWatcher<T>;
13
- } : object;
15
+ export interface EntityWatcher<T, TValue = unknown> {
16
+ (event: EntityWatchEvent<T, TValue>): void;
17
+ }
18
+ export type PropertyPath<T, K extends keyof T = keyof T & string> = K extends infer TKey ? `${TKey & (string | number)}${'' | DotAccessorFieldPath<T[TKey & keyof T]>}` : never;
19
+ export type DotAccessorFieldPath<T> = T extends unknown[] ? '.length' | `${'' | `.${number}`}${DotAccessorFieldPath<T[number]>}` : T extends object ? `.${PropertyPath<T>}` : '';
20
+ export type FieldPath<T> = T extends unknown[] ? FieldPath<T[number]> | 'length' : T extends object ? PropertyPath<T> : never;
21
+ export type ExtractPropertyType<T, TPath> = TPath extends `${infer TKey}.${infer TSubPath}` ? T extends unknown[] ? ExtractPropertyType<T[number], TKey extends `${number}` ? TSubPath : TPath> : ExtractPropertyType<T[TKey & keyof T], TSubPath> : T extends unknown[] ? TPath extends 'length' ? T[TPath] : TPath extends `${number}` ? T[number] : ExtractPropertyType<T[number], TPath> : T[TPath & keyof T];
22
+ export type ExtractFieldType<T, TPath> = TPath extends `${infer TKey}.${infer TSubProperty}` ? ExtractPropertyType<T[TKey & keyof T], TSubProperty> : T[TPath & keyof T];
23
+ export type EntityWatchMap<T> = {
24
+ [K in FieldPath<T>]?: EntityWatcher<T, ExtractFieldType<T, K>>;
25
+ };
14
26
  export interface UseCaseHookContextualOptions<T> {
15
27
  watch?: EntityWatchMap<T>;
16
- onChange?(newEntity: T, prevEntity: T): void;
28
+ onChange?(newEntity: T, oldEntity: T): void;
17
29
  }
18
30
  export interface UseCaseHookOwnOptions<T, TUseCaseOptions extends object> extends UseCaseHookContextualOptions<T> {
19
31
  stateless?: boolean;
package/es/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { UseCaseFragment } from './components/UseCaseFragment';
2
+ export { useReducer } from './hooks/useReducer';
2
3
  export { useUseCase } from './hooks/useUseCase';
3
4
  export type { CoreCollection } from './hooks/useUseCase/types';
4
5
  export type { UseCaseHookOptions } from './hooks/useUseCase/types';
package/es/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { UseCaseFragment } from './components/UseCaseFragment';
2
+ export { useReducer } from './hooks/useReducer';
2
3
  export { useUseCase } from './hooks/useUseCase';
@@ -0,0 +1,2 @@
1
+ import { ComparePropertyCallback } from './types';
2
+ export declare const compareProperty: <T, S>(from: T, to: S, fieldPath: string, callback: ComparePropertyCallback, fieldPathStack?: string[]) => void;
@@ -0,0 +1,34 @@
1
+ import { hasField } from '../hasField';
2
+ export const compareProperty = (from, to, fieldPath, callback, fieldPathStack = []) => {
3
+ const undef = void 0;
4
+ const [, key = fieldPath, subFieldPath = ''] = fieldPath.match(/^([^.]+)\.(.+)$/) || [];
5
+ const hasFromField = hasField(from, key);
6
+ const hasToField = hasField(to, key);
7
+ const currentFieldPathStack = [...fieldPathStack, key];
8
+ if (hasFromField || hasToField) {
9
+ const fromValue = hasFromField ? from[key] : undef;
10
+ const toValue = hasToField ? to[key] : undef;
11
+ if (subFieldPath) {
12
+ compareProperty(fromValue, toValue, subFieldPath, callback, currentFieldPathStack);
13
+ return;
14
+ }
15
+ if (fromValue === toValue) {
16
+ return;
17
+ }
18
+ callback(fromValue, toValue, currentFieldPathStack);
19
+ return;
20
+ }
21
+ if (/^\d+^/.test(key)) {
22
+ return;
23
+ }
24
+ const fromArray = Array.isArray(from) ? from : [];
25
+ const toArray = Array.isArray(to) ? to : [];
26
+ const { length: fromLength } = fromArray;
27
+ const { length: toLength } = toArray;
28
+ const length = Math.max(fromLength, toLength);
29
+ for (let i = 0; i < length; i++) {
30
+ const fromItem = fromArray[i];
31
+ const toItem = toArray[i];
32
+ compareProperty(fromItem, toItem, fieldPath, callback, [...fieldPathStack, `${i}`]);
33
+ }
34
+ };
@@ -0,0 +1,3 @@
1
+ export interface ComparePropertyCallback {
2
+ <T, S>(fromValue: T, toValue: S, fieldPaths: string[]): void;
3
+ }
@@ -0,0 +1 @@
1
+ export declare const hasField: <T>(data: T, field: string) => boolean;
@@ -0,0 +1,6 @@
1
+ export const hasField = (data, field) => {
2
+ if (typeof data !== 'object' || data === null) {
3
+ return false;
4
+ }
5
+ return Object.hasOwn(data, field);
6
+ };
@@ -1,3 +1,3 @@
1
1
  export interface EntityChangeEventHandler<T> {
2
- (newEntity: T, prevEntity: T): void;
2
+ (newEntity: T, oldEntity: T): void;
3
3
  }
@@ -0,0 +1 @@
1
+ export declare const isSameArray: (array1: unknown[], array2: unknown[]) => boolean;
@@ -0,0 +1,14 @@
1
+ export const isSameArray = (array1, array2) => {
2
+ const { length: length1 } = array1;
3
+ const { length: length2 } = array2;
4
+ if (length1 !== length2) {
5
+ return false;
6
+ }
7
+ for (let i = 0; i < length1; i++) {
8
+ if (array1[i] === array2[i]) {
9
+ continue;
10
+ }
11
+ return false;
12
+ }
13
+ return true;
14
+ };
@@ -1,3 +1,3 @@
1
1
  import { OptionsRefCollection } from '../../hooks/useOptionsRefCollection/types';
2
2
  import { UseCaseHookOptions } from '../../hooks/useUseCase/types';
3
- export declare const triggerCallbacks: <T, TUseCaseOptions extends object, TOptions extends UseCaseHookOptions<T, TUseCaseOptions> = UseCaseHookOptions<T, TUseCaseOptions>>(optionsRefCollection: OptionsRefCollection<TOptions>, newEntity: T, prevEntity: T) => void;
3
+ export declare const triggerCallbacks: <T, TUseCaseOptions extends object, TOptions extends UseCaseHookOptions<T, TUseCaseOptions> = UseCaseHookOptions<T, TUseCaseOptions>>(optionsRefCollection: OptionsRefCollection<TOptions>, newEntity: T, oldEntity: T) => void;
@@ -1,5 +1,5 @@
1
1
  import { triggerWatchers } from '../triggerWatchers';
2
- export const triggerCallbacks = (optionsRefCollection, newEntity, prevEntity) => {
2
+ export const triggerCallbacks = (optionsRefCollection, newEntity, oldEntity) => {
3
3
  for (let { length: i } = optionsRefCollection; i > 0; i--) {
4
4
  const { current: options } = optionsRefCollection[i - 1];
5
5
  if (!options) {
@@ -7,8 +7,8 @@ export const triggerCallbacks = (optionsRefCollection, newEntity, prevEntity) =>
7
7
  }
8
8
  const { onChange, watch } = options;
9
9
  if (watch) {
10
- triggerWatchers(watch, newEntity, prevEntity);
10
+ triggerWatchers(watch, newEntity, oldEntity);
11
11
  }
12
- onChange?.(newEntity, prevEntity);
12
+ onChange?.(newEntity, oldEntity);
13
13
  }
14
14
  };
@@ -1,2 +1,2 @@
1
1
  import { EntityWatchMap } from '../../hooks/useUseCase/types';
2
- export declare const triggerWatchers: <T>(watch: EntityWatchMap<T>, newEntity: T, prevEntity: T) => void;
2
+ export declare const triggerWatchers: <T>(watch: EntityWatchMap<T>, newEntity: T, oldEntity: T) => void;
@@ -1,10 +1,14 @@
1
- export const triggerWatchers = (watch, newEntity, prevEntity) => {
2
- for (const [property, watcher] of Object.entries(watch)) {
3
- const newValue = newEntity?.[property];
4
- const prevValue = prevEntity?.[property];
5
- if (newValue === prevValue) {
6
- continue;
7
- }
8
- watcher(newEntity, prevEntity);
1
+ import { compareProperty } from '../compareProperty';
2
+ export const triggerWatchers = (watch, newEntity, oldEntity) => {
3
+ for (const [fieldPath, watcher] of Object.entries(watch)) {
4
+ compareProperty(oldEntity, newEntity, fieldPath, (oldValue, newValue, fieldPaths) => {
5
+ watcher({
6
+ fieldPaths,
7
+ newEntity,
8
+ oldEntity,
9
+ newValue,
10
+ oldValue,
11
+ });
12
+ });
9
13
  }
10
14
  };
@@ -5,27 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useCompareDeps = void 0;
7
7
  var _react = require("react");
8
- var _useScope = require("../useScope");
8
+ var _isSameArray = require("../../methods/isSameArray");
9
9
  var useCompareDeps = function useCompareDeps(deps) {
10
10
  var updateTimesRef = (0, _react.useRef)(0);
11
11
  var prevDepsRef = (0, _react.useRef)([]);
12
12
  var prevDeps = prevDepsRef.current;
13
- var prevLength = prevDeps.length;
14
- var length = deps.length;
15
- var updated = (0, _useScope.useScope)(function () {
16
- if (length !== prevLength) {
17
- return true;
18
- }
19
- for (var i = 0; i < length; i++) {
20
- if (deps[i] === prevDeps[i]) {
21
- continue;
22
- }
23
- return true;
24
- }
25
- return false;
26
- });
13
+ var isSame = (0, _isSameArray.isSameArray)(deps, prevDeps);
27
14
  prevDepsRef.current = deps;
28
- updateTimesRef.current += updated ? 1 : 0;
15
+ updateTimesRef.current += isSame ? 0 : 1;
29
16
  return updateTimesRef.current;
30
17
  };
31
18
  exports.useCompareDeps = useCompareDeps;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useReducer = void 0;
7
+ var _isSameArray = require("../../methods/isSameArray");
8
+ var _ahooks = require("ahooks");
9
+ var _react = require("react");
10
+ var useReducer = function useReducer(reducer) {
11
+ var prevReducerRef = (0, _react.useRef)();
12
+ var prevArgsRef = (0, _react.useRef)([]);
13
+ var prevReturnValueRef = (0, _react.useRef)();
14
+ return (0, _ahooks.useMemoizedFn)(function () {
15
+ var returnValue = prevReturnValueRef.current;
16
+ var prevReducer = prevReducerRef.current;
17
+ var prevArgs = prevArgsRef.current;
18
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
19
+ args[_key] = arguments[_key];
20
+ }
21
+ if (reducer !== prevReducer || !(0, _isSameArray.isSameArray)(args, prevArgs)) {
22
+ returnValue = reducer.apply(void 0, args);
23
+ }
24
+ prevReducerRef.current = reducer;
25
+ prevArgsRef.current = args;
26
+ prevReturnValueRef.current = returnValue;
27
+ return returnValue;
28
+ });
29
+ };
30
+ exports.useReducer = useReducer;
@@ -51,11 +51,11 @@ var useUseCase = function useUseCase(arg1, arg2, arg3, arg4) {
51
51
  }
52
52
  return (0, _getRootEntity.getRootEntity)(entityState, arg1, stateless);
53
53
  }, [hasInitialEntity, contextEntity, stateless, entityState, arg1]);
54
- var onEntityChange = (0, _ahooks.useMemoizedFn)(function (newEntity, prevEntity) {
54
+ var onEntityChange = (0, _ahooks.useMemoizedFn)(function (newEntity, oldEntity) {
55
55
  if (!stateless) {
56
56
  setEntityState(newEntity);
57
57
  }
58
- (0, _triggerCallbacks.triggerCallbacks)(optionsRefCollection, newEntity, prevEntity);
58
+ (0, _triggerCallbacks.triggerCallbacks)(optionsRefCollection, newEntity, oldEntity);
59
59
  });
60
60
  var createReducers = (0, _ahooks.useMemoizedFn)(function () {
61
61
  var reducers = {};