@logicflow/engine 0.0.11-beta.0 → 0.0.12-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/es/EventEmitter.d.ts +34 -4
- package/es/EventEmitter.js +70 -48
- package/es/EventEmitter.js.map +1 -0
- package/es/FlowModel.d.ts +75 -73
- package/es/FlowModel.js +130 -173
- package/es/FlowModel.js.map +1 -0
- package/es/Scheduler.d.ts +50 -34
- package/es/Scheduler.js +134 -209
- package/es/Scheduler.js.map +1 -0
- package/es/constant/{constant.js → index.js} +8 -7
- package/es/constant/index.js.map +1 -0
- package/es/constant/logCode.js +29 -0
- package/es/constant/logCode.js.map +1 -0
- package/es/index.d.ts +135 -38
- package/es/index.js +92 -144
- package/es/index.js.map +1 -0
- package/es/nodes/base.d.ts +108 -0
- package/es/nodes/base.js +151 -0
- package/es/nodes/base.js.map +1 -0
- package/es/nodes/index.d.ts +3 -0
- package/es/nodes/index.js +4 -0
- package/es/nodes/index.js.map +1 -0
- package/es/nodes/{StartNode.d.ts → start.d.ts} +3 -2
- package/es/nodes/start.js +11 -0
- package/es/nodes/start.js.map +1 -0
- package/es/nodes/{TaskNode.d.ts → task.d.ts} +3 -2
- package/es/nodes/task.js +11 -0
- package/es/nodes/task.js.map +1 -0
- package/es/platform/browser/browserVm.d.ts +1 -0
- package/es/platform/browser/browserVm.js +66 -0
- package/es/platform/browser/browserVm.js.map +1 -0
- package/es/platform/browser/index.d.ts +4 -0
- package/es/platform/browser/index.js +23 -0
- package/es/platform/browser/index.js.map +1 -0
- package/es/platform/index.d.ts +1 -0
- package/es/platform/index.js +2 -0
- package/es/platform/index.js.map +1 -0
- package/es/platform/node/index.d.ts +4 -0
- package/es/platform/node/index.js +23 -0
- package/es/platform/node/index.js.map +1 -0
- package/es/platform/node/nodeVm.d.ts +1 -0
- package/es/platform/node/nodeVm.js +9 -0
- package/es/platform/node/nodeVm.js.map +1 -0
- package/es/recorder/index.d.ts +36 -10
- package/es/recorder/index.js +82 -135
- package/es/recorder/index.js.map +1 -0
- package/es/utils/global.d.ts +5 -0
- package/es/utils/global.js +27 -0
- package/es/utils/global.js.map +1 -0
- package/es/utils/id.js +14 -0
- package/es/utils/id.js.map +1 -0
- package/es/utils/index.d.ts +4 -0
- package/es/utils/index.js +5 -0
- package/es/utils/index.js.map +1 -0
- package/es/{util → utils}/storage.js +17 -16
- package/es/utils/storage.js.map +1 -0
- package/lib/EventEmitter.d.ts +37 -0
- package/lib/EventEmitter.js +94 -0
- package/lib/EventEmitter.js.map +1 -0
- package/lib/FlowModel.d.ts +146 -0
- package/lib/FlowModel.js +236 -0
- package/lib/FlowModel.js.map +1 -0
- package/lib/Scheduler.d.ts +78 -0
- package/lib/Scheduler.js +179 -0
- package/lib/Scheduler.js.map +1 -0
- package/lib/constant/index.d.ts +16 -0
- package/{cjs/constant/constant.js → lib/constant/index.js} +4 -3
- package/lib/constant/index.js.map +1 -0
- package/lib/constant/logCode.d.ts +12 -0
- package/{cjs/constant/LogCode.js → lib/constant/logCode.js} +16 -13
- package/lib/constant/logCode.js.map +1 -0
- package/lib/index.d.ts +157 -0
- package/lib/index.js +159 -0
- package/lib/index.js.map +1 -0
- package/lib/nodes/base.d.ts +108 -0
- package/lib/nodes/base.js +154 -0
- package/lib/nodes/base.js.map +1 -0
- package/lib/nodes/index.d.ts +3 -0
- package/lib/nodes/index.js +7 -0
- package/lib/nodes/index.js.map +1 -0
- package/lib/nodes/start.d.ts +6 -0
- package/lib/nodes/start.js +15 -0
- package/lib/nodes/start.js.map +1 -0
- package/lib/nodes/task.d.ts +6 -0
- package/lib/nodes/task.js +15 -0
- package/lib/nodes/task.js.map +1 -0
- package/lib/platform/browser/browserVm.d.ts +1 -0
- package/lib/platform/browser/browserVm.js +70 -0
- package/lib/platform/browser/browserVm.js.map +1 -0
- package/lib/platform/browser/index.d.ts +4 -0
- package/lib/platform/browser/index.js +28 -0
- package/lib/platform/browser/index.js.map +1 -0
- package/lib/platform/index.d.ts +1 -0
- package/lib/platform/index.js +5 -0
- package/lib/platform/index.js.map +1 -0
- package/lib/platform/node/index.d.ts +4 -0
- package/lib/platform/node/index.js +28 -0
- package/lib/platform/node/index.js.map +1 -0
- package/lib/platform/node/nodeVm.d.ts +1 -0
- package/lib/platform/node/nodeVm.js +13 -0
- package/lib/platform/node/nodeVm.js.map +1 -0
- package/lib/recorder/index.d.ts +46 -0
- package/lib/recorder/index.js +117 -0
- package/lib/recorder/index.js.map +1 -0
- package/lib/utils/global.d.ts +5 -0
- package/lib/utils/global.js +31 -0
- package/lib/utils/global.js.map +1 -0
- package/lib/utils/id.d.ts +3 -0
- package/lib/utils/id.js +20 -0
- package/lib/utils/id.js.map +1 -0
- package/lib/utils/index.d.ts +4 -0
- package/lib/utils/index.js +9 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/storage.d.ts +7 -0
- package/{cjs/util → lib/utils}/storage.js +18 -17
- package/lib/utils/storage.js.map +1 -0
- package/package.json +31 -71
- package/src/EventEmitter.ts +103 -0
- package/src/FlowModel.ts +325 -0
- package/src/Scheduler.ts +244 -0
- package/src/constant/index.ts +23 -0
- package/src/constant/logCode.ts +34 -0
- package/src/index.ts +300 -0
- package/src/nodes/base.ts +236 -0
- package/src/nodes/index.ts +3 -0
- package/src/nodes/start.ts +8 -0
- package/src/nodes/task.ts +8 -0
- package/src/platform/browser/browserVm.ts +68 -0
- package/src/platform/browser/index.ts +28 -0
- package/src/platform/index.ts +1 -0
- package/src/platform/node/index.ts +28 -0
- package/src/platform/node/nodeVm.ts +12 -0
- package/src/recorder/index.ts +137 -0
- package/src/typings.d.ts +0 -0
- package/src/utils/global.ts +41 -0
- package/src/utils/id.ts +16 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/storage.ts +55 -0
- package/cjs/EventEmitter.js +0 -70
- package/cjs/FlowModel.js +0 -277
- package/cjs/Scheduler.js +0 -252
- package/cjs/expression/browserVm.js +0 -81
- package/cjs/expression/index.js +0 -57
- package/cjs/index.js +0 -210
- package/cjs/nodes/BaseNode.js +0 -252
- package/cjs/nodes/StartNode.js +0 -27
- package/cjs/nodes/TaskNode.js +0 -27
- package/cjs/recorder/index.js +0 -168
- package/cjs/util/ID.js +0 -16
- package/cjs/util/global.js +0 -32
- package/es/constant/LogCode.js +0 -28
- package/es/expression/browserVm.d.ts +0 -4
- package/es/expression/browserVm.js +0 -76
- package/es/expression/index.d.ts +0 -2
- package/es/expression/index.js +0 -54
- package/es/nodes/BaseNode.d.ts +0 -110
- package/es/nodes/BaseNode.js +0 -250
- package/es/nodes/StartNode.js +0 -25
- package/es/nodes/TaskNode.js +0 -25
- package/es/util/ID.js +0 -13
- package/es/util/global.d.ts +0 -5
- package/es/util/global.js +0 -26
- package/lib/main.js +0 -1
- /package/es/constant/{constant.d.ts → index.d.ts} +0 -0
- /package/es/constant/{LogCode.d.ts → logCode.d.ts} +0 -0
- /package/es/{util/ID.d.ts → utils/id.d.ts} +0 -0
- /package/es/{util → utils}/storage.d.ts +0 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// import { LogicFlow } from '@logicflow/core';
|
|
2
|
+
import { BaseNode, StartNode, TaskNode } from './nodes'
|
|
3
|
+
import { FlowModel } from './FlowModel'
|
|
4
|
+
import { Recorder } from './recorder'
|
|
5
|
+
import { createEngineId } from './utils'
|
|
6
|
+
|
|
7
|
+
export class Engine {
|
|
8
|
+
readonly instanceId: string
|
|
9
|
+
graphData?: Engine.GraphConfigData
|
|
10
|
+
|
|
11
|
+
flowModel?: FlowModel
|
|
12
|
+
recorder?: Recorder
|
|
13
|
+
context?: Record<string, unknown>
|
|
14
|
+
nodeModelMap: Map<string, BaseNode.NodeConstructor>
|
|
15
|
+
|
|
16
|
+
constructor(options?: Engine.Options) {
|
|
17
|
+
this.nodeModelMap = new Map()
|
|
18
|
+
this.instanceId = createEngineId()
|
|
19
|
+
if (options?.debug) {
|
|
20
|
+
this.recorder = new Recorder({
|
|
21
|
+
instanceId: this.instanceId,
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
// 默认注册节点 register default nodes
|
|
25
|
+
this.register({
|
|
26
|
+
type: StartNode.nodeTypeName,
|
|
27
|
+
model: StartNode,
|
|
28
|
+
})
|
|
29
|
+
this.register({
|
|
30
|
+
type: TaskNode.nodeTypeName,
|
|
31
|
+
model: TaskNode,
|
|
32
|
+
})
|
|
33
|
+
this.context = options?.context || {}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 注册节点
|
|
38
|
+
* @param nodeConfig { type: 'custom-node', model: NodeClass }
|
|
39
|
+
*/
|
|
40
|
+
register(nodeConfig: Engine.NodeConfig) {
|
|
41
|
+
this.nodeModelMap.set(nodeConfig.type, nodeConfig.model)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 自定义执行记录的存储,默认浏览器使用 sessionStorage, nodejs 使用内存存储
|
|
46
|
+
* 注意:由于执行记录不全会主动删除,所以需要自行清理。
|
|
47
|
+
* nodejs 环境建议自定义为持久化存储。
|
|
48
|
+
* engine.setCustomRecorder({{
|
|
49
|
+
* async addActionRecord(task) {}
|
|
50
|
+
* async getTask(actionId) {}
|
|
51
|
+
* async getExecutionTasks(executionId) {}
|
|
52
|
+
* clear(instanceId) {}
|
|
53
|
+
* }}
|
|
54
|
+
* @param recorder
|
|
55
|
+
*/
|
|
56
|
+
setCustomRecorder(recorder: Recorder) {
|
|
57
|
+
this.recorder = recorder
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 加载流程图数据
|
|
62
|
+
*/
|
|
63
|
+
load({
|
|
64
|
+
graphData,
|
|
65
|
+
startNodeType = 'StartNode',
|
|
66
|
+
globalData = {},
|
|
67
|
+
}: Engine.LoadGraphParam): FlowModel {
|
|
68
|
+
this.graphData = graphData
|
|
69
|
+
const flowModel = new FlowModel({
|
|
70
|
+
nodeModelMap: this.nodeModelMap,
|
|
71
|
+
recorder: this.recorder,
|
|
72
|
+
context: this.context,
|
|
73
|
+
globalData,
|
|
74
|
+
startNodeType,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
flowModel.load(graphData)
|
|
78
|
+
this.flowModel = flowModel
|
|
79
|
+
return flowModel
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 执行流程,允许多次调用
|
|
84
|
+
*/
|
|
85
|
+
async execute(
|
|
86
|
+
param?: Partial<Engine.ActionParam>,
|
|
87
|
+
): Promise<Engine.NextActionParam> {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
let execParam = param
|
|
90
|
+
if (!param) {
|
|
91
|
+
execParam = {}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.flowModel?.execute({
|
|
95
|
+
...execParam,
|
|
96
|
+
callback: (result) => {
|
|
97
|
+
resolve(result)
|
|
98
|
+
},
|
|
99
|
+
onError: (error) => {
|
|
100
|
+
reject(error)
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 中断流程恢复
|
|
108
|
+
* @param resumeParam
|
|
109
|
+
* @returns
|
|
110
|
+
*/
|
|
111
|
+
async resume(
|
|
112
|
+
resumeParam: Engine.ResumeParam,
|
|
113
|
+
): Promise<Engine.NextActionParam | undefined> {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
this.flowModel?.resume({
|
|
116
|
+
...resumeParam,
|
|
117
|
+
callback: (result) => {
|
|
118
|
+
resolve(result)
|
|
119
|
+
},
|
|
120
|
+
onError: (error) => {
|
|
121
|
+
reject(error)
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async getExecutionList() {
|
|
128
|
+
return await this.recorder?.getExecutionList()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 获取执行任务记录
|
|
133
|
+
* @param executionId
|
|
134
|
+
* @returns
|
|
135
|
+
*/
|
|
136
|
+
async getExecutionRecord(
|
|
137
|
+
executionId: Engine.Key,
|
|
138
|
+
): Promise<Recorder.Info[] | null> {
|
|
139
|
+
const actions = await this.recorder?.getExecutionActions(executionId)
|
|
140
|
+
|
|
141
|
+
if (!actions) {
|
|
142
|
+
return null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// DONE: 确认 records 的类型
|
|
146
|
+
const records: Promise<Recorder.Info>[] = []
|
|
147
|
+
for (let i = 0; i < actions?.length; i++) {
|
|
148
|
+
const action = actions[i]
|
|
149
|
+
if (this.recorder) {
|
|
150
|
+
records.push(this.recorder?.getActionRecord(action))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return Promise.all(records)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
destroy() {
|
|
158
|
+
this.recorder?.clear()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getGlobalData() {
|
|
162
|
+
return this.flowModel?.globalData
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
setGlobalData(data: Record<string, unknown>) {
|
|
166
|
+
if (this.flowModel) {
|
|
167
|
+
this.flowModel.globalData = data
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
updateGlobalData(data: Record<string, unknown>) {
|
|
172
|
+
if (this.flowModel) {
|
|
173
|
+
Object.assign(this.flowModel.globalData, data)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export namespace Engine {
|
|
179
|
+
export type Point = {
|
|
180
|
+
id?: string
|
|
181
|
+
x: number
|
|
182
|
+
y: number
|
|
183
|
+
[key: string]: unknown
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export type TextConfig = {
|
|
187
|
+
value: string
|
|
188
|
+
} & Point
|
|
189
|
+
|
|
190
|
+
export type NodeData = {
|
|
191
|
+
id: string
|
|
192
|
+
type: string
|
|
193
|
+
x?: number
|
|
194
|
+
y?: number
|
|
195
|
+
text?: TextConfig | string
|
|
196
|
+
zIndex?: number
|
|
197
|
+
properties?: Record<string, unknown>
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type EdgeData = {
|
|
201
|
+
id: string
|
|
202
|
+
/**
|
|
203
|
+
* 边的类型,不传默认为lf.setDefaultEdgeType(type)传入的类型。
|
|
204
|
+
* LogicFlow内部默认为polyline
|
|
205
|
+
*/
|
|
206
|
+
type?: string
|
|
207
|
+
sourceNodeId: string
|
|
208
|
+
sourceAnchorId?: string
|
|
209
|
+
targetNodeId: string
|
|
210
|
+
targetAnchorId?: string
|
|
211
|
+
startPoint?: {
|
|
212
|
+
x: number
|
|
213
|
+
y: number
|
|
214
|
+
}
|
|
215
|
+
endPoint?: {
|
|
216
|
+
x: number
|
|
217
|
+
y: number
|
|
218
|
+
}
|
|
219
|
+
text?:
|
|
220
|
+
| {
|
|
221
|
+
x: number
|
|
222
|
+
y: number
|
|
223
|
+
value: string
|
|
224
|
+
}
|
|
225
|
+
| string
|
|
226
|
+
pointsList?: Point[]
|
|
227
|
+
zIndex?: number
|
|
228
|
+
properties?: Record<string, unknown>
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export type GraphConfigData = {
|
|
232
|
+
nodes: NodeData[]
|
|
233
|
+
edges: EdgeData[]
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export type LoadGraphParam = {
|
|
237
|
+
graphData: GraphConfigData
|
|
238
|
+
startNodeType?: string
|
|
239
|
+
globalData?: Record<string, unknown>
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export type Options = {
|
|
243
|
+
context?: Record<string, unknown>
|
|
244
|
+
debug?: boolean
|
|
245
|
+
}
|
|
246
|
+
export type Key = string | number
|
|
247
|
+
export type NodeConfig = {
|
|
248
|
+
type: string
|
|
249
|
+
model: any // TODO: NodeModel 可能有多个,类型该如何定义呢???
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export type NodeParam = {
|
|
253
|
+
executionId: Key
|
|
254
|
+
nodeId: Key
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export type CommonActionInfo = {
|
|
258
|
+
actionId: Key
|
|
259
|
+
} & NodeParam
|
|
260
|
+
|
|
261
|
+
export type ActionParam = CommonActionInfo
|
|
262
|
+
|
|
263
|
+
export type ResumeParam = {
|
|
264
|
+
data?: Record<string, unknown>
|
|
265
|
+
} & CommonActionInfo
|
|
266
|
+
|
|
267
|
+
export type ExecParam = {
|
|
268
|
+
next: (data: NextActionParam) => void
|
|
269
|
+
} & ActionParam
|
|
270
|
+
|
|
271
|
+
export type ExecResumeParam = {
|
|
272
|
+
next: (data: NextActionParam) => void
|
|
273
|
+
} & ResumeParam
|
|
274
|
+
|
|
275
|
+
export type ActionStatus = 'success' | 'error' | 'interrupted' | '' // ??? Question: '' 状态是什么状态
|
|
276
|
+
|
|
277
|
+
export type NextActionParam = {
|
|
278
|
+
executionId: Key
|
|
279
|
+
nodeId: Key
|
|
280
|
+
actionId: Key
|
|
281
|
+
nodeType: string
|
|
282
|
+
outgoing: BaseNode.OutgoingConfig[]
|
|
283
|
+
properties?: Record<string, unknown>
|
|
284
|
+
detail?: Record<string, unknown>
|
|
285
|
+
status?: ActionStatus
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export type ActionResult = NextActionParam
|
|
289
|
+
|
|
290
|
+
export type NodeExecResult = {
|
|
291
|
+
nodeType: string
|
|
292
|
+
properties?: Record<string, unknown>
|
|
293
|
+
} & CommonActionInfo &
|
|
294
|
+
ActionResult
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export * from './constant'
|
|
298
|
+
export { BaseNode, StartNode, TaskNode, Recorder }
|
|
299
|
+
|
|
300
|
+
export default Engine
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Engine } from '..'
|
|
2
|
+
import { ActionStatus } from '../constant'
|
|
3
|
+
import { getExpressionResult } from '../platform'
|
|
4
|
+
|
|
5
|
+
export interface IBaseNodeProps {
|
|
6
|
+
nodeConfig: BaseNode.NodeConfig
|
|
7
|
+
context: Record<string, any>
|
|
8
|
+
globalData: Record<string, unknown>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class BaseNode implements BaseNode.Base {
|
|
12
|
+
readonly baseType: string
|
|
13
|
+
static nodeTypeName = 'BaseNode'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 节点的入边
|
|
17
|
+
*/
|
|
18
|
+
incoming: BaseNode.IncomingConfig[]
|
|
19
|
+
/**
|
|
20
|
+
* 节点的出边
|
|
21
|
+
*/
|
|
22
|
+
outgoing: BaseNode.OutgoingConfig[]
|
|
23
|
+
/**
|
|
24
|
+
* 节点的属性
|
|
25
|
+
*/
|
|
26
|
+
properties?: Record<string, unknown>
|
|
27
|
+
nodeId: Engine.Key
|
|
28
|
+
type: string
|
|
29
|
+
/**
|
|
30
|
+
* 节点的上下文,是调用流程时传入的上下文
|
|
31
|
+
*/
|
|
32
|
+
context: Record<string, any>
|
|
33
|
+
/**
|
|
34
|
+
* 节点的全局数据,是调用流程时传入的全局数据
|
|
35
|
+
* 在计算表达式时,即基于全局数据进行计算
|
|
36
|
+
*/
|
|
37
|
+
globalData: Record<string, unknown>
|
|
38
|
+
|
|
39
|
+
constructor({ nodeConfig, context, globalData }: IBaseNodeProps) {
|
|
40
|
+
const { outgoing, incoming, id, type, properties } = nodeConfig
|
|
41
|
+
this.baseType = 'base'
|
|
42
|
+
this.outgoing = outgoing
|
|
43
|
+
this.incoming = incoming
|
|
44
|
+
this.nodeId = id
|
|
45
|
+
this.type = type
|
|
46
|
+
this.properties = properties
|
|
47
|
+
|
|
48
|
+
this.context = context
|
|
49
|
+
this.globalData = globalData
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 节点的执行逻辑
|
|
54
|
+
* @overridable 可以自定义节点重写此方法
|
|
55
|
+
* @param param.executionId 流程执行记录 ID
|
|
56
|
+
* @param param.actionId 此节点执行记录 ID
|
|
57
|
+
* @param param.nodeId 节点 ID
|
|
58
|
+
* @return 返回下一步的执行参数
|
|
59
|
+
* 当不返回时,表示此节点执行成功,流程会继续执行下一步。
|
|
60
|
+
* 当返回时,返回格式为
|
|
61
|
+
*/
|
|
62
|
+
public async action(
|
|
63
|
+
param?: Engine.ActionParam,
|
|
64
|
+
): Promise<BaseNode.ActionResult | undefined> {
|
|
65
|
+
console.log('action param --->>>', param)
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 节点重新恢复执行的逻辑
|
|
71
|
+
* @overridable 可以自定义节点重写此方法
|
|
72
|
+
* @param params.executionId 流程执行记录 ID
|
|
73
|
+
* @param params.actionId 此节点执行记录 ID
|
|
74
|
+
* @param params.nodeId 节点 ID
|
|
75
|
+
*/
|
|
76
|
+
public async onResume(params: Engine.ResumeParam): Promise<void> {
|
|
77
|
+
console.log('onResume params --->>>', params)
|
|
78
|
+
return undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 判断该节点是否满足条件
|
|
83
|
+
*/
|
|
84
|
+
private async isPass(properties?: Record<string, unknown>): Promise<boolean> {
|
|
85
|
+
if (!properties) return true
|
|
86
|
+
|
|
87
|
+
const { conditionExpression } = properties
|
|
88
|
+
if (!conditionExpression) return true
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
// bug:uuid 创建的 NodeId 为 xxxx-xxxx-xxxx-zzzz 格式,eval 执行时会将 - 识别为数学减号,导致执行报错
|
|
92
|
+
// 解决方案: 赋值变量直接命名为 isPassResult, 因为每次执行 getExpressionResult 时,都会重新射程一个 context
|
|
93
|
+
return await getExpressionResult(
|
|
94
|
+
`
|
|
95
|
+
const isPassResult = (${conditionExpression})
|
|
96
|
+
return isPassResult
|
|
97
|
+
`,
|
|
98
|
+
{
|
|
99
|
+
...this.globalData,
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 获取当前节点执行的下一个节点
|
|
109
|
+
*/
|
|
110
|
+
private async getOutgoing(): Promise<BaseNode.OutgoingConfig[]> {
|
|
111
|
+
const outgoing: BaseNode.OutgoingConfig[] = []
|
|
112
|
+
const expressions: any = []
|
|
113
|
+
for (const item of this.outgoing) {
|
|
114
|
+
const { properties } = item
|
|
115
|
+
expressions.push(this.isPass(properties))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const result = await Promise.all(expressions)
|
|
119
|
+
result.forEach((item, index) => {
|
|
120
|
+
const out = this.outgoing[index]
|
|
121
|
+
out.result = item
|
|
122
|
+
outgoing.push(out)
|
|
123
|
+
})
|
|
124
|
+
return outgoing
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 节点的每一次执行都会生成一个唯一的 actionId
|
|
129
|
+
*/
|
|
130
|
+
public async execute(
|
|
131
|
+
params: Engine.ExecParam,
|
|
132
|
+
): Promise<Engine.NextActionParam> {
|
|
133
|
+
const { executionId, actionId } = params
|
|
134
|
+
const res = await this.action({
|
|
135
|
+
nodeId: this.nodeId,
|
|
136
|
+
executionId,
|
|
137
|
+
actionId,
|
|
138
|
+
})
|
|
139
|
+
const status = res ? res.status : 'success'
|
|
140
|
+
|
|
141
|
+
if (status === ActionStatus.SUCCESS) {
|
|
142
|
+
const outgoing = await this.getOutgoing()
|
|
143
|
+
const detail = res ? res.detail : {}
|
|
144
|
+
params.next({
|
|
145
|
+
status: ActionStatus.SUCCESS,
|
|
146
|
+
detail,
|
|
147
|
+
nodeId: this.nodeId,
|
|
148
|
+
nodeType: this.type,
|
|
149
|
+
properties: this.properties,
|
|
150
|
+
executionId,
|
|
151
|
+
actionId,
|
|
152
|
+
outgoing,
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
status,
|
|
158
|
+
detail: res?.detail,
|
|
159
|
+
executionId,
|
|
160
|
+
actionId,
|
|
161
|
+
nodeId: this.nodeId,
|
|
162
|
+
nodeType: this.type,
|
|
163
|
+
properties: this.properties,
|
|
164
|
+
outgoing: [],
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public async resume(params: Engine.ExecResumeParam): Promise<undefined> {
|
|
169
|
+
const outgoing = await this.getOutgoing()
|
|
170
|
+
await this.onResume({
|
|
171
|
+
executionId: params.executionId,
|
|
172
|
+
actionId: params.actionId,
|
|
173
|
+
nodeId: params.nodeId,
|
|
174
|
+
data: params.data,
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
params.next({
|
|
178
|
+
executionId: params.executionId,
|
|
179
|
+
actionId: params.actionId,
|
|
180
|
+
nodeId: this.nodeId,
|
|
181
|
+
nodeType: this.type,
|
|
182
|
+
properties: this.properties,
|
|
183
|
+
outgoing,
|
|
184
|
+
status: ActionStatus.SUCCESS,
|
|
185
|
+
})
|
|
186
|
+
return undefined
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export namespace BaseNode {
|
|
191
|
+
export interface Base {
|
|
192
|
+
incoming: IncomingConfig[]
|
|
193
|
+
outgoing: OutgoingConfig[]
|
|
194
|
+
properties?: Record<string, unknown>
|
|
195
|
+
nodeId: Engine.Key
|
|
196
|
+
type: string
|
|
197
|
+
readonly baseType: string
|
|
198
|
+
execute(actionParam: Engine.ActionParam): Promise<Engine.NextActionParam>
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type IncomingConfig = {
|
|
202
|
+
id: Engine.Key
|
|
203
|
+
source: string
|
|
204
|
+
properties?: Record<string, unknown>
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export type OutgoingConfig = {
|
|
208
|
+
id: Engine.Key
|
|
209
|
+
target: string
|
|
210
|
+
properties?: Record<string, unknown>
|
|
211
|
+
result?: string | boolean
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export type NodeConfig = {
|
|
215
|
+
id: Engine.Key
|
|
216
|
+
type: string
|
|
217
|
+
properties?: Record<string, unknown>
|
|
218
|
+
incoming: IncomingConfig[]
|
|
219
|
+
outgoing: OutgoingConfig[]
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type NodeConstructor = {
|
|
223
|
+
new (config: {
|
|
224
|
+
nodeConfig: NodeConfig
|
|
225
|
+
context: Record<string, any>
|
|
226
|
+
globalData: Record<string, unknown>
|
|
227
|
+
}): BaseNode
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export type ActionResult = {
|
|
231
|
+
status: ActionStatus
|
|
232
|
+
detail?: Record<string, unknown>
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default BaseNode
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// import {
|
|
2
|
+
// ErrorCode,
|
|
3
|
+
// getErrorMsg,
|
|
4
|
+
// getWarningMsg,
|
|
5
|
+
// WarningCode,
|
|
6
|
+
// } from '../../constant/logCode'
|
|
7
|
+
//
|
|
8
|
+
// const createContext = (globalData: Record<string, unknown>) => {
|
|
9
|
+
// const iframe = document.createElement('iframe')
|
|
10
|
+
// iframe.style.display = 'none'
|
|
11
|
+
// if (!document || !document.body) {
|
|
12
|
+
// console.error(getErrorMsg(ErrorCode.NO_DOCUMENT_BODY))
|
|
13
|
+
// }
|
|
14
|
+
// document.body.appendChild(iframe)
|
|
15
|
+
// const iframeWindow = iframe.contentWindow
|
|
16
|
+
// if (iframeWindow) {
|
|
17
|
+
// // TODO: 确认是否需要该代码,parent 置为空是为了解决什么问题
|
|
18
|
+
// // @ts-ignore
|
|
19
|
+
// ;(iframeWindow!.parent as any) = null
|
|
20
|
+
// Object.keys(globalData).forEach((key) => {
|
|
21
|
+
// iframeWindow[key] = globalData[key]
|
|
22
|
+
// })
|
|
23
|
+
// }
|
|
24
|
+
// return iframeWindow
|
|
25
|
+
// }
|
|
26
|
+
//
|
|
27
|
+
// const runInContext = (code: string, context: any) => {
|
|
28
|
+
// try {
|
|
29
|
+
// const iframeEval = context.eval
|
|
30
|
+
// iframeEval.call(context, code)
|
|
31
|
+
// console.log('context --->>> ===>>>', context)
|
|
32
|
+
// if (context.frameElement) {
|
|
33
|
+
// document.body.removeChild(context.frameElement)
|
|
34
|
+
// }
|
|
35
|
+
// } catch (e) {
|
|
36
|
+
// console.warn(getWarningMsg(WarningCode.EXPRESSION_EXEC_ERROR), {
|
|
37
|
+
// code,
|
|
38
|
+
// context,
|
|
39
|
+
// e,
|
|
40
|
+
// })
|
|
41
|
+
// }
|
|
42
|
+
// }
|
|
43
|
+
//
|
|
44
|
+
// const runInBrowserContext = async (
|
|
45
|
+
// code: string,
|
|
46
|
+
// globalData = {},
|
|
47
|
+
// ): Promise<any> => {
|
|
48
|
+
// const context = createContext(globalData)
|
|
49
|
+
// runInContext(code, context)
|
|
50
|
+
// return context
|
|
51
|
+
// }
|
|
52
|
+
//
|
|
53
|
+
// export { createContext, runInContext, runInBrowserContext }
|
|
54
|
+
|
|
55
|
+
import Sandbox from '@nyariv/sandboxjs'
|
|
56
|
+
|
|
57
|
+
export const runInBrowserContext = async (
|
|
58
|
+
code: string,
|
|
59
|
+
globalData = {},
|
|
60
|
+
): Promise<any> => {
|
|
61
|
+
try {
|
|
62
|
+
const sandbox = new Sandbox()
|
|
63
|
+
const exec = sandbox.compile(code)
|
|
64
|
+
return await exec(globalData).run()
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.log('runInBrowserContext error --->>>', e)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { runInBrowserContext } from './browserVm'
|
|
2
|
+
|
|
3
|
+
const isInBrowser = typeof window === 'object' && window.window === window
|
|
4
|
+
|
|
5
|
+
const globalScope: any = (() => {
|
|
6
|
+
if (isInBrowser) {
|
|
7
|
+
return window
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (typeof self === 'object' && self.self === self) {
|
|
11
|
+
return self
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof globalThis === 'object') {
|
|
15
|
+
return globalThis
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
eval: () => undefined,
|
|
20
|
+
} as Record<string, unknown>
|
|
21
|
+
})()
|
|
22
|
+
|
|
23
|
+
const getExpressionResult = async (code: string, context: any) => {
|
|
24
|
+
const r = await runInBrowserContext(code, context)
|
|
25
|
+
return r
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { isInBrowser, globalScope, getExpressionResult }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './node'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { runInNodeContext } from './nodeVm'
|
|
2
|
+
|
|
3
|
+
const isInNodeJS = typeof global === 'object' && global.global === global
|
|
4
|
+
|
|
5
|
+
const globalScope: any = (() => {
|
|
6
|
+
if (typeof self === 'object' && self.self === self) {
|
|
7
|
+
return self
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (isInNodeJS) {
|
|
11
|
+
return global
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof globalThis === 'object') {
|
|
15
|
+
return globalThis
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
eval: () => undefined,
|
|
20
|
+
} as Record<string, unknown>
|
|
21
|
+
})()
|
|
22
|
+
|
|
23
|
+
const getExpressionResult = async (code: string, context: any) => {
|
|
24
|
+
const r = await runInNodeContext(code, context)
|
|
25
|
+
return r
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { isInNodeJS, globalScope, getExpressionResult }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import vm from 'node:vm'
|
|
2
|
+
// const vm = require('node:vm');
|
|
3
|
+
|
|
4
|
+
export const runInNodeContext = async (
|
|
5
|
+
code: string,
|
|
6
|
+
globalData: Record<string, unknown> = {},
|
|
7
|
+
): Promise<any> => {
|
|
8
|
+
const context = vm.createContext(globalData)
|
|
9
|
+
vm.runInContext(code, context)
|
|
10
|
+
|
|
11
|
+
return context
|
|
12
|
+
}
|