@arronqzy/blueprint-dsl 0.0.1 → 1.0.3
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/package.json +2 -2
- package/readme.md +54 -12
- package/src/fetch-config.ts +15 -0
- package/src/runtime/graph-runner.ts +72 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/blueprint-dsl",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Abuilder blueprint DSL runtime",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"eslint": "^8.57.0",
|
|
18
18
|
"typescript": "^5.5.4",
|
|
19
19
|
"@arronqzy/eslint-config": "0.0.0",
|
|
20
|
-
"@arronqzy/typescript-config": "
|
|
20
|
+
"@arronqzy/typescript-config": "1.0.0"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|
package/readme.md
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
+
# @arronqzy/blueprint-dsl
|
|
2
|
+
|
|
3
|
+
Abuilder 蓝图的 **DSL 与运行时** 包,定义节点类型、行为注册与图执行逻辑,不依赖 React。
|
|
4
|
+
|
|
5
|
+
## 功能概览
|
|
6
|
+
|
|
7
|
+
- **节点定义**:Flow / Data 端口、节点元数据与默认行为
|
|
8
|
+
- **行为注册表**:`BehaviorRegistry` 注册 JS / 内置行为
|
|
9
|
+
- **执行器**:按 Token 驱动节点执行、Scope 传递
|
|
10
|
+
- **图运行器**:整图调度、循环检测、执行轨迹
|
|
11
|
+
- **内置节点**:逻辑判断、HTTP 请求、JSON 处理、时钟定时、Swagger 等
|
|
12
|
+
- **时钟调度**:多 tick 输出、中止与活跃状态订阅
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @arronqzy/blueprint-dsl rxjs
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 快速开始
|
|
21
|
+
|
|
1
22
|
```ts
|
|
23
|
+
import {
|
|
24
|
+
BehaviorRegistry,
|
|
25
|
+
Executor,
|
|
26
|
+
type NodeDefinition,
|
|
27
|
+
} from "@arronqzy/blueprint-dsl";
|
|
28
|
+
|
|
2
29
|
const behaviors = new BehaviorRegistry();
|
|
3
30
|
|
|
4
31
|
behaviors.registerJS("print-js", async ({ io }) => {
|
|
@@ -6,27 +33,42 @@ behaviors.registerJS("print-js", async ({ io }) => {
|
|
|
6
33
|
io.emitFlow("out");
|
|
7
34
|
});
|
|
8
35
|
|
|
9
|
-
behaviors.registerJS("sleep-js", async ({ io }) => {
|
|
10
|
-
const ms = await io.getInput("ms");
|
|
11
|
-
await new Promise((r) => setTimeout(r, ms));
|
|
12
|
-
io.emitFlow("out");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
|
|
16
36
|
const PrintNode: NodeDefinition = {
|
|
17
37
|
type: "Print",
|
|
18
38
|
inputs: [{ name: "msg", kind: "data" }],
|
|
19
39
|
outputs: [{ name: "out", kind: "flow" }],
|
|
20
|
-
behavior: { kind: "js", ref: "print-js" }
|
|
21
|
-
}
|
|
40
|
+
behavior: { kind: "js", ref: "print-js" },
|
|
41
|
+
};
|
|
22
42
|
|
|
43
|
+
const executor = new Executor(behaviors);
|
|
23
44
|
|
|
24
45
|
await executor.executeToken({
|
|
25
46
|
tokenId: "t1",
|
|
26
47
|
nodeId: "n1",
|
|
27
48
|
nodeType: "Print",
|
|
28
49
|
inPort: "in",
|
|
29
|
-
scope: { vars: new Map() }
|
|
30
|
-
})
|
|
31
|
-
|
|
50
|
+
scope: { vars: new Map() },
|
|
51
|
+
});
|
|
32
52
|
```
|
|
53
|
+
|
|
54
|
+
## 核心模块
|
|
55
|
+
|
|
56
|
+
| 路径 | 说明 |
|
|
57
|
+
|------|------|
|
|
58
|
+
| `core/behavior.js` | 行为接口与 IO |
|
|
59
|
+
| `core/behavior-registry.js` | 行为注册 |
|
|
60
|
+
| `core/executor.js` | 单节点执行 |
|
|
61
|
+
| `runtime/graph-runner.js` | 整图运行 |
|
|
62
|
+
| `runtime/execution-trace.js` | 执行轨迹 |
|
|
63
|
+
| `runtime/clock-scheduler.js` | 时钟节点调度 |
|
|
64
|
+
| `nodes/definitions.js` | 内置节点定义 |
|
|
65
|
+
| `fetch-config.js` / `logic-config.js` 等 | 各类型节点配置结构 |
|
|
66
|
+
|
|
67
|
+
## 与上层包的关系
|
|
68
|
+
|
|
69
|
+
- **`@arronqzy/react-blueprint`**:React Flow 画布、调试 UI、蓝图库
|
|
70
|
+
- **`@arronqzy/react-view`**:蓝图执行结果通过 Scope 驱动视图节点
|
|
71
|
+
|
|
72
|
+
## 许可证
|
|
73
|
+
|
|
74
|
+
MIT
|
package/src/fetch-config.ts
CHANGED
|
@@ -67,6 +67,21 @@ export const DEFAULT_FETCH_REQUEST_CONFIG: FetchRequestConfig = {
|
|
|
67
67
|
timeoutMs: 30000,
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
/** 合并默认项与节点上保存的 fetch 配置,供运行时发起请求 */
|
|
71
|
+
export function normalizeFetchRequestConfig(
|
|
72
|
+
config?: FetchRequestConfig
|
|
73
|
+
): FetchRequestConfig {
|
|
74
|
+
return {
|
|
75
|
+
...DEFAULT_FETCH_REQUEST_CONFIG,
|
|
76
|
+
...config,
|
|
77
|
+
headers: {
|
|
78
|
+
...DEFAULT_FETCH_REQUEST_CONFIG.headers,
|
|
79
|
+
...config?.headers,
|
|
80
|
+
},
|
|
81
|
+
swaggerEndpoints: config?.swaggerEndpoints,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
70
85
|
export type FetchResultValue = {
|
|
71
86
|
status: number;
|
|
72
87
|
statusText: string;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { FetchRequestConfig } from "../fetch-config.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
executeFetch,
|
|
4
|
+
normalizeFetchRequestConfig,
|
|
5
|
+
resolveFetchRequestUrl,
|
|
6
|
+
} from "../fetch-config.js";
|
|
3
7
|
import type { JsonNodeConfig } from "../json-config.js";
|
|
4
8
|
import {
|
|
5
9
|
DEFAULT_JSON_NODE_CONFIG,
|
|
@@ -275,6 +279,7 @@ export class BlueprintGraphRunner {
|
|
|
275
279
|
return;
|
|
276
280
|
}
|
|
277
281
|
const token = queue.shift()!;
|
|
282
|
+
if (!this.syncTokenFromGraph(token)) continue;
|
|
278
283
|
try {
|
|
279
284
|
await executor.executeToken(token);
|
|
280
285
|
} catch (error) {
|
|
@@ -357,6 +362,7 @@ export class BlueprintGraphRunner {
|
|
|
357
362
|
/** 调试过程中同步最新蓝图拓扑与节点配置 */
|
|
358
363
|
updateGraph(graph: RunnableGraph): void {
|
|
359
364
|
this.graph = graph;
|
|
365
|
+
this.syncDebugQueueWithLatestGraph();
|
|
360
366
|
}
|
|
361
367
|
|
|
362
368
|
/**
|
|
@@ -367,14 +373,7 @@ export class BlueprintGraphRunner {
|
|
|
367
373
|
if (!this.debugQueue) return;
|
|
368
374
|
|
|
369
375
|
if (this.traceEntries.length === 0) {
|
|
370
|
-
|
|
371
|
-
if (!head) return;
|
|
372
|
-
const node = this.graph.nodes.find((n) => n.id === head.nodeId);
|
|
373
|
-
if (!node) {
|
|
374
|
-
this.debugQueue = [];
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
head.nodeType = node.nodeType;
|
|
376
|
+
this.syncDebugQueueWithLatestGraph();
|
|
378
377
|
return;
|
|
379
378
|
}
|
|
380
379
|
|
|
@@ -423,7 +422,9 @@ export class BlueprintGraphRunner {
|
|
|
423
422
|
});
|
|
424
423
|
}
|
|
425
424
|
}
|
|
426
|
-
this.debugQueue
|
|
425
|
+
if (newQueue.length > 0 || this.debugQueue.length === 0) {
|
|
426
|
+
this.debugQueue = newQueue;
|
|
427
|
+
}
|
|
427
428
|
}
|
|
428
429
|
|
|
429
430
|
canDebugStepBack(): boolean {
|
|
@@ -479,7 +480,9 @@ export class BlueprintGraphRunner {
|
|
|
479
480
|
|
|
480
481
|
this.applyLifecycleScopeForNode(lifecycleNodeId);
|
|
481
482
|
|
|
482
|
-
this.debugExecutor = this.createExecutor(this.debugQueue
|
|
483
|
+
this.debugExecutor = this.createExecutor(this.debugQueue, {
|
|
484
|
+
emitToActiveDebugQueue: true,
|
|
485
|
+
});
|
|
483
486
|
this.debugHistory = [this.captureDebugSnapshot()];
|
|
484
487
|
}
|
|
485
488
|
|
|
@@ -542,6 +545,13 @@ export class BlueprintGraphRunner {
|
|
|
542
545
|
try {
|
|
543
546
|
this.pushDebugSnapshot();
|
|
544
547
|
const token = this.debugQueue.shift()!;
|
|
548
|
+
if (!this.syncTokenFromGraph(token)) {
|
|
549
|
+
this.pushDebugSnapshot();
|
|
550
|
+
return {
|
|
551
|
+
done: this.debugQueue.length === 0,
|
|
552
|
+
haltedByFalseSignal: false,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
545
555
|
|
|
546
556
|
if (token.nodeType === CLOCK_NODE_TYPE) {
|
|
547
557
|
const node = this.requireNode(token.nodeId);
|
|
@@ -721,6 +731,12 @@ export class BlueprintGraphRunner {
|
|
|
721
731
|
this.debugExecutor ??
|
|
722
732
|
this.createExecutor(this.debugQueue ?? []);
|
|
723
733
|
|
|
734
|
+
if (!this.syncTokenFromGraph(token)) {
|
|
735
|
+
return this.appendDebugTraceEntry(token, nodeLabelById, startedAt, {
|
|
736
|
+
error: "节点已从蓝图中移除",
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
|
|
724
740
|
try {
|
|
725
741
|
await runExecutor.executeToken(token);
|
|
726
742
|
} catch (err) {
|
|
@@ -941,6 +957,7 @@ export class BlueprintGraphRunner {
|
|
|
941
957
|
resolveLibraryBlueprint: runner.resolveLibraryBlueprint,
|
|
942
958
|
rootLibraryBlueprintId: libraryId,
|
|
943
959
|
resolveBlueprintName: runner.resolveBlueprintName,
|
|
960
|
+
onViewScopeUpdate: runner.onViewScopeUpdate,
|
|
944
961
|
});
|
|
945
962
|
await subRunner.emitBlueprintActivated(input.value, nestedScope);
|
|
946
963
|
const nestedOutputs = await subRunner.runFromFlowEntries(nestedScope, {
|
|
@@ -975,22 +992,32 @@ export class BlueprintGraphRunner {
|
|
|
975
992
|
const node = runner.requireNode(token.nodeId);
|
|
976
993
|
|
|
977
994
|
try {
|
|
978
|
-
const
|
|
995
|
+
const inputPort = token.inPort || "in";
|
|
996
|
+
const input = await io.getInput(inputPort);
|
|
997
|
+
if (isFalseSignal(input)) {
|
|
998
|
+
io.setOutput("out", input);
|
|
999
|
+
io.emitFlow("out");
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
979
1002
|
if (!isTrueSignal(input)) {
|
|
980
1003
|
io.setOutput(
|
|
981
1004
|
"out",
|
|
982
|
-
createFalseSignal(
|
|
1005
|
+
createFalseSignal(
|
|
1006
|
+
input === undefined
|
|
1007
|
+
? "数据源节点未收到上游输出,请确认连线与上游节点已执行"
|
|
1008
|
+
: "数据源节点需要收到真信号后才会发起请求"
|
|
1009
|
+
)
|
|
983
1010
|
);
|
|
984
1011
|
io.emitFlow("out");
|
|
985
1012
|
return;
|
|
986
1013
|
}
|
|
987
1014
|
|
|
988
|
-
const config
|
|
989
|
-
|
|
990
|
-
...node.fetchConfig,
|
|
991
|
-
};
|
|
1015
|
+
const config = normalizeFetchRequestConfig(node.fetchConfig);
|
|
1016
|
+
resolveFetchRequestUrl(config);
|
|
992
1017
|
|
|
993
|
-
const result = await executeFetch(config
|
|
1018
|
+
const result = await executeFetch(config, {
|
|
1019
|
+
allowHttpError: runner.isDebugSessionActive(),
|
|
1020
|
+
});
|
|
994
1021
|
io.setOutput("out", createTrueSignal(result));
|
|
995
1022
|
} catch (error) {
|
|
996
1023
|
io.setOutput(
|
|
@@ -1190,6 +1217,7 @@ export class BlueprintGraphRunner {
|
|
|
1190
1217
|
|
|
1191
1218
|
while (queue.length > 0) {
|
|
1192
1219
|
const token = queue.shift()!;
|
|
1220
|
+
if (!this.syncTokenFromGraph(token)) continue;
|
|
1193
1221
|
try {
|
|
1194
1222
|
await executor.executeToken(token);
|
|
1195
1223
|
} catch (error) {
|
|
@@ -1215,7 +1243,10 @@ export class BlueprintGraphRunner {
|
|
|
1215
1243
|
}
|
|
1216
1244
|
}
|
|
1217
1245
|
|
|
1218
|
-
private createExecutor(
|
|
1246
|
+
private createExecutor(
|
|
1247
|
+
queue: ExecutionToken[],
|
|
1248
|
+
options?: { emitToActiveDebugQueue?: boolean }
|
|
1249
|
+
) {
|
|
1219
1250
|
return new Executor({
|
|
1220
1251
|
getNodeDefinition,
|
|
1221
1252
|
behaviors: this.behaviors,
|
|
@@ -1223,15 +1254,20 @@ export class BlueprintGraphRunner {
|
|
|
1223
1254
|
// 由 blueprint-ref-run 行为处理
|
|
1224
1255
|
},
|
|
1225
1256
|
getInputValue: async (token, port) => {
|
|
1226
|
-
|
|
1257
|
+
const resolvedPort = port || token.inPort || "in";
|
|
1258
|
+
return this.resolvePortInputValue(token.nodeId, resolvedPort);
|
|
1227
1259
|
},
|
|
1228
1260
|
setNodeOutput: (token, port, value) => {
|
|
1229
1261
|
this.setNodeOutput(token.nodeId, port, value);
|
|
1230
1262
|
},
|
|
1231
1263
|
emitFlow: (token, outPort) => {
|
|
1264
|
+
const targetQueue =
|
|
1265
|
+
options?.emitToActiveDebugQueue && this.debugQueue
|
|
1266
|
+
? this.debugQueue
|
|
1267
|
+
: queue;
|
|
1232
1268
|
const nextNodes = this.findSignalTargets(token.nodeId, outPort);
|
|
1233
1269
|
for (const target of nextNodes) {
|
|
1234
|
-
|
|
1270
|
+
targetQueue.push({
|
|
1235
1271
|
tokenId: createTokenId(),
|
|
1236
1272
|
nodeId: target.nodeId,
|
|
1237
1273
|
nodeType: target.nodeType,
|
|
@@ -1271,6 +1307,21 @@ export class BlueprintGraphRunner {
|
|
|
1271
1307
|
return node;
|
|
1272
1308
|
}
|
|
1273
1309
|
|
|
1310
|
+
/** 队列中的 token 可能是在节点改类型(如视图绑定)之前入队的,执行前与最新图对齐 */
|
|
1311
|
+
private syncTokenFromGraph(token: ExecutionToken): boolean {
|
|
1312
|
+
const node = this.graph.nodes.find((n) => n.id === token.nodeId);
|
|
1313
|
+
if (!node) return false;
|
|
1314
|
+
token.nodeType = node.nodeType;
|
|
1315
|
+
return true;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
private syncDebugQueueWithLatestGraph(): void {
|
|
1319
|
+
if (!this.debugQueue) return;
|
|
1320
|
+
this.debugQueue = this.debugQueue.filter((token) =>
|
|
1321
|
+
this.syncTokenFromGraph(token)
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1274
1325
|
private findSignalTargets(nodeId: string, outPort: string) {
|
|
1275
1326
|
return this.graph.edges
|
|
1276
1327
|
.filter(
|