aaa-irule-script-bin23 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/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # bin
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.js
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.3.11. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/app.7z ADDED
Binary file
package/bun.lock ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "bin",
7
+ "devDependencies": {
8
+ "@types/bun": "latest",
9
+ },
10
+ "peerDependencies": {
11
+ "typescript": "^5",
12
+ },
13
+ },
14
+ },
15
+ "packages": {
16
+ "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
17
+
18
+ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
19
+
20
+ "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
21
+
22
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
23
+
24
+ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
25
+ }
26
+ }
@@ -0,0 +1,410 @@
1
+ /**
2
+ * 规则流美化 — 与 iruleeditweb-tpc 的 beautifyFlow2GraphData 逻辑一致
3
+ *
4
+ * 核心流程:
5
+ * 1. dagre 层次化布局(节点尺寸膨胀 + begin 偏移,与 @antv/layout DagreLayout 一致)
6
+ * 2. 折线边路由(calcPointsList,含 TB/LR 方向感知)
7
+ * 3. pointFilter 去除共线冗余点
8
+ * 4. 边文本位置重算(getBytesLength + 方向适配)
9
+ *
10
+ * 输入 parse() 返回的 nodes/edges/nodeSizeMap,输出美化后的 nodes/edges。
11
+ * 布局方向默认 TB(上到下),节点间距 40px(适配 LogicFlow 40px grid)。
12
+ */
13
+
14
+ import type { EdgeItem, NodeItem, NodeSize, Point } from './types'
15
+ import dagre from 'dagre'
16
+
17
+ export interface BeautifyOptions {
18
+ /** 布局方向,默认 TB(上到下) */
19
+ rankdir?: 'TB' | 'BT' | 'LR' | 'RL'
20
+ /** 节点水平间距,默认 40 */
21
+ nodesep?: number
22
+ /** 层级间距,默认 40 */
23
+ ranksep?: number
24
+ }
25
+
26
+ // —————————————————————————————————————— 主入口 ——————————————————————————————————————
27
+
28
+ /**
29
+ * 与 @antv/layout DagreLayout 保持一致的布局:
30
+ * - 节点尺寸膨胀 (w + 2*nodesep, h + 2*ranksep) 后喂给 dagre
31
+ * - 布局后以 begin 坐标偏移,使最小坐标落在 begin 处
32
+ * - LogicFlow 使用 center-based 坐标系,与 dagre 输出天然一致
33
+ */
34
+ export function beautifyFlow(
35
+ nodes: NodeItem[],
36
+ edges: EdgeItem[],
37
+ nodeSizeMap: Map<string, NodeSize>,
38
+ options: BeautifyOptions = {},
39
+ ): { nodes: NodeItem[], edges: EdgeItem[] } {
40
+ const rankdir = options.rankdir || 'TB'
41
+ const nodesep = options.nodesep ?? 40
42
+ const ranksep = options.ranksep ?? 40
43
+ const begin: [number, number] = [120, 120]
44
+
45
+ // 根据布局方向交换水平/垂直间距
46
+ const isHorizontal = rankdir === 'LR' || rankdir === 'RL'
47
+ const horisep = isHorizontal ? ranksep : nodesep
48
+ const vertisep = isHorizontal ? nodesep : ranksep
49
+
50
+ // ——— 1. 构建 dagre 图(节点尺寸膨胀,与 @antv/layout 一致) ———
51
+ const g = new dagre.graphlib.Graph()
52
+ g.setDefaultEdgeLabel(() => ({}))
53
+ g.setGraph({ rankdir, nodesep, ranksep })
54
+
55
+ for (const node of nodes) {
56
+ const size = nodeSizeMap.get(node.id) || { w: 100, h: 40 }
57
+ g.setNode(node.id, {
58
+ width: size.w + 2 * horisep,
59
+ height: size.h + 2 * vertisep,
60
+ })
61
+ }
62
+
63
+ for (const edge of edges) {
64
+ g.setEdge(edge.sourceNodeId, edge.targetNodeId)
65
+ }
66
+
67
+ // ——— 2. 执行布局 ———
68
+ dagre.layout(g)
69
+
70
+ // ——— 3. 计算 begin 偏移(与 @antv/layout 的 dBegin 逻辑一致) ———
71
+ let minX = Infinity
72
+ let minY = Infinity
73
+ g.nodes().forEach((nodeId) => {
74
+ const coord = g.node(nodeId)
75
+ if (coord && coord.x < minX)
76
+ minX = coord.x
77
+ if (coord && coord.y < minY)
78
+ minY = coord.y
79
+ })
80
+ g.edges().forEach((e) => {
81
+ const coord = g.edge(e)
82
+ coord?.points?.forEach((p: { x: number, y: number }) => {
83
+ if (p.x < minX)
84
+ minX = p.x
85
+ if (p.y < minY)
86
+ minY = p.y
87
+ })
88
+ })
89
+
90
+ const dBeginX = Number.isFinite(minX) ? begin[0] - minX : 0
91
+ const dBeginY = Number.isFinite(minY) ? begin[1] - minY : 0
92
+
93
+ // ——— 4. 更新节点坐标(加上 begin 偏移) ———
94
+ const nodeMap = new Map<string, NodeItem>()
95
+ for (const node of nodes) {
96
+ const pos = g.node(node.id)
97
+ if (pos) {
98
+ node.x = pos.x + dBeginX
99
+ node.y = pos.y + dBeginY
100
+ }
101
+ nodeMap.set(node.id, node)
102
+ }
103
+
104
+ // ——— 5. 重算边几何(与 iruleeditweb-tpc 的 calcPointsList 逻辑一致) ———
105
+ for (const edge of edges) {
106
+ const sourceNode = nodeMap.get(edge.sourceNodeId)
107
+ const targetNode = nodeMap.get(edge.targetNodeId)
108
+ if (!sourceNode || !targetNode)
109
+ continue
110
+
111
+ const sSize = nodeSizeMap.get(edge.sourceNodeId) || { w: 100, h: 40 }
112
+ const tSize = nodeSizeMap.get(edge.targetNodeId) || { w: 100, h: 40 }
113
+ const offset = Math.max((edge as any).offset ?? 0, 50)
114
+
115
+ const sourceNodeModel = { width: sSize.w, height: sSize.h }
116
+ const targetNodeModel = { width: tSize.w, height: tSize.h }
117
+ const newSourceNodeData = { x: sourceNode.x, y: sourceNode.y }
118
+ const newTargetNodeData = { x: targetNode.x, y: targetNode.y }
119
+
120
+ const pointsList = calcPointsList(
121
+ rankdir,
122
+ offset,
123
+ sourceNodeModel,
124
+ targetNodeModel,
125
+ newSourceNodeData,
126
+ newTargetNodeData,
127
+ )
128
+
129
+ if (pointsList) {
130
+ const first = pointsList[0]!
131
+ const last = pointsList[pointsList.length - 1]!
132
+ edge.startPoint = { x: first.x, y: first.y }
133
+ edge.endPoint = { x: last.x, y: last.y }
134
+ edge.pointsList = pointsList
135
+
136
+ if (edge.text && (edge.text as any).value) {
137
+ if (rankdir === 'TB') {
138
+ (edge.text as any) = {
139
+ x: last.x,
140
+ y: last.y - 40,
141
+ value: (edge.text as any).value,
142
+ }
143
+ }
144
+ else {
145
+ (edge.text as any) = {
146
+ x: last.x - getBytesLength((edge.text as any).value) * 6 - 10,
147
+ y: last.y,
148
+ value: (edge.text as any).value,
149
+ }
150
+ }
151
+ }
152
+ }
153
+ else {
154
+ edge.startPoint = undefined as any
155
+ edge.endPoint = undefined as any
156
+ edge.pointsList = undefined as any
157
+ if (edge.text && (edge.text as any).value) {
158
+ edge.text = (edge.text as any).value as any
159
+ }
160
+ }
161
+
162
+ edge.sourceAnchorId = `${edge.sourceNodeId}_1`
163
+ edge.targetAnchorId = `${edge.targetNodeId}_3`
164
+ }
165
+
166
+ return { nodes, edges }
167
+ }
168
+
169
+ // ——————————————————————————————————— 折线路由 ————————————————————————————————————
170
+
171
+ interface NodeLayoutModel {
172
+ width: number
173
+ height: number
174
+ }
175
+ interface NodeLayoutData {
176
+ x: number
177
+ y: number
178
+ }
179
+
180
+ function calcPointsList(
181
+ rankdir: string,
182
+ offset: number,
183
+ sourceNodeModel: NodeLayoutModel,
184
+ targetNodeModel: NodeLayoutModel,
185
+ newSourceNodeData: NodeLayoutData,
186
+ newTargetNodeData: NodeLayoutData,
187
+ ): Point[] | undefined {
188
+ if (rankdir === 'TB' || rankdir === 'BT') {
189
+ return getTBPoints({
190
+ offset,
191
+ sourceNodeModel,
192
+ targetNodeModel,
193
+ newSourceNodeData,
194
+ newTargetNodeData,
195
+ })
196
+ }
197
+ else { // LR / RL
198
+ return getLRPoints({
199
+ offset,
200
+ sourceNodeModel,
201
+ targetNodeModel,
202
+ newSourceNodeData,
203
+ newTargetNodeData,
204
+ })
205
+ }
206
+ }
207
+
208
+ function getTBPoints({
209
+ offset,
210
+ sourceNodeModel,
211
+ targetNodeModel,
212
+ newSourceNodeData,
213
+ newTargetNodeData,
214
+ }: {
215
+ offset: number
216
+ sourceNodeModel: NodeLayoutModel
217
+ targetNodeModel: NodeLayoutModel
218
+ newSourceNodeData: NodeLayoutData
219
+ newTargetNodeData: NodeLayoutData
220
+ }): Point[] | undefined {
221
+ const pointsList: Point[] = []
222
+
223
+ if (newSourceNodeData.y < newTargetNodeData.y) {
224
+ // 从上到下
225
+ pointsList.push({
226
+ x: newSourceNodeData.x,
227
+ y: newSourceNodeData.y + sourceNodeModel.height / 2,
228
+ })
229
+ pointsList.push({
230
+ x: newSourceNodeData.x,
231
+ y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
232
+ })
233
+ pointsList.push({
234
+ x: newTargetNodeData.x,
235
+ y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
236
+ })
237
+ pointsList.push({
238
+ x: newTargetNodeData.x,
239
+ y: newTargetNodeData.y - targetNodeModel.height / 2,
240
+ })
241
+ return pointFilter(pointsList)
242
+ }
243
+
244
+ if (newSourceNodeData.y > newTargetNodeData.y) {
245
+ if (newSourceNodeData.x >= newTargetNodeData.x) {
246
+ // 回连,目标在左
247
+ pointsList.push({
248
+ x: newSourceNodeData.x + sourceNodeModel.width / 2,
249
+ y: newSourceNodeData.y,
250
+ })
251
+ pointsList.push({
252
+ x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
253
+ y: newSourceNodeData.y,
254
+ })
255
+ pointsList.push({
256
+ x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
257
+ y: newTargetNodeData.y,
258
+ })
259
+ pointsList.push({
260
+ x: newTargetNodeData.x + targetNodeModel.width / 2,
261
+ y: newTargetNodeData.y,
262
+ })
263
+ }
264
+ else {
265
+ // 回连,目标在右
266
+ pointsList.push({
267
+ x: newSourceNodeData.x - sourceNodeModel.width / 2,
268
+ y: newSourceNodeData.y,
269
+ })
270
+ pointsList.push({
271
+ x: newSourceNodeData.x - sourceNodeModel.width / 2 - offset,
272
+ y: newSourceNodeData.y,
273
+ })
274
+ pointsList.push({
275
+ x: newSourceNodeData.x - sourceNodeModel.width / 2 - offset,
276
+ y: newTargetNodeData.y,
277
+ })
278
+ pointsList.push({
279
+ x: newTargetNodeData.x - targetNodeModel.width / 2,
280
+ y: newTargetNodeData.y,
281
+ })
282
+ }
283
+ return pointFilter(pointsList)
284
+ }
285
+
286
+ return undefined
287
+ }
288
+
289
+ function getLRPoints({
290
+ offset,
291
+ sourceNodeModel,
292
+ targetNodeModel,
293
+ newSourceNodeData,
294
+ newTargetNodeData,
295
+ }: {
296
+ offset: number
297
+ sourceNodeModel: NodeLayoutModel
298
+ targetNodeModel: NodeLayoutModel
299
+ newSourceNodeData: NodeLayoutData
300
+ newTargetNodeData: NodeLayoutData
301
+ }): Point[] | undefined {
302
+ const pointsList: Point[] = []
303
+
304
+ if (newSourceNodeData.x < newTargetNodeData.x) {
305
+ // 从左到右
306
+ pointsList.push({
307
+ x: newSourceNodeData.x + sourceNodeModel.width / 2,
308
+ y: newSourceNodeData.y,
309
+ })
310
+ pointsList.push({
311
+ x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
312
+ y: newSourceNodeData.y,
313
+ })
314
+ pointsList.push({
315
+ x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
316
+ y: newTargetNodeData.y,
317
+ })
318
+ pointsList.push({
319
+ x: newTargetNodeData.x - targetNodeModel.width / 2,
320
+ y: newTargetNodeData.y,
321
+ })
322
+ return pointFilter(pointsList)
323
+ }
324
+
325
+ if (newSourceNodeData.x > newTargetNodeData.x) {
326
+ if (newSourceNodeData.y >= newTargetNodeData.y) {
327
+ // 回连,目标在上
328
+ pointsList.push({
329
+ x: newSourceNodeData.x,
330
+ y: newSourceNodeData.y + sourceNodeModel.height / 2,
331
+ })
332
+ pointsList.push({
333
+ x: newSourceNodeData.x,
334
+ y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
335
+ })
336
+ pointsList.push({
337
+ x: newTargetNodeData.x,
338
+ y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
339
+ })
340
+ pointsList.push({
341
+ x: newTargetNodeData.x,
342
+ y: newTargetNodeData.y + targetNodeModel.height / 2,
343
+ })
344
+ }
345
+ else {
346
+ // 回连,目标在下
347
+ pointsList.push({
348
+ x: newSourceNodeData.x,
349
+ y: newSourceNodeData.y - sourceNodeModel.height / 2,
350
+ })
351
+ pointsList.push({
352
+ x: newSourceNodeData.x,
353
+ y: newSourceNodeData.y - sourceNodeModel.height / 2 - offset,
354
+ })
355
+ pointsList.push({
356
+ x: newTargetNodeData.x,
357
+ y: newSourceNodeData.y - sourceNodeModel.height / 2 - offset,
358
+ })
359
+ pointsList.push({
360
+ x: newTargetNodeData.x,
361
+ y: newTargetNodeData.y - targetNodeModel.height / 2,
362
+ })
363
+ }
364
+ return pointFilter(pointsList)
365
+ }
366
+
367
+ return undefined
368
+ }
369
+
370
+ // ——————————————————————————————————— 工具函数 ————————————————————————————————————
371
+
372
+ /** 过滤连续共线的中间点 */
373
+ function pointFilter(points: Point[]): Point[] {
374
+ let i = 1
375
+ while (i < points.length - 1) {
376
+ const pre = points[i - 1]!
377
+ const cur = points[i]!
378
+ const next = points[i + 1]!
379
+ if (
380
+ (pre.x === cur.x && cur.x === next.x)
381
+ || (pre.y === cur.y && cur.y === next.y)
382
+ ) {
383
+ points.splice(i, 1)
384
+ }
385
+ else {
386
+ i++
387
+ }
388
+ }
389
+ return points
390
+ }
391
+
392
+ /** 粗略估算字符串像素宽度(ASCII=1, 大写字母=1.5, 中文=2) */
393
+ function getBytesLength(word: string): number {
394
+ if (!word)
395
+ return 0
396
+ let totalLength = 0
397
+ for (let i = 0; i < word.length; i++) {
398
+ const c = word.charCodeAt(i)
399
+ if (/[A-Z]/.test(word[i]!)) {
400
+ totalLength += 1.5
401
+ }
402
+ else if ((c >= 0x0001 && c <= 0x007E) || (c >= 0xFF60 && c <= 0xFF9F)) {
403
+ totalLength += 1
404
+ }
405
+ else {
406
+ totalLength += 2
407
+ }
408
+ }
409
+ return totalLength
410
+ }
package/index.js ADDED
@@ -0,0 +1 @@
1
+ console.log("Hello via Bun!");
package/jsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+
24
+ // Some stricter flags (disabled by default)
25
+ "noUnusedLocals": false,
26
+ "noUnusedParameters": false,
27
+ "noPropertyAccessFromIndexSignature": false
28
+ }
29
+ }
package/node-svc.xml ADDED
@@ -0,0 +1,21 @@
1
+ <service>
2
+ <id>node-app</id>
3
+ <name>Node.js App Daemon</name>
4
+ <description>Node.js 应用守护进程</description>
5
+ <!-- 路径指向 node 解释器 -->
6
+ <executable>C:\nvm4w\nodejs\node.exe</executable>
7
+ <!-- 参数指向 app.js -->
8
+ <arguments>D:\git\scripts-ui\build\server\index.js</arguments>
9
+ <!-- 1. 指定日志存放目录 (相对路径或绝对路径均可) -->
10
+ <logpath>logs</logpath>
11
+ <!-- 2. 日志模式配置:推荐使用 roll (滚动模式) -->
12
+ <log mode="roll">
13
+ <!-- 单个日志文件超过 10MB 则切分 -->
14
+ <sizeThreshold>10240</sizeThreshold>
15
+ <!-- 最多保留 10 个历史日志文件 -->
16
+ <keepFiles>10</keepFiles>
17
+ </log>
18
+
19
+ <onfailure action="restart" delay="10 sec"/>
20
+ <stopparentfirst>true</stopparentfirst>
21
+ </service>
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "aaa-irule-script-bin23",
3
+ "version": "1.0.3",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "private": false,
13
+ "devDependencies": {
14
+ },
15
+ "peerDependencies": {
16
+ }
17
+ }