@nocobase/flow-engine 2.0.0-alpha.2
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 +661 -0
- package/README.md +30 -0
- package/lib/ContextPathProxy.d.ts +17 -0
- package/lib/ContextPathProxy.js +65 -0
- package/lib/ElementProxy.d.ts +17 -0
- package/lib/ElementProxy.js +93 -0
- package/lib/FlowContextProvider.d.ts +24 -0
- package/lib/FlowContextProvider.js +82 -0
- package/lib/FlowDefinition.d.ts +423 -0
- package/lib/FlowDefinition.js +257 -0
- package/lib/JSRunner.d.ts +32 -0
- package/lib/JSRunner.js +95 -0
- package/lib/ReactView.d.ts +20 -0
- package/lib/ReactView.js +120 -0
- package/lib/ViewScopedFlowEngine.d.ts +23 -0
- package/lib/ViewScopedFlowEngine.js +81 -0
- package/lib/acl/Acl.d.ts +31 -0
- package/lib/acl/Acl.js +115 -0
- package/lib/action-registry/BaseActionRegistry.d.ts +23 -0
- package/lib/action-registry/BaseActionRegistry.js +57 -0
- package/lib/action-registry/EngineActionRegistry.d.ts +20 -0
- package/lib/action-registry/EngineActionRegistry.js +47 -0
- package/lib/action-registry/ModelActionRegistry.d.ts +34 -0
- package/lib/action-registry/ModelActionRegistry.js +79 -0
- package/lib/components/DynamicFlowsEditor.d.ts +17 -0
- package/lib/components/DynamicFlowsEditor.js +49 -0
- package/lib/components/FieldModelRenderer.d.ts +10 -0
- package/lib/components/FieldModelRenderer.js +94 -0
- package/lib/components/FlowContextSelector.d.ts +11 -0
- package/lib/components/FlowContextSelector.js +221 -0
- package/lib/components/FlowErrorFallback.d.ts +25 -0
- package/lib/components/FlowErrorFallback.js +264 -0
- package/lib/components/FlowModelRenderer.d.ts +64 -0
- package/lib/components/FlowModelRenderer.js +254 -0
- package/lib/components/FormItem.d.ts +18 -0
- package/lib/components/FormItem.js +147 -0
- package/lib/components/common/FlowSettingsButton.d.ts +11 -0
- package/lib/components/common/FlowSettingsButton.js +66 -0
- package/lib/components/common/index.d.ts +9 -0
- package/lib/components/common/index.js +30 -0
- package/lib/components/common/withFlowDesignMode.d.ts +26 -0
- package/lib/components/common/withFlowDesignMode.js +61 -0
- package/lib/components/dnd/getMousePositionOnElement.d.ts +50 -0
- package/lib/components/dnd/getMousePositionOnElement.js +95 -0
- package/lib/components/dnd/index.d.ts +24 -0
- package/lib/components/dnd/index.js +164 -0
- package/lib/components/dnd/moveBlock.d.ts +33 -0
- package/lib/components/dnd/moveBlock.js +302 -0
- package/lib/components/index.d.ts +18 -0
- package/lib/components/index.js +48 -0
- package/lib/components/settings/independents/dropdown/FlowsDropdownButton.d.ts +46 -0
- package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +225 -0
- package/lib/components/settings/independents/dropdown/index.d.ts +9 -0
- package/lib/components/settings/independents/dropdown/index.js +30 -0
- package/lib/components/settings/independents/index.d.ts +1 -0
- package/lib/components/settings/independents/index.js +30 -0
- package/lib/components/settings/index.d.ts +10 -0
- package/lib/components/settings/index.js +32 -0
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +24 -0
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +501 -0
- package/lib/components/settings/wrappers/contextual/FlowsContextMenu.d.ts +45 -0
- package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +231 -0
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +111 -0
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +484 -0
- package/lib/components/settings/wrappers/contextual/StepRequiredSettingsDialog.d.ts +26 -0
- package/lib/components/settings/wrappers/contextual/StepRequiredSettingsDialog.js +342 -0
- package/lib/components/settings/wrappers/contextual/StepSettings.d.ts +23 -0
- package/lib/components/settings/wrappers/contextual/StepSettings.js +110 -0
- package/lib/components/settings/wrappers/contextual/StepSettingsDialog.d.ts +20 -0
- package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +206 -0
- package/lib/components/settings/wrappers/contextual/StepSettingsDrawer.d.ts +20 -0
- package/lib/components/settings/wrappers/contextual/StepSettingsDrawer.js +47 -0
- package/lib/components/settings/wrappers/contextual/index.d.ts +14 -0
- package/lib/components/settings/wrappers/contextual/index.js +40 -0
- package/lib/components/settings/wrappers/embedded/FlowSettings.d.ts +33 -0
- package/lib/components/settings/wrappers/embedded/FlowSettings.js +207 -0
- package/lib/components/settings/wrappers/embedded/FlowsSettings.d.ts +41 -0
- package/lib/components/settings/wrappers/embedded/FlowsSettings.js +84 -0
- package/lib/components/settings/wrappers/embedded/FlowsSettingsContent.d.ts +16 -0
- package/lib/components/settings/wrappers/embedded/FlowsSettingsContent.js +88 -0
- package/lib/components/settings/wrappers/embedded/index.d.ts +10 -0
- package/lib/components/settings/wrappers/embedded/index.js +32 -0
- package/lib/components/settings/wrappers/index.d.ts +2 -0
- package/lib/components/settings/wrappers/index.js +32 -0
- package/lib/components/subModel/AddSubModelButton.d.ts +62 -0
- package/lib/components/subModel/AddSubModelButton.js +415 -0
- package/lib/components/subModel/LazyDropdown.d.ts +55 -0
- package/lib/components/subModel/LazyDropdown.js +524 -0
- package/lib/components/subModel/index.d.ts +10 -0
- package/lib/components/subModel/index.js +32 -0
- package/lib/components/subModel/utils.d.ts +34 -0
- package/lib/components/subModel/utils.js +287 -0
- package/lib/components/variables/InlineVariableTag.d.ts +21 -0
- package/lib/components/variables/InlineVariableTag.js +123 -0
- package/lib/components/variables/SlateVariableEditor.d.ts +46 -0
- package/lib/components/variables/SlateVariableEditor.js +302 -0
- package/lib/components/variables/VariableInput.d.ts +11 -0
- package/lib/components/variables/VariableInput.js +322 -0
- package/lib/components/variables/VariableTag.d.ts +11 -0
- package/lib/components/variables/VariableTag.js +148 -0
- package/lib/components/variables/VariableTrigger.d.ts +20 -0
- package/lib/components/variables/VariableTrigger.js +136 -0
- package/lib/components/variables/index.d.ts +15 -0
- package/lib/components/variables/index.js +53 -0
- package/lib/components/variables/types.d.ts +93 -0
- package/lib/components/variables/types.js +24 -0
- package/lib/components/variables/useResolvedMetaTree.d.ts +19 -0
- package/lib/components/variables/useResolvedMetaTree.js +91 -0
- package/lib/components/variables/utils.d.ts +22 -0
- package/lib/components/variables/utils.js +177 -0
- package/lib/data-source/index.d.ts +180 -0
- package/lib/data-source/index.js +733 -0
- package/lib/data-source/jioToJoiSchema.d.ts +19 -0
- package/lib/data-source/jioToJoiSchema.js +114 -0
- package/lib/decorators/index.d.ts +9 -0
- package/lib/decorators/index.js +36 -0
- package/lib/decorators/largeField.d.ts +9 -0
- package/lib/decorators/largeField.js +42 -0
- package/lib/emitter.d.ts +16 -0
- package/lib/emitter.js +58 -0
- package/lib/event-registry/BaseEventRegistry.d.ts +22 -0
- package/lib/event-registry/BaseEventRegistry.js +57 -0
- package/lib/event-registry/EngineEventRegistry.d.ts +19 -0
- package/lib/event-registry/EngineEventRegistry.js +47 -0
- package/lib/event-registry/ModelEventRegistry.d.ts +33 -0
- package/lib/event-registry/ModelEventRegistry.js +79 -0
- package/lib/executor/FlowExecutor.d.ts +26 -0
- package/lib/executor/FlowExecutor.js +262 -0
- package/lib/flow-registry/BaseFlowRegistry.d.ts +46 -0
- package/lib/flow-registry/BaseFlowRegistry.js +86 -0
- package/lib/flow-registry/GlobalFlowRegistry.d.ts +22 -0
- package/lib/flow-registry/GlobalFlowRegistry.js +95 -0
- package/lib/flow-registry/InstanceFlowRegistry.d.ts +21 -0
- package/lib/flow-registry/InstanceFlowRegistry.js +59 -0
- package/lib/flow-registry/index.d.ts +11 -0
- package/lib/flow-registry/index.js +34 -0
- package/lib/flowContext.d.ts +215 -0
- package/lib/flowContext.js +1266 -0
- package/lib/flowEngine.d.ts +340 -0
- package/lib/flowEngine.js +781 -0
- package/lib/flowI18n.d.ts +46 -0
- package/lib/flowI18n.js +117 -0
- package/lib/flowSettings.d.ts +266 -0
- package/lib/flowSettings.js +850 -0
- package/lib/hooks/index.d.ts +14 -0
- package/lib/hooks/index.js +40 -0
- package/lib/hooks/useApplyAutoFlows.d.ts +21 -0
- package/lib/hooks/useApplyAutoFlows.js +62 -0
- package/lib/hooks/useFlowModel.d.ts +29 -0
- package/lib/hooks/useFlowModel.js +72 -0
- package/lib/hooks/useFlowModelById.d.ts +11 -0
- package/lib/hooks/useFlowModelById.js +61 -0
- package/lib/hooks/useFlowSettingsContext.d.ts +20 -0
- package/lib/hooks/useFlowSettingsContext.js +61 -0
- package/lib/hooks/useFlowStep.d.ts +17 -0
- package/lib/hooks/useFlowStep.js +56 -0
- package/lib/hooks/useNiceDropdownMaxHeight.d.ts +13 -0
- package/lib/hooks/useNiceDropdownMaxHeight.js +52 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.js +73 -0
- package/lib/locale/en-US.json +61 -0
- package/lib/locale/index.d.ts +141 -0
- package/lib/locale/index.js +70 -0
- package/lib/locale/zh-CN.json +61 -0
- package/lib/models/CollectionFieldModel.d.ts +50 -0
- package/lib/models/CollectionFieldModel.js +242 -0
- package/lib/models/DisplayItemModel.d.ts +12 -0
- package/lib/models/DisplayItemModel.js +41 -0
- package/lib/models/EditableItemModel.d.ts +12 -0
- package/lib/models/EditableItemModel.js +41 -0
- package/lib/models/FilterableItemModel.d.ts +12 -0
- package/lib/models/FilterableItemModel.js +41 -0
- package/lib/models/flowModel.d.ts +344 -0
- package/lib/models/flowModel.js +1133 -0
- package/lib/models/forkFlowModel.d.ts +83 -0
- package/lib/models/forkFlowModel.js +257 -0
- package/lib/models/index.d.ts +14 -0
- package/lib/models/index.js +40 -0
- package/lib/provider.d.ts +22 -0
- package/lib/provider.js +114 -0
- package/lib/resources/apiResource.d.ts +34 -0
- package/lib/resources/apiResource.js +153 -0
- package/lib/resources/baseRecordResource.d.ts +61 -0
- package/lib/resources/baseRecordResource.js +264 -0
- package/lib/resources/filterItem.d.ts +33 -0
- package/lib/resources/filterItem.js +93 -0
- package/lib/resources/flowResource.d.ts +45 -0
- package/lib/resources/flowResource.js +146 -0
- package/lib/resources/index.d.ts +15 -0
- package/lib/resources/index.js +42 -0
- package/lib/resources/multiRecordResource.d.ts +53 -0
- package/lib/resources/multiRecordResource.js +230 -0
- package/lib/resources/singleRecordResource.d.ts +23 -0
- package/lib/resources/singleRecordResource.js +111 -0
- package/lib/resources/sqlResource.d.ts +73 -0
- package/lib/resources/sqlResource.js +294 -0
- package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +38 -0
- package/lib/runjs-context/contexts/FlowRunJSContext.js +217 -0
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +16 -0
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +66 -0
- package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +16 -0
- package/lib/runjs-context/contexts/JSBlockRunJSContext.js +78 -0
- package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +12 -0
- package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +59 -0
- package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +16 -0
- package/lib/runjs-context/contexts/JSFieldRunJSContext.js +70 -0
- package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +16 -0
- package/lib/runjs-context/contexts/JSItemRunJSContext.js +66 -0
- package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +12 -0
- package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +61 -0
- package/lib/runjs-context/contexts/LinkageRunJSContext.d.ts +12 -0
- package/lib/runjs-context/contexts/LinkageRunJSContext.js +62 -0
- package/lib/runjs-context/helpers.d.ts +17 -0
- package/lib/runjs-context/helpers.js +79 -0
- package/lib/runjs-context/index.d.ts +19 -0
- package/lib/runjs-context/index.js +57 -0
- package/lib/runjs-context/registry.d.ts +17 -0
- package/lib/runjs-context/registry.js +93 -0
- package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/api-request-get.snippet.js +42 -0
- package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/api-request-post.snippet.js +42 -0
- package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/console-log-ctx.snippet.js +41 -0
- package/lib/runjs-context/snippets/global/copy-record-json.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/copy-record-json.snippet.js +42 -0
- package/lib/runjs-context/snippets/global/copy-to-clipboard.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/copy-to-clipboard.snippet.js +42 -0
- package/lib/runjs-context/snippets/global/log-json-record.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/log-json-record.snippet.js +42 -0
- package/lib/runjs-context/snippets/global/message-error.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/message-error.snippet.js +41 -0
- package/lib/runjs-context/snippets/global/message-success.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/message-success.snippet.js +41 -0
- package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/notification-open.snippet.js +43 -0
- package/lib/runjs-context/snippets/global/open-view-dialog.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +47 -0
- package/lib/runjs-context/snippets/global/open-view-drawer.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +47 -0
- package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/requireAsync.snippet.js +46 -0
- package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/sleep.snippet.js +43 -0
- package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/try-catch-async.snippet.js +44 -0
- package/lib/runjs-context/snippets/global/view-navigation-push.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/view-navigation-push.snippet.js +44 -0
- package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +16 -0
- package/lib/runjs-context/snippets/global/window-open.snippet.js +41 -0
- package/lib/runjs-context/snippets/index.d.ts +11 -0
- package/lib/runjs-context/snippets/index.js +94 -0
- package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/libs/echarts-init.snippet.js +46 -0
- package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.js +44 -0
- package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.js +43 -0
- package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +43 -0
- package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +40 -0
- package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.js +46 -0
- package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +42 -0
- package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +46 -0
- package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +41 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +41 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.js +46 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-card.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-card.snippet.js +45 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.js +56 -0
- package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.js +42 -0
- package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.js +41 -0
- package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.js +40 -0
- package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.js +44 -0
- package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.js +60 -0
- package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.js +59 -0
- package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.js +60 -0
- package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +15 -0
- package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.js +60 -0
- package/lib/runjs-context/snippets/types.d.ts +16 -0
- package/lib/runjs-context/snippets/types.js +24 -0
- package/lib/types.d.ts +398 -0
- package/lib/types.js +43 -0
- package/lib/utils/autoFlowError.d.ts +16 -0
- package/lib/utils/autoFlowError.js +53 -0
- package/lib/utils/constants.d.ts +29 -0
- package/lib/utils/constants.js +77 -0
- package/lib/utils/context.d.ts +40 -0
- package/lib/utils/context.js +63 -0
- package/lib/utils/createCollectionContextMeta.d.ts +11 -0
- package/lib/utils/createCollectionContextMeta.js +117 -0
- package/lib/utils/exceptions.d.ts +22 -0
- package/lib/utils/exceptions.js +62 -0
- package/lib/utils/flow-definitions.d.ts +11 -0
- package/lib/utils/flow-definitions.js +40 -0
- package/lib/utils/index.d.ts +22 -0
- package/lib/utils/index.js +117 -0
- package/lib/utils/inheritance.d.ts +16 -0
- package/lib/utils/inheritance.js +53 -0
- package/lib/utils/params-resolvers.d.ts +51 -0
- package/lib/utils/params-resolvers.js +309 -0
- package/lib/utils/parsePathnameToViewParams.d.ts +34 -0
- package/lib/utils/parsePathnameToViewParams.js +84 -0
- package/lib/utils/safeGlobals.d.ts +16 -0
- package/lib/utils/safeGlobals.js +179 -0
- package/lib/utils/schema-utils.d.ts +40 -0
- package/lib/utils/schema-utils.js +161 -0
- package/lib/utils/serverContextParams.d.ts +28 -0
- package/lib/utils/serverContextParams.js +106 -0
- package/lib/utils/setupRuntimeContextSteps.d.ts +19 -0
- package/lib/utils/setupRuntimeContextSteps.js +88 -0
- package/lib/utils/translation.d.ts +18 -0
- package/lib/utils/translation.js +58 -0
- package/lib/utils/variablesParams.d.ts +51 -0
- package/lib/utils/variablesParams.js +150 -0
- package/lib/views/DialogComponent.d.ts +22 -0
- package/lib/views/DialogComponent.js +98 -0
- package/lib/views/DrawerComponent.d.ts +11 -0
- package/lib/views/DrawerComponent.js +101 -0
- package/lib/views/FlowView.d.ts +76 -0
- package/lib/views/FlowView.js +81 -0
- package/lib/views/PageComponent.d.ts +10 -0
- package/lib/views/PageComponent.js +167 -0
- package/lib/views/ViewNavigation.d.ts +45 -0
- package/lib/views/ViewNavigation.js +97 -0
- package/lib/views/createViewMeta.d.ts +16 -0
- package/lib/views/createViewMeta.js +171 -0
- package/lib/views/index.d.ts +13 -0
- package/lib/views/index.js +48 -0
- package/lib/views/useDialog.d.ts +32 -0
- package/lib/views/useDialog.js +199 -0
- package/lib/views/useDrawer.d.ts +33 -0
- package/lib/views/useDrawer.js +206 -0
- package/lib/views/usePage.d.ts +32 -0
- package/lib/views/usePage.js +193 -0
- package/lib/views/usePatchElement.d.ts +10 -0
- package/lib/views/usePatchElement.js +54 -0
- package/lib/views/usePopover.d.ts +17 -0
- package/lib/views/usePopover.js +159 -0
- package/package.json +37 -0
- package/src/ContextPathProxy.ts +45 -0
- package/src/ElementProxy.ts +69 -0
- package/src/FlowContextProvider.tsx +40 -0
- package/src/FlowDefinition.ts +275 -0
- package/src/JSRunner.ts +84 -0
- package/src/ReactView.tsx +104 -0
- package/src/ViewScopedFlowEngine.ts +75 -0
- package/src/__tests__/ElementProxy.test.ts +51 -0
- package/src/__tests__/JSRunner.test.ts +92 -0
- package/src/__tests__/ReactView.test.tsx +63 -0
- package/src/__tests__/context-path-proxy.test.ts +35 -0
- package/src/__tests__/flow-engine.test.ts +189 -0
- package/src/__tests__/flowContext.test.ts +2012 -0
- package/src/__tests__/flowEngine.saveModel.test.ts +171 -0
- package/src/__tests__/flowI18n.test.ts +28 -0
- package/src/__tests__/flowModel.getFlows.test.ts +61 -0
- package/src/__tests__/flowModel.openView.navigation.test.ts +78 -0
- package/src/__tests__/flowRuntimeContext.test.ts +187 -0
- package/src/__tests__/flowSettings.open.test.tsx +1920 -0
- package/src/__tests__/flowSettings.test.ts +566 -0
- package/src/__tests__/globalFlowRegistry.test.ts +77 -0
- package/src/__tests__/isFieldInterfaceMatch.test.ts +51 -0
- package/src/__tests__/metaTreeNodeCache.test.ts +234 -0
- package/src/__tests__/path-aggregation.test.ts +85 -0
- package/src/__tests__/provider.test.tsx +28 -0
- package/src/__tests__/renderHiddenInConfig.test.tsx +91 -0
- package/src/__tests__/runjsContext.test.ts +60 -0
- package/src/__tests__/viewScopedFlowEngine.test.ts +212 -0
- package/src/acl/Acl.tsx +109 -0
- package/src/acl/__tests__/Acl.test.tsx +72 -0
- package/src/action-registry/BaseActionRegistry.ts +46 -0
- package/src/action-registry/EngineActionRegistry.ts +32 -0
- package/src/action-registry/ModelActionRegistry.ts +75 -0
- package/src/action-registry/__tests__/engineActionRegistry.test.ts +43 -0
- package/src/action-registry/__tests__/modelActionRegistry.test.ts +107 -0
- package/src/components/DynamicFlowsEditor.tsx +318 -0
- package/src/components/FieldModelRenderer.tsx +62 -0
- package/src/components/FlowContextSelector.tsx +255 -0
- package/src/components/FlowErrorFallback.tsx +316 -0
- package/src/components/FlowModelRenderer.tsx +428 -0
- package/src/components/FormItem.tsx +130 -0
- package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +226 -0
- package/src/components/common/FlowSettingsButton.tsx +30 -0
- package/src/components/common/index.ts +10 -0
- package/src/components/common/withFlowDesignMode.tsx +49 -0
- package/src/components/dnd/getMousePositionOnElement.ts +115 -0
- package/src/components/dnd/index.tsx +128 -0
- package/src/components/dnd/moveBlock.ts +379 -0
- package/src/components/index.ts +20 -0
- package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +279 -0
- package/src/components/settings/independents/dropdown/index.ts +10 -0
- package/src/components/settings/independents/index.ts +2 -0
- package/src/components/settings/index.ts +11 -0
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +617 -0
- package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +292 -0
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +655 -0
- package/src/components/settings/wrappers/contextual/StepRequiredSettingsDialog.tsx +446 -0
- package/src/components/settings/wrappers/contextual/StepSettings.tsx +109 -0
- package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +217 -0
- package/src/components/settings/wrappers/contextual/StepSettingsDrawer.tsx +32 -0
- package/src/components/settings/wrappers/contextual/index.ts +15 -0
- package/src/components/settings/wrappers/embedded/FlowSettings.tsx +258 -0
- package/src/components/settings/wrappers/embedded/FlowsSettings.tsx +111 -0
- package/src/components/settings/wrappers/embedded/FlowsSettingsContent.tsx +96 -0
- package/src/components/settings/wrappers/embedded/index.ts +11 -0
- package/src/components/settings/wrappers/index.ts +5 -0
- package/src/components/subModel/AddSubModelButton.tsx +575 -0
- package/src/components/subModel/LazyDropdown.tsx +714 -0
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +1185 -0
- package/src/components/subModel/__tests__/buildWrapperFieldChildren.test.ts +192 -0
- package/src/components/subModel/__tests__/utils.test.ts +425 -0
- package/src/components/subModel/index.ts +12 -0
- package/src/components/subModel/utils.ts +278 -0
- package/src/components/variables/InlineVariableTag.tsx +97 -0
- package/src/components/variables/SlateVariableEditor.tsx +384 -0
- package/src/components/variables/VariableInput.tsx +342 -0
- package/src/components/variables/VariableTag.tsx +123 -0
- package/src/components/variables/VariableTrigger.tsx +116 -0
- package/src/components/variables/__tests__/FlowContextSelector.test.tsx +553 -0
- package/src/components/variables/__tests__/VariableInput.test.tsx +550 -0
- package/src/components/variables/__tests__/VariableTag.test.tsx +347 -0
- package/src/components/variables/__tests__/test-utils.tsx +62 -0
- package/src/components/variables/__tests__/utils.test.ts +310 -0
- package/src/components/variables/index.ts +16 -0
- package/src/components/variables/types.ts +100 -0
- package/src/components/variables/useResolvedMetaTree.ts +76 -0
- package/src/components/variables/utils.ts +192 -0
- package/src/data-source/__tests__/collection.test.ts +58 -0
- package/src/data-source/__tests__/index.test.ts +82 -0
- package/src/data-source/__tests__/jioToJoiSchema.test.ts +56 -0
- package/src/data-source/index.ts +812 -0
- package/src/data-source/jioToJoiSchema.ts +103 -0
- package/src/decorators/index.ts +10 -0
- package/src/decorators/largeField.ts +14 -0
- package/src/emitter.ts +33 -0
- package/src/event-registry/BaseEventRegistry.ts +40 -0
- package/src/event-registry/EngineEventRegistry.ts +26 -0
- package/src/event-registry/ModelEventRegistry.ts +69 -0
- package/src/event-registry/__tests__/engineEventRegistry.test.ts +48 -0
- package/src/executor/FlowExecutor.ts +256 -0
- package/src/executor/__tests__/eventStep.test.ts +157 -0
- package/src/executor/__tests__/flowExecutor.test.ts +163 -0
- package/src/flow-registry/BaseFlowRegistry.ts +91 -0
- package/src/flow-registry/GlobalFlowRegistry.ts +82 -0
- package/src/flow-registry/InstanceFlowRegistry.ts +39 -0
- package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +141 -0
- package/src/flow-registry/__tests__/instance-and-global-registry.test.ts +67 -0
- package/src/flow-registry/__tests__/instanceFlowRegistry.test.ts +83 -0
- package/src/flow-registry/index.ts +12 -0
- package/src/flowContext.ts +1639 -0
- package/src/flowEngine.ts +905 -0
- package/src/flowI18n.ts +96 -0
- package/src/flowSettings.ts +1045 -0
- package/src/hooks/index.ts +15 -0
- package/src/hooks/useApplyAutoFlows.ts +51 -0
- package/src/hooks/useFlowModel.tsx +59 -0
- package/src/hooks/useFlowModelById.ts +37 -0
- package/src/hooks/useFlowSettingsContext.tsx +37 -0
- package/src/hooks/useFlowStep.tsx +19 -0
- package/src/hooks/useNiceDropdownMaxHeight.ts +34 -0
- package/src/index.ts +38 -0
- package/src/locale/en-US.json +61 -0
- package/src/locale/index.ts +38 -0
- package/src/locale/zh-CN.json +61 -0
- package/src/models/CollectionFieldModel.tsx +269 -0
- package/src/models/DisplayItemModel.tsx +13 -0
- package/src/models/EditableItemModel.tsx +13 -0
- package/src/models/FilterableItemModel.tsx +13 -0
- package/src/models/__tests__/CollectionFieldModel.test.ts +122 -0
- package/src/models/__tests__/defaultParams-on-create.test.ts +83 -0
- package/src/models/__tests__/flow-model-oninit.test.ts +44 -0
- package/src/models/__tests__/flowModel.actions.integration.test.ts +100 -0
- package/src/models/__tests__/flowModel.getFlows.sort.test.ts +100 -0
- package/src/models/__tests__/flowModel.test.ts +2746 -0
- package/src/models/__tests__/flowRegistry.test.ts +512 -0
- package/src/models/__tests__/forkFlowModel.test.ts +1047 -0
- package/src/models/__tests__/model-actions.test.ts +70 -0
- package/src/models/__tests__/model-events.test.ts +69 -0
- package/src/models/flowModel.tsx +1398 -0
- package/src/models/forkFlowModel.ts +287 -0
- package/src/models/index.ts +17 -0
- package/src/provider.tsx +101 -0
- package/src/resources/__tests__/apiResource.test.ts +201 -0
- package/src/resources/__tests__/baseRecordResource.test.ts +262 -0
- package/src/resources/__tests__/filterItem.test.ts +260 -0
- package/src/resources/__tests__/flowResource.test.ts +127 -0
- package/src/resources/apiResource.ts +148 -0
- package/src/resources/baseRecordResource.ts +279 -0
- package/src/resources/filterItem.ts +74 -0
- package/src/resources/flowResource.ts +143 -0
- package/src/resources/index.ts +17 -0
- package/src/resources/multiRecordResource.ts +219 -0
- package/src/resources/singleRecordResource.ts +83 -0
- package/src/resources/sqlResource.ts +299 -0
- package/src/runjs-context/contexts/FlowRunJSContext.ts +190 -0
- package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +39 -0
- package/src/runjs-context/contexts/JSBlockRunJSContext.ts +52 -0
- package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +32 -0
- package/src/runjs-context/contexts/JSFieldRunJSContext.ts +43 -0
- package/src/runjs-context/contexts/JSItemRunJSContext.ts +39 -0
- package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +34 -0
- package/src/runjs-context/contexts/LinkageRunJSContext.ts +35 -0
- package/src/runjs-context/helpers.ts +56 -0
- package/src/runjs-context/index.ts +20 -0
- package/src/runjs-context/registry.ts +65 -0
- package/src/runjs-context/snippets/global/api-request-get.snippet.ts +20 -0
- package/src/runjs-context/snippets/global/api-request-post.snippet.ts +20 -0
- package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +19 -0
- package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +21 -0
- package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +21 -0
- package/src/runjs-context/snippets/global/log-json-record.snippet.ts +21 -0
- package/src/runjs-context/snippets/global/message-error.snippet.ts +20 -0
- package/src/runjs-context/snippets/global/message-success.snippet.ts +20 -0
- package/src/runjs-context/snippets/global/notification-open.snippet.ts +21 -0
- package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +26 -0
- package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +26 -0
- package/src/runjs-context/snippets/global/requireAsync.snippet.ts +24 -0
- package/src/runjs-context/snippets/global/sleep.snippet.ts +21 -0
- package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +22 -0
- package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +23 -0
- package/src/runjs-context/snippets/global/window-open.snippet.ts +19 -0
- package/src/runjs-context/snippets/index.ts +59 -0
- package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +24 -0
- package/src/runjs-context/snippets/scene/actions/collection-selected-count.snippet.ts +22 -0
- package/src/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.ts +21 -0
- package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +21 -0
- package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +18 -0
- package/src/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.ts +29 -0
- package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +20 -0
- package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +24 -0
- package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +19 -0
- package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +24 -0
- package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +24 -0
- package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +30 -0
- package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +34 -0
- package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +20 -0
- package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +19 -0
- package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +18 -0
- package/src/runjs-context/snippets/scene/jsitem/render-basic.snippet.ts +27 -0
- package/src/runjs-context/snippets/scene/linkage/set-disabled.snippet.ts +38 -0
- package/src/runjs-context/snippets/scene/linkage/set-field-value.snippet.ts +37 -0
- package/src/runjs-context/snippets/scene/linkage/set-required.snippet.ts +38 -0
- package/src/runjs-context/snippets/scene/linkage/toggle-visible.snippet.ts +38 -0
- package/src/runjs-context/snippets/types.ts +17 -0
- package/src/types.ts +474 -0
- package/src/utils/__tests__/context.test.ts +93 -0
- package/src/utils/__tests__/params-resolvers.test.ts +652 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +104 -0
- package/src/utils/__tests__/safeGlobals.test.ts +29 -0
- package/src/utils/__tests__/utils.test.ts +1021 -0
- package/src/utils/__tests__/variablesParams.test.ts +52 -0
- package/src/utils/autoFlowError.ts +29 -0
- package/src/utils/constants.ts +60 -0
- package/src/utils/context.ts +70 -0
- package/src/utils/createCollectionContextMeta.ts +122 -0
- package/src/utils/exceptions.ts +36 -0
- package/src/utils/flow-definitions.ts +16 -0
- package/src/utils/index.ts +63 -0
- package/src/utils/inheritance.ts +39 -0
- package/src/utils/params-resolvers.ts +482 -0
- package/src/utils/parsePathnameToViewParams.ts +103 -0
- package/src/utils/safeGlobals.ts +188 -0
- package/src/utils/schema-utils.ts +201 -0
- package/src/utils/serverContextParams.ts +111 -0
- package/src/utils/setupRuntimeContextSteps.ts +89 -0
- package/src/utils/translation.ts +37 -0
- package/src/utils/variablesParams.ts +175 -0
- package/src/views/DialogComponent.tsx +79 -0
- package/src/views/DrawerComponent.tsx +72 -0
- package/src/views/FlowView.tsx +103 -0
- package/src/views/PageComponent.tsx +150 -0
- package/src/views/ViewNavigation.ts +122 -0
- package/src/views/__tests__/FlowView.test.ts +31 -0
- package/src/views/__tests__/ViewNavigation.test.ts +191 -0
- package/src/views/__tests__/usePatchElement.test.tsx +28 -0
- package/src/views/createViewMeta.ts +157 -0
- package/src/views/index.tsx +14 -0
- package/src/views/useDialog.tsx +192 -0
- package/src/views/useDrawer.tsx +205 -0
- package/src/views/usePage.tsx +182 -0
- package/src/views/usePatchElement.tsx +27 -0
- package/src/views/usePopover.tsx +131 -0
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { vi } from 'vitest';
|
|
11
|
+
import { FlowEngine } from '../../flowEngine';
|
|
12
|
+
import type { FlowModelOptions, IModelComponentProps } from '../../types';
|
|
13
|
+
import { FlowModel } from '../flowModel';
|
|
14
|
+
import { ForkFlowModel } from '../forkFlowModel';
|
|
15
|
+
|
|
16
|
+
// Helper functions
|
|
17
|
+
const createMockFlowEngine = (): FlowEngine => {
|
|
18
|
+
return new FlowEngine();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const createMockFlowModel = (overrides: Partial<FlowModelOptions> = {}): FlowModel => {
|
|
22
|
+
const flowEngine = createMockFlowEngine();
|
|
23
|
+
const options = {
|
|
24
|
+
uid: 'test-master-uid',
|
|
25
|
+
flowEngine,
|
|
26
|
+
props: { masterProp: 'masterValue' },
|
|
27
|
+
stepParams: { testFlow: { step1: { param1: 'value1' } } },
|
|
28
|
+
sortIndex: 0,
|
|
29
|
+
subModels: {},
|
|
30
|
+
async: false,
|
|
31
|
+
...overrides,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const model = new FlowModel(options);
|
|
35
|
+
return model;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Test setup
|
|
39
|
+
let mockMaster: FlowModel;
|
|
40
|
+
let initialProps: IModelComponentProps;
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
mockMaster = createMockFlowModel();
|
|
44
|
+
initialProps = { forkProp: 'forkValue' };
|
|
45
|
+
vi.clearAllMocks();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('ForkFlowModel', () => {
|
|
49
|
+
// ==================== CONSTRUCTOR & INITIALIZATION ====================
|
|
50
|
+
describe('Constructor & Initialization', () => {
|
|
51
|
+
test('should create fork with basic parameters', () => {
|
|
52
|
+
const fork = new ForkFlowModel(mockMaster, initialProps, 1);
|
|
53
|
+
|
|
54
|
+
expect(fork.uid).toBe(mockMaster.uid);
|
|
55
|
+
expect(fork.forkId).toBe(1);
|
|
56
|
+
expect(fork.localProps).toEqual(initialProps);
|
|
57
|
+
expect(fork.isFork).toBe(true);
|
|
58
|
+
expect((fork as any).master).toBe(mockMaster);
|
|
59
|
+
expect((fork as any).disposed).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should create fork with default parameters', () => {
|
|
63
|
+
const fork = new ForkFlowModel(mockMaster);
|
|
64
|
+
|
|
65
|
+
expect(fork.uid).toBe(mockMaster.uid);
|
|
66
|
+
expect(fork.forkId).toBe(0);
|
|
67
|
+
expect(fork.localProps).toEqual({});
|
|
68
|
+
expect(fork.isFork).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should return Proxy object', () => {
|
|
72
|
+
const fork = new ForkFlowModel(mockMaster, initialProps);
|
|
73
|
+
|
|
74
|
+
// Verify it's a Proxy by checking transparent property access
|
|
75
|
+
expect(typeof fork).toBe('object');
|
|
76
|
+
expect(fork.constructor).toBe(mockMaster.constructor);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ==================== HIDDEN STATE ====================
|
|
81
|
+
describe('Hidden State', () => {
|
|
82
|
+
test('should initialize hidden from master', () => {
|
|
83
|
+
mockMaster.hidden = true;
|
|
84
|
+
const fork = new ForkFlowModel(mockMaster);
|
|
85
|
+
|
|
86
|
+
expect(fork.hidden).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should keep hidden independent between master and fork', () => {
|
|
90
|
+
mockMaster.hidden = true;
|
|
91
|
+
const fork = new ForkFlowModel(mockMaster);
|
|
92
|
+
|
|
93
|
+
// initial copy from master
|
|
94
|
+
expect(fork.hidden).toBe(true);
|
|
95
|
+
|
|
96
|
+
// change fork.hidden should not affect master
|
|
97
|
+
fork.hidden = false;
|
|
98
|
+
expect(fork.hidden).toBe(false);
|
|
99
|
+
expect(mockMaster.hidden).toBe(true);
|
|
100
|
+
|
|
101
|
+
// change master.hidden should not affect existing fork
|
|
102
|
+
mockMaster.hidden = false;
|
|
103
|
+
expect(mockMaster.hidden).toBe(false);
|
|
104
|
+
expect(fork.hidden).toBe(false);
|
|
105
|
+
|
|
106
|
+
// toggle master again; fork remains unchanged
|
|
107
|
+
mockMaster.hidden = true;
|
|
108
|
+
expect(mockMaster.hidden).toBe(true);
|
|
109
|
+
expect(fork.hidden).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// ==================== PROXY GET MECHANISM ====================
|
|
114
|
+
describe('Proxy Get Mechanism', () => {
|
|
115
|
+
let fork: ForkFlowModel;
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
fork = new ForkFlowModel(mockMaster, initialProps, 1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('should return disposed status correctly', () => {
|
|
122
|
+
expect(fork['disposed']).toBe(false);
|
|
123
|
+
|
|
124
|
+
fork.dispose();
|
|
125
|
+
|
|
126
|
+
expect(fork['disposed']).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should return master constructor for constructor property', () => {
|
|
130
|
+
expect(fork.constructor).toBe(mockMaster.constructor);
|
|
131
|
+
expect(fork.constructor).toBe(FlowModel);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('should merge props from master and local', () => {
|
|
135
|
+
const masterProps = { masterProp: 'masterValue', shared: 'master' };
|
|
136
|
+
const localProps = { localProp: 'localValue', shared: 'local' };
|
|
137
|
+
|
|
138
|
+
mockMaster.getProps = vi.fn(() => masterProps);
|
|
139
|
+
fork.localProps = localProps;
|
|
140
|
+
|
|
141
|
+
const mergedProps = fork.props;
|
|
142
|
+
|
|
143
|
+
expect(mergedProps).toEqual({
|
|
144
|
+
masterProp: 'masterValue',
|
|
145
|
+
localProp: 'localValue',
|
|
146
|
+
shared: 'local', // Local should override master
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('should return fork own properties first', () => {
|
|
151
|
+
expect(fork.uid).toBe(mockMaster.uid);
|
|
152
|
+
expect(fork.forkId).toBe(1);
|
|
153
|
+
expect(fork.isFork).toBe(true);
|
|
154
|
+
expect(fork.localProps).toEqual(initialProps);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('should access local properties storage', () => {
|
|
158
|
+
// Set a local property directly
|
|
159
|
+
(fork as any).localCustomProp = 'localValue';
|
|
160
|
+
|
|
161
|
+
expect((fork as any).localCustomProp).toBe('localValue');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('should fallback to master properties', () => {
|
|
165
|
+
// Access master property that doesn\'t exist on fork
|
|
166
|
+
const masterStepParams = mockMaster.stepParams;
|
|
167
|
+
|
|
168
|
+
expect((fork as any).stepParams).toBe(masterStepParams);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('should bind functions to fork instance', () => {
|
|
172
|
+
const testMethod = vi.fn(function (this: any) {
|
|
173
|
+
return this.uid;
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
(mockMaster as any).testMethod = testMethod;
|
|
177
|
+
|
|
178
|
+
const result = (fork as any).testMethod();
|
|
179
|
+
|
|
180
|
+
expect(testMethod).toHaveBeenCalled();
|
|
181
|
+
expect(result).toBe(fork.uid);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('should preserve master constructor in function context', () => {
|
|
185
|
+
const testMethod = vi.fn(function (this: any) {
|
|
186
|
+
return this.constructor;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
(mockMaster as any).testMethod = testMethod;
|
|
190
|
+
|
|
191
|
+
const result = (fork as any).testMethod();
|
|
192
|
+
|
|
193
|
+
expect(result).toBe(mockMaster.constructor);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('should pass arguments to bound functions', () => {
|
|
197
|
+
const testMethod = vi.fn((arg1: string, arg2: number) => `${arg1}-${arg2}`);
|
|
198
|
+
|
|
199
|
+
(mockMaster as any).testMethod = testMethod;
|
|
200
|
+
|
|
201
|
+
const result = (fork as any).testMethod('test', 123);
|
|
202
|
+
|
|
203
|
+
expect(testMethod).toHaveBeenCalledWith('test', 123);
|
|
204
|
+
expect(result).toBe('test-123');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('should handle non-function master properties', () => {
|
|
208
|
+
(mockMaster as any).masterData = { key: 'value' };
|
|
209
|
+
|
|
210
|
+
expect((fork as any).masterData).toEqual({ key: 'value' });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('should handle undefined master properties', () => {
|
|
214
|
+
expect((fork as any).nonExistentProperty).toBeUndefined();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('should create correct context object for functions', () => {
|
|
218
|
+
const contextChecker = vi.fn(function (this: any) {
|
|
219
|
+
return {
|
|
220
|
+
hasConstructor: 'constructor' in this,
|
|
221
|
+
constructorValue: this.constructor,
|
|
222
|
+
isConfigurable: Object.getOwnPropertyDescriptor(this, 'constructor')?.configurable,
|
|
223
|
+
isEnumerable: Object.getOwnPropertyDescriptor(this, 'constructor')?.enumerable,
|
|
224
|
+
isWritable: Object.getOwnPropertyDescriptor(this, 'constructor')?.writable,
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
(mockMaster as any).contextChecker = contextChecker;
|
|
229
|
+
|
|
230
|
+
const result = (fork as any).contextChecker();
|
|
231
|
+
|
|
232
|
+
expect(result.hasConstructor).toBe(true);
|
|
233
|
+
expect(result.constructorValue).toBe(mockMaster.constructor);
|
|
234
|
+
expect(result.isConfigurable).toBe(true);
|
|
235
|
+
expect(result.isEnumerable).toBe(false);
|
|
236
|
+
expect(result.isWritable).toBe(false);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// ==================== PROXY SET MECHANISM ====================
|
|
241
|
+
describe('Proxy Set Mechanism', () => {
|
|
242
|
+
let fork: ForkFlowModel;
|
|
243
|
+
|
|
244
|
+
beforeEach(() => {
|
|
245
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('should ignore setting props property', () => {
|
|
249
|
+
const originalProps = fork.props;
|
|
250
|
+
|
|
251
|
+
(fork as any).props = { newProp: 'newValue' };
|
|
252
|
+
|
|
253
|
+
// Props should remain unchanged since set returns true but doesn't actually set
|
|
254
|
+
expect(fork.props).toEqual(originalProps);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('should set fork own properties directly', () => {
|
|
258
|
+
fork.localProps = { newLocal: 'value' };
|
|
259
|
+
|
|
260
|
+
expect(fork.localProps).toEqual({ newLocal: 'value' });
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('should sync shared properties to master', () => {
|
|
264
|
+
const newStepParams = { newFlow: { newStep: { param: 'value' } } };
|
|
265
|
+
|
|
266
|
+
(fork as any).stepParams = newStepParams;
|
|
267
|
+
|
|
268
|
+
expect((mockMaster as any).stepParams).toEqual(newStepParams);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('should store non-shared properties locally', () => {
|
|
272
|
+
const customValue = { data: 'localData' };
|
|
273
|
+
|
|
274
|
+
(fork as any).customProperty = customValue;
|
|
275
|
+
|
|
276
|
+
expect((fork as any).customProperty).toBe(customValue);
|
|
277
|
+
expect((mockMaster as any).customProperty).toBeUndefined();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test('should call master setter for shared properties', () => {
|
|
281
|
+
const setterSpy = vi.fn();
|
|
282
|
+
|
|
283
|
+
// Mock a setter on master
|
|
284
|
+
Object.defineProperty(mockMaster, 'sortIndex', {
|
|
285
|
+
get: () => 0,
|
|
286
|
+
set: setterSpy,
|
|
287
|
+
configurable: true,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
(fork as any).sortIndex = 5;
|
|
291
|
+
|
|
292
|
+
expect(setterSpy).toHaveBeenCalledWith(5);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('should handle shared property without setter', () => {
|
|
296
|
+
// stepParams should be a shared property without custom setter
|
|
297
|
+
const newParams = { flow: { step: { param: 'test' } } };
|
|
298
|
+
|
|
299
|
+
(fork as any).stepParams = newParams;
|
|
300
|
+
|
|
301
|
+
expect((mockMaster as any).stepParams).toEqual(newParams);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('should identify shared properties correctly', () => {
|
|
305
|
+
const originalSharedProps = ForkFlowModel.getSharedProperties();
|
|
306
|
+
|
|
307
|
+
expect(originalSharedProps).toContain('stepParams');
|
|
308
|
+
expect(originalSharedProps).toContain('sortIndex');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test('should handle property descriptor lookup', () => {
|
|
312
|
+
// Create a property with descriptor on master
|
|
313
|
+
Object.defineProperty(mockMaster, 'testDescriptor', {
|
|
314
|
+
get: () => 'test',
|
|
315
|
+
set: vi.fn(),
|
|
316
|
+
configurable: true,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const fork = new ForkFlowModel(mockMaster, initialProps);
|
|
320
|
+
|
|
321
|
+
// Since testDescriptor is not a shared property, our fix now makes
|
|
322
|
+
// non-shared properties also check for setters and call them if they exist
|
|
323
|
+
(fork as any).testDescriptor = 'newValue';
|
|
324
|
+
|
|
325
|
+
// With our fix, the setter should be called even for non-shared properties
|
|
326
|
+
const descriptor = Object.getOwnPropertyDescriptor(mockMaster, 'testDescriptor');
|
|
327
|
+
expect(descriptor?.set).toHaveBeenCalledWith('newValue');
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('should handle non-existent property descriptors', () => {
|
|
331
|
+
ForkFlowModel.setSharedProperties(['nonExistentProp']);
|
|
332
|
+
|
|
333
|
+
// Should not throw when setting property without descriptor
|
|
334
|
+
expect(() => {
|
|
335
|
+
(fork as any).nonExistentProp = 'value';
|
|
336
|
+
}).not.toThrow();
|
|
337
|
+
|
|
338
|
+
expect((mockMaster as any).nonExistentProp).toBe('value');
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// ==================== SHARED PROPERTIES MANAGEMENT ====================
|
|
343
|
+
describe('Shared Properties Management', () => {
|
|
344
|
+
test('should set shared properties configuration', () => {
|
|
345
|
+
const newSharedProps = ['customProp1', 'customProp2'];
|
|
346
|
+
|
|
347
|
+
ForkFlowModel.setSharedProperties(newSharedProps);
|
|
348
|
+
|
|
349
|
+
expect(ForkFlowModel.getSharedProperties()).toEqual(newSharedProps);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test('should get current shared properties', () => {
|
|
353
|
+
const currentProps = ForkFlowModel.getSharedProperties();
|
|
354
|
+
|
|
355
|
+
expect(Array.isArray(currentProps)).toBe(true);
|
|
356
|
+
expect(currentProps.length).toBeGreaterThan(0);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test('should have default shared properties', () => {
|
|
360
|
+
// Reset to defaults
|
|
361
|
+
ForkFlowModel.setSharedProperties(['stepParams', 'sortIndex']);
|
|
362
|
+
|
|
363
|
+
const defaultProps = ForkFlowModel.getSharedProperties();
|
|
364
|
+
|
|
365
|
+
expect(defaultProps).toContain('stepParams');
|
|
366
|
+
expect(defaultProps).toContain('sortIndex');
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test('should identify shared property correctly', () => {
|
|
370
|
+
ForkFlowModel.setSharedProperties(['testProp']);
|
|
371
|
+
const fork = new ForkFlowModel(mockMaster, initialProps);
|
|
372
|
+
|
|
373
|
+
// Use private method indirectly through property setting behavior
|
|
374
|
+
(fork as any).testProp = 'value';
|
|
375
|
+
|
|
376
|
+
expect((mockMaster as any).testProp).toBe('value');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
test('should identify non-shared property correctly', () => {
|
|
380
|
+
ForkFlowModel.setSharedProperties(['onlyThisProp']);
|
|
381
|
+
const fork = new ForkFlowModel(mockMaster, initialProps);
|
|
382
|
+
|
|
383
|
+
(fork as any).nonSharedProp = 'value';
|
|
384
|
+
|
|
385
|
+
expect((fork as any).nonSharedProp).toBe('value');
|
|
386
|
+
expect((mockMaster as any).nonSharedProp).toBeUndefined();
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// ==================== PROPS MANAGEMENT ====================
|
|
391
|
+
describe('Props Management', () => {
|
|
392
|
+
let fork: ForkFlowModel;
|
|
393
|
+
|
|
394
|
+
beforeEach(() => {
|
|
395
|
+
fork = new ForkFlowModel(mockMaster, { initial: 'value' });
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test('should set props with string key-value', () => {
|
|
399
|
+
fork.setProps('newKey', 'newValue');
|
|
400
|
+
|
|
401
|
+
expect(fork.localProps.newKey).toBe('newValue');
|
|
402
|
+
expect(fork.localProps.initial).toBe('value'); // Should preserve existing
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test('should set props with object', () => {
|
|
406
|
+
const newProps = { prop1: 'value1', prop2: 'value2' };
|
|
407
|
+
|
|
408
|
+
fork.setProps(newProps);
|
|
409
|
+
|
|
410
|
+
expect(fork.localProps).toEqual({
|
|
411
|
+
initial: 'value',
|
|
412
|
+
prop1: 'value1',
|
|
413
|
+
prop2: 'value2',
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('should merge props correctly', () => {
|
|
418
|
+
fork.setProps({ existing: 'updated', new: 'added' });
|
|
419
|
+
|
|
420
|
+
expect(fork.localProps).toEqual({
|
|
421
|
+
initial: 'value',
|
|
422
|
+
existing: 'updated',
|
|
423
|
+
new: 'added',
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test('should get merged props from master and local', () => {
|
|
428
|
+
const masterProps = { master: 'value', shared: 'master' };
|
|
429
|
+
const localProps = { local: 'value', shared: 'local' };
|
|
430
|
+
|
|
431
|
+
mockMaster.getProps = vi.fn(() => masterProps);
|
|
432
|
+
fork.localProps = localProps;
|
|
433
|
+
|
|
434
|
+
const result = fork.getProps();
|
|
435
|
+
|
|
436
|
+
expect(result).toEqual({
|
|
437
|
+
master: 'value',
|
|
438
|
+
local: 'value',
|
|
439
|
+
shared: 'local', // Local should override
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test('should maintain local props independence', () => {
|
|
444
|
+
const originalProps = { ...fork.localProps };
|
|
445
|
+
|
|
446
|
+
fork.setProps('newKey', 'newValue');
|
|
447
|
+
|
|
448
|
+
expect(fork.localProps.newKey).toBe('newValue');
|
|
449
|
+
expect(originalProps).not.toHaveProperty('newKey');
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test('should ignore setProps when disposed', () => {
|
|
453
|
+
fork.dispose();
|
|
454
|
+
const originalProps = { ...fork.localProps };
|
|
455
|
+
|
|
456
|
+
fork.setProps('shouldIgnore', 'value');
|
|
457
|
+
|
|
458
|
+
expect(fork.localProps).toEqual(originalProps);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('should handle props priority in getter', () => {
|
|
462
|
+
mockMaster.getProps = vi.fn(() => ({
|
|
463
|
+
masterOnly: 'master',
|
|
464
|
+
conflict: 'master',
|
|
465
|
+
}));
|
|
466
|
+
|
|
467
|
+
fork.localProps = {
|
|
468
|
+
localOnly: 'local',
|
|
469
|
+
conflict: 'local',
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const merged = fork.props;
|
|
473
|
+
|
|
474
|
+
expect(merged.masterOnly).toBe('master');
|
|
475
|
+
expect(merged.localOnly).toBe('local');
|
|
476
|
+
expect(merged.conflict).toBe('local'); // Local wins
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test('should handle nested object props', () => {
|
|
480
|
+
const nestedProps = {
|
|
481
|
+
user: { name: 'John', settings: { theme: 'dark' } },
|
|
482
|
+
config: { debug: true },
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
fork.setProps(nestedProps);
|
|
486
|
+
|
|
487
|
+
expect(fork.localProps.user).toEqual(nestedProps.user);
|
|
488
|
+
expect(fork.localProps.config).toEqual(nestedProps.config);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// ==================== CONTEXT AND SHARED STATE ====================
|
|
493
|
+
describe('Context and Shared State', () => {
|
|
494
|
+
let fork: ForkFlowModel;
|
|
495
|
+
|
|
496
|
+
beforeEach(() => {
|
|
497
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test('should set shared context', () => {
|
|
501
|
+
const contextData = { key1: 'value1', key2: 'value2' };
|
|
502
|
+
|
|
503
|
+
// Set context properties on the master model first
|
|
504
|
+
mockMaster.context.defineProperty('key1', { value: contextData.key1 });
|
|
505
|
+
mockMaster.context.defineProperty('key2', { value: contextData.key2 });
|
|
506
|
+
|
|
507
|
+
// Check that the context properties are accessible through fork
|
|
508
|
+
expect(fork.context.key1).toEqual('value1');
|
|
509
|
+
expect(fork.context.key2).toEqual('value2');
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test('should merge shared context', () => {
|
|
513
|
+
// Set initial context properties on master
|
|
514
|
+
mockMaster.context.defineProperty('initial', { value: 'original' });
|
|
515
|
+
|
|
516
|
+
// Update the property on master
|
|
517
|
+
mockMaster.context.defineProperty('initial', { value: 'updated' });
|
|
518
|
+
mockMaster.context.defineProperty('additional', { value: 'data' });
|
|
519
|
+
|
|
520
|
+
// Check that context properties are merged correctly
|
|
521
|
+
expect(fork.context.initial).toEqual('updated');
|
|
522
|
+
expect(fork.context.additional).toEqual('data');
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test('should get ctx with globals and shared', () => {
|
|
526
|
+
// Set shared property on master
|
|
527
|
+
mockMaster.context.defineProperty('shared', { value: 'data' });
|
|
528
|
+
|
|
529
|
+
const ctx = fork.context;
|
|
530
|
+
|
|
531
|
+
// Check that shared properties are accessible through ctx
|
|
532
|
+
expect(ctx.shared).toEqual('data');
|
|
533
|
+
|
|
534
|
+
// Verify that fork has its own context instance
|
|
535
|
+
expect(ctx).toBeDefined();
|
|
536
|
+
expect(ctx).toBeInstanceOf(Object);
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// ==================== RENDER MECHANISM ====================
|
|
541
|
+
describe('Render Mechanism', () => {
|
|
542
|
+
let fork: ForkFlowModel;
|
|
543
|
+
|
|
544
|
+
beforeEach(() => {
|
|
545
|
+
fork = new ForkFlowModel(mockMaster, { localStyle: 'local' });
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
test('should render with merged props', () => {
|
|
549
|
+
const masterProps = { masterStyle: 'master', shared: 'master' };
|
|
550
|
+
const expectedMerged = {
|
|
551
|
+
masterStyle: 'master',
|
|
552
|
+
localStyle: 'local',
|
|
553
|
+
shared: 'local',
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
mockMaster.getProps = vi.fn(() => masterProps);
|
|
557
|
+
fork.localProps = { localStyle: 'local', shared: 'local' };
|
|
558
|
+
|
|
559
|
+
mockMaster.render = vi.fn(function (this: any) {
|
|
560
|
+
return { type: 'div', props: this.props };
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
const result = fork.render();
|
|
564
|
+
|
|
565
|
+
expect(mockMaster.render).toHaveBeenCalled();
|
|
566
|
+
expect(result.props).toEqual(expectedMerged);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
test('should call master render with fork as this', () => {
|
|
570
|
+
let renderThis: any;
|
|
571
|
+
|
|
572
|
+
mockMaster.render = vi.fn(function (this: any) {
|
|
573
|
+
renderThis = this;
|
|
574
|
+
return { type: 'span', props: this.props };
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
fork.render();
|
|
578
|
+
|
|
579
|
+
expect(renderThis).toBe(fork);
|
|
580
|
+
expect(renderThis.isFork).toBe(true);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// TODO: This test case indicates a bug? even it is passing... we should not restore!
|
|
584
|
+
// test('should restore original props after render', () => {
|
|
585
|
+
// const originalProps = fork.props;
|
|
586
|
+
|
|
587
|
+
// mockMaster.render = vi.fn(function(this: any) {
|
|
588
|
+
// // Modify props during render
|
|
589
|
+
// this.props = { modified: 'during-render' };
|
|
590
|
+
// return { type: 'div', props: this.props };
|
|
591
|
+
// });
|
|
592
|
+
|
|
593
|
+
// fork.render();
|
|
594
|
+
|
|
595
|
+
// // Props should be restored
|
|
596
|
+
// expect(fork.props).toEqual(originalProps);
|
|
597
|
+
// });
|
|
598
|
+
|
|
599
|
+
test('should return null when disposed', () => {
|
|
600
|
+
mockMaster.render = vi.fn();
|
|
601
|
+
fork.dispose();
|
|
602
|
+
|
|
603
|
+
const result = fork.render();
|
|
604
|
+
|
|
605
|
+
expect(result).toBeNull();
|
|
606
|
+
expect(mockMaster.render).not.toHaveBeenCalled();
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
test('should handle render exceptions gracefully', () => {
|
|
610
|
+
mockMaster.render = vi.fn(() => {
|
|
611
|
+
throw new Error('Render error');
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
expect(() => fork.render()).toThrow('Render error');
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// ==================== LIFECYCLE MANAGEMENT ====================
|
|
619
|
+
describe('Lifecycle Management', () => {
|
|
620
|
+
let fork: ForkFlowModel;
|
|
621
|
+
|
|
622
|
+
beforeEach(() => {
|
|
623
|
+
mockMaster = createMockFlowModel();
|
|
624
|
+
(mockMaster as any).forks = new Set();
|
|
625
|
+
(mockMaster as any).forkCache = new Map();
|
|
626
|
+
|
|
627
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
628
|
+
(mockMaster as any).forks.add(fork);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
test('should dispose and change status', () => {
|
|
632
|
+
expect(fork['disposed']).toBe(false);
|
|
633
|
+
|
|
634
|
+
fork.dispose();
|
|
635
|
+
|
|
636
|
+
expect(fork['disposed']).toBe(true);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test('should remove from master forks collection', () => {
|
|
640
|
+
expect((mockMaster as any).forks.has(fork)).toBe(true);
|
|
641
|
+
|
|
642
|
+
fork.dispose();
|
|
643
|
+
|
|
644
|
+
expect((mockMaster as any).forks.has(fork)).toBe(false);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test('should remove from master fork cache', () => {
|
|
648
|
+
const cacheKey = 'testKey';
|
|
649
|
+
(mockMaster as any).forkCache.set(cacheKey, fork);
|
|
650
|
+
|
|
651
|
+
fork.dispose();
|
|
652
|
+
|
|
653
|
+
expect((mockMaster as any).forkCache.has(cacheKey)).toBe(false);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
test('should handle dispose when already disposed', () => {
|
|
657
|
+
fork.dispose();
|
|
658
|
+
|
|
659
|
+
// Should not throw on second dispose
|
|
660
|
+
expect(() => fork.dispose()).not.toThrow();
|
|
661
|
+
expect(fork['disposed']).toBe(true);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
test('should find and remove correct fork from cache', () => {
|
|
665
|
+
const fork1 = new ForkFlowModel(mockMaster, {}, 1);
|
|
666
|
+
const fork2 = new ForkFlowModel(mockMaster, {}, 2);
|
|
667
|
+
|
|
668
|
+
(mockMaster as any).forkCache.set('key1', fork1);
|
|
669
|
+
(mockMaster as any).forkCache.set('key2', fork2);
|
|
670
|
+
|
|
671
|
+
fork1.dispose();
|
|
672
|
+
|
|
673
|
+
expect((mockMaster as any).forkCache.has('key1')).toBe(false);
|
|
674
|
+
expect((mockMaster as any).forkCache.has('key2')).toBe(true);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// ==================== FUNCTION BINDING AND CONTEXT ====================
|
|
679
|
+
describe('Function Binding and Context', () => {
|
|
680
|
+
let fork: ForkFlowModel;
|
|
681
|
+
|
|
682
|
+
beforeEach(() => {
|
|
683
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
test('should bind master methods to fork instance', () => {
|
|
687
|
+
const boundMethod = vi.fn(function (this: any) {
|
|
688
|
+
return {
|
|
689
|
+
uid: this.uid,
|
|
690
|
+
isFork: this.isFork,
|
|
691
|
+
forkId: this.forkId,
|
|
692
|
+
};
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
(mockMaster as any).boundMethod = boundMethod;
|
|
696
|
+
|
|
697
|
+
const result = (fork as any).boundMethod();
|
|
698
|
+
|
|
699
|
+
expect(result.uid).toBe(fork.uid);
|
|
700
|
+
expect(result.isFork).toBe(true);
|
|
701
|
+
expect(result.forkId).toBe(fork.forkId);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
test('should preserve constructor in bound method context', () => {
|
|
705
|
+
const constructorChecker = vi.fn(function (this: any) {
|
|
706
|
+
return this.constructor === mockMaster.constructor;
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
(mockMaster as any).constructorChecker = constructorChecker;
|
|
710
|
+
|
|
711
|
+
const result = (fork as any).constructorChecker();
|
|
712
|
+
|
|
713
|
+
expect(result).toBe(true);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
test('should handle async methods correctly', async () => {
|
|
717
|
+
const asyncMethod = vi.fn(async function (this: any) {
|
|
718
|
+
return new Promise((resolve) => {
|
|
719
|
+
setTimeout(() => {
|
|
720
|
+
resolve({
|
|
721
|
+
uid: this.uid,
|
|
722
|
+
constructor: this.constructor,
|
|
723
|
+
});
|
|
724
|
+
}, 0);
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
(mockMaster as any).asyncMethod = asyncMethod;
|
|
729
|
+
|
|
730
|
+
const result = await (fork as any).asyncMethod();
|
|
731
|
+
|
|
732
|
+
expect(result.uid).toBe(fork.uid);
|
|
733
|
+
expect(result.constructor).toBe(mockMaster.constructor);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
test('should pass method arguments correctly', () => {
|
|
737
|
+
const methodWithArgs = vi.fn(function (arg1: string, arg2: number, arg3: object) {
|
|
738
|
+
return { arg1, arg2, arg3 };
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
(mockMaster as any).methodWithArgs = methodWithArgs;
|
|
742
|
+
|
|
743
|
+
const testObj = { test: 'object' };
|
|
744
|
+
const result = (fork as any).methodWithArgs('test', 123, testObj);
|
|
745
|
+
|
|
746
|
+
expect(methodWithArgs).toHaveBeenCalledWith('test', 123, testObj);
|
|
747
|
+
expect(result).toEqual({ arg1: 'test', arg2: 123, arg3: testObj });
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
test('should handle method return values correctly', () => {
|
|
751
|
+
const methodWithReturn = vi.fn(() => ({ success: true, data: 'result' }));
|
|
752
|
+
|
|
753
|
+
(mockMaster as any).methodWithReturn = methodWithReturn;
|
|
754
|
+
|
|
755
|
+
const result = (fork as any).methodWithReturn();
|
|
756
|
+
|
|
757
|
+
expect(result).toEqual({ success: true, data: 'result' });
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
test('should create correct context object properties', () => {
|
|
761
|
+
const contextInspector = vi.fn(function (this: any) {
|
|
762
|
+
const descriptor = Object.getOwnPropertyDescriptor(this, 'constructor');
|
|
763
|
+
return {
|
|
764
|
+
hasOwnConstructor: Object.prototype.hasOwnProperty.call(this, 'constructor'),
|
|
765
|
+
constructorValue: this.constructor,
|
|
766
|
+
descriptorExists: !!descriptor,
|
|
767
|
+
configurable: descriptor?.configurable,
|
|
768
|
+
enumerable: descriptor?.enumerable,
|
|
769
|
+
writable: descriptor?.writable,
|
|
770
|
+
};
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
(mockMaster as any).contextInspector = contextInspector;
|
|
774
|
+
|
|
775
|
+
const result = (fork as any).contextInspector();
|
|
776
|
+
|
|
777
|
+
expect(result.hasOwnConstructor).toBe(true);
|
|
778
|
+
expect(result.constructorValue).toBe(mockMaster.constructor);
|
|
779
|
+
expect(result.descriptorExists).toBe(true);
|
|
780
|
+
expect(result.configurable).toBe(true);
|
|
781
|
+
expect(result.enumerable).toBe(false);
|
|
782
|
+
expect(result.writable).toBe(false);
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
test('should handle closure constructor capture', () => {
|
|
786
|
+
// Create a method that captures constructor in closure
|
|
787
|
+
let capturedConstructor: any;
|
|
788
|
+
|
|
789
|
+
const closureMethod = function (this: any) {
|
|
790
|
+
capturedConstructor = this.constructor;
|
|
791
|
+
return this.constructor;
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
(mockMaster as any).closureMethod = closureMethod;
|
|
795
|
+
|
|
796
|
+
const result = (fork as any).closureMethod();
|
|
797
|
+
|
|
798
|
+
expect(capturedConstructor).toBe(mockMaster.constructor);
|
|
799
|
+
expect(result).toBe(mockMaster.constructor);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
test('should maintain correct this binding in nested calls', () => {
|
|
803
|
+
const nestedMethod = vi.fn(function (this: any) {
|
|
804
|
+
return this.uid;
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
const callerMethod = vi.fn(function (this: any) {
|
|
808
|
+
return {
|
|
809
|
+
directUid: this.uid,
|
|
810
|
+
nestedUid: nestedMethod.call(this),
|
|
811
|
+
};
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
(mockMaster as any).nestedMethod = nestedMethod;
|
|
815
|
+
(mockMaster as any).callerMethod = callerMethod;
|
|
816
|
+
|
|
817
|
+
const result = (fork as any).callerMethod();
|
|
818
|
+
|
|
819
|
+
expect(result.directUid).toBe(fork.uid);
|
|
820
|
+
expect(result.nestedUid).toBe(fork.uid);
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// ==================== EDGE CASES AND ERROR HANDLING ====================
|
|
825
|
+
describe('Edge Cases and Error Handling', () => {
|
|
826
|
+
let fork: ForkFlowModel;
|
|
827
|
+
|
|
828
|
+
beforeEach(() => {
|
|
829
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
test('should handle accessing non-existent properties', () => {
|
|
833
|
+
const value = (fork as any).totallyNonExistentProperty;
|
|
834
|
+
|
|
835
|
+
expect(value).toBeUndefined();
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
test('should handle setting props property directly', () => {
|
|
839
|
+
const originalProps = fork.props;
|
|
840
|
+
|
|
841
|
+
// This should be ignored by the proxy
|
|
842
|
+
(fork as any).props = { ignored: 'value' };
|
|
843
|
+
|
|
844
|
+
// Props should be accessed through the getter mechanism
|
|
845
|
+
expect(fork.props).toEqual(originalProps);
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
test('should handle setProps with null/undefined values', () => {
|
|
849
|
+
fork.setProps('nullProp', null);
|
|
850
|
+
fork.setProps('undefinedProp', undefined);
|
|
851
|
+
|
|
852
|
+
expect(fork.localProps.nullProp).toBeNull();
|
|
853
|
+
expect(fork.localProps.undefinedProp).toBeUndefined();
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
test('should handle complex nested property access patterns', () => {
|
|
857
|
+
// Set up complex nested structure
|
|
858
|
+
(mockMaster as any).nested = {
|
|
859
|
+
deep: {
|
|
860
|
+
property: {
|
|
861
|
+
value: 'deep value',
|
|
862
|
+
},
|
|
863
|
+
},
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
expect((fork as any).nested.deep.property.value).toBe('deep value');
|
|
867
|
+
});
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
// ==================== SETTER BEHAVIOR ====================
|
|
871
|
+
describe('Setter Behavior', () => {
|
|
872
|
+
let fork: ForkFlowModel;
|
|
873
|
+
|
|
874
|
+
beforeEach(() => {
|
|
875
|
+
fork = new ForkFlowModel(mockMaster, initialProps);
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
describe('non-shared properties with setters', () => {
|
|
879
|
+
test('should call master setter methods in fork instances', () => {
|
|
880
|
+
// 直接在 master 上定义 setter
|
|
881
|
+
let testValue = '';
|
|
882
|
+
Object.defineProperty(mockMaster, 'customProperty', {
|
|
883
|
+
get() {
|
|
884
|
+
return testValue;
|
|
885
|
+
},
|
|
886
|
+
set(value: string) {
|
|
887
|
+
testValue = `processed_${value}`;
|
|
888
|
+
},
|
|
889
|
+
configurable: true,
|
|
890
|
+
enumerable: true,
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
// 在 fork 上设置属性应该调用 master 的 setter
|
|
894
|
+
(fork as any).customProperty = 'test_value';
|
|
895
|
+
|
|
896
|
+
// 验证 setter 被正确调用(值被处理)
|
|
897
|
+
expect((fork as any).customProperty).toBe('processed_test_value');
|
|
898
|
+
expect((mockMaster as any).customProperty).toBe('processed_test_value');
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
test('should preserve this context in fork setter calls', () => {
|
|
902
|
+
let setterContext: any = null;
|
|
903
|
+
let testValue = '';
|
|
904
|
+
|
|
905
|
+
Object.defineProperty(mockMaster, 'testProperty', {
|
|
906
|
+
get() {
|
|
907
|
+
return testValue;
|
|
908
|
+
},
|
|
909
|
+
set(value: string) {
|
|
910
|
+
setterContext = this;
|
|
911
|
+
testValue = value;
|
|
912
|
+
// 验证 this 指向 fork 实例,而不是 master
|
|
913
|
+
expect(this.isFork).toBe(true);
|
|
914
|
+
},
|
|
915
|
+
configurable: true,
|
|
916
|
+
enumerable: true,
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
// 在 fork 上设置属性
|
|
920
|
+
(fork as any).testProperty = 'context_test';
|
|
921
|
+
|
|
922
|
+
// 验证 setter 中的 this 指向 fork
|
|
923
|
+
expect(setterContext).toBe(fork);
|
|
924
|
+
expect(setterContext.isFork).toBe(true);
|
|
925
|
+
expect((fork as any).testProperty).toBe('context_test');
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
test('should handle non-shared properties with setters correctly', () => {
|
|
929
|
+
let nonSharedValue = 0;
|
|
930
|
+
|
|
931
|
+
Object.defineProperty(mockMaster, 'nonSharedProperty', {
|
|
932
|
+
get() {
|
|
933
|
+
return nonSharedValue;
|
|
934
|
+
},
|
|
935
|
+
set(value: number) {
|
|
936
|
+
nonSharedValue = value * 2;
|
|
937
|
+
},
|
|
938
|
+
configurable: true,
|
|
939
|
+
enumerable: true,
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
// 设置非共享属性应该调用 setter
|
|
943
|
+
(fork as any).nonSharedProperty = 5;
|
|
944
|
+
|
|
945
|
+
// 验证 setter 被调用且 this 指向正确
|
|
946
|
+
expect((fork as any).nonSharedProperty).toBe(10); // 5 * 2
|
|
947
|
+
// master 也应该受到影响,因为我们共享同一个变量
|
|
948
|
+
expect((mockMaster as any).nonSharedProperty).toBe(10);
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
test('should fallback to local storage when no setter exists', () => {
|
|
952
|
+
// 设置一个没有 setter 的属性
|
|
953
|
+
(fork as any).customNonSetterProperty = 'local_value';
|
|
954
|
+
|
|
955
|
+
// 应该存储在 fork 的本地属性中
|
|
956
|
+
expect((fork as any).customNonSetterProperty).toBe('local_value');
|
|
957
|
+
// master 不应该有这个属性
|
|
958
|
+
expect((mockMaster as any).customNonSetterProperty).toBeUndefined();
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
describe('shared properties with setters', () => {
|
|
963
|
+
test('should handle shared properties with setters', () => {
|
|
964
|
+
// 临时修改 SHARED_PROPERTIES 来包含我们的测试属性
|
|
965
|
+
const originalSharedProps = ForkFlowModel.getSharedProperties();
|
|
966
|
+
ForkFlowModel.setSharedProperties([...originalSharedProps, 'sharedTestProperty']);
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
let sharedValue = '';
|
|
970
|
+
Object.defineProperty(mockMaster, 'sharedTestProperty', {
|
|
971
|
+
get() {
|
|
972
|
+
return sharedValue;
|
|
973
|
+
},
|
|
974
|
+
set(value: string) {
|
|
975
|
+
sharedValue = `shared_${value}`;
|
|
976
|
+
},
|
|
977
|
+
configurable: true,
|
|
978
|
+
enumerable: true,
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
// 设置共享属性应该调用 setter
|
|
982
|
+
(fork as any).sharedTestProperty = 'test';
|
|
983
|
+
|
|
984
|
+
// 验证 setter 被调用
|
|
985
|
+
expect((fork as any).sharedTestProperty).toBe('shared_test');
|
|
986
|
+
expect((mockMaster as any).sharedTestProperty).toBe('shared_test');
|
|
987
|
+
} finally {
|
|
988
|
+
// 恢复原始的共享属性
|
|
989
|
+
ForkFlowModel.setSharedProperties(originalSharedProps);
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
test('should handle shared properties without setters', () => {
|
|
994
|
+
// 临时修改 SHARED_PROPERTIES 来包含我们的测试属性
|
|
995
|
+
const originalSharedProps = ForkFlowModel.getSharedProperties();
|
|
996
|
+
ForkFlowModel.setSharedProperties([...originalSharedProps, 'plainSharedProperty']);
|
|
997
|
+
|
|
998
|
+
try {
|
|
999
|
+
// 设置共享属性(没有 setter)
|
|
1000
|
+
(fork as any).plainSharedProperty = 'shared_value';
|
|
1001
|
+
|
|
1002
|
+
// 应该直接设置在 master 上
|
|
1003
|
+
expect((mockMaster as any).plainSharedProperty).toBe('shared_value');
|
|
1004
|
+
expect((fork as any).plainSharedProperty).toBe('shared_value');
|
|
1005
|
+
} finally {
|
|
1006
|
+
// 恢复原始的共享属性
|
|
1007
|
+
ForkFlowModel.setSharedProperties(originalSharedProps);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
describe('UploadEditableFieldModel scenario', () => {
|
|
1013
|
+
test('should handle customRequest setter like in UploadEditableFieldModel', () => {
|
|
1014
|
+
// 模拟 UploadEditableFieldModel 的 customRequest setter
|
|
1015
|
+
let customRequestValue: any = null;
|
|
1016
|
+
|
|
1017
|
+
Object.defineProperty(mockMaster, 'customRequest', {
|
|
1018
|
+
set(fn: any) {
|
|
1019
|
+
customRequestValue = fn;
|
|
1020
|
+
// 模拟实际的 setter 逻辑
|
|
1021
|
+
console.log('customRequest setter called');
|
|
1022
|
+
},
|
|
1023
|
+
get() {
|
|
1024
|
+
return customRequestValue;
|
|
1025
|
+
},
|
|
1026
|
+
configurable: true,
|
|
1027
|
+
enumerable: true,
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
const testFunction = (fileData: any) => {
|
|
1031
|
+
console.log('custom request executed', fileData);
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
// 在 fork 上设置 customRequest 应该调用 master 的 setter
|
|
1035
|
+
(fork as any).customRequest = testFunction;
|
|
1036
|
+
|
|
1037
|
+
// 验证 setter 被调用,值被正确存储
|
|
1038
|
+
expect((mockMaster as any).customRequest).toBe(testFunction);
|
|
1039
|
+
expect(customRequestValue).toBe(testFunction);
|
|
1040
|
+
|
|
1041
|
+
// 注意:由于 ForkFlowModel 的 get proxy 会重新绑定函数,
|
|
1042
|
+
// fork.customRequest 返回的是一个绑定的版本,但原始值正确存储了
|
|
1043
|
+
expect(typeof (fork as any).customRequest).toBe('function');
|
|
1044
|
+
});
|
|
1045
|
+
});
|
|
1046
|
+
});
|
|
1047
|
+
});
|