palistor 0.0.24
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/LICENSE +21 -0
- package/README.md +947 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/react/createTrackingProxy.d.ts +55 -0
- package/dist/react/createTrackingProxy.d.ts.map +1 -0
- package/dist/react/createTrackingProxy.js +149 -0
- package/dist/react/createTrackingProxy.js.map +1 -0
- package/dist/react/useForm.d.ts +108 -0
- package/dist/react/useForm.d.ts.map +1 -0
- package/dist/react/useForm.js +180 -0
- package/dist/react/useForm.js.map +1 -0
- package/dist/react/useNotifier.d.ts +35 -0
- package/dist/react/useNotifier.d.ts.map +1 -0
- package/dist/react/useNotifier.js +41 -0
- package/dist/react/useNotifier.js.map +1 -0
- package/dist/react/usePersist.d.ts +45 -0
- package/dist/react/usePersist.d.ts.map +1 -0
- package/dist/react/usePersist.js +60 -0
- package/dist/react/usePersist.js.map +1 -0
- package/dist/react/useStoreContext.d.ts +42 -0
- package/dist/react/useStoreContext.d.ts.map +1 -0
- package/dist/react/useStoreContext.js +46 -0
- package/dist/react/useStoreContext.js.map +1 -0
- package/dist/react/useTranslator.d.ts +37 -0
- package/dist/react/useTranslator.d.ts.map +1 -0
- package/dist/react/useTranslator.js +43 -0
- package/dist/react/useTranslator.js.map +1 -0
- package/dist/store/applyPatch/applyPatch.d.ts +17 -0
- package/dist/store/applyPatch/applyPatch.d.ts.map +1 -0
- package/dist/store/applyPatch/applyPatch.js +44 -0
- package/dist/store/applyPatch/applyPatch.js.map +1 -0
- package/dist/store/buildProxy/buildEntityProjectionProxy.d.ts +52 -0
- package/dist/store/buildProxy/buildEntityProjectionProxy.d.ts.map +1 -0
- package/dist/store/buildProxy/buildEntityProjectionProxy.js +321 -0
- package/dist/store/buildProxy/buildEntityProjectionProxy.js.map +1 -0
- package/dist/store/buildProxy/buildListProxy.d.ts +33 -0
- package/dist/store/buildProxy/buildListProxy.d.ts.map +1 -0
- package/dist/store/buildProxy/buildListProxy.js +306 -0
- package/dist/store/buildProxy/buildListProxy.js.map +1 -0
- package/dist/store/buildProxy/buildProxy.d.ts +41 -0
- package/dist/store/buildProxy/buildProxy.d.ts.map +1 -0
- package/dist/store/buildProxy/buildProxy.js +380 -0
- package/dist/store/buildProxy/buildProxy.js.map +1 -0
- package/dist/store/buildProxy/computeProxyKeys.d.ts +15 -0
- package/dist/store/buildProxy/computeProxyKeys.d.ts.map +1 -0
- package/dist/store/buildProxy/computeProxyKeys.js +28 -0
- package/dist/store/buildProxy/computeProxyKeys.js.map +1 -0
- package/dist/store/buildProxy/handleLazyResolve.d.ts +10 -0
- package/dist/store/buildProxy/handleLazyResolve.d.ts.map +1 -0
- package/dist/store/buildProxy/handleLazyResolve.js +26 -0
- package/dist/store/buildProxy/handleLazyResolve.js.map +1 -0
- package/dist/store/buildProxy/initProxyCaches.d.ts +16 -0
- package/dist/store/buildProxy/initProxyCaches.d.ts.map +1 -0
- package/dist/store/buildProxy/initProxyCaches.js +17 -0
- package/dist/store/buildProxy/initProxyCaches.js.map +1 -0
- package/dist/store/compute/computeFieldState.d.ts +10 -0
- package/dist/store/compute/computeFieldState.d.ts.map +1 -0
- package/dist/store/compute/computeFieldState.js +53 -0
- package/dist/store/compute/computeFieldState.js.map +1 -0
- package/dist/store/compute/fieldStateChanged.d.ts +6 -0
- package/dist/store/compute/fieldStateChanged.d.ts.map +1 -0
- package/dist/store/compute/fieldStateChanged.js +20 -0
- package/dist/store/compute/fieldStateChanged.js.map +1 -0
- package/dist/store/compute/index.d.ts +7 -0
- package/dist/store/compute/index.d.ts.map +1 -0
- package/dist/store/compute/index.js +6 -0
- package/dist/store/compute/index.js.map +1 -0
- package/dist/store/compute/isEmpty.d.ts +6 -0
- package/dist/store/compute/isEmpty.d.ts.map +1 -0
- package/dist/store/compute/isEmpty.js +14 -0
- package/dist/store/compute/isEmpty.js.map +1 -0
- package/dist/store/compute/recompute/collectGroupComputeNodes.d.ts +11 -0
- package/dist/store/compute/recompute/collectGroupComputeNodes.d.ts.map +1 -0
- package/dist/store/compute/recompute/collectGroupComputeNodes.js +26 -0
- package/dist/store/compute/recompute/collectGroupComputeNodes.js.map +1 -0
- package/dist/store/compute/recompute/collectGroupLeafNodes.d.ts +11 -0
- package/dist/store/compute/recompute/collectGroupLeafNodes.d.ts.map +1 -0
- package/dist/store/compute/recompute/collectGroupLeafNodes.js +26 -0
- package/dist/store/compute/recompute/collectGroupLeafNodes.js.map +1 -0
- package/dist/store/compute/recompute/index.d.ts +7 -0
- package/dist/store/compute/recompute/index.d.ts.map +1 -0
- package/dist/store/compute/recompute/index.js +6 -0
- package/dist/store/compute/recompute/index.js.map +1 -0
- package/dist/store/compute/recompute/recomputeAndNotify.d.ts +8 -0
- package/dist/store/compute/recompute/recomputeAndNotify.d.ts.map +1 -0
- package/dist/store/compute/recompute/recomputeAndNotify.js +13 -0
- package/dist/store/compute/recompute/recomputeAndNotify.js.map +1 -0
- package/dist/store/compute/recompute/recomputeLeaves.d.ts +23 -0
- package/dist/store/compute/recompute/recomputeLeaves.d.ts.map +1 -0
- package/dist/store/compute/recompute/recomputeLeaves.js +77 -0
- package/dist/store/compute/recompute/recomputeLeaves.js.map +1 -0
- package/dist/store/compute/recompute/recomputeTargeted.d.ts +14 -0
- package/dist/store/compute/recompute/recomputeTargeted.d.ts.map +1 -0
- package/dist/store/compute/recompute/recomputeTargeted.js +50 -0
- package/dist/store/compute/recompute/recomputeTargeted.js.map +1 -0
- package/dist/store/compute/recompute/topologicalSortComputed.d.ts +16 -0
- package/dist/store/compute/recompute/topologicalSortComputed.d.ts.map +1 -0
- package/dist/store/compute/recompute/topologicalSortComputed.js +60 -0
- package/dist/store/compute/recompute/topologicalSortComputed.js.map +1 -0
- package/dist/store/compute/recompute/types.d.ts +24 -0
- package/dist/store/compute/recompute/types.d.ts.map +1 -0
- package/dist/store/compute/recompute/types.js +2 -0
- package/dist/store/compute/recompute/types.js.map +1 -0
- package/dist/store/compute/resolveFlag.d.ts +7 -0
- package/dist/store/compute/resolveFlag.d.ts.map +1 -0
- package/dist/store/compute/resolveFlag.js +12 -0
- package/dist/store/compute/resolveFlag.js.map +1 -0
- package/dist/store/compute/resolveString.d.ts +11 -0
- package/dist/store/compute/resolveString.d.ts.map +1 -0
- package/dist/store/compute/resolveString.js +18 -0
- package/dist/store/compute/resolveString.js.map +1 -0
- package/dist/store/compute/types.d.ts +37 -0
- package/dist/store/compute/types.d.ts.map +1 -0
- package/dist/store/compute/types.js +2 -0
- package/dist/store/compute/types.js.map +1 -0
- package/dist/store/constants.d.ts +83 -0
- package/dist/store/constants.d.ts.map +1 -0
- package/dist/store/constants.js +145 -0
- package/dist/store/constants.js.map +1 -0
- package/dist/store/defineFieldMapping.d.ts +41 -0
- package/dist/store/defineFieldMapping.d.ts.map +1 -0
- package/dist/store/defineFieldMapping.js +42 -0
- package/dist/store/defineFieldMapping.js.map +1 -0
- package/dist/store/defineList.d.ts +14 -0
- package/dist/store/defineList.d.ts.map +1 -0
- package/dist/store/defineList.js +7 -0
- package/dist/store/defineList.js.map +1 -0
- package/dist/store/dirtyTracking/captureInitialValues.d.ts +8 -0
- package/dist/store/dirtyTracking/captureInitialValues.d.ts.map +1 -0
- package/dist/store/dirtyTracking/captureInitialValues.js +16 -0
- package/dist/store/dirtyTracking/captureInitialValues.js.map +1 -0
- package/dist/store/dirtyTracking/collectInitialSnapshot.d.ts +10 -0
- package/dist/store/dirtyTracking/collectInitialSnapshot.d.ts.map +1 -0
- package/dist/store/dirtyTracking/collectInitialSnapshot.js +35 -0
- package/dist/store/dirtyTracking/collectInitialSnapshot.js.map +1 -0
- package/dist/store/dirtyTracking/index.d.ts +7 -0
- package/dist/store/dirtyTracking/index.d.ts.map +1 -0
- package/dist/store/dirtyTracking/index.js +6 -0
- package/dist/store/dirtyTracking/index.js.map +1 -0
- package/dist/store/dirtyTracking/isDirtyValue.d.ts +7 -0
- package/dist/store/dirtyTracking/isDirtyValue.d.ts.map +1 -0
- package/dist/store/dirtyTracking/isDirtyValue.js +25 -0
- package/dist/store/dirtyTracking/isDirtyValue.js.map +1 -0
- package/dist/store/dirtyTracking/mergeInitialValues.d.ts +11 -0
- package/dist/store/dirtyTracking/mergeInitialValues.d.ts.map +1 -0
- package/dist/store/dirtyTracking/mergeInitialValues.js +29 -0
- package/dist/store/dirtyTracking/mergeInitialValues.js.map +1 -0
- package/dist/store/dirtyTracking/recomputeDirtyTargeted.d.ts +17 -0
- package/dist/store/dirtyTracking/recomputeDirtyTargeted.d.ts.map +1 -0
- package/dist/store/dirtyTracking/recomputeDirtyTargeted.js +90 -0
- package/dist/store/dirtyTracking/recomputeDirtyTargeted.js.map +1 -0
- package/dist/store/dirtyTracking/setGroupRevalidate.d.ts +13 -0
- package/dist/store/dirtyTracking/setGroupRevalidate.d.ts.map +1 -0
- package/dist/store/dirtyTracking/setGroupRevalidate.js +32 -0
- package/dist/store/dirtyTracking/setGroupRevalidate.js.map +1 -0
- package/dist/store/entityRegistry/entityRegistry.d.ts +166 -0
- package/dist/store/entityRegistry/entityRegistry.d.ts.map +1 -0
- package/dist/store/entityRegistry/entityRegistry.js +402 -0
- package/dist/store/entityRegistry/entityRegistry.js.map +1 -0
- package/dist/store/entityRegistry/generateId.d.ts +7 -0
- package/dist/store/entityRegistry/generateId.d.ts.map +1 -0
- package/dist/store/entityRegistry/generateId.js +18 -0
- package/dist/store/entityRegistry/generateId.js.map +1 -0
- package/dist/store/entityRegistry/index.d.ts +4 -0
- package/dist/store/entityRegistry/index.d.ts.map +1 -0
- package/dist/store/entityRegistry/index.js +3 -0
- package/dist/store/entityRegistry/index.js.map +1 -0
- package/dist/store/entityRegistry/types.d.ts +50 -0
- package/dist/store/entityRegistry/types.d.ts.map +1 -0
- package/dist/store/entityRegistry/types.js +2 -0
- package/dist/store/entityRegistry/types.js.map +1 -0
- package/dist/store/fieldMapping.typecheck.d.ts +2 -0
- package/dist/store/fieldMapping.typecheck.d.ts.map +1 -0
- package/dist/store/fieldMapping.typecheck.js +71 -0
- package/dist/store/fieldMapping.typecheck.js.map +1 -0
- package/dist/store/groupDeps/createGroupDeps.d.ts +9 -0
- package/dist/store/groupDeps/createGroupDeps.d.ts.map +1 -0
- package/dist/store/groupDeps/createGroupDeps.js +29 -0
- package/dist/store/groupDeps/createGroupDeps.js.map +1 -0
- package/dist/store/groupDeps/createTrackingValues.d.ts +15 -0
- package/dist/store/groupDeps/createTrackingValues.d.ts.map +1 -0
- package/dist/store/groupDeps/createTrackingValues.js +39 -0
- package/dist/store/groupDeps/createTrackingValues.js.map +1 -0
- package/dist/store/groupDeps/getNodeGroupPath.d.ts +9 -0
- package/dist/store/groupDeps/getNodeGroupPath.d.ts.map +1 -0
- package/dist/store/groupDeps/getNodeGroupPath.js +20 -0
- package/dist/store/groupDeps/getNodeGroupPath.js.map +1 -0
- package/dist/store/groupDeps/getRecipientGroups.d.ts +5 -0
- package/dist/store/groupDeps/getRecipientGroups.d.ts.map +1 -0
- package/dist/store/groupDeps/getRecipientGroups.js +15 -0
- package/dist/store/groupDeps/getRecipientGroups.js.map +1 -0
- package/dist/store/groupDeps/groupDeps.d.ts +19 -0
- package/dist/store/groupDeps/groupDeps.d.ts.map +1 -0
- package/dist/store/groupDeps/groupDeps.js +19 -0
- package/dist/store/groupDeps/groupDeps.js.map +1 -0
- package/dist/store/groupDeps/index.d.ts +7 -0
- package/dist/store/groupDeps/index.d.ts.map +1 -0
- package/dist/store/groupDeps/index.js +7 -0
- package/dist/store/groupDeps/index.js.map +1 -0
- package/dist/store/groupDeps/pairKey.d.ts +7 -0
- package/dist/store/groupDeps/pairKey.d.ts.map +1 -0
- package/dist/store/groupDeps/pairKey.js +12 -0
- package/dist/store/groupDeps/pairKey.js.map +1 -0
- package/dist/store/groupDeps/resolveGroupByPath.d.ts +8 -0
- package/dist/store/groupDeps/resolveGroupByPath.d.ts.map +1 -0
- package/dist/store/groupDeps/resolveGroupByPath.js +19 -0
- package/dist/store/groupDeps/resolveGroupByPath.js.map +1 -0
- package/dist/store/init/createNotificationHub.d.ts +81 -0
- package/dist/store/init/createNotificationHub.d.ts.map +1 -0
- package/dist/store/init/createNotificationHub.js +149 -0
- package/dist/store/init/createNotificationHub.js.map +1 -0
- package/dist/store/init/createResolveManager.d.ts +166 -0
- package/dist/store/init/createResolveManager.d.ts.map +1 -0
- package/dist/store/init/createResolveManager.js +502 -0
- package/dist/store/init/createResolveManager.js.map +1 -0
- package/dist/store/init/initGroupSubmitting.d.ts +8 -0
- package/dist/store/init/initGroupSubmitting.d.ts.map +1 -0
- package/dist/store/init/initGroupSubmitting.js +39 -0
- package/dist/store/init/initGroupSubmitting.js.map +1 -0
- package/dist/store/normalizeConfig.d.ts +28 -0
- package/dist/store/normalizeConfig.d.ts.map +1 -0
- package/dist/store/normalizeConfig.js +76 -0
- package/dist/store/normalizeConfig.js.map +1 -0
- package/dist/store/onChangePipeline/computeFieldKey.d.ts +11 -0
- package/dist/store/onChangePipeline/computeFieldKey.d.ts.map +1 -0
- package/dist/store/onChangePipeline/computeFieldKey.js +18 -0
- package/dist/store/onChangePipeline/computeFieldKey.js.map +1 -0
- package/dist/store/onChangePipeline/findOnChangeAncestors.d.ts +8 -0
- package/dist/store/onChangePipeline/findOnChangeAncestors.d.ts.map +1 -0
- package/dist/store/onChangePipeline/findOnChangeAncestors.js +22 -0
- package/dist/store/onChangePipeline/findOnChangeAncestors.js.map +1 -0
- package/dist/store/onChangePipeline/onChangePipeline.d.ts +29 -0
- package/dist/store/onChangePipeline/onChangePipeline.d.ts.map +1 -0
- package/dist/store/onChangePipeline/onChangePipeline.js +99 -0
- package/dist/store/onChangePipeline/onChangePipeline.js.map +1 -0
- package/dist/store/persist/drivers.d.ts +34 -0
- package/dist/store/persist/drivers.d.ts.map +1 -0
- package/dist/store/persist/drivers.js +89 -0
- package/dist/store/persist/drivers.js.map +1 -0
- package/dist/store/persist/index.d.ts +7 -0
- package/dist/store/persist/index.d.ts.map +1 -0
- package/dist/store/persist/index.js +3 -0
- package/dist/store/persist/index.js.map +1 -0
- package/dist/store/persist/persistManager.d.ts +67 -0
- package/dist/store/persist/persistManager.d.ts.map +1 -0
- package/dist/store/persist/persistManager.js +198 -0
- package/dist/store/persist/persistManager.js.map +1 -0
- package/dist/store/persist/types.d.ts +66 -0
- package/dist/store/persist/types.d.ts.map +1 -0
- package/dist/store/persist/types.js +9 -0
- package/dist/store/persist/types.js.map +1 -0
- package/dist/store/resetPipeline/buildResetPatch.d.ts +11 -0
- package/dist/store/resetPipeline/buildResetPatch.d.ts.map +1 -0
- package/dist/store/resetPipeline/buildResetPatch.js +22 -0
- package/dist/store/resetPipeline/buildResetPatch.js.map +1 -0
- package/dist/store/resetPipeline/collectDefaults.d.ts +12 -0
- package/dist/store/resetPipeline/collectDefaults.d.ts.map +1 -0
- package/dist/store/resetPipeline/collectDefaults.js +31 -0
- package/dist/store/resetPipeline/collectDefaults.js.map +1 -0
- package/dist/store/resetPipeline/resetPipeline.d.ts +19 -0
- package/dist/store/resetPipeline/resetPipeline.d.ts.map +1 -0
- package/dist/store/resetPipeline/resetPipeline.js +49 -0
- package/dist/store/resetPipeline/resetPipeline.js.map +1 -0
- package/dist/store/resolvePipeline/applyPendingWrites.d.ts +26 -0
- package/dist/store/resolvePipeline/applyPendingWrites.d.ts.map +1 -0
- package/dist/store/resolvePipeline/applyPendingWrites.js +68 -0
- package/dist/store/resolvePipeline/applyPendingWrites.js.map +1 -0
- package/dist/store/resolvePipeline/createContextTrackingProxy.d.ts +16 -0
- package/dist/store/resolvePipeline/createContextTrackingProxy.d.ts.map +1 -0
- package/dist/store/resolvePipeline/createContextTrackingProxy.js +29 -0
- package/dist/store/resolvePipeline/createContextTrackingProxy.js.map +1 -0
- package/dist/store/resolvePipeline/createValuesTrackingProxy.d.ts +75 -0
- package/dist/store/resolvePipeline/createValuesTrackingProxy.d.ts.map +1 -0
- package/dist/store/resolvePipeline/createValuesTrackingProxy.js +128 -0
- package/dist/store/resolvePipeline/createValuesTrackingProxy.js.map +1 -0
- package/dist/store/resolvePipeline/executeEntityFieldResolve.d.ts +29 -0
- package/dist/store/resolvePipeline/executeEntityFieldResolve.d.ts.map +1 -0
- package/dist/store/resolvePipeline/executeEntityFieldResolve.js +218 -0
- package/dist/store/resolvePipeline/executeEntityFieldResolve.js.map +1 -0
- package/dist/store/resolvePipeline/executeListResolve.d.ts +32 -0
- package/dist/store/resolvePipeline/executeListResolve.d.ts.map +1 -0
- package/dist/store/resolvePipeline/executeListResolve.js +157 -0
- package/dist/store/resolvePipeline/executeListResolve.js.map +1 -0
- package/dist/store/resolvePipeline/executeResolve.d.ts +26 -0
- package/dist/store/resolvePipeline/executeResolve.d.ts.map +1 -0
- package/dist/store/resolvePipeline/executeResolve.js +201 -0
- package/dist/store/resolvePipeline/executeResolve.js.map +1 -0
- package/dist/store/resolvePipeline/findResolvesToRetrigger.d.ts +10 -0
- package/dist/store/resolvePipeline/findResolvesToRetrigger.d.ts.map +1 -0
- package/dist/store/resolvePipeline/findResolvesToRetrigger.js +29 -0
- package/dist/store/resolvePipeline/findResolvesToRetrigger.js.map +1 -0
- package/dist/store/resolvePipeline/index.d.ts +22 -0
- package/dist/store/resolvePipeline/index.d.ts.map +1 -0
- package/dist/store/resolvePipeline/index.js +18 -0
- package/dist/store/resolvePipeline/index.js.map +1 -0
- package/dist/store/resolvePipeline/initResolveStates.d.ts +41 -0
- package/dist/store/resolvePipeline/initResolveStates.d.ts.map +1 -0
- package/dist/store/resolvePipeline/initResolveStates.js +95 -0
- package/dist/store/resolvePipeline/initResolveStates.js.map +1 -0
- package/dist/store/resolvePipeline/resetResolveState.d.ts +8 -0
- package/dist/store/resolvePipeline/resetResolveState.d.ts.map +1 -0
- package/dist/store/resolvePipeline/resetResolveState.js +18 -0
- package/dist/store/resolvePipeline/resetResolveState.js.map +1 -0
- package/dist/store/resolvePipeline/types.d.ts +134 -0
- package/dist/store/resolvePipeline/types.d.ts.map +1 -0
- package/dist/store/resolvePipeline/types.js +54 -0
- package/dist/store/resolvePipeline/types.js.map +1 -0
- package/dist/store/store/NodeRegistry/index.d.ts +3 -0
- package/dist/store/store/NodeRegistry/index.d.ts.map +1 -0
- package/dist/store/store/NodeRegistry/index.js +2 -0
- package/dist/store/store/NodeRegistry/index.js.map +1 -0
- package/dist/store/store/NodeRegistry/nodeRegistry.d.ts +139 -0
- package/dist/store/store/NodeRegistry/nodeRegistry.d.ts.map +1 -0
- package/dist/store/store/NodeRegistry/nodeRegistry.js +255 -0
- package/dist/store/store/NodeRegistry/nodeRegistry.js.map +1 -0
- package/dist/store/store/NodeRegistry/nodeUtils.d.ts +17 -0
- package/dist/store/store/NodeRegistry/nodeUtils.d.ts.map +1 -0
- package/dist/store/store/NodeRegistry/nodeUtils.js +21 -0
- package/dist/store/store/NodeRegistry/nodeUtils.js.map +1 -0
- package/dist/store/store/NodeRegistry/nodeView.d.ts +28 -0
- package/dist/store/store/NodeRegistry/nodeView.d.ts.map +1 -0
- package/dist/store/store/NodeRegistry/nodeView.js +16 -0
- package/dist/store/store/NodeRegistry/nodeView.js.map +1 -0
- package/dist/store/store/dirtyTracker.d.ts +27 -0
- package/dist/store/store/dirtyTracker.d.ts.map +1 -0
- package/dist/store/store/dirtyTracker.js +38 -0
- package/dist/store/store/dirtyTracker.js.map +1 -0
- package/dist/store/store/groupDepsMap.d.ts +52 -0
- package/dist/store/store/groupDepsMap.d.ts.map +1 -0
- package/dist/store/store/groupDepsMap.js +84 -0
- package/dist/store/store/groupDepsMap.js.map +1 -0
- package/dist/store/store/hasComputedProps.d.ts +7 -0
- package/dist/store/store/hasComputedProps.d.ts.map +1 -0
- package/dist/store/store/hasComputedProps.js +15 -0
- package/dist/store/store/hasComputedProps.js.map +1 -0
- package/dist/store/store/index.d.ts +6 -0
- package/dist/store/store/index.d.ts.map +1 -0
- package/dist/store/store/index.js +3 -0
- package/dist/store/store/index.js.map +1 -0
- package/dist/store/store/nodeMap.d.ts +12 -0
- package/dist/store/store/nodeMap.d.ts.map +1 -0
- package/dist/store/store/nodeMap.js +30 -0
- package/dist/store/store/nodeMap.js.map +1 -0
- package/dist/store/store/palistor.d.ts +256 -0
- package/dist/store/store/palistor.d.ts.map +1 -0
- package/dist/store/store/palistor.js +772 -0
- package/dist/store/store/palistor.js.map +1 -0
- package/dist/store/store/registerNodes.d.ts +33 -0
- package/dist/store/store/registerNodes.d.ts.map +1 -0
- package/dist/store/store/registerNodes.js +88 -0
- package/dist/store/store/registerNodes.js.map +1 -0
- package/dist/store/store/serviceRegistry.d.ts +24 -0
- package/dist/store/store/serviceRegistry.d.ts.map +1 -0
- package/dist/store/store/serviceRegistry.js +32 -0
- package/dist/store/store/serviceRegistry.js.map +1 -0
- package/dist/store/store/types.d.ts +622 -0
- package/dist/store/store/types.d.ts.map +1 -0
- package/dist/store/store/types.js +2 -0
- package/dist/store/store/types.js.map +1 -0
- package/dist/store/submitPipeline/applyLeafBeforeSubmit.d.ts +7 -0
- package/dist/store/submitPipeline/applyLeafBeforeSubmit.d.ts.map +1 -0
- package/dist/store/submitPipeline/applyLeafBeforeSubmit.js +26 -0
- package/dist/store/submitPipeline/applyLeafBeforeSubmit.js.map +1 -0
- package/dist/store/submitPipeline/collectLeafStates.d.ts +11 -0
- package/dist/store/submitPipeline/collectLeafStates.d.ts.map +1 -0
- package/dist/store/submitPipeline/collectLeafStates.js +17 -0
- package/dist/store/submitPipeline/collectLeafStates.js.map +1 -0
- package/dist/store/submitPipeline/getSubValues.d.ts +9 -0
- package/dist/store/submitPipeline/getSubValues.d.ts.map +1 -0
- package/dist/store/submitPipeline/getSubValues.js +26 -0
- package/dist/store/submitPipeline/getSubValues.js.map +1 -0
- package/dist/store/submitPipeline/submitPipeline.d.ts +32 -0
- package/dist/store/submitPipeline/submitPipeline.d.ts.map +1 -0
- package/dist/store/submitPipeline/submitPipeline.js +119 -0
- package/dist/store/submitPipeline/submitPipeline.js.map +1 -0
- package/dist/store/submitPipeline/types.d.ts +12 -0
- package/dist/store/submitPipeline/types.d.ts.map +1 -0
- package/dist/store/submitPipeline/types.js +2 -0
- package/dist/store/submitPipeline/types.js.map +1 -0
- package/dist/store/traversal/index.d.ts +4 -0
- package/dist/store/traversal/index.d.ts.map +1 -0
- package/dist/store/traversal/index.js +3 -0
- package/dist/store/traversal/index.js.map +1 -0
- package/dist/store/traversal/nodeClassifier.d.ts +23 -0
- package/dist/store/traversal/nodeClassifier.d.ts.map +1 -0
- package/dist/store/traversal/nodeClassifier.js +46 -0
- package/dist/store/traversal/nodeClassifier.js.map +1 -0
- package/dist/store/traversal/walkFull.d.ts +33 -0
- package/dist/store/traversal/walkFull.d.ts.map +1 -0
- package/dist/store/traversal/walkFull.js +28 -0
- package/dist/store/traversal/walkFull.js.map +1 -0
- package/dist/store/valuesCache/valuesCache.d.ts +27 -0
- package/dist/store/valuesCache/valuesCache.d.ts.map +1 -0
- package/dist/store/valuesCache/valuesCache.js +58 -0
- package/dist/store/valuesCache/valuesCache.js.map +1 -0
- package/dist/store/writePipeline/formatPatch.d.ts +14 -0
- package/dist/store/writePipeline/formatPatch.d.ts.map +1 -0
- package/dist/store/writePipeline/formatPatch.js +35 -0
- package/dist/store/writePipeline/formatPatch.js.map +1 -0
- package/dist/store/writePipeline/formatValue.d.ts +12 -0
- package/dist/store/writePipeline/formatValue.d.ts.map +1 -0
- package/dist/store/writePipeline/formatValue.js +15 -0
- package/dist/store/writePipeline/formatValue.js.map +1 -0
- package/dist/store/writePipeline/index.d.ts +8 -0
- package/dist/store/writePipeline/index.d.ts.map +1 -0
- package/dist/store/writePipeline/index.js +7 -0
- package/dist/store/writePipeline/index.js.map +1 -0
- package/dist/store/writePipeline/mergeChanged.d.ts +9 -0
- package/dist/store/writePipeline/mergeChanged.d.ts.map +1 -0
- package/dist/store/writePipeline/mergeChanged.js +15 -0
- package/dist/store/writePipeline/mergeChanged.js.map +1 -0
- package/dist/store/writePipeline/runSetter.d.ts +16 -0
- package/dist/store/writePipeline/runSetter.d.ts.map +1 -0
- package/dist/store/writePipeline/runSetter.js +35 -0
- package/dist/store/writePipeline/runSetter.js.map +1 -0
- package/dist/store/writePipeline/storeValue.d.ts +11 -0
- package/dist/store/writePipeline/storeValue.d.ts.map +1 -0
- package/dist/store/writePipeline/storeValue.js +17 -0
- package/dist/store/writePipeline/storeValue.js.map +1 -0
- package/dist/store/writePipeline/types.d.ts +10 -0
- package/dist/store/writePipeline/types.d.ts.map +1 -0
- package/dist/store/writePipeline/types.js +2 -0
- package/dist/store/writePipeline/types.js.map +1 -0
- package/dist/store/writePipeline/writePipeline.d.ts +31 -0
- package/dist/store/writePipeline/writePipeline.d.ts.map +1 -0
- package/dist/store/writePipeline/writePipeline.js +97 -0
- package/dist/store/writePipeline/writePipeline.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
import { applyPatch } from "../applyPatch/applyPatch";
|
|
2
|
+
import { recomputeAndNotify as _recomputeAndNotify } from "../compute/recompute";
|
|
3
|
+
import { recomputeTargeted, collectGroupComputeNodes, recomputeLeaves } from "../compute/recompute";
|
|
4
|
+
import { ProxyBuilder } from "../buildProxy/buildProxy";
|
|
5
|
+
import { PersistManager } from "../persist/persistManager";
|
|
6
|
+
import { ResetPipeline } from "../resetPipeline/resetPipeline";
|
|
7
|
+
import { SubmitPipeline } from "../submitPipeline/submitPipeline";
|
|
8
|
+
import { OnChangePipeline } from "../onChangePipeline/onChangePipeline";
|
|
9
|
+
import { WritePipeline } from "../writePipeline/writePipeline";
|
|
10
|
+
import { formatPatch } from "../writePipeline/writePipeline";
|
|
11
|
+
import { NotificationHub } from "../init/createNotificationHub";
|
|
12
|
+
import { ResolveManager } from "../init/createResolveManager";
|
|
13
|
+
import { buildValuesCache, updateValuesCacheEntry } from "../valuesCache/valuesCache";
|
|
14
|
+
import { NodeRegistry } from "./NodeRegistry/nodeRegistry";
|
|
15
|
+
import { ServiceRegistry } from "./serviceRegistry";
|
|
16
|
+
import { DirtyTracker } from "./dirtyTracker";
|
|
17
|
+
import { GroupDepsMap } from "./groupDepsMap";
|
|
18
|
+
import { EntityRegistry } from "../entityRegistry";
|
|
19
|
+
import { generateTmpId } from "../entityRegistry";
|
|
20
|
+
import { isLeafNode, isListNode, isGroupNode, configKeys } from "../traversal";
|
|
21
|
+
import { normalizeConfig } from "../normalizeConfig";
|
|
22
|
+
// ─── Palistor ─────────────────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Публичный класс формы. Одновременно является DI-контейнером для всех
|
|
25
|
+
* внутренних подсистем и реализует публичный интерфейс `ProxyStore`.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const store = new Palistor({ config: myConfig, initialValues: {...} });
|
|
29
|
+
* store.proxy.email.value = "test@example.com";
|
|
30
|
+
* store.submit();
|
|
31
|
+
*/
|
|
32
|
+
export class Palistor {
|
|
33
|
+
// ─── Конструктор ──────────────────────────────────────────────────────────
|
|
34
|
+
constructor(options) {
|
|
35
|
+
/**
|
|
36
|
+
* @internal Plain POJO mirrors for each entity — used in valuesCache.values
|
|
37
|
+
* (list arrays) and nodeSlot for O(1) updates.
|
|
38
|
+
* Key: entityId, Value: plain object `{ id, field1, field2, ... }`.
|
|
39
|
+
*/
|
|
40
|
+
this.entityProjectionObjs = new Map();
|
|
41
|
+
/**
|
|
42
|
+
* Нереактивный контекст — произвольные данные, доступные через `store.context`.
|
|
43
|
+
* Устанавливается через `setContext()` или хук `useStoreContext()`.
|
|
44
|
+
*/
|
|
45
|
+
this._context = {};
|
|
46
|
+
const { config, initialValues = {} } = options;
|
|
47
|
+
// ─── Field mapping (две проекции карты) ──────────────────────────────────
|
|
48
|
+
// fwd: internal → external (для ownKeys/spread).
|
|
49
|
+
// externalToInternal: external → internal (для GET/SET/tracking).
|
|
50
|
+
// Обе пусты, когда fieldMapping не передан → `?? key` возвращает ключ как есть
|
|
51
|
+
// → нулевой оверхед по умолчанию.
|
|
52
|
+
const fwd = options.fieldMapping ?? {};
|
|
53
|
+
this.fieldMapping = fwd;
|
|
54
|
+
this.externalToInternal = {};
|
|
55
|
+
for (const internal in fwd) {
|
|
56
|
+
const external = fwd[internal];
|
|
57
|
+
if (external !== undefined)
|
|
58
|
+
this.externalToInternal[external] = internal;
|
|
59
|
+
}
|
|
60
|
+
// ─── Нормализация конфига (external → internal) ───────────────────────────
|
|
61
|
+
// Конфиг пишется в ПУБЛИЧНЫХ (замапленных) именах. Один проход приводит его
|
|
62
|
+
// к internal-именам ДО init/compute/traversal — всё ядро ниже работает с
|
|
63
|
+
// internal-именами без изменений. Пустая карта → возвращается исходный
|
|
64
|
+
// config без копий (нулевой оверхед).
|
|
65
|
+
const rootConfig = normalizeConfig(config, this.externalToInternal, fwd);
|
|
66
|
+
this.rootConfig = rootConfig;
|
|
67
|
+
// ─── Сервисы ────────────────────────────────────────────────────────────
|
|
68
|
+
this.services = new ServiceRegistry();
|
|
69
|
+
const { translate, notify } = this.services;
|
|
70
|
+
// ─── NodeRegistry ────────────────────────────────────────────────────────
|
|
71
|
+
this.nodes = new NodeRegistry(rootConfig, initialValues, translate);
|
|
72
|
+
this.nodes.setKernel(this);
|
|
73
|
+
const { nodeState, nodePaths, nodeParents, computeNodes } = this.nodes;
|
|
74
|
+
// ─── DirtyTracker + ValuesCache ──────────────────────────────────────────
|
|
75
|
+
this.dirty = new DirtyTracker();
|
|
76
|
+
this.values = buildValuesCache(rootConfig, nodeState);
|
|
77
|
+
// ─── EntityRegistry ──────────────────────────────────────────────────────
|
|
78
|
+
this.entityRegistry = new EntityRegistry();
|
|
79
|
+
// Register all list states so EntityRegistry.rekey() can update itemIds
|
|
80
|
+
for (const ls of this.nodes.allListStates) {
|
|
81
|
+
this.entityRegistry.registerList(ls);
|
|
82
|
+
}
|
|
83
|
+
// ─── GroupDepsMap + первый recompute ──────────────────────────────────────
|
|
84
|
+
this.groupDepsMap = new GroupDepsMap(rootConfig, nodePaths, nodeParents);
|
|
85
|
+
this.recompute(); // первый полный пересчёт — строит карту зависимостей
|
|
86
|
+
this.dirty.capture(rootConfig, nodeState);
|
|
87
|
+
// ─── NotificationHub ────────────────────────────────────────────────────
|
|
88
|
+
this.hub = new NotificationHub({ computeNodes, nodePaths });
|
|
89
|
+
// ─── ResolveManager ──────────────────────────────────────────────────────
|
|
90
|
+
this.resolveManager = new ResolveManager({
|
|
91
|
+
rootConfig,
|
|
92
|
+
nodeState,
|
|
93
|
+
recompute: () => this.recompute(),
|
|
94
|
+
notifyChanged: (c) => this.notifyChanged(c),
|
|
95
|
+
notify,
|
|
96
|
+
initialValueMap: this.dirty.initialValueMap,
|
|
97
|
+
valuesCache: this.values,
|
|
98
|
+
store: this,
|
|
99
|
+
listStates: this.nodes.listStates,
|
|
100
|
+
setEntitiesRaw: (items, listNode) => this._setEntitiesRaw(items, listNode),
|
|
101
|
+
syncListValuesCache: (listState) => this.syncListValuesCache(listState),
|
|
102
|
+
entityRegistry: this.entityRegistry,
|
|
103
|
+
});
|
|
104
|
+
// ─── Pipeline классы ─────────────────────────────────────────────────────
|
|
105
|
+
this.writePipeline = new WritePipeline(this);
|
|
106
|
+
this.resetPipeline = new ResetPipeline(this);
|
|
107
|
+
this.submitPipeline = new SubmitPipeline(this);
|
|
108
|
+
this.onChangePipeline = new OnChangePipeline(this);
|
|
109
|
+
this.proxyBuilder = new ProxyBuilder(this);
|
|
110
|
+
this._proxy = this.proxyBuilder.build(rootConfig);
|
|
111
|
+
// ─── PersistManager ───────────────────────────────────────────────────────
|
|
112
|
+
this._persist = new PersistManager(this);
|
|
113
|
+
// ─── Wire resolve retrigger ──────────────────────────────────────────────
|
|
114
|
+
const postNotifyHook = this.resolveManager.createPostNotifyHook();
|
|
115
|
+
if (postNotifyHook)
|
|
116
|
+
this.hub.setPostNotifyHook(postNotifyHook);
|
|
117
|
+
// ─── Начальный контекст (Phase 4) ────────────────────────────────────────
|
|
118
|
+
if (options.context) {
|
|
119
|
+
this._context = options.context;
|
|
120
|
+
}
|
|
121
|
+
// ─── Launch eager resolvers ──────────────────────────────────────────────
|
|
122
|
+
this.resolveManager.launchEager();
|
|
123
|
+
}
|
|
124
|
+
// ─── @internal методы-фасады ──────────────────────────────────────────────
|
|
125
|
+
/**
|
|
126
|
+
* Пересчитать состояние узлов.
|
|
127
|
+
*
|
|
128
|
+
* - `changedNodes` передан и не пуст → таргетированный пересчёт (быстро)
|
|
129
|
+
* - иначе → полный пересчёт всего дерева (init, reset, resolve-завершение)
|
|
130
|
+
*
|
|
131
|
+
* При первом вызове без changedNodes строит карту групповых зависимостей.
|
|
132
|
+
*
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
recompute(changedNodes) {
|
|
136
|
+
const { nodeState, nodePaths, nodeParents, groupComputeMap } = this.nodes;
|
|
137
|
+
const { translate } = this.services;
|
|
138
|
+
if (changedNodes && changedNodes.size > 0) {
|
|
139
|
+
return recomputeTargeted(changedNodes, {
|
|
140
|
+
rootConfig: this.rootConfig,
|
|
141
|
+
groupComputeMap,
|
|
142
|
+
nodeState,
|
|
143
|
+
nodeParents,
|
|
144
|
+
nodePaths,
|
|
145
|
+
groupDeps: this.groupDepsMap.deps,
|
|
146
|
+
valuesCache: this.values,
|
|
147
|
+
translate,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const computeNodes = collectGroupComputeNodes(this.rootConfig, groupComputeMap);
|
|
151
|
+
if (!this.groupDepsMap.isBuilt) {
|
|
152
|
+
const trackingWrap = this.groupDepsMap.getTrackingWrap();
|
|
153
|
+
const result = recomputeLeaves(computeNodes, nodeState, this.values, translate, trackingWrap);
|
|
154
|
+
this.groupDepsMap.markBuilt();
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
return recomputeLeaves(computeNodes, nodeState, this.values, translate);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Уведомить подписчиков об изменённых узлах.
|
|
161
|
+
* Пересчитывает dirty-флаги и инкрементирует версии.
|
|
162
|
+
*
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
notifyChanged(changed) {
|
|
166
|
+
this.hub.notifyChanged(changed, {
|
|
167
|
+
rootConfig: this.rootConfig,
|
|
168
|
+
nodeState: this.nodes.nodeState,
|
|
169
|
+
initialValueMap: this.dirty.initialValueMap,
|
|
170
|
+
listStates: this.nodes.listStates,
|
|
171
|
+
nodeParents: this.nodes.nodeParents,
|
|
172
|
+
nodePaths: this.nodes.nodePaths,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// ─── @internal pipeline-методы ────────────────────────────────────────────
|
|
176
|
+
/** @internal Применить bulk-патч к узлу (один recompute + notify). */
|
|
177
|
+
setValuesNode(node, patch) {
|
|
178
|
+
const formatted = formatPatch(node, patch, this.values.values);
|
|
179
|
+
const changed = applyPatch(node, this.nodes.nodeState, formatted, new Set(), this.values);
|
|
180
|
+
_recomputeAndNotify(changed, () => this.recompute(), (c) => this.notifyChanged(c));
|
|
181
|
+
}
|
|
182
|
+
// ─── ProxyStore — публичный API ───────────────────────────────────────────
|
|
183
|
+
get proxy() {
|
|
184
|
+
return this._proxy;
|
|
185
|
+
}
|
|
186
|
+
get context() {
|
|
187
|
+
return this._context;
|
|
188
|
+
}
|
|
189
|
+
setContext(ctx) {
|
|
190
|
+
const changedKeys = new Set();
|
|
191
|
+
for (const key of Object.keys(ctx)) {
|
|
192
|
+
if (this._context[key] !== ctx[key])
|
|
193
|
+
changedKeys.add(key);
|
|
194
|
+
}
|
|
195
|
+
this._context = { ...this._context, ...ctx };
|
|
196
|
+
if (changedKeys.size > 0) {
|
|
197
|
+
const changedPaths = new Set();
|
|
198
|
+
for (const key of changedKeys)
|
|
199
|
+
changedPaths.add(`$context.${key}`);
|
|
200
|
+
this.resolveManager.retriggerByPaths(changedPaths);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
get persist() {
|
|
204
|
+
return this._persist;
|
|
205
|
+
}
|
|
206
|
+
subscribe(node, listener) {
|
|
207
|
+
return this.hub.subscribe(node, listener);
|
|
208
|
+
}
|
|
209
|
+
subscribeGlobal(listener) {
|
|
210
|
+
return this.hub.subscribeGlobal(listener);
|
|
211
|
+
}
|
|
212
|
+
getVersion() {
|
|
213
|
+
return this.hub.getVersion();
|
|
214
|
+
}
|
|
215
|
+
getNodeVersion(node) {
|
|
216
|
+
return this.hub.getNodeVersion(node);
|
|
217
|
+
}
|
|
218
|
+
getValues() {
|
|
219
|
+
return structuredClone(this.values.values);
|
|
220
|
+
}
|
|
221
|
+
setTranslator(t) {
|
|
222
|
+
if (this.services.setTranslator(t))
|
|
223
|
+
this.hub.bumpLeafVersions();
|
|
224
|
+
}
|
|
225
|
+
setNotifier(fn) {
|
|
226
|
+
this.services.setNotifier(fn);
|
|
227
|
+
}
|
|
228
|
+
submit() {
|
|
229
|
+
return this.submitPipeline.execute(this.rootConfig);
|
|
230
|
+
}
|
|
231
|
+
reset(values) {
|
|
232
|
+
this.resetPipeline.execute(this.rootConfig, values);
|
|
233
|
+
}
|
|
234
|
+
setValues(patch) {
|
|
235
|
+
this.setValuesNode(this.rootConfig, patch);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Создать или обновить entity (или массив entities) в реестре.
|
|
239
|
+
*
|
|
240
|
+
* - Если entity с таким id не существует — создаётся и регистрируются leaf-ноды.
|
|
241
|
+
* - Если существует — рекурсивный merge; обновлённые leaf-ноды маркируются как изменённые.
|
|
242
|
+
* - Batch-режим: массив entities обрабатывается одним recompute + notifyChanged.
|
|
243
|
+
*/
|
|
244
|
+
set(data) {
|
|
245
|
+
const items = Array.isArray(data) ? data : [data];
|
|
246
|
+
const changed = this._setEntitiesRaw(items);
|
|
247
|
+
if (changed.size === 0)
|
|
248
|
+
return;
|
|
249
|
+
const recomputed = this.recompute(changed);
|
|
250
|
+
// Merge original changed: entity leaves have no computed props,
|
|
251
|
+
// so recomputed may be empty — still need to notify about the entity values.
|
|
252
|
+
for (const n of changed)
|
|
253
|
+
recomputed.add(n);
|
|
254
|
+
this.notifyChanged(recomputed);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Переименовать entity: перенести с oldId на newId.
|
|
258
|
+
*
|
|
259
|
+
* - Обновляет EntityRegistry (entities Map, bindings, resolvedCache, id leaf value).
|
|
260
|
+
* - Обновляет itemIds во всех ListState-объектах.
|
|
261
|
+
* - Обновляет entityProjectionObjs (переносит POJO-зеркало).
|
|
262
|
+
* - Уведомляет подписчиков об изменении id leaf.
|
|
263
|
+
*
|
|
264
|
+
* No-op если entity с oldId не существует.
|
|
265
|
+
*/
|
|
266
|
+
rekey(oldId, newId) {
|
|
267
|
+
const entity = this.entityRegistry.get(oldId);
|
|
268
|
+
if (!entity)
|
|
269
|
+
return;
|
|
270
|
+
// EntityRegistry.rekey() updates: entities Map, id.value, bindings, resolvedCache, allRegisteredLists.itemIds
|
|
271
|
+
this.entityRegistry.rekey(oldId, newId);
|
|
272
|
+
// Move entityProjectionObjs entry
|
|
273
|
+
const projObj = this.entityProjectionObjs.get(oldId);
|
|
274
|
+
if (projObj) {
|
|
275
|
+
this.entityProjectionObjs.delete(oldId);
|
|
276
|
+
this.entityProjectionObjs.set(newId, projObj);
|
|
277
|
+
}
|
|
278
|
+
// Notify: id leaf changed
|
|
279
|
+
const idLeaf = entity.id;
|
|
280
|
+
const changed = new Set([idLeaf]);
|
|
281
|
+
// Update nodeState value for id leaf
|
|
282
|
+
const leafState = this.nodes.nodeState.get(idLeaf);
|
|
283
|
+
if (leafState) {
|
|
284
|
+
this.nodes.nodeState.set(idLeaf, { ...leafState, value: newId });
|
|
285
|
+
if (projObj)
|
|
286
|
+
projObj["id"] = newId;
|
|
287
|
+
}
|
|
288
|
+
const recomputed = this.recompute(changed);
|
|
289
|
+
for (const n of changed)
|
|
290
|
+
recomputed.add(n);
|
|
291
|
+
this.notifyChanged(recomputed);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Удалить entity из реестра по ID.
|
|
295
|
+
*
|
|
296
|
+
* - Удаляет leaf-ноды entity из NodeRegistry (computeNodes, groupComputeMap).
|
|
297
|
+
* - Очищает bindings и resolvedCache.
|
|
298
|
+
* - Уведомляет подписчиков.
|
|
299
|
+
*
|
|
300
|
+
* No-op если entity не существует.
|
|
301
|
+
*/
|
|
302
|
+
delete(id) {
|
|
303
|
+
const entityNode = this.entityRegistry.get(id);
|
|
304
|
+
if (!entityNode)
|
|
305
|
+
return;
|
|
306
|
+
// C2: каскадное удаление child-entity, принадлежащих этой entity.
|
|
307
|
+
// Снимаем копию множества — childrenByOwner мутируется при рекурсивном delete.
|
|
308
|
+
const childIds = this.entityRegistry.getChildrenByOwner(id);
|
|
309
|
+
if (childIds && childIds.size > 0) {
|
|
310
|
+
for (const childId of [...childIds]) {
|
|
311
|
+
this.delete(childId);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Собрать все leaf-ноды entity
|
|
315
|
+
const deletedLeaves = new Set();
|
|
316
|
+
this.collectEntityLeaves(entityNode, deletedLeaves);
|
|
317
|
+
// Удалить leaf-ноды из NodeRegistry (предотвращает утечку памяти)
|
|
318
|
+
for (const leaf of deletedLeaves) {
|
|
319
|
+
this.nodes.unregisterLeaf(leaf);
|
|
320
|
+
}
|
|
321
|
+
// Phase 4: cleanup per-entity field resolve states
|
|
322
|
+
this.resolveManager.cleanupEntityResolveStates(id);
|
|
323
|
+
// Удалить entity из реестра (очищает bindings + resolvedCache)
|
|
324
|
+
this.entityRegistry.delete(id);
|
|
325
|
+
// Уведомить подписчиков
|
|
326
|
+
this.notifyChanged(deletedLeaves);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Сбросить resolved-кэш для entity (все template или конкретный).
|
|
330
|
+
*
|
|
331
|
+
* - `invalidate(id)` — очистить весь кэш для entity
|
|
332
|
+
* - `invalidate(id, templateNode)` — очистить только для конкретной пары
|
|
333
|
+
*
|
|
334
|
+
* При следующем mount useForm(entity, template) resolve будет перезапущен.
|
|
335
|
+
*/
|
|
336
|
+
invalidate(id, templateNode) {
|
|
337
|
+
this.entityRegistry.clearResolved(id, templateNode);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Submit entity через template.
|
|
341
|
+
* Вызывается из EntityProjectionProxy.submit().
|
|
342
|
+
*
|
|
343
|
+
* 1. submitting: true → notify
|
|
344
|
+
* 2. Валидация через template field rules (validate)
|
|
345
|
+
* 3. templateNode.onSubmit(entityProxy, store)
|
|
346
|
+
* 4. templateNode.afterSubmit(result, { reset })
|
|
347
|
+
* 5. submitting: false → notify
|
|
348
|
+
*
|
|
349
|
+
* @internal
|
|
350
|
+
*/
|
|
351
|
+
async executeEntityTemplateSubmit(entityId, templateNode, entityProxy) {
|
|
352
|
+
// Шаг 1: Найти entity в реестре. Если не найдена — ранний выход с ошибкой.
|
|
353
|
+
const entityNode = this.entityRegistry.get(entityId);
|
|
354
|
+
if (!entityNode) {
|
|
355
|
+
return {
|
|
356
|
+
success: false,
|
|
357
|
+
errors: [{ path: "", message: `Entity "${entityId}" not found` }],
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// Шаг 2: Получить (или создать) объект состояния привязки { loading, submitting }
|
|
361
|
+
// для пары (entityId, templateNode). Используется EntityProjectionProxy
|
|
362
|
+
// для отображения спиннера в UI.
|
|
363
|
+
const bindingState = this.resolveManager.entityStates.getOrCreate(entityId, templateNode);
|
|
364
|
+
const entityNodeObj = entityNode;
|
|
365
|
+
// Шаг 3: Поднять флаг submitting и уведомить подписчиков (React перерендерит
|
|
366
|
+
// компоненты, привязанные к этой entity — например, кнопка покажет спиннер).
|
|
367
|
+
bindingState.submitting = true;
|
|
368
|
+
this.notifyChanged(new Set([entityNodeObj]));
|
|
369
|
+
try {
|
|
370
|
+
// Шаг 4: Валидация — рекурсивно обойти template-поля и вызвать validate()
|
|
371
|
+
// для каждого leaf-поля, у которого есть валидатор. Текущие значения
|
|
372
|
+
// берутся из nodeState entity.
|
|
373
|
+
const errors = [];
|
|
374
|
+
this.collectEntityTemplateErrors(templateNode, entityNode, errors, "");
|
|
375
|
+
// Если есть ошибки валидации — вернуть их, не вызывая onSubmit.
|
|
376
|
+
if (errors.length > 0) {
|
|
377
|
+
return { success: false, errors };
|
|
378
|
+
}
|
|
379
|
+
// Шаг 5: Вызвать пользовательский onSubmit(entityProxy, store).
|
|
380
|
+
// entityProxy — это Proxy entity с template-правилами, store — сам Palistor.
|
|
381
|
+
// Обычно здесь выполняется API-запрос на сервер.
|
|
382
|
+
let result;
|
|
383
|
+
if (typeof templateNode.onSubmit === "function") {
|
|
384
|
+
result = await templateNode.onSubmit(entityProxy, this);
|
|
385
|
+
}
|
|
386
|
+
// Шаг 6: Вызвать afterSubmit(result, { reset }) — хук после успешного submit.
|
|
387
|
+
// reset для entity template — no-op (у entity нет встроенного сброса, в отличие от form).
|
|
388
|
+
if (typeof templateNode.afterSubmit === "function") {
|
|
389
|
+
const reset = () => void 0; // entity template has no built-in reset
|
|
390
|
+
await templateNode.afterSubmit(result, { reset });
|
|
391
|
+
}
|
|
392
|
+
return { success: true, result };
|
|
393
|
+
}
|
|
394
|
+
finally {
|
|
395
|
+
// Шаг 7 (always): Снять флаг submitting и уведомить подписчиков.
|
|
396
|
+
// finally гарантирует сброс даже при ошибке в onSubmit/afterSubmit.
|
|
397
|
+
bindingState.submitting = false;
|
|
398
|
+
this.notifyChanged(new Set([entityNodeObj]));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// ─── Приватные helpers для entity ────────────────────────────────────────
|
|
402
|
+
/**
|
|
403
|
+
* Upsert entities in EntityRegistry and register/update their leaf nodes.
|
|
404
|
+
* Returns Set of changed leaf nodes. Does NOT call recompute or notifyChanged.
|
|
405
|
+
*
|
|
406
|
+
* Used internally by `set()` and by `executeListResolve` via the
|
|
407
|
+
* `setEntitiesRaw` callback in ResolveManagerDeps.
|
|
408
|
+
*
|
|
409
|
+
* Phase 4: when `listNode` is provided, triggers entity field resolves for
|
|
410
|
+
* each template field entry belonging to that list.
|
|
411
|
+
*
|
|
412
|
+
* @internal
|
|
413
|
+
*/
|
|
414
|
+
_setEntitiesRaw(items, listNode) {
|
|
415
|
+
const changed = new Set();
|
|
416
|
+
for (const item of items) {
|
|
417
|
+
// Создать новый EntityNode или обновить существующий (рекурсивный merge).
|
|
418
|
+
// Если item.id отсутствует — EntityRegistry сгенерирует временный _tmp_* id.
|
|
419
|
+
const entityNode = this.entityRegistry.upsert(item);
|
|
420
|
+
const entityId = entityNode.id.value;
|
|
421
|
+
// Все entity-ноды живут в namespace "_entity_." для изоляции от config-нод формы.
|
|
422
|
+
const entityPrefix = `_entity_.${entityId}`;
|
|
423
|
+
// projectionObj — «зеркало» entity в виде plain POJO { id, field1, field2 }.
|
|
424
|
+
// Используется в valuesCache.values как элемент массива списка.
|
|
425
|
+
// Ссылочная идентичность POJO сохраняется между upsert-ами, меняются только значения.
|
|
426
|
+
let projectionObj = this.entityProjectionObjs.get(entityId);
|
|
427
|
+
if (!projectionObj) {
|
|
428
|
+
projectionObj = {};
|
|
429
|
+
this.entityProjectionObjs.set(entityId, projectionObj);
|
|
430
|
+
}
|
|
431
|
+
// DFS-обход entity-дерева: зарегистрировать новые leaf-ноды
|
|
432
|
+
// или обнаружить изменения в существующих.
|
|
433
|
+
this.walkAndSyncEntityNode(entityNode, entityPrefix, entityNode, changed, projectionObj);
|
|
434
|
+
// Entity field resolves are lazy-only: triggered when a component first reads
|
|
435
|
+
// field.value or field.loading (via queueMicrotask in buildEntityProjectionProxy).
|
|
436
|
+
// This avoids N×M concurrent requests for large lists where N = entities, M = resolve fields.
|
|
437
|
+
}
|
|
438
|
+
return changed;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Синхронизировать valuesCache с составом списка — ЕДИНЫЙ метод (root + per-entity).
|
|
442
|
+
*
|
|
443
|
+
* Ветвится по `listState.ownerEntity`:
|
|
444
|
+
* - `null` → root: пишем массив POJO-зеркал в `nodeSlot` config-узла
|
|
445
|
+
* (`valuesCache.values.users = [{id:"u1",…}, …]` — тот же массив, что читает
|
|
446
|
+
* `proxy.users.value`, поэтому React видит обновление);
|
|
447
|
+
* - entity → per-entity (вариант C, C3/C4): материализуем состав в projectionObj
|
|
448
|
+
* владельца по пути списка (`["contacts"]` или `["profile","contacts"]`). Это
|
|
449
|
+
* включает вложенный список в `store.getValues()` — projectionObj владельца
|
|
450
|
+
* входит в массив корневого списка по ссылке, а child-projectionObj-ы
|
|
451
|
+
* рекурсивно материализуют свои списки.
|
|
452
|
+
*
|
|
453
|
+
* No-op, если слот/путь/projectionObj владельца отсутствуют.
|
|
454
|
+
*
|
|
455
|
+
* @internal
|
|
456
|
+
*/
|
|
457
|
+
syncListValuesCache(listState) {
|
|
458
|
+
const materialized = listState.itemIds
|
|
459
|
+
.map((id) => this.entityProjectionObjs.get(id))
|
|
460
|
+
.filter((obj) => obj !== undefined);
|
|
461
|
+
if (listState.ownerEntity === null) {
|
|
462
|
+
// Root: слот в valuesCache (пара { parent, key }) по config-узлу.
|
|
463
|
+
const slot = this.values.nodeSlot.get(listState.listConfigNode);
|
|
464
|
+
if (!slot)
|
|
465
|
+
return;
|
|
466
|
+
slot.parent[slot.key] = materialized;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
// Per-entity: спускаемся к родительскому POJO по пути и пишем состав.
|
|
470
|
+
const listConfigNode = listState.listConfigNode;
|
|
471
|
+
const path = this.nodes.listFieldKeys.get(listConfigNode);
|
|
472
|
+
if (!path || path.length === 0)
|
|
473
|
+
return;
|
|
474
|
+
const ownerId = this._entityId(listState.ownerEntity);
|
|
475
|
+
const projectionObj = this.entityProjectionObjs.get(ownerId);
|
|
476
|
+
if (!projectionObj)
|
|
477
|
+
return;
|
|
478
|
+
let target = projectionObj;
|
|
479
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
480
|
+
const k = path[i];
|
|
481
|
+
let next = target[k];
|
|
482
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
|
483
|
+
next = {};
|
|
484
|
+
target[k] = next;
|
|
485
|
+
}
|
|
486
|
+
target = next;
|
|
487
|
+
}
|
|
488
|
+
target[path[path.length - 1]] = materialized;
|
|
489
|
+
}
|
|
490
|
+
/** @internal Текущий id entity (учитывает rekey через nodeState). */
|
|
491
|
+
_entityId(entity) {
|
|
492
|
+
const idLeaf = entity.id;
|
|
493
|
+
return (this.nodes.nodeState.get(idLeaf)?.value ??
|
|
494
|
+
entity.id.value);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Восстановить состав корневых И per-entity списков из снимка значений
|
|
498
|
+
* (вариант C, C3 — persist hydrate).
|
|
499
|
+
*
|
|
500
|
+
* `applyPatch` пропускает list-узлы, поэтому состав списков восстанавливается
|
|
501
|
+
* отдельным проходом: для каждого list-поля создаём child-entity, проставляем
|
|
502
|
+
* owner-ссылку (для вложенных), заполняем `itemIds`/`initialItemIds` и
|
|
503
|
+
* синхронизируем valuesCache. Рекурсивно обрабатывает nested-of-nested.
|
|
504
|
+
*
|
|
505
|
+
* Возвращает множество изменённых узлов для последующего notify.
|
|
506
|
+
*
|
|
507
|
+
* @internal
|
|
508
|
+
*/
|
|
509
|
+
restoreLists(values) {
|
|
510
|
+
const changed = new Set();
|
|
511
|
+
this._restoreListsRec(this.rootConfig, values, null, changed);
|
|
512
|
+
return changed;
|
|
513
|
+
}
|
|
514
|
+
_restoreListsRec(configNode, valueObj, ownerEntity, changed) {
|
|
515
|
+
for (const key of configKeys(configNode)) {
|
|
516
|
+
const child = configNode[key];
|
|
517
|
+
if (!child || typeof child !== "object")
|
|
518
|
+
continue;
|
|
519
|
+
// Вложенная группа (не список): рекурсия, чтобы достать списки внутри неё.
|
|
520
|
+
if (!Array.isArray(child)) {
|
|
521
|
+
if (isGroupNode(child)) {
|
|
522
|
+
const nested = valueObj?.[key];
|
|
523
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
524
|
+
this._restoreListsRec(child, nested, ownerEntity, changed);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (!isListNode(child))
|
|
530
|
+
continue;
|
|
531
|
+
const arr = valueObj?.[key];
|
|
532
|
+
if (!Array.isArray(arr))
|
|
533
|
+
continue;
|
|
534
|
+
const listConfigNode = child;
|
|
535
|
+
const template = child[0];
|
|
536
|
+
const ids = [];
|
|
537
|
+
for (const itemObj of arr) {
|
|
538
|
+
if (!itemObj || typeof itemObj !== "object")
|
|
539
|
+
continue;
|
|
540
|
+
const rawId = itemObj.id;
|
|
541
|
+
const id = typeof rawId === "string" && rawId.trim() !== "" ? rawId : generateTmpId();
|
|
542
|
+
const flat = this._stripListFields({ ...itemObj, id }, template);
|
|
543
|
+
const leafChanged = this._setEntitiesRaw([flat]);
|
|
544
|
+
for (const n of leafChanged)
|
|
545
|
+
changed.add(n);
|
|
546
|
+
ids.push(id);
|
|
547
|
+
const childEntity = this.entityRegistry.get(id);
|
|
548
|
+
if (childEntity) {
|
|
549
|
+
if (ownerEntity) {
|
|
550
|
+
this.entityRegistry.setEntityOwner(childEntity, this._entityId(ownerEntity), listConfigNode);
|
|
551
|
+
}
|
|
552
|
+
// Рекурсия во вложенные списки этого item.
|
|
553
|
+
this._restoreListsRec(template, itemObj, childEntity, changed);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (ownerEntity) {
|
|
557
|
+
const els = this.entityRegistry.getOrCreateEntityListState(ownerEntity, listConfigNode);
|
|
558
|
+
els.itemIds = ids;
|
|
559
|
+
els.initialItemIds = [...ids];
|
|
560
|
+
this.syncListValuesCache(els);
|
|
561
|
+
changed.add(els);
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
const listState = this.nodes.listStates.get(listConfigNode);
|
|
565
|
+
if (listState) {
|
|
566
|
+
listState.itemIds = ids;
|
|
567
|
+
listState.initialItemIds = [...ids];
|
|
568
|
+
this.syncListValuesCache(listState);
|
|
569
|
+
// U2: ListState — ключ трекинга; listConfigNode — мост обратной совместимости.
|
|
570
|
+
changed.add(listState);
|
|
571
|
+
changed.add(listConfigNode);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Вернуть поверхностную копию объекта данных entity без list-полей
|
|
578
|
+
* (их состав восстанавливается отдельно через EntityListState). Иначе
|
|
579
|
+
* `createEntityNode` затянул бы массив как обычный leaf-value.
|
|
580
|
+
*/
|
|
581
|
+
_stripListFields(itemObj, template) {
|
|
582
|
+
const result = {};
|
|
583
|
+
for (const key of Object.keys(itemObj)) {
|
|
584
|
+
const tField = template?.[key];
|
|
585
|
+
if (Array.isArray(tField))
|
|
586
|
+
continue; // list-поле — пропускаем
|
|
587
|
+
result[key] = itemObj[key];
|
|
588
|
+
}
|
|
589
|
+
return result;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Рекурсивный обход entity node: регистрирует новые leaf-ноды через
|
|
593
|
+
* `registerDynamicLeaf` и собирает изменённые в `changed`.
|
|
594
|
+
*
|
|
595
|
+
* Также поддерживает entity projection POJO (projectionObj):
|
|
596
|
+
* - Новые leaf-ноды: регистрируют nodeSlot → projectionObj
|
|
597
|
+
* - Существующие leaf-ноды: обновляют через updateValuesCacheEntry
|
|
598
|
+
*
|
|
599
|
+
* @param node Текущий узел entity для обхода
|
|
600
|
+
* @param prefix Dot-путь текущего узла (e.g. "_entity_.u1")
|
|
601
|
+
* @param parent Родительский объект (для регистрации leaf-нод)
|
|
602
|
+
* @param changed Множество изменённых узлов (накапливается)
|
|
603
|
+
* @param projectionObj Plain POJO at the current nesting level for valuesCache
|
|
604
|
+
*/
|
|
605
|
+
walkAndSyncEntityNode(node, prefix, parent, changed, projectionObj) {
|
|
606
|
+
// Зарегистрировать dot-path группового узла (e.g. "_entity_.u1", "_entity_.u1.address").
|
|
607
|
+
// nodePaths используется в compute-подсистеме для определения «группы» листа
|
|
608
|
+
// (getNodeGroupPath) и при таргетированном recompute.
|
|
609
|
+
if (!this.nodes.nodePaths.has(parent)) {
|
|
610
|
+
this.nodes.nodePaths.set(parent, prefix);
|
|
611
|
+
}
|
|
612
|
+
for (const key of Object.keys(node)) {
|
|
613
|
+
const child = node[key];
|
|
614
|
+
// Пропускаем примитивы (не часть entity-дерева)
|
|
615
|
+
if (!child || typeof child !== "object")
|
|
616
|
+
continue;
|
|
617
|
+
const childObj = child;
|
|
618
|
+
const childPath = `${prefix}.${key}`;
|
|
619
|
+
if (isLeafNode(childObj)) {
|
|
620
|
+
// ── Листовой узел (EntityLeafNode): { value: <текущее значение> } ──
|
|
621
|
+
const leaf = childObj;
|
|
622
|
+
if (!this.nodes.nodeState.has(childObj)) {
|
|
623
|
+
// Первая встреча с этим leaf — зарегистрировать в NodeRegistry:
|
|
624
|
+
// - nodeState: хранит FieldState (value, isVisible, dirty, etc.)
|
|
625
|
+
// - nodePaths: маппинг node → dot-path
|
|
626
|
+
// - nodeParents: маппинг node → parent group
|
|
627
|
+
// Все entity leaf-ы всегда visible, не обязательны, не disabled.
|
|
628
|
+
this.nodes.registerDynamicLeaf(childObj, childPath, parent, {
|
|
629
|
+
value: leaf.value,
|
|
630
|
+
isVisible: true,
|
|
631
|
+
isRequired: false,
|
|
632
|
+
isDisabled: false,
|
|
633
|
+
isReadOnly: false,
|
|
634
|
+
dirty: false,
|
|
635
|
+
revalidate: false,
|
|
636
|
+
});
|
|
637
|
+
// Seed initialValueMap so recomputeDirtyTargeted compares against the entity's
|
|
638
|
+
// loaded value instead of `undefined` — prevents spurious dirty=true on first load.
|
|
639
|
+
this.dirty.initialValueMap.set(childObj, leaf.value);
|
|
640
|
+
// Привязать leaf к POJO-зеркалу через nodeSlot.
|
|
641
|
+
// При следующих updateValuesCacheEntry(node, newValue)
|
|
642
|
+
// значение в projectionObj обновится автоматически за O(1).
|
|
643
|
+
if (projectionObj !== undefined) {
|
|
644
|
+
this.values.nodeSlot.set(childObj, { parent: projectionObj, key });
|
|
645
|
+
projectionObj[key] = leaf.value;
|
|
646
|
+
}
|
|
647
|
+
changed.add(childObj);
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
// Leaf уже зарегистрирован — проверяем, изменилось ли значение.
|
|
651
|
+
// Это происходит при повторном upsert (обновление entity с сервера).
|
|
652
|
+
const state = this.nodes.nodeState.get(childObj);
|
|
653
|
+
if (state.value !== leaf.value) {
|
|
654
|
+
// Обновляем nodeState напрямую (без writePipeline — это raw-запись)
|
|
655
|
+
state.value = leaf.value;
|
|
656
|
+
// Обновить projectionObj через nodeSlot: O(1), не нужно искать POJO.
|
|
657
|
+
updateValuesCacheEntry(this.values, childObj, leaf.value);
|
|
658
|
+
changed.add(childObj);
|
|
659
|
+
}
|
|
660
|
+
// Если значение не изменилось — leaf не попадёт в changed,
|
|
661
|
+
// подписчики не будут уведомлены (оптимизация).
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
// ── Групповой узел (EntityGroupNode): вложенный объект без "value" ──
|
|
666
|
+
// Например: address: { city: { value: "Moscow" } }
|
|
667
|
+
// Создаём вложенный POJO в projectionObj (если нужно) и рекурсируем.
|
|
668
|
+
let nestedProjectionObj;
|
|
669
|
+
if (projectionObj !== undefined) {
|
|
670
|
+
if (!projectionObj[key] || typeof projectionObj[key] !== "object") {
|
|
671
|
+
projectionObj[key] = {};
|
|
672
|
+
}
|
|
673
|
+
nestedProjectionObj = projectionObj[key];
|
|
674
|
+
}
|
|
675
|
+
this.walkAndSyncEntityNode(child, childPath, childObj, changed, nestedProjectionObj);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Рекурсивно собрать все leaf-ноды из entity node tree.
|
|
681
|
+
* Используется в `delete()` для очистки NodeRegistry.
|
|
682
|
+
*/
|
|
683
|
+
collectEntityLeaves(node, result) {
|
|
684
|
+
for (const key of Object.keys(node)) {
|
|
685
|
+
const child = node[key];
|
|
686
|
+
if (!child || typeof child !== "object")
|
|
687
|
+
continue;
|
|
688
|
+
if (isLeafNode(child)) {
|
|
689
|
+
// Leaf-нода: объект с полем "value" → добавить в результат
|
|
690
|
+
result.add(child);
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
// Группа — рекурсивно обойти вложенные узлы
|
|
694
|
+
this.collectEntityLeaves(child, result);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Collect validation errors for entity-template fields.
|
|
700
|
+
* Iterates template fields recursively, calls templateField.validate() with
|
|
701
|
+
* current entity values.
|
|
702
|
+
*
|
|
703
|
+
* @internal
|
|
704
|
+
*/
|
|
705
|
+
collectEntityTemplateErrors(templateNode, entityNode, errors, parentPath) {
|
|
706
|
+
const translate = this.services.translate;
|
|
707
|
+
// Построить plain-объект значений entity — передаётся вторым аргументом
|
|
708
|
+
// в каждый validate(), чтобы валидатор мог проверять зависимости между полями.
|
|
709
|
+
// Пример: validate: (v, vals) => vals.password !== vals.confirmPassword ? "Mismatch" : undefined
|
|
710
|
+
const entityValues = this.buildEntityValuesForTemplate(entityNode);
|
|
711
|
+
for (const key of configKeys(templateNode)) {
|
|
712
|
+
const templateField = templateNode[key];
|
|
713
|
+
if (!templateField || typeof templateField !== "object")
|
|
714
|
+
continue;
|
|
715
|
+
// Формируем dot-path для сообщения об ошибке (e.g. "address.city")
|
|
716
|
+
const path = parentPath ? `${parentPath}.${key}` : key;
|
|
717
|
+
if (isLeafNode(templateField)) {
|
|
718
|
+
// Leaf-поле template — проверяем, есть ли validate() функция
|
|
719
|
+
if (typeof templateField.validate === "function") {
|
|
720
|
+
// Извлечь текущее значение из entity. Приоритет:
|
|
721
|
+
// 1. nodeState (актуальное значение после write pipeline)
|
|
722
|
+
// 2. fallback на entityField.value (если node ещё не зарегистрирован)
|
|
723
|
+
const entityField = entityNode[key];
|
|
724
|
+
const currentValue = entityField && typeof entityField === "object"
|
|
725
|
+
? this.nodes.nodeState.get(entityField)?.value ?? entityField.value
|
|
726
|
+
: undefined;
|
|
727
|
+
// Вызвать validate(currentValue, allEntityValues, translateFn).
|
|
728
|
+
// Если возвращает строку — это сообщение об ошибке.
|
|
729
|
+
// undefined / false = поле валидно.
|
|
730
|
+
const result = templateField.validate(currentValue, entityValues, translate);
|
|
731
|
+
if (result)
|
|
732
|
+
errors.push({ path, message: result });
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
// Группа template — рекурсия в соответствующий вложенный узел entity.
|
|
737
|
+
// Template и entity должны иметь одинаковую структуру вложенности.
|
|
738
|
+
const entityField = entityNode[key];
|
|
739
|
+
if (entityField && typeof entityField === "object") {
|
|
740
|
+
this.collectEntityTemplateErrors(templateField, entityField, errors, path);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Build flat values object from entity node, reading from nodeState.
|
|
747
|
+
* Used in template validators (collectEntityTemplateErrors).
|
|
748
|
+
*
|
|
749
|
+
* @internal
|
|
750
|
+
*/
|
|
751
|
+
buildEntityValuesForTemplate(entityNode) {
|
|
752
|
+
// Результат: plain-объект вида { id: "u1", name: "Alice", address: { city: "Moscow" } }
|
|
753
|
+
const values = {};
|
|
754
|
+
for (const key of Object.keys(entityNode)) {
|
|
755
|
+
const field = entityNode[key];
|
|
756
|
+
if (field && typeof field === "object") {
|
|
757
|
+
if (isLeafNode(field)) {
|
|
758
|
+
// Leaf: читаем value из nodeState (актуальное), fallback на field.value
|
|
759
|
+
values[key] =
|
|
760
|
+
this.nodes.nodeState.get(field)?.value ??
|
|
761
|
+
field.value;
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
// Группа: рекурсивно собрать вложенный объект
|
|
765
|
+
values[key] = this.buildEntityValuesForTemplate(field);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return values;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
//# sourceMappingURL=palistor.js.map
|