@nocobase/flow-engine 2.0.0-alpha.7 → 2.0.0-alpha.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (589) hide show
  1. package/lib/BlockScopedFlowEngine.d.ts +23 -0
  2. package/lib/BlockScopedFlowEngine.js +91 -0
  3. package/lib/FlowContextProvider.d.ts +2 -2
  4. package/lib/FlowContextProvider.js +3 -3
  5. package/lib/FlowDefinition.d.ts +6 -4
  6. package/lib/JSRunner.d.ts +6 -0
  7. package/lib/JSRunner.js +27 -1
  8. package/lib/ViewScopedFlowEngine.d.ts +1 -1
  9. package/lib/ViewScopedFlowEngine.js +18 -1
  10. package/lib/acl/Acl.d.ts +12 -12
  11. package/lib/acl/Acl.js +88 -30
  12. package/lib/components/DynamicFlowsEditor.js +2 -4
  13. package/lib/components/FieldModelRenderer.js +17 -9
  14. package/lib/components/FieldSkeleton.d.ts +10 -0
  15. package/lib/components/FieldSkeleton.js +64 -0
  16. package/lib/components/FlowContextSelector.js +19 -3
  17. package/lib/components/FlowModelRenderer.d.ts +4 -6
  18. package/lib/components/FlowModelRenderer.js +35 -53
  19. package/lib/components/FormItem.js +5 -1
  20. package/lib/components/MobilePopup.d.ts +20 -0
  21. package/lib/components/MobilePopup.js +102 -0
  22. package/lib/components/MobilePopup.style.d.ts +17 -0
  23. package/lib/components/MobilePopup.style.js +186 -0
  24. package/lib/components/common/withFlowDesignMode.d.ts +1 -1
  25. package/lib/components/common/withFlowDesignMode.js +5 -5
  26. package/lib/components/dnd/gridDragPlanner.d.ts +1 -0
  27. package/lib/components/dnd/gridDragPlanner.js +53 -1
  28. package/lib/components/index.d.ts +1 -0
  29. package/lib/components/index.js +3 -1
  30. package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +71 -53
  31. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +19 -0
  32. package/lib/components/settings/wrappers/component/SelectWithTitle.js +136 -0
  33. package/lib/components/settings/wrappers/component/SwitchWithTitle.d.ts +10 -0
  34. package/lib/components/settings/wrappers/component/SwitchWithTitle.js +111 -0
  35. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +233 -97
  36. package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +71 -54
  37. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +2 -2
  38. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +63 -23
  39. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +13 -2
  40. package/lib/components/settings/wrappers/embedded/FlowSettings.js +42 -28
  41. package/lib/components/settings/wrappers/embedded/FlowsSettings.js +3 -3
  42. package/lib/components/settings/wrappers/embedded/FlowsSettingsContent.js +52 -32
  43. package/lib/components/subModel/AddSubModelButton.d.ts +7 -0
  44. package/lib/components/subModel/AddSubModelButton.js +78 -8
  45. package/lib/components/subModel/LazyDropdown.js +14 -15
  46. package/lib/components/subModel/utils.d.ts +1 -1
  47. package/lib/components/subModel/utils.js +21 -11
  48. package/lib/components/variables/VariableInput.js +26 -6
  49. package/lib/components/variables/VariableTag.js +43 -2
  50. package/lib/components/variables/types.d.ts +2 -0
  51. package/lib/components/variables/utils.js +4 -2
  52. package/lib/data-source/index.d.ts +23 -4
  53. package/lib/data-source/index.js +135 -14
  54. package/lib/data-source/jioToJoiSchema.js +1 -0
  55. package/lib/emitter.d.ts +6 -0
  56. package/lib/emitter.js +12 -0
  57. package/lib/executor/FlowExecutor.d.ts +6 -6
  58. package/lib/executor/FlowExecutor.js +302 -99
  59. package/lib/flow-registry/GlobalFlowRegistry.d.ts +1 -0
  60. package/lib/flow-registry/GlobalFlowRegistry.js +3 -0
  61. package/lib/flow-registry/InstanceFlowRegistry.d.ts +1 -0
  62. package/lib/flow-registry/InstanceFlowRegistry.js +3 -0
  63. package/lib/flowContext.d.ts +105 -6
  64. package/lib/flowContext.js +447 -139
  65. package/lib/flowEngine.d.ts +71 -1
  66. package/lib/flowEngine.js +319 -16
  67. package/lib/flowSettings.d.ts +4 -3
  68. package/lib/flowSettings.js +45 -21
  69. package/lib/hooks/useApplyAutoFlows.d.ts +1 -0
  70. package/lib/hooks/useApplyAutoFlows.js +3 -2
  71. package/lib/index.d.ts +14 -3
  72. package/lib/index.js +54 -7
  73. package/lib/locale/de-DE.json +62 -0
  74. package/lib/locale/en-US.json +57 -45
  75. package/lib/locale/es-ES.json +62 -0
  76. package/lib/locale/fr-FR.json +62 -0
  77. package/lib/locale/hu-HU.json +62 -0
  78. package/lib/locale/id-ID.json +62 -0
  79. package/lib/locale/index.d.ts +114 -90
  80. package/lib/locale/it-IT.json +62 -0
  81. package/lib/locale/ja-JP.json +62 -0
  82. package/lib/locale/ko-KR.json +62 -0
  83. package/lib/locale/nl-NL.json +62 -0
  84. package/lib/locale/pt-BR.json +62 -0
  85. package/lib/locale/ru-RU.json +62 -0
  86. package/lib/locale/tr-TR.json +62 -0
  87. package/lib/locale/uk-UA.json +62 -0
  88. package/lib/locale/vi-VN.json +62 -0
  89. package/lib/locale/zh-CN.json +58 -46
  90. package/lib/locale/zh-TW.json +62 -0
  91. package/lib/models/CollectionFieldModel.d.ts +7 -2
  92. package/lib/models/CollectionFieldModel.js +63 -16
  93. package/lib/models/flowModel.d.ts +76 -32
  94. package/lib/models/flowModel.js +300 -112
  95. package/lib/models/forkFlowModel.d.ts +8 -4
  96. package/lib/models/forkFlowModel.js +38 -8
  97. package/lib/provider.d.ts +3 -1
  98. package/lib/provider.js +14 -11
  99. package/lib/reactive/index.d.ts +10 -0
  100. package/lib/{runjs-context/snippets/global/api-request-post.snippet.js → reactive/index.js} +14 -15
  101. package/lib/reactive/observer.d.ts +19 -0
  102. package/lib/reactive/observer.js +109 -0
  103. package/lib/resources/baseRecordResource.d.ts +6 -0
  104. package/lib/resources/baseRecordResource.js +38 -3
  105. package/lib/resources/multiRecordResource.d.ts +5 -2
  106. package/lib/resources/multiRecordResource.js +26 -10
  107. package/lib/resources/singleRecordResource.js +8 -3
  108. package/lib/resources/sqlResource.d.ts +5 -3
  109. package/lib/resources/sqlResource.js +30 -28
  110. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
  111. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +37 -20
  112. package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
  113. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
  114. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
  115. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
  116. package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
  117. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
  118. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.d.ts +16 -0
  119. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +125 -0
  120. package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
  121. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
  122. package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
  123. package/lib/runjs-context/contexts/JSItemRunJSContext.js +34 -20
  124. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
  125. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
  126. package/lib/runjs-context/contexts/base.d.ts +9 -0
  127. package/lib/runjs-context/contexts/base.js +879 -0
  128. package/lib/runjs-context/contributions.d.ts +33 -0
  129. package/lib/runjs-context/contributions.js +88 -0
  130. package/lib/runjs-context/helpers.d.ts +5 -2
  131. package/lib/runjs-context/helpers.js +36 -27
  132. package/lib/runjs-context/registry.d.ts +7 -4
  133. package/lib/runjs-context/registry.js +10 -42
  134. package/lib/runjs-context/setup.d.ts +9 -0
  135. package/lib/runjs-context/setup.js +88 -0
  136. package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
  137. package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
  138. package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
  139. package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
  140. package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
  141. package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
  142. package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
  143. package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
  144. package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
  145. package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
  146. package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
  147. package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
  148. package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
  149. package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
  150. package/lib/runjs-context/snippets/index.d.ts +24 -3
  151. package/lib/runjs-context/snippets/index.js +183 -40
  152. package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
  153. package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
  154. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
  155. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
  156. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
  157. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
  158. package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
  159. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.d.ts +11 -0
  160. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.js +65 -0
  161. package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
  162. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
  163. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
  164. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
  165. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
  166. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
  167. package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
  168. package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
  169. package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
  170. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
  171. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
  172. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
  173. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
  174. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
  175. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
  176. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
  177. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
  178. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
  179. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
  180. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
  181. package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
  182. package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
  183. package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
  184. package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
  185. package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
  186. package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
  187. package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
  188. package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
  189. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
  190. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
  191. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
  192. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
  193. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
  194. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
  195. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
  196. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
  197. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
  198. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
  199. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
  200. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
  201. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
  202. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
  203. package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
  204. package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
  205. package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
  206. package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
  207. package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
  208. package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
  209. package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
  210. package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
  211. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
  212. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
  213. package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
  214. package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
  215. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
  216. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
  217. package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
  218. package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
  219. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
  220. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
  221. package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
  222. package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
  223. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
  224. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
  225. package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
  226. package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
  227. package/lib/runjs-context/snippets/types.d.ts +9 -1
  228. package/lib/runjsLibs.d.ts +28 -0
  229. package/lib/runjsLibs.js +532 -0
  230. package/lib/scheduler/ModelOperationScheduler.d.ts +53 -0
  231. package/lib/scheduler/ModelOperationScheduler.js +262 -0
  232. package/lib/types.d.ts +66 -7
  233. package/lib/types.js +4 -3
  234. package/lib/utils/associationObjectVariable.d.ts +32 -0
  235. package/lib/utils/associationObjectVariable.js +157 -0
  236. package/lib/utils/createCollectionContextMeta.d.ts +1 -1
  237. package/lib/utils/createCollectionContextMeta.js +9 -4
  238. package/lib/utils/createEphemeralContext.d.ts +13 -0
  239. package/lib/utils/createEphemeralContext.js +140 -0
  240. package/lib/utils/flows.d.ts +10 -0
  241. package/lib/{runjs-context/snippets/global/console-log-ctx.snippet.js → utils/flows.js} +21 -14
  242. package/lib/utils/index.d.ts +9 -3
  243. package/lib/utils/index.js +30 -2
  244. package/lib/utils/jsxTransform.d.ts +15 -0
  245. package/lib/utils/jsxTransform.js +68 -0
  246. package/lib/utils/params-resolvers.js +19 -12
  247. package/lib/utils/parsePathnameToViewParams.d.ts +1 -1
  248. package/lib/utils/parsePathnameToViewParams.js +41 -5
  249. package/lib/utils/pruneFilter.d.ts +21 -0
  250. package/lib/{runjs-context/snippets/global/try-catch-async.snippet.js → utils/pruneFilter.js} +24 -16
  251. package/lib/utils/resolveModuleUrl.d.ts +58 -0
  252. package/lib/utils/resolveModuleUrl.js +65 -0
  253. package/lib/utils/runjsModuleLoader.d.ts +58 -0
  254. package/lib/utils/runjsModuleLoader.js +422 -0
  255. package/lib/utils/runjsTemplateCompat.d.ts +35 -0
  256. package/lib/utils/runjsTemplateCompat.js +743 -0
  257. package/lib/utils/safeGlobals.d.ts +6 -8
  258. package/lib/utils/safeGlobals.js +169 -14
  259. package/lib/utils/schema-utils.d.ts +6 -0
  260. package/lib/utils/schema-utils.js +71 -6
  261. package/lib/utils/serverContextParams.d.ts +4 -0
  262. package/lib/utils/serverContextParams.js +2 -0
  263. package/lib/utils/translation.d.ts +4 -1
  264. package/lib/utils/translation.js +6 -2
  265. package/lib/utils/variablesParams.d.ts +22 -5
  266. package/lib/utils/variablesParams.js +141 -61
  267. package/lib/views/DialogComponent.js +1 -5
  268. package/lib/views/DrawerComponent.js +18 -9
  269. package/lib/views/PageComponent.js +5 -5
  270. package/lib/views/ViewNavigation.d.ts +11 -15
  271. package/lib/views/ViewNavigation.js +37 -19
  272. package/lib/views/createViewMeta.d.ts +27 -5
  273. package/lib/views/createViewMeta.js +338 -72
  274. package/lib/views/index.d.ts +1 -1
  275. package/lib/views/index.js +4 -0
  276. package/lib/views/useDialog.d.ts +10 -9
  277. package/lib/views/useDialog.js +46 -34
  278. package/lib/views/useDrawer.d.ts +10 -9
  279. package/lib/views/useDrawer.js +74 -48
  280. package/lib/views/usePage.d.ts +14 -9
  281. package/lib/views/usePage.js +82 -33
  282. package/lib/views/usePopover.js +4 -1
  283. package/lib/views/viewEvents.d.ts +17 -0
  284. package/lib/views/viewEvents.js +90 -0
  285. package/package.json +6 -3
  286. package/src/BlockScopedFlowEngine.ts +85 -0
  287. package/src/FlowContextProvider.tsx +4 -2
  288. package/src/JSRunner.ts +39 -1
  289. package/src/ViewScopedFlowEngine.ts +21 -1
  290. package/src/__tests__/JSRunner.test.ts +125 -52
  291. package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
  292. package/src/__tests__/createViewMeta.popup.test.ts +203 -0
  293. package/src/__tests__/flow-engine.test.ts +3 -0
  294. package/src/__tests__/flowContext.test.ts +160 -0
  295. package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
  296. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
  297. package/src/__tests__/flowEngine.destroyModel.test.ts +74 -0
  298. package/src/__tests__/flowEngine.moveModel.test.ts +43 -0
  299. package/src/__tests__/flowEngine.removeModel.test.ts +72 -0
  300. package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
  301. package/src/__tests__/flowModel.openView.navigation.test.ts +31 -2
  302. package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
  303. package/src/__tests__/flowSettings.open.test.tsx +71 -15
  304. package/src/__tests__/flowSettings.test.ts +2 -0
  305. package/src/__tests__/globalFlowRegistry.test.ts +1 -1
  306. package/src/__tests__/modelOperationScheduler.test.ts +346 -0
  307. package/src/__tests__/objectVariable.test.ts +464 -0
  308. package/src/__tests__/provider.test.tsx +0 -5
  309. package/src/__tests__/runjsContext.test.ts +219 -35
  310. package/src/__tests__/runjsContextImplementations.test.ts +217 -0
  311. package/src/__tests__/runjsContextRuntime.test.ts +269 -0
  312. package/src/__tests__/runjsEdgeCases.test.ts +281 -0
  313. package/src/__tests__/runjsExternalLibs.test.ts +242 -0
  314. package/src/__tests__/runjsLibsLazyLoading.test.ts +44 -0
  315. package/src/__tests__/runjsLocales.test.ts +39 -0
  316. package/src/__tests__/runjsPreprocessDefault.test.ts +49 -0
  317. package/src/__tests__/runjsRuntimeFeatures.test.ts +461 -0
  318. package/src/__tests__/runjsSnippets.test.ts +140 -0
  319. package/src/__tests__/viewScopedFlowEngine.test.ts +101 -3
  320. package/src/acl/Acl.tsx +85 -31
  321. package/src/acl/__tests__/Acl.test.tsx +43 -1
  322. package/src/components/DynamicFlowsEditor.tsx +0 -10
  323. package/src/components/FieldModelRenderer.tsx +22 -9
  324. package/src/components/FieldSkeleton.tsx +27 -0
  325. package/src/components/FlowContextSelector.tsx +20 -2
  326. package/src/components/FlowModelRenderer.tsx +52 -84
  327. package/src/components/FormItem.tsx +8 -1
  328. package/src/components/MobilePopup.style.ts +220 -0
  329. package/src/components/MobilePopup.tsx +86 -0
  330. package/src/components/__tests__/FlowModelRenderer.test.tsx +89 -0
  331. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +6 -6
  332. package/src/components/__tests__/gridDragPlanner.test.ts +141 -1
  333. package/src/components/common/withFlowDesignMode.tsx +5 -5
  334. package/src/components/dnd/gridDragPlanner.ts +60 -0
  335. package/src/components/index.ts +1 -0
  336. package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +34 -17
  337. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +110 -0
  338. package/src/components/settings/wrappers/component/SwitchWithTitle.tsx +83 -0
  339. package/src/components/settings/wrappers/component/__tests__/InlineControls.test.tsx +74 -0
  340. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +272 -125
  341. package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +34 -18
  342. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +56 -18
  343. package/src/components/settings/wrappers/contextual/StepSettings.tsx +1 -2
  344. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +13 -1
  345. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +624 -0
  346. package/src/components/settings/wrappers/embedded/FlowSettings.tsx +47 -35
  347. package/src/components/settings/wrappers/embedded/FlowsSettings.tsx +1 -1
  348. package/src/components/settings/wrappers/embedded/FlowsSettingsContent.tsx +64 -42
  349. package/src/components/subModel/AddSubModelButton.tsx +104 -9
  350. package/src/components/subModel/LazyDropdown.tsx +14 -14
  351. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +168 -7
  352. package/src/components/subModel/__tests__/utils.test.ts +12 -12
  353. package/src/components/subModel/utils.ts +25 -6
  354. package/src/components/variables/VariableInput.tsx +32 -6
  355. package/src/components/variables/VariableTag.tsx +54 -2
  356. package/src/components/variables/types.ts +2 -0
  357. package/src/components/variables/utils.ts +7 -3
  358. package/src/data-source/index.ts +143 -12
  359. package/src/data-source/jioToJoiSchema.ts +1 -0
  360. package/src/emitter.ts +14 -0
  361. package/src/executor/FlowExecutor.ts +383 -119
  362. package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
  363. package/src/executor/__tests__/flowExecutor.test.ts +217 -5
  364. package/src/flow-registry/GlobalFlowRegistry.ts +1 -0
  365. package/src/flow-registry/InstanceFlowRegistry.ts +1 -0
  366. package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +54 -0
  367. package/src/flowContext.ts +646 -158
  368. package/src/flowEngine.ts +385 -14
  369. package/src/flowSettings.ts +59 -30
  370. package/src/hooks/useApplyAutoFlows.ts +5 -3
  371. package/src/index.ts +26 -3
  372. package/src/locale/de-DE.json +62 -0
  373. package/src/locale/en-US.json +57 -45
  374. package/src/locale/es-ES.json +62 -0
  375. package/src/locale/fr-FR.json +62 -0
  376. package/src/locale/hu-HU.json +62 -0
  377. package/src/locale/id-ID.json +62 -0
  378. package/src/locale/it-IT.json +62 -0
  379. package/src/locale/ja-JP.json +62 -0
  380. package/src/locale/ko-KR.json +62 -0
  381. package/src/locale/nl-NL.json +62 -0
  382. package/src/locale/pt-BR.json +62 -0
  383. package/src/locale/ru-RU.json +62 -0
  384. package/src/locale/tr-TR.json +62 -0
  385. package/src/locale/uk-UA.json +62 -0
  386. package/src/locale/vi-VN.json +62 -0
  387. package/src/locale/zh-CN.json +58 -46
  388. package/src/locale/zh-TW.json +62 -0
  389. package/src/models/CollectionFieldModel.tsx +82 -18
  390. package/src/models/__tests__/dispatchEvent.behavior.test.ts +169 -0
  391. package/src/models/__tests__/dispatchEvent.when.test.ts +356 -0
  392. package/src/models/__tests__/flowEngine.resolveUse.test.ts +170 -0
  393. package/src/models/__tests__/flowModel.clone.test.ts +416 -0
  394. package/src/models/__tests__/flowModel.getFlows.sort.test.ts +33 -9
  395. package/src/models/__tests__/flowModel.scheduleModelOperation.test.tsx +129 -0
  396. package/src/models/__tests__/flowModel.test.ts +296 -119
  397. package/src/models/__tests__/forkFlowModel.test.ts +40 -7
  398. package/src/models/flowModel.tsx +426 -148
  399. package/src/models/forkFlowModel.ts +48 -8
  400. package/src/provider.tsx +18 -14
  401. package/src/reactive/__tests__/observer.test.tsx +211 -0
  402. package/src/reactive/index.ts +11 -0
  403. package/src/reactive/observer.tsx +101 -0
  404. package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
  405. package/src/resources/__tests__/sqlResource.test.ts +60 -0
  406. package/src/resources/baseRecordResource.ts +46 -3
  407. package/src/resources/multiRecordResource.ts +28 -12
  408. package/src/resources/singleRecordResource.ts +9 -3
  409. package/src/resources/sqlResource.ts +33 -32
  410. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +38 -21
  411. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +50 -34
  412. package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
  413. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
  414. package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +106 -0
  415. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
  416. package/src/runjs-context/contexts/JSItemRunJSContext.ts +35 -21
  417. package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
  418. package/src/runjs-context/contexts/base.ts +871 -0
  419. package/src/runjs-context/contributions.ts +88 -0
  420. package/src/runjs-context/helpers.ts +32 -30
  421. package/src/runjs-context/registry.ts +16 -47
  422. package/src/runjs-context/setup.ts +57 -0
  423. package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
  424. package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
  425. package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
  426. package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
  427. package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
  428. package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
  429. package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
  430. package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
  431. package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
  432. package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
  433. package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
  434. package/src/runjs-context/snippets/index.ts +212 -39
  435. package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
  436. package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
  437. package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
  438. package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
  439. package/src/runjs-context/snippets/scene/block/render-antd-icons.snippet.ts +46 -0
  440. package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
  441. package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
  442. package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
  443. package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
  444. package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
  445. package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
  446. package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
  447. package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
  448. package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
  449. package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
  450. package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
  451. package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
  452. package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
  453. package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
  454. package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
  455. package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
  456. package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
  457. package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
  458. package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
  459. package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
  460. package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
  461. package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
  462. package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
  463. package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
  464. package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
  465. package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
  466. package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
  467. package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
  468. package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
  469. package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
  470. package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
  471. package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
  472. package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
  473. package/src/runjs-context/snippets/types.ts +5 -1
  474. package/src/runjsLibs.ts +622 -0
  475. package/src/scheduler/ModelOperationScheduler.ts +306 -0
  476. package/src/types.ts +86 -5
  477. package/src/utils/__tests__/createCollectionContextMeta.test.ts +51 -0
  478. package/src/utils/__tests__/flows.test.ts +65 -0
  479. package/src/utils/__tests__/jsxTransform.test.ts +38 -0
  480. package/src/utils/__tests__/params-resolvers.test.ts +40 -0
  481. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +25 -0
  482. package/src/utils/__tests__/pruneFilter.test.ts +38 -0
  483. package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +38 -0
  484. package/src/utils/__tests__/runjsTemplateCompat.test.ts +159 -0
  485. package/src/utils/__tests__/safeGlobals.test.ts +79 -2
  486. package/src/utils/__tests__/utils.test.ts +114 -15
  487. package/src/utils/__tests__/variablesParams.test.ts +120 -0
  488. package/src/utils/associationObjectVariable.ts +180 -0
  489. package/src/utils/createCollectionContextMeta.ts +9 -3
  490. package/src/utils/createEphemeralContext.ts +142 -0
  491. package/src/utils/flows.ts +23 -0
  492. package/src/utils/index.ts +17 -3
  493. package/src/utils/jsxTransform.ts +39 -0
  494. package/src/utils/params-resolvers.ts +25 -11
  495. package/src/utils/parsePathnameToViewParams.ts +50 -6
  496. package/src/utils/pruneFilter.ts +41 -0
  497. package/src/utils/resolveModuleUrl.ts +91 -0
  498. package/src/utils/runjsModuleLoader.ts +553 -0
  499. package/src/utils/runjsTemplateCompat.ts +828 -0
  500. package/src/utils/safeGlobals.ts +181 -15
  501. package/src/utils/schema-utils.ts +81 -3
  502. package/src/utils/serverContextParams.ts +6 -0
  503. package/src/utils/translation.ts +7 -2
  504. package/src/utils/variablesParams.ts +164 -72
  505. package/src/views/DialogComponent.tsx +1 -4
  506. package/src/views/DrawerComponent.tsx +19 -7
  507. package/src/views/PageComponent.tsx +3 -5
  508. package/src/views/ViewNavigation.ts +49 -43
  509. package/src/views/__tests__/FlowView.usePage.test.tsx +186 -0
  510. package/src/views/__tests__/ViewNavigation.test.ts +54 -34
  511. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +159 -0
  512. package/src/views/__tests__/viewEvents.resolveOpenerEngine.test.ts +28 -0
  513. package/src/views/createViewMeta.ts +402 -73
  514. package/src/views/index.tsx +1 -1
  515. package/src/views/useDialog.tsx +52 -31
  516. package/src/views/useDrawer.tsx +99 -55
  517. package/src/views/usePage.tsx +101 -33
  518. package/src/views/usePopover.tsx +4 -1
  519. package/src/views/viewEvents.ts +55 -0
  520. package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
  521. package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
  522. package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
  523. package/lib/runjs-context/index.d.ts +0 -19
  524. package/lib/runjs-context/index.js +0 -57
  525. package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
  526. package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
  527. package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
  528. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
  529. package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +0 -16
  530. package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
  531. package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
  532. package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
  533. package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
  534. package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
  535. package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
  536. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
  537. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
  538. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
  539. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
  540. package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
  541. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
  542. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
  543. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
  544. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +0 -46
  545. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
  546. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
  547. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
  548. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
  549. package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
  550. package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
  551. package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
  552. package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
  553. package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
  554. package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
  555. package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
  556. package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
  557. package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
  558. package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
  559. package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
  560. package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
  561. package/src/runjs-context/index.ts +0 -20
  562. package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
  563. package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
  564. package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
  565. package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
  566. package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
  567. package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
  568. package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
  569. package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
  570. package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
  571. package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
  572. package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
  573. package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
  574. package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
  575. package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
  576. package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
  577. package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
  578. package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
  579. package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
  580. package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
  581. package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
  582. package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
  583. package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
  584. package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
  585. /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
  586. /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
  587. /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
  588. /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
  589. /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
@@ -11,14 +11,16 @@ import { ISchema } from '@formily/json-schema';
11
11
  import { observable } from '@formily/reactive';
12
12
  import { APIClient } from '@nocobase/sdk';
13
13
  import type { Router } from '@remix-run/router';
14
- import * as antd from 'antd';
15
14
  import { MessageInstance } from 'antd/es/message/interface';
15
+ import * as antd from 'antd';
16
16
  import type { HookAPI } from 'antd/es/modal/useModal';
17
17
  import { NotificationInstance } from 'antd/es/notification/interface';
18
18
  import _ from 'lodash';
19
19
  import pino from 'pino';
20
20
  import qs from 'qs';
21
21
  import React, { createRef } from 'react';
22
+ import * as ReactDOMClient from 'react-dom/client';
23
+ import { ElementProxy } from './ElementProxy';
22
24
  import type { Location } from 'react-router-dom';
23
25
  import { ACL } from './acl/Acl';
24
26
  import { ContextPathProxy } from './ContextPathProxy';
@@ -26,33 +28,32 @@ import { DataSource, DataSourceManager } from './data-source';
26
28
  import { FlowEngine } from './flowEngine';
27
29
  import { FlowI18n } from './flowI18n';
28
30
  import { JSRunner, JSRunnerOptions } from './JSRunner';
29
- import { createJSRunnerWithVersion } from './runjs-context';
30
- import { FlowModel, ForkFlowModel } from './models';
31
- import {
32
- APIResource,
33
- BaseRecordResource,
34
- FlowResource,
35
- FlowSQLRepository,
36
- MultiRecordResource,
37
- SingleRecordResource,
38
- SQLResource,
39
- } from './resources';
31
+ import type { FlowModel } from './models/flowModel';
32
+ import type { ForkFlowModel } from './models/forkFlowModel';
33
+ import { FlowResource, FlowSQLRepository } from './resources';
40
34
  import type { ActionDefinition, EventDefinition, ResourceType } from './types';
41
35
  import {
42
- createSafeDocument,
43
- createSafeWindow,
44
36
  escapeT,
45
37
  extractPropertyPath,
46
38
  extractUsedVariablePaths,
47
39
  FlowExitException,
40
+ isCssFile,
41
+ prepareRunJsCode,
48
42
  resolveDefaultParams,
49
43
  resolveExpressions,
44
+ resolveModuleUrl,
50
45
  } from './utils';
51
46
  import { FlowExitAllException } from './utils/exceptions';
52
47
  import { enqueueVariablesResolve, JSONValue } from './utils/params-resolvers';
53
48
  import type { RecordRef } from './utils/serverContextParams';
54
49
  import { buildServerContextParams as _buildServerContextParams } from './utils/serverContextParams';
50
+ import { inferRecordRef } from './utils/variablesParams';
55
51
  import { FlowView, FlowViewer } from './views/FlowView';
52
+ import { RunJSContextRegistry, getModelClassName } from './runjs-context/registry';
53
+ import { createEphemeralContext } from './utils/createEphemeralContext';
54
+ import dayjs from 'dayjs';
55
+ import { externalReactRender, setupRunJSLibs } from './runjsLibs';
56
+ import { runjsImportAsync, runjsImportModule, runjsRequireAsync } from './utils/runjsModuleLoader';
56
57
 
57
58
  // Helper: detect a RecordRef-like object
58
59
  function isRecordRefLike(val: any): boolean {
@@ -75,6 +76,61 @@ function filterBuilderOutputByPaths(built: any, neededPaths: string[]): any {
75
76
  return undefined;
76
77
  }
77
78
 
79
+ // Helper: extract top-level segment of a subpath (e.g. 'a.b' -> 'a', 'tags[0].name' -> 'tags')
80
+ function topLevelOf(subPath: string): string | undefined {
81
+ if (!subPath) return undefined;
82
+ const m = String(subPath).match(/^([^.[]+)/);
83
+ return m?.[1];
84
+ }
85
+
86
+ // Helper: infer selects (fields/appends) from usage paths (mirrors server-side inferSelectsFromUsage)
87
+ function inferSelectsFromUsage(paths: string[] = []): { generatedAppends?: string[]; generatedFields?: string[] } {
88
+ if (!Array.isArray(paths) || paths.length === 0) {
89
+ return { generatedAppends: undefined, generatedFields: undefined };
90
+ }
91
+
92
+ const appendSet = new Set<string>();
93
+ const fieldSet = new Set<string>();
94
+
95
+ const normalizePath = (raw: string): string => {
96
+ if (!raw) return '';
97
+ let s = String(raw);
98
+ // remove numeric indexes like [0]
99
+ s = s.replace(/\[(?:\d+)\]/g, '');
100
+ // normalize string indexes like ["name"] / ['name'] into .name
101
+ s = s.replace(/\[(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')\]/g, (_m, g1, g2) => `.${(g1 || g2) as string}`);
102
+ s = s.replace(/\.\.+/g, '.');
103
+ s = s.replace(/^\./, '').replace(/\.$/, '');
104
+ return s;
105
+ };
106
+
107
+ for (let path of paths) {
108
+ if (!path) continue;
109
+ // drop leading numeric index like [0].name
110
+ while (/^\[(\d+)\](\.|$)/.test(path)) {
111
+ path = path.replace(/^\[(\d+)\]\.?/, '');
112
+ }
113
+ const norm = normalizePath(path);
114
+ if (!norm) continue;
115
+ const segments = norm.split('.').filter(Boolean);
116
+ if (segments.length === 0) continue;
117
+
118
+ if (segments.length === 1) {
119
+ fieldSet.add(segments[0]);
120
+ continue;
121
+ }
122
+
123
+ for (let i = 0; i < segments.length - 1; i++) {
124
+ appendSet.add(segments.slice(0, i + 1).join('.'));
125
+ }
126
+ fieldSet.add(segments.join('.'));
127
+ }
128
+
129
+ const generatedAppends = appendSet.size ? Array.from(appendSet) : undefined;
130
+ const generatedFields = fieldSet.size ? Array.from(fieldSet) : undefined;
131
+ return { generatedAppends, generatedFields };
132
+ }
133
+
78
134
  type Getter<T = any> = (ctx: FlowContext) => T | Promise<T>;
79
135
 
80
136
  export interface MetaTreeNode {
@@ -82,11 +138,14 @@ export interface MetaTreeNode {
82
138
  title: string;
83
139
  type: string;
84
140
  interface?: string;
141
+ options?: any;
85
142
  uiSchema?: ISchema;
86
143
  render?: (props: any) => JSX.Element;
87
144
  // display?: 'default' | 'flatten' | 'none'; // 显示模式:默认、平铺子菜单、完全隐藏, 用于简化meta树显示层级
88
145
  paths: string[];
89
146
  parentTitles?: string[]; // 父级标题数组,不包含自身title,第一层可省略
147
+ // 显示控制:当 hidden 为 true(或函数返回 true)时,不在变量选择器中展示该节点
148
+ hidden?: boolean | (() => boolean);
90
149
  // 变量禁用状态与原因(用于变量选择器 UI 展示)
91
150
  disabled?: boolean | (() => boolean);
92
151
  disabledReason?: string | (() => string | undefined);
@@ -97,6 +156,7 @@ export interface PropertyMeta {
97
156
  type: string;
98
157
  title: string;
99
158
  interface?: string;
159
+ options?: any;
100
160
  uiSchema?: ISchema; // TODO: 这个是不是压根没必要啊?
101
161
  render?: (props: any) => JSX.Element; // 自定义渲染函数
102
162
  // 用于 VariableInput 的排序:数值越大,显示越靠前;相同值保持稳定顺序
@@ -107,6 +167,8 @@ export interface PropertyMeta {
107
167
  disabled?: boolean | (() => boolean);
108
168
  // 禁用原因(用于 UI 小问号提示),可为函数
109
169
  disabledReason?: string | (() => string | undefined);
170
+ // 显示控制:当 hidden 为 true(或函数返回 true)时,不在变量选择器中展示该节点
171
+ hidden?: boolean | (() => boolean);
110
172
  // 变量解析参数构造器(用于 variables:resolve 的 contextParams,按属性名归位)。
111
173
  // 支持返回 RecordRef 或任意嵌套对象(将被 buildServerContextParams 扁平化,例如 { record: RecordRef } -> 'view.record')。
112
174
  buildVariablesParams?: (
@@ -142,6 +204,10 @@ export interface PropertyOptions {
142
204
  // - boolean: true 表示整个顶层变量交给服务端;false 表示仅前端解析
143
205
  // - function: 根据子路径决定是否交给服务端(子路径示例:'record.roles[0].name'、'id'、'')
144
206
  resolveOnServer?: boolean | ((subPath: string) => boolean);
207
+ // 优化:当需要服务端解析但本属性在 buildVariablesParams 返回空时,是否跳过调用服务端。
208
+ // - 典型场景:formValues / currentObject 仅在“已选关联值”存在时才需要服务端;否则没有必要请求。
209
+ // - 默认 false:保持兼容,其他变量即使没有 contextParams 也可选择调用服务端。
210
+ serverOnlyWhenContextParams?: boolean;
145
211
  }
146
212
 
147
213
  type RouteOptions = {
@@ -658,12 +724,13 @@ export class FlowContext {
658
724
 
659
725
  let node: MetaTreeNode;
660
726
 
661
- // 计算禁用状态与原因的帮助函数
662
- const computeDisabledFromMeta = (m: PropertyMeta): { disabled: boolean; reason?: string } => {
663
- if (!m) return { disabled: false };
727
+ // 计算禁用/隐藏状态与原因的帮助函数
728
+ const computeStateFromMeta = (m: PropertyMeta): { disabled: boolean; reason?: string; hidden: boolean } => {
729
+ if (!m) return { disabled: false, hidden: false };
664
730
  const disabledVal = typeof m.disabled === 'function' ? m.disabled() : m.disabled;
665
731
  const reason = typeof m.disabledReason === 'function' ? m.disabledReason() : m.disabledReason;
666
- return { disabled: !!disabledVal, reason };
732
+ const hiddenVal = typeof m.hidden === 'function' ? m.hidden() : m.hidden;
733
+ return { disabled: !!disabledVal, reason, hidden: !!hiddenVal };
667
734
  };
668
735
 
669
736
  if (typeof metaOrFactory === 'function') {
@@ -674,18 +741,24 @@ export class FlowContext {
674
741
  title: metaOrFactory.title || initialTitle, // 初始使用 name 作为 title
675
742
  type: 'object', // 初始类型
676
743
  interface: undefined,
744
+ options: undefined,
677
745
  uiSchema: undefined,
678
746
  paths,
679
747
  parentTitles: parentTitles.length > 0 ? parentTitles : undefined,
680
748
  disabled: () => {
681
749
  const maybe = metaOrFactory();
682
750
  if (maybe && typeof maybe['then'] === 'function') return false;
683
- return computeDisabledFromMeta(maybe as PropertyMeta).disabled;
751
+ return computeStateFromMeta(maybe as PropertyMeta).disabled;
684
752
  },
685
753
  disabledReason: () => {
686
754
  const maybe = metaOrFactory();
687
755
  if (maybe && typeof maybe['then'] === 'function') return undefined;
688
- return computeDisabledFromMeta(maybe as PropertyMeta).reason;
756
+ return computeStateFromMeta(maybe as PropertyMeta).reason;
757
+ },
758
+ hidden: () => {
759
+ const maybe = metaOrFactory();
760
+ if (maybe && typeof maybe['then'] === 'function') return false;
761
+ return computeStateFromMeta(maybe as PropertyMeta).hidden;
689
762
  },
690
763
  // 注意:即便 hasChildren === false,也只是“没有子节点”的 UI 提示;
691
764
  // 节点自身依然通过 meta 工厂保持惰性特性(需要时可解析出 title/type 等)。
@@ -700,6 +773,7 @@ export class FlowContext {
700
773
  node.title = finalTitle;
701
774
  node.type = meta?.type;
702
775
  node.interface = meta?.interface;
776
+ node.options = meta?.options;
703
777
  node.uiSchema = meta?.uiSchema;
704
778
  // parentTitles 保持不变,因为它不包含自身 title
705
779
 
@@ -726,17 +800,19 @@ export class FlowContext {
726
800
  } else {
727
801
  // 同步 meta:直接创建节点
728
802
  const nodeTitle = metaOrFactory.title;
729
- const { disabled, reason } = computeDisabledFromMeta(metaOrFactory);
803
+ const { disabled, reason, hidden } = computeStateFromMeta(metaOrFactory);
730
804
  node = {
731
805
  name,
732
806
  title: nodeTitle,
733
807
  type: metaOrFactory.type,
734
808
  interface: metaOrFactory.interface,
809
+ options: metaOrFactory.options,
735
810
  uiSchema: metaOrFactory.uiSchema,
736
811
  paths,
737
812
  parentTitles: parentTitles.length > 0 ? parentTitles : undefined,
738
813
  disabled,
739
814
  disabledReason: reason,
815
+ hidden,
740
816
  children: metaOrFactory.properties
741
817
  ? this.#createChildNodes(metaOrFactory.properties, paths, [...parentTitles, nodeTitle], metaOrFactory)
742
818
  : undefined,
@@ -890,33 +966,86 @@ export class FlowContext {
890
966
  }
891
967
  return this._findPropertyInDelegates(this._delegates, key);
892
968
  }
893
- }
894
969
 
895
- export class FlowRunjsContext extends FlowContext {
896
- constructor(delegate: FlowContext) {
897
- super();
898
- this.addDelegate(delegate);
899
- // Expose React and antd only within runjs context
900
- // This keeps the scope minimal while enabling React/AntD rendering in scripts
901
- this.defineProperty('React', { value: React });
902
- this.defineProperty('antd', { value: antd });
903
- this.defineMethod(
904
- 'dispatchModelEvent',
905
- async (modelOrUid: FlowModel | string, eventName: string, inputArgs?: Record<string, any>) => {
906
- let model: FlowModel | null = null;
907
- if (typeof modelOrUid === 'string') {
908
- model = await this.engine.loadModel({ uid: modelOrUid });
909
- } else if (modelOrUid instanceof FlowModel) {
910
- model = modelOrUid;
970
+ /**
971
+ * 获取当前上下文可用的顶层 API 信息(主要用于编辑器补全/工具)。
972
+ *
973
+ * 注意:
974
+ * - 目前返回值以“尽量可用”为目标,允许不完整。
975
+ * - 该方法不会展开变量 meta(变量结构应由 `getPropertyMetaTree()`/VariableInput 等机制负责)。
976
+ */
977
+ async getApiInfos(options: { version?: string } = {}): Promise<Record<string, any>> {
978
+ const version = (options as any)?.version || ('v1' as any);
979
+ const modelClass = getModelClassName(this as any);
980
+ const Ctor =
981
+ RunJSContextRegistry.resolve(version as any, modelClass) || RunJSContextRegistry.resolve(version as any, '*');
982
+ const locale = (this as any)?.api?.auth?.locale || (this as any)?.i18n?.language || (this as any)?.locale;
983
+
984
+ let doc: any = {};
985
+ try {
986
+ if ((Ctor as any)?.getDoc?.length) doc = (Ctor as any).getDoc(locale) || {};
987
+ else doc = (Ctor as any)?.getDoc?.() || {};
988
+ } catch (_) {
989
+ doc = {};
990
+ }
991
+
992
+ const isPrivateKey = (key: string) => typeof key === 'string' && key.startsWith('_');
993
+ const out: Record<string, any> = {};
994
+ const visited = new WeakSet<any>();
995
+
996
+ const walk = (ctx: any) => {
997
+ if (!ctx || visited.has(ctx)) return;
998
+ visited.add(ctx);
999
+
1000
+ try {
1001
+ for (const key of Object.keys(ctx._props || {})) {
1002
+ if (isPrivateKey(key)) continue;
1003
+ if (typeof out[key] === 'undefined') out[key] = { type: 'property' };
911
1004
  }
912
- if (model) {
913
- model.context.addDelegate(this);
914
- model.dispatchEvent(eventName, { navigation: false, ...this.model?.['getInputArgs']?.(), ...inputArgs });
915
- } else {
916
- this.message.error(this.t('Model with ID {{uid}} not found', { uid: modelOrUid }));
1005
+ } catch (_) {
1006
+ // ignore
1007
+ }
1008
+
1009
+ try {
1010
+ for (const key of Object.keys(ctx._methods || {})) {
1011
+ if (isPrivateKey(key)) continue;
1012
+ if (typeof out[key] === 'undefined') out[key] = { type: 'function' };
917
1013
  }
918
- },
919
- );
1014
+ } catch (_) {
1015
+ // ignore
1016
+ }
1017
+
1018
+ try {
1019
+ const delegates = Array.isArray(ctx._delegates) ? ctx._delegates : [];
1020
+ for (const d of delegates) walk(d);
1021
+ } catch (_) {
1022
+ // ignore
1023
+ }
1024
+ };
1025
+
1026
+ walk(this);
1027
+
1028
+ return {
1029
+ ...out,
1030
+ ...(doc?.properties || {}),
1031
+ ...(doc?.methods || {}),
1032
+ };
1033
+ }
1034
+
1035
+ /**
1036
+ * 变量结构信息(保留给编辑器/工具使用)。
1037
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
1038
+ */
1039
+ async getVarInfos(_options: { path?: string | string[]; maxDepth?: number } = {}): Promise<Record<string, any>> {
1040
+ return {};
1041
+ }
1042
+
1043
+ /**
1044
+ * 运行时环境信息(保留给编辑器/工具使用)。
1045
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
1046
+ */
1047
+ async getEnvInfos(): Promise<Record<string, any>> {
1048
+ return {};
920
1049
  }
921
1050
  }
922
1051
 
@@ -924,14 +1053,16 @@ class BaseFlowEngineContext extends FlowContext {
924
1053
  declare router: Router;
925
1054
  declare dataSourceManager: DataSourceManager;
926
1055
  declare requireAsync: (url: string) => Promise<any>;
927
- declare createJSRunner: (options?: JSRunnerOptions) => JSRunner;
1056
+ declare importAsync: (url: string) => Promise<any>;
1057
+ declare createJSRunner: (options?: JSRunnerOptions) => Promise<JSRunner>;
1058
+ declare pageInfo: { version?: 'v1' | 'v2' };
928
1059
  /**
929
1060
  * @deprecated use `resolveJsonTemplate` instead
930
1061
  */
931
1062
  declare renderJson: (template: JSONValue) => Promise<any>;
932
1063
  declare resolveJsonTemplate: (template: JSONValue) => Promise<any>;
1064
+ declare getVar: (path: string) => Promise<any>;
933
1065
  declare runjs: (code: string, variables?: Record<string, any>, options?: JSRunnerOptions) => Promise<any>;
934
- declare copyToClipboard: (text: string) => Promise<void>;
935
1066
  declare getAction: <TModel extends FlowModel = FlowModel, TCtx extends FlowContext = FlowContext>(
936
1067
  name: string,
937
1068
  ) => ActionDefinition<TModel, TCtx> | undefined;
@@ -955,6 +1086,25 @@ class BaseFlowEngineContext extends FlowContext {
955
1086
  declare location: Location;
956
1087
  declare sql: FlowSQLRepository;
957
1088
  declare logger: pino.Logger;
1089
+
1090
+ constructor() {
1091
+ super();
1092
+ this.defineMethod(
1093
+ 'runjs',
1094
+ async function (code: string, variables?: Record<string, any>, options?: JSRunnerOptions) {
1095
+ const { preprocessTemplates, ...runnerOptions } = options || {};
1096
+ const mergedGlobals = { ...(runnerOptions?.globals || {}), ...(variables || {}) };
1097
+ const runner = await this.createJSRunner({
1098
+ ...(runnerOptions || {}),
1099
+ globals: mergedGlobals,
1100
+ });
1101
+ // Enable by default; use `preprocessTemplates: false` to explicitly disable.
1102
+ const shouldPreprocessTemplates = preprocessTemplates !== false;
1103
+ const jsCode = await prepareRunJsCode(String(code ?? ''), { preprocessTemplates: shouldPreprocessTemplates });
1104
+ return runner.run(jsCode);
1105
+ },
1106
+ );
1107
+ }
958
1108
  }
959
1109
 
960
1110
  class BaseFlowModelContext extends BaseFlowEngineContext {
@@ -994,7 +1144,8 @@ export class FlowEngineContext extends BaseFlowEngineContext {
994
1144
  value: this.engine,
995
1145
  });
996
1146
  this.defineProperty('sql', {
997
- get: () => new FlowSQLRepository(this),
1147
+ get: (ctx) => new FlowSQLRepository(ctx),
1148
+ cache: false,
998
1149
  });
999
1150
  this.defineProperty('dataSourceManager', {
1000
1151
  value: dataSourceManager,
@@ -1003,14 +1154,6 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1003
1154
  this.defineMethod('t', (keyOrTemplate: string, options?: any) => {
1004
1155
  return i18n.translate(keyOrTemplate, options);
1005
1156
  });
1006
- this.defineMethod('runjs', async (code, variables, options?: JSRunnerOptions) => {
1007
- const mergedGlobals = { ...(options?.globals || {}), ...(variables || {}) };
1008
- const runner = this.createJSRunner({
1009
- ...(options || {}),
1010
- globals: mergedGlobals,
1011
- });
1012
- return runner.run(code);
1013
- });
1014
1157
  this.defineMethod('renderJson', function (template: any) {
1015
1158
  return this.resolveJsonTemplate(template);
1016
1159
  });
@@ -1046,6 +1189,22 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1046
1189
  const needServer = Object.keys(serverVarPaths).length > 0;
1047
1190
  let serverResolved = template;
1048
1191
  if (needServer) {
1192
+ const inferRecordRefWithMeta = (ctx: any): RecordRef | undefined => {
1193
+ const ref = inferRecordRef(ctx as any);
1194
+ if (ref) return ref as RecordRef;
1195
+ try {
1196
+ const tk = ctx?.resource?.getMeta?.('currentFilterByTk');
1197
+ if (typeof tk === 'undefined' || tk === null) return undefined;
1198
+ const collection =
1199
+ ctx?.collection?.name || ctx?.resource?.getResourceName?.()?.split?.('.')?.slice?.(-1)?.[0];
1200
+ if (!collection) return undefined;
1201
+ const dataSourceKey = ctx?.collection?.dataSourceKey || ctx?.resource?.getDataSourceKey?.();
1202
+ return { collection, dataSourceKey, filterByTk: tk } as RecordRef;
1203
+ } catch (_) {
1204
+ return undefined;
1205
+ }
1206
+ };
1207
+
1049
1208
  const collectFromMeta = async (): Promise<Record<string, any>> => {
1050
1209
  const out: Record<string, any> = {};
1051
1210
  try {
@@ -1085,11 +1244,77 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1085
1244
  };
1086
1245
 
1087
1246
  const inputFromMeta = await collectFromMeta();
1088
- const autoInput = { ...inputFromMeta };
1247
+ const autoInput = { ...inputFromMeta } as Record<string, any>;
1248
+
1249
+ // Special-case: formValues
1250
+ // If server needs to resolve some formValues paths but meta params only cover association anchors
1251
+ // (e.g. formValues.customer) and some top-level paths are missing (e.g. formValues.status),
1252
+ // inject a top-level record anchor (formValues -> { collection, filterByTk, fields/appends }) so server can fetch DB values.
1253
+ // This anchor MUST be selective (fields/appends derived from serverVarPaths['formValues']) to avoid server overriding
1254
+ // client-only values for configured form fields in the same template.
1255
+ try {
1256
+ const varName = 'formValues';
1257
+ const neededPaths = serverVarPaths[varName] || [];
1258
+ if (neededPaths.length) {
1259
+ const requiredTop = new Set<string>();
1260
+ for (const p of neededPaths) {
1261
+ const top = topLevelOf(p);
1262
+ if (top) requiredTop.add(top);
1263
+ }
1264
+ const metaOut = inputFromMeta?.[varName];
1265
+ const builtTop = new Set<string>();
1266
+ if (metaOut && typeof metaOut === 'object' && !Array.isArray(metaOut) && !isRecordRefLike(metaOut)) {
1267
+ Object.keys(metaOut).forEach((k) => builtTop.add(k));
1268
+ }
1269
+
1270
+ const missing = [...requiredTop].filter((k) => !builtTop.has(k));
1271
+ if (missing.length) {
1272
+ const ref = inferRecordRefWithMeta(this);
1273
+ if (ref) {
1274
+ const { generatedFields, generatedAppends } = inferSelectsFromUsage(neededPaths);
1275
+ const recordRef: RecordRef = {
1276
+ ...ref,
1277
+ fields: generatedFields,
1278
+ appends: generatedAppends,
1279
+ };
1280
+
1281
+ // Preserve existing association anchors by lifting them to dotted keys before overwriting formValues
1282
+ const existing = autoInput[varName];
1283
+ if (
1284
+ existing &&
1285
+ typeof existing === 'object' &&
1286
+ !Array.isArray(existing) &&
1287
+ !isRecordRefLike(existing)
1288
+ ) {
1289
+ for (const [k, v] of Object.entries(existing)) {
1290
+ autoInput[`${varName}.${k}`] = v;
1291
+ }
1292
+ delete autoInput[varName];
1293
+ }
1294
+
1295
+ autoInput[varName] = recordRef;
1296
+ }
1297
+ }
1298
+ }
1299
+ } catch (_) {
1300
+ // ignore
1301
+ }
1302
+
1089
1303
  const autoContextParams = Object.keys(autoInput).length
1090
1304
  ? _buildServerContextParams(this, autoInput)
1091
1305
  : undefined;
1092
1306
 
1307
+ // 优化:若所有需要服务端解析的变量都声明了 “仅当有 contextParams 时才请求服务端”,
1308
+ // 且本次未能构建出任何 contextParams,则跳过服务端请求,回退到前端解析。
1309
+ if (!autoContextParams) {
1310
+ const keys = Object.keys(serverVarPaths);
1311
+ const allOptional =
1312
+ keys.length > 0 && keys.every((k) => this.getPropertyOptions(k)?.serverOnlyWhenContextParams);
1313
+ if (allOptional) {
1314
+ return resolveExpressions(template, this);
1315
+ }
1316
+ }
1317
+
1093
1318
  if (this.api) {
1094
1319
  try {
1095
1320
  serverResolved = await enqueueVariablesResolve(this as FlowRuntimeContext<FlowModel>, {
@@ -1105,6 +1330,23 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1105
1330
 
1106
1331
  return resolveExpressions(serverResolved, this);
1107
1332
  });
1333
+
1334
+ // Helper: resolve a single ctx expression value via resolveJsonTemplate behavior.
1335
+ // Example: await ctx.getVar('ctx.record.id')
1336
+ this.defineMethod(
1337
+ 'getVar',
1338
+ async function (this: BaseFlowEngineContext, varPath: string) {
1339
+ const raw = typeof varPath === 'string' ? varPath : String(varPath ?? '');
1340
+ const s = raw.trim();
1341
+ if (!s) return undefined;
1342
+ // Preferred input: 'ctx.xxx.yyy' (expression), consistent with envs.getVar outputs.
1343
+ if (s !== 'ctx' && !s.startsWith('ctx.')) {
1344
+ throw new Error(`ctx.getVar(path) expects an expression starting with "ctx.", got: "${s}"`);
1345
+ }
1346
+ return this.resolveJsonTemplate(`{{ ${s} }}` as any);
1347
+ },
1348
+ 'Resolve a ctx expression value by path (expression starts with "ctx.").',
1349
+ );
1108
1350
  this.defineProperty('requirejs', {
1109
1351
  get: () => this.app?.requirejs?.requirejs,
1110
1352
  });
@@ -1186,7 +1428,8 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1186
1428
  user: this.user,
1187
1429
  }),
1188
1430
  });
1189
- this.defineMethod('loadCSS', async (url: string) => {
1431
+ this.defineMethod('loadCSS', async (href: string) => {
1432
+ const url = resolveModuleUrl(href);
1190
1433
  return new Promise((resolve, reject) => {
1191
1434
  // Check if CSS is already loaded
1192
1435
  const existingLink = document.querySelector(`link[href="${url}"]`);
@@ -1204,64 +1447,34 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1204
1447
  });
1205
1448
  });
1206
1449
  this.defineMethod('requireAsync', async (url: string) => {
1207
- return new Promise((resolve, reject) => {
1208
- if (!this.requirejs) {
1209
- reject(new Error('requirejs is not available'));
1210
- return;
1211
- }
1212
- this.requirejs(
1213
- [url],
1214
- (...args: any[]) => {
1215
- resolve(args[0]);
1216
- },
1217
- reject,
1218
- );
1219
- });
1450
+ const u = resolveModuleUrl(url, { raw: true });
1451
+ return await runjsRequireAsync(this.requirejs, u);
1220
1452
  });
1221
- this.defineMethod('createJSRunner', function (options?: JSRunnerOptions) {
1222
- // return createJSRunnerWithVersion.call(this, options as any);
1223
- const runCtx = new FlowRunjsContext(this.createProxy());
1224
- return new JSRunner({
1225
- ...options,
1226
- globals: {
1227
- ctx: runCtx,
1228
- window: createSafeWindow(),
1229
- document: createSafeDocument(),
1230
- ...options?.globals,
1231
- },
1232
- });
1453
+ // 动态按 URL 加载 ESM 模块
1454
+ // - 使用 Vite / Webpack ignore 注释,避免被预打包或重写
1455
+ // - 返回模块命名空间对象(包含 default 与命名导出)
1456
+ this.defineMethod('importAsync', async function (this: any, url: string) {
1457
+ // 判断是否为 CSS 文件(支持 example.css?v=123 等形式)
1458
+ if (isCssFile(url)) {
1459
+ return this.loadCSS(url);
1460
+ }
1461
+
1462
+ return await runjsImportModule(this, url, { importer: runjsImportAsync });
1233
1463
  });
1234
- // 复制文本到剪贴板(优先使用 Clipboard API,降级到 execCommand)
1235
- this.defineMethod('copyToClipboard', async (text: string) => {
1236
- const content = String(text ?? '');
1464
+ this.defineMethod('createJSRunner', async function (options?: JSRunnerOptions) {
1237
1465
  try {
1238
- if (typeof navigator !== 'undefined' && navigator.clipboard && navigator.clipboard.writeText) {
1239
- await navigator.clipboard.writeText(content);
1240
- return;
1241
- }
1242
- } catch (e) {
1243
- // 忽略,尝试降级方案
1466
+ const mod: any = await import('./runjs-context/setup');
1467
+ if (typeof mod?.setupRunJSContexts === 'function') await mod.setupRunJSContexts();
1468
+ } catch (_) {
1469
+ // ignore if setup is not available
1244
1470
  }
1245
-
1246
- // 降级方案:创建临时 textarea + execCommand('copy')
1247
- return new Promise<void>((resolve, reject) => {
1248
- try {
1249
- const ta = document.createElement('textarea');
1250
- ta.value = content;
1251
- ta.setAttribute('readonly', '');
1252
- ta.style.position = 'fixed';
1253
- ta.style.top = '-9999px';
1254
- document.body.appendChild(ta);
1255
- ta.focus();
1256
- ta.select();
1257
- const ok = document.execCommand('copy');
1258
- document.body.removeChild(ta);
1259
- if (ok) resolve();
1260
- else reject(new Error('execCommand copy failed'));
1261
- } catch (err) {
1262
- reject(err);
1263
- }
1264
- });
1471
+ const version = options?.version || 'v1';
1472
+ const modelClass = getModelClassName(this);
1473
+ const Ctor: new (delegate: any) => any = RunJSContextRegistry.resolve(version, modelClass) || FlowRunJSContext;
1474
+ const runCtx = new Ctor(this);
1475
+ const globals: Record<string, any> = { ctx: runCtx, ...(options?.globals || {}) };
1476
+ const { timeoutMs } = options || {};
1477
+ return new JSRunner({ globals, timeoutMs });
1265
1478
  });
1266
1479
  // Helper: build server contextParams for variables:resolve
1267
1480
  this.defineMethod('buildServerContextParams', function (this: BaseFlowEngineContext, input?: any) {
@@ -1332,7 +1545,8 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1332
1545
  'runAction',
1333
1546
  async function (this: BaseFlowEngineContext, actionName: string, params?: Record<string, any>) {
1334
1547
  const def = this.engine.getAction<FlowModel, FlowEngineContext>(actionName);
1335
- const ctx = this.createProxy() as unknown as FlowEngineContext;
1548
+ // 使用“临时作用域”上下文,避免将临时定义污染到引擎级上下文,并在创建时应用定义
1549
+ const ctx = await createEphemeralContext(this as unknown as FlowEngineContext, def);
1336
1550
  if (!def) {
1337
1551
  throw new Error(`Action '${actionName}' not found.`);
1338
1552
  }
@@ -1346,7 +1560,7 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1346
1560
  }
1347
1561
  if (!useRawParams) {
1348
1562
  // 先服务端解析,再前端补齐
1349
- combinedParams = await (ctx as any).resolveJsonTemplate(combinedParams);
1563
+ combinedParams = await ctx.resolveJsonTemplate(combinedParams);
1350
1564
  }
1351
1565
 
1352
1566
  if (!def.handler) {
@@ -1369,12 +1583,25 @@ export class FlowEngineContext extends BaseFlowEngineContext {
1369
1583
  context: this.createProxy(),
1370
1584
  });
1371
1585
  });
1586
+ // Provide useResource in base engine context so RunJS can call it directly
1587
+ this.defineMethod(
1588
+ 'useResource',
1589
+ function (
1590
+ this: BaseFlowEngineContext,
1591
+ className: 'APIResource' | 'SingleRecordResource' | 'MultiRecordResource' | 'SQLResource',
1592
+ ) {
1593
+ if (this.has('resource')) return;
1594
+ this.defineProperty('resource', {
1595
+ get: () => this.createResource(className),
1596
+ });
1597
+ },
1598
+ );
1372
1599
  }
1373
1600
  }
1374
1601
 
1375
1602
  export class FlowModelContext extends BaseFlowModelContext {
1376
1603
  constructor(model: FlowModel) {
1377
- if (!(model instanceof FlowModel)) {
1604
+ if (!model || typeof model !== 'object') {
1378
1605
  throw new Error('Invalid FlowModel instance');
1379
1606
  }
1380
1607
  super();
@@ -1382,13 +1609,6 @@ export class FlowModelContext extends BaseFlowModelContext {
1382
1609
  this.defineMethod('onRefReady', (ref, cb, timeout) => {
1383
1610
  this.engine.reactView.onRefReady(ref, cb, timeout);
1384
1611
  });
1385
- this.defineMethod('runjs', async (code, variables, options?: { version?: string }) => {
1386
- const runner = this.createJSRunner({
1387
- globals: variables,
1388
- version: options?.version,
1389
- });
1390
- return runner.run(code);
1391
- });
1392
1612
  this.defineProperty('model', {
1393
1613
  value: model,
1394
1614
  });
@@ -1402,12 +1622,22 @@ export class FlowModelContext extends BaseFlowModelContext {
1402
1622
  });
1403
1623
  this.defineMethod('openView', async function (uid: string, options) {
1404
1624
  const opts = { ...options };
1405
- if (opts.defineProperties || opts.defineMethod) {
1625
+ // NOTE: when custom context is passed, route navigation must be disabled to avoid losing it after refresh.
1626
+ if (opts.defineProperties || opts.defineMethods) {
1406
1627
  opts.navigation = false; // 强制不使用路由导航, 避免刷新页面时丢失上下文
1407
1628
  }
1408
1629
  let model: FlowModel | null = null;
1409
1630
  model = await this.engine.loadModel({ uid });
1410
1631
  if (!model) {
1632
+ const pickDefined = (src: Record<string, any>, keys: string[]) => {
1633
+ const res: Record<string, any> = {};
1634
+ for (const k of keys) {
1635
+ if (typeof src?.[k] !== 'undefined') {
1636
+ res[k] = src[k];
1637
+ }
1638
+ }
1639
+ return res;
1640
+ };
1411
1641
  model = this.engine.createModel({
1412
1642
  uid, // 注意: 新建的 model 应该使用 ${parentModel.uid}-xxx 形式的 uid
1413
1643
  use: 'PopupActionModel',
@@ -1417,23 +1647,16 @@ export class FlowModelContext extends BaseFlowModelContext {
1417
1647
  stepParams: {
1418
1648
  popupSettings: {
1419
1649
  openView: {
1420
- ..._.pick(opts, ['dataSourceKey', 'collectionName', 'associationName']),
1650
+ // 仅在创建时持久化一份默认配置;运行时以本次 opts 为准,避免多个 opener 互相覆盖。
1651
+ ...pickDefined(opts, ['dataSourceKey', 'collectionName', 'associationName', 'mode', 'size']),
1421
1652
  },
1422
1653
  },
1423
1654
  },
1424
1655
  });
1425
1656
  await model.save();
1426
1657
  }
1427
- if (model.getStepParams('popupSettings')?.openView?.dataSourceKey) {
1428
- model.setStepParams('popupSettings', {
1429
- openView: {
1430
- ...model.getStepParams('popupSettings')?.openView,
1431
- ..._.pick(opts, ['dataSourceKey', 'collectionName', 'associationName']),
1432
- },
1433
- });
1434
- await model.save();
1435
- }
1436
1658
 
1659
+ model.setParent(this.model);
1437
1660
  // 路由层级的 viewUid:优先使用 routeViewUid(仅用于路由展示);
1438
1661
  // 否则回退到 opts.viewUid;再否则沿用原有规则(若子模型具备弹窗配置则使用子模型 uid,否则使用发起者 uid)。
1439
1662
  const viewUid =
@@ -1456,13 +1679,26 @@ export class FlowModelContext extends BaseFlowModelContext {
1456
1679
  engineCtx: this.engine.context,
1457
1680
  };
1458
1681
  model.context.defineProperty('view', { value: pendingView });
1459
- await model.dispatchEvent('click', {
1460
- // navigation: false, // TODO: 路由模式有bug,不支持多层同样viewId的弹窗,因此这里默认先用false
1461
- // ...this.model?.['getInputArgs']?.(), // 避免部分关系字段信息丢失, 仿照 ClickableCollectionField 做法
1462
- ...opts,
1463
- });
1464
- // 清理 pending view,避免污染子模型 context(例如后续直接点击该模型按钮时被遗留 viewUid 干扰)
1465
- model.context.defineProperty('view', { value: undefined });
1682
+ // 默认按 click 打开,但兼容 popupSettings 绑定到其他事件(例如 DuplicateActionModel 监听 openDuplicatePopup)。
1683
+ const popupFlow = model.getFlow?.('popupSettings');
1684
+ const on = (popupFlow as any)?.on;
1685
+ let openEventName = 'click';
1686
+ if (typeof on === 'string' && on) {
1687
+ openEventName = on;
1688
+ } else if (on && typeof on === 'object' && typeof (on as any).eventName === 'string' && (on as any).eventName) {
1689
+ openEventName = (on as any).eventName;
1690
+ }
1691
+ await model.dispatchEvent(
1692
+ openEventName,
1693
+ {
1694
+ // navigation: false, // TODO: 路由模式有bug,不支持多层同样viewId的弹窗,因此这里默认先用false
1695
+ // ...this.model?.['getInputArgs']?.(), // 避免部分关系字段信息丢失, 仿照 ClickableCollectionField 做法
1696
+ ...opts,
1697
+ },
1698
+ {
1699
+ debounce: true,
1700
+ },
1701
+ );
1466
1702
  });
1467
1703
  this.defineMethod('getEvents', function (this: BaseFlowModelContext) {
1468
1704
  return this.model.getEvents();
@@ -1477,7 +1713,8 @@ export class FlowModelContext extends BaseFlowModelContext {
1477
1713
  'runAction',
1478
1714
  async function (this: BaseFlowModelContext, actionName: string, params?: Record<string, any>) {
1479
1715
  const def = this.model.getAction<FlowModel, FlowModelContext>(actionName);
1480
- const ctx = this.createProxy() as unknown as FlowModelContext;
1716
+ // 使用“临时作用域”上下文,避免将临时定义污染到模型级上下文,并在创建时应用定义
1717
+ const ctx = await createEphemeralContext(this as unknown as FlowModelContext, def);
1481
1718
  if (!def) {
1482
1719
  throw new Error(`Action '${actionName}' not found.`);
1483
1720
  }
@@ -1490,7 +1727,7 @@ export class FlowModelContext extends BaseFlowModelContext {
1490
1727
  useRawParams = await useRawParams(ctx);
1491
1728
  }
1492
1729
  if (!useRawParams) {
1493
- combinedParams = await (ctx as any).resolveJsonTemplate(combinedParams);
1730
+ combinedParams = await ctx.resolveJsonTemplate(combinedParams);
1494
1731
  }
1495
1732
 
1496
1733
  if (!def.handler) {
@@ -1507,11 +1744,11 @@ export class FlowForkModelContext extends BaseFlowModelContext {
1507
1744
  public master: FlowModel,
1508
1745
  public fork: ForkFlowModel,
1509
1746
  ) {
1510
- if (!(master instanceof FlowModel)) {
1747
+ if (!master || typeof master !== 'object') {
1511
1748
  throw new Error('Invalid FlowModel instance');
1512
1749
  }
1513
1750
  super();
1514
- this.addDelegate((this.master as any).context);
1751
+ this.addDelegate(this.master.context);
1515
1752
  this.defineMethod('onRefReady', (ref, cb, timeout) => {
1516
1753
  this.engine.reactView.onRefReady(ref, cb, timeout);
1517
1754
  });
@@ -1526,13 +1763,6 @@ export class FlowForkModelContext extends BaseFlowModelContext {
1526
1763
  return stableRef;
1527
1764
  },
1528
1765
  });
1529
- this.defineMethod('runjs', async (code, variables, options?: { version?: string }) => {
1530
- const runner = this.createJSRunner({
1531
- globals: variables,
1532
- version: options?.version,
1533
- });
1534
- return runner.run(code);
1535
- });
1536
1766
  }
1537
1767
  }
1538
1768
 
@@ -1587,13 +1817,6 @@ export class FlowRuntimeContext<
1587
1817
  this.defineMethod('onRefReady', (ref, cb, timeout) => {
1588
1818
  this.engine.reactView.onRefReady(ref, cb, timeout);
1589
1819
  });
1590
- this.defineMethod('runjs', async (code, variables, options?: { version?: string }) => {
1591
- const runner = this.createJSRunner({
1592
- globals: variables,
1593
- version: options?.version,
1594
- });
1595
- return runner.run(code);
1596
- });
1597
1820
  }
1598
1821
 
1599
1822
  protected _getOwnProperty(key: string): any {
@@ -1641,3 +1864,268 @@ export class FlowRuntimeContext<
1641
1864
 
1642
1865
  // 类型别名,方便使用
1643
1866
  export type FlowSettingsContext<TModel extends FlowModel = FlowModel> = FlowRuntimeContext<TModel, 'settings'>;
1867
+
1868
+ export type FlowContextDocRef = string | { url: string; title?: string };
1869
+
1870
+ export type FlowDeprecationDoc =
1871
+ | boolean
1872
+ | {
1873
+ message?: string;
1874
+ replacedBy?: string | string[];
1875
+ since?: string;
1876
+ removedIn?: string;
1877
+ ref?: FlowContextDocRef;
1878
+ };
1879
+
1880
+ export type FlowContextDocParam = {
1881
+ name: string;
1882
+ description?: string;
1883
+ type?: string;
1884
+ optional?: boolean;
1885
+ default?: JSONValue;
1886
+ };
1887
+
1888
+ export type FlowContextDocReturn = {
1889
+ description?: string;
1890
+ type?: string;
1891
+ };
1892
+
1893
+ export type RunJSDocCompletionDoc = {
1894
+ insertText?: string;
1895
+ };
1896
+
1897
+ export type RunJSDocHiddenDoc = boolean | ((ctx: any) => boolean | Promise<boolean>);
1898
+
1899
+ // `hidden` is the single visibility entrypoint for RunJSDoc property docs:
1900
+ // - boolean: hide the whole node and its subtree
1901
+ // - string[]: hide specific subpaths under the node (relative dot-paths)
1902
+ export type RunJSDocHiddenOrPathsDoc =
1903
+ | boolean
1904
+ | string[]
1905
+ | ((ctx: any) => boolean | string[] | Promise<boolean | string[]>);
1906
+
1907
+ export type RunJSDocPropertyDoc =
1908
+ | string
1909
+ | {
1910
+ description?: string;
1911
+ detail?: string;
1912
+ type?: string;
1913
+ examples?: string[];
1914
+ completion?: RunJSDocCompletionDoc;
1915
+ ref?: FlowContextDocRef;
1916
+ deprecated?: FlowDeprecationDoc;
1917
+ params?: FlowContextDocParam[];
1918
+ returns?: FlowContextDocReturn;
1919
+ properties?: Record<string, RunJSDocPropertyDoc>;
1920
+ hidden?: RunJSDocHiddenOrPathsDoc;
1921
+ disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
1922
+ disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
1923
+ };
1924
+
1925
+ export type RunJSDocMethodDoc =
1926
+ | string
1927
+ | {
1928
+ description?: string;
1929
+ detail?: string;
1930
+ examples?: string[];
1931
+ completion?: RunJSDocCompletionDoc;
1932
+ ref?: FlowContextDocRef;
1933
+ deprecated?: FlowDeprecationDoc;
1934
+ params?: FlowContextDocParam[];
1935
+ returns?: FlowContextDocReturn;
1936
+ hidden?: RunJSDocHiddenDoc;
1937
+ disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
1938
+ disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
1939
+ };
1940
+
1941
+ export type RunJSDocMeta = {
1942
+ label?: string;
1943
+ properties?: Record<string, RunJSDocPropertyDoc>;
1944
+ methods?: Record<string, RunJSDocMethodDoc>;
1945
+ snippets?: Record<string, any>;
1946
+ };
1947
+
1948
+ const __runjsClassDefaultMeta = new WeakMap<Function, RunJSDocMeta>();
1949
+ const __runjsClassLocaleMeta = new WeakMap<Function, Map<string, RunJSDocMeta>>();
1950
+ const __runjsDocCache = new WeakMap<Function, Map<string, RunJSDocMeta>>();
1951
+
1952
+ function __runjsDeepMerge(base: any, patch: any) {
1953
+ if (patch === null) return undefined;
1954
+ if (Array.isArray(base) || Array.isArray(patch) || typeof base !== 'object' || typeof patch !== 'object') {
1955
+ return patch ?? base;
1956
+ }
1957
+ const out: any = { ...base };
1958
+ for (const k of Object.keys(patch)) {
1959
+ const v = __runjsDeepMerge(base?.[k], patch[k]);
1960
+ if (typeof v === 'undefined') delete out[k];
1961
+ else out[k] = v;
1962
+ }
1963
+ return out;
1964
+ }
1965
+
1966
+ export class FlowRunJSContext extends FlowContext {
1967
+ constructor(delegate: FlowContext) {
1968
+ super();
1969
+ this.addDelegate(delegate);
1970
+ this.defineProperty('React', { value: React });
1971
+ this.defineProperty('antd', { value: antd });
1972
+ this.defineProperty('dayjs', { value: dayjs });
1973
+ // 为 JS 运行时代码提供带有 antd/App/ConfigProvider 包裹的 React 根
1974
+ // 保持与 ReactDOMClient 接口一致,优先覆盖 createRoot,其余方法透传
1975
+ const ReactDOMShim: any = {
1976
+ ...ReactDOMClient,
1977
+ createRoot: (container: Element | DocumentFragment, options?: any) => {
1978
+ // 兼容 ElementProxy:若传入的是代理对象,取其底层原生元素
1979
+ const realContainer: any = (container as any)?.__el || container;
1980
+ // 使用引擎自带的 reactView.createRoot,以继承应用内的 ConfigProvider/App 上下文与主题
1981
+ return this.engine.reactView.createRoot(realContainer as HTMLElement, options);
1982
+ },
1983
+ };
1984
+ ReactDOMShim.__nbRunjsInternalShim = true;
1985
+ this.defineProperty('ReactDOM', { value: ReactDOMShim });
1986
+
1987
+ setupRunJSLibs(this);
1988
+
1989
+ // Convenience: ctx.render(<App />[, container])
1990
+ // - container defaults to ctx.element if available
1991
+ // - internally uses engine.reactView.createRoot to inherit app context
1992
+ // - caches root per container via global WeakMap
1993
+ this.defineMethod(
1994
+ 'render',
1995
+ function (
1996
+ this: any,
1997
+ vnode: React.ReactElement | Node | DocumentFragment | string,
1998
+ container?: Element | DocumentFragment,
1999
+ ) {
2000
+ const el = (container as any) || (this.element as any);
2001
+ if (!el) throw new Error('ctx.render: container not provided and ctx.element is not available');
2002
+ const containerEl: any = (el as any)?.__el || el; // unwrap ElementProxy
2003
+ const globalRef: any = globalThis as any;
2004
+ globalRef.__nbRunjsRoots = globalRef.__nbRunjsRoots || new WeakMap<any, any>();
2005
+ const rootMap: WeakMap<any, any> = globalRef.__nbRunjsRoots;
2006
+
2007
+ const disposeEntry = (entry: any) => {
2008
+ if (!entry) return;
2009
+ if (entry.disposeTheme && typeof entry.disposeTheme === 'function') {
2010
+ try {
2011
+ entry.disposeTheme();
2012
+ } catch (_) {
2013
+ // ignore
2014
+ }
2015
+ entry.disposeTheme = undefined;
2016
+ }
2017
+ const root = entry.root || entry;
2018
+ if (root && typeof root.unmount === 'function') {
2019
+ try {
2020
+ root.unmount();
2021
+ } catch (_) {
2022
+ // ignore
2023
+ }
2024
+ }
2025
+ };
2026
+
2027
+ const unmountContainerRoot = () => {
2028
+ const existing = rootMap.get(containerEl);
2029
+ if (existing) {
2030
+ disposeEntry(existing);
2031
+ rootMap.delete(containerEl);
2032
+ }
2033
+ };
2034
+
2035
+ // If vnode is string (HTML), unmount react root and set sanitized HTML
2036
+ if (typeof vnode === 'string') {
2037
+ unmountContainerRoot();
2038
+ const proxy: any = new ElementProxy(containerEl);
2039
+ proxy.innerHTML = String(vnode ?? '');
2040
+ return null;
2041
+ }
2042
+
2043
+ // If vnode is a DOM Node or DocumentFragment, unmount and replace content
2044
+ if (
2045
+ vnode &&
2046
+ (vnode as any).nodeType &&
2047
+ ((vnode as any).nodeType === 1 || (vnode as any).nodeType === 3 || (vnode as any).nodeType === 11)
2048
+ ) {
2049
+ unmountContainerRoot();
2050
+ while (containerEl.firstChild) containerEl.removeChild(containerEl.firstChild);
2051
+ containerEl.appendChild(vnode as any);
2052
+ return null;
2053
+ }
2054
+
2055
+ // 注意:rootMap 是“全局按容器复用”的(key=containerEl)。
2056
+ // 若不同 RunJS ctx 复用同一个 containerEl,且 ReactDOM 实例引用也相同,
2057
+ // 则会复用到旧 entry,进而复用旧 ctx 创建的 autorun(闭包捕获旧 ctx),造成:
2058
+ // 1) 旧 ctx 的 reaction 继续驱动新渲染(跨 ctx 复用风险)
2059
+ // 2) 新 ctx 的主题变化不再触发 rerender
2060
+ // 3) 旧 ctx 被 entry/autorun 间接持有,无法被 GC(内存泄漏)
2061
+ // 因此这里把 ownerKey(当前 ctx)也纳入复用判断;owner 变化时必须重建 entry。
2062
+ const rendererKey = this.ReactDOM;
2063
+ const ownerKey = this;
2064
+ let entry = rootMap.get(containerEl);
2065
+ if (!entry || entry.rendererKey !== rendererKey || entry.ownerKey !== ownerKey) {
2066
+ if (entry) {
2067
+ disposeEntry(entry);
2068
+ rootMap.delete(containerEl);
2069
+ }
2070
+ const root = this.ReactDOM.createRoot(containerEl);
2071
+ entry = { rendererKey, ownerKey, root, disposeTheme: undefined, lastVnode: undefined };
2072
+ rootMap.set(containerEl, entry);
2073
+ }
2074
+
2075
+ return externalReactRender({
2076
+ ctx: this,
2077
+ entry,
2078
+ vnode,
2079
+ containerEl,
2080
+ rootMap,
2081
+ unmountContainerRoot,
2082
+ internalReact: React,
2083
+ internalAntd: antd,
2084
+ });
2085
+ },
2086
+ );
2087
+ }
2088
+ static define(meta: RunJSDocMeta, options?: { locale?: string }) {
2089
+ const locale = options?.locale;
2090
+ if (locale) {
2091
+ const map = __runjsClassLocaleMeta.get(this) || new Map<string, RunJSDocMeta>();
2092
+ const prev = map.get(locale) || {};
2093
+ map.set(locale, __runjsDeepMerge(prev, meta));
2094
+ __runjsClassLocaleMeta.set(this, map);
2095
+ } else {
2096
+ const prev = __runjsClassDefaultMeta.get(this) || {};
2097
+ __runjsClassDefaultMeta.set(this, __runjsDeepMerge(prev, meta));
2098
+ }
2099
+ __runjsDocCache.delete(this);
2100
+ }
2101
+ static getDoc(locale?: string): RunJSDocMeta {
2102
+ const self = this as any as Function;
2103
+ let cacheForClass = __runjsDocCache.get(self);
2104
+ const cacheKey = String(locale || 'default');
2105
+ if (cacheForClass && cacheForClass.has(cacheKey)) return cacheForClass.get(cacheKey) as RunJSDocMeta;
2106
+ const chain: Function[] = [];
2107
+ let cur: any = self;
2108
+ while (cur && cur.prototype) {
2109
+ chain.unshift(cur);
2110
+ cur = Object.getPrototypeOf(cur);
2111
+ }
2112
+ let merged: RunJSDocMeta = {};
2113
+ for (const cls of chain) {
2114
+ merged = __runjsDeepMerge(merged, __runjsClassDefaultMeta.get(cls) || {});
2115
+ }
2116
+ if (locale) {
2117
+ for (const cls of chain) {
2118
+ const lmap = __runjsClassLocaleMeta.get(cls);
2119
+ if (lmap && lmap.has(locale)) {
2120
+ merged = __runjsDeepMerge(merged, lmap.get(locale));
2121
+ }
2122
+ }
2123
+ }
2124
+ if (!cacheForClass) {
2125
+ cacheForClass = new Map<string, RunJSDocMeta>();
2126
+ __runjsDocCache.set(self, cacheForClass);
2127
+ }
2128
+ cacheForClass.set(cacheKey, merged);
2129
+ return merged;
2130
+ }
2131
+ }