@huanban/rulego-editor-core 1.0.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.
Files changed (102) hide show
  1. package/README.md +211 -0
  2. package/dist/api/RuleChainAPI.d.ts +163 -0
  3. package/dist/api/RuleChainAPI.d.ts.map +1 -0
  4. package/dist/api/index.d.ts +15 -0
  5. package/dist/api/index.d.ts.map +1 -0
  6. package/dist/api/types.d.ts +244 -0
  7. package/dist/api/types.d.ts.map +1 -0
  8. package/dist/core/ComponentRegistry.d.ts +141 -0
  9. package/dist/core/ComponentRegistry.d.ts.map +1 -0
  10. package/dist/core/DataAdapter.d.ts +129 -0
  11. package/dist/core/DataAdapter.d.ts.map +1 -0
  12. package/dist/core/EditorCore.d.ts +251 -0
  13. package/dist/core/EditorCore.d.ts.map +1 -0
  14. package/dist/core/EventBus.d.ts +101 -0
  15. package/dist/core/EventBus.d.ts.map +1 -0
  16. package/dist/core/HistoryManager.d.ts +166 -0
  17. package/dist/core/HistoryManager.d.ts.map +1 -0
  18. package/dist/core/I18nManager.d.ts +130 -0
  19. package/dist/core/I18nManager.d.ts.map +1 -0
  20. package/dist/core/StateStore.d.ts +160 -0
  21. package/dist/core/StateStore.d.ts.map +1 -0
  22. package/dist/core/ThemeManager.d.ts +175 -0
  23. package/dist/core/ThemeManager.d.ts.map +1 -0
  24. package/dist/core/ValidationEngine.d.ts +139 -0
  25. package/dist/core/ValidationEngine.d.ts.map +1 -0
  26. package/dist/core/index.d.ts +30 -0
  27. package/dist/core/index.d.ts.map +1 -0
  28. package/dist/defaults/components.d.ts +30 -0
  29. package/dist/defaults/components.d.ts.map +1 -0
  30. package/dist/defaults/index.d.ts +18 -0
  31. package/dist/defaults/index.d.ts.map +1 -0
  32. package/dist/defaults/locale-en-US.d.ts +26 -0
  33. package/dist/defaults/locale-en-US.d.ts.map +1 -0
  34. package/dist/defaults/locale-zh-CN.d.ts +41 -0
  35. package/dist/defaults/locale-zh-CN.d.ts.map +1 -0
  36. package/dist/iconRegistry.d.ts +17 -0
  37. package/dist/iconRegistry.d.ts.map +1 -0
  38. package/dist/index.cjs.js +2490 -0
  39. package/dist/index.cjs.js.map +1 -0
  40. package/dist/index.d.ts +49 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.esm.js +59608 -0
  43. package/dist/index.esm.js.map +1 -0
  44. package/dist/index.umd.js +2490 -0
  45. package/dist/index.umd.js.map +1 -0
  46. package/dist/standalone/HuanbanRulegoEditor.d.ts +392 -0
  47. package/dist/standalone/HuanbanRulegoEditor.d.ts.map +1 -0
  48. package/dist/standalone/code-editor.d.ts +95 -0
  49. package/dist/standalone/code-editor.d.ts.map +1 -0
  50. package/dist/standalone/custom-nodes.d.ts +26 -0
  51. package/dist/standalone/custom-nodes.d.ts.map +1 -0
  52. package/dist/standalone/editor-chain-info.d.ts +46 -0
  53. package/dist/standalone/editor-chain-info.d.ts.map +1 -0
  54. package/dist/standalone/editor-context-menu.d.ts +21 -0
  55. package/dist/standalone/editor-context-menu.d.ts.map +1 -0
  56. package/dist/standalone/editor-debug-ws.d.ts +170 -0
  57. package/dist/standalone/editor-debug-ws.d.ts.map +1 -0
  58. package/dist/standalone/editor-dialogs.d.ts +73 -0
  59. package/dist/standalone/editor-dialogs.d.ts.map +1 -0
  60. package/dist/standalone/editor-events.d.ts +28 -0
  61. package/dist/standalone/editor-events.d.ts.map +1 -0
  62. package/dist/standalone/editor-property-drawers.d.ts +78 -0
  63. package/dist/standalone/editor-property-drawers.d.ts.map +1 -0
  64. package/dist/standalone/editor-route-settings.d.ts +49 -0
  65. package/dist/standalone/editor-route-settings.d.ts.map +1 -0
  66. package/dist/standalone/editor-sidebar.d.ts +19 -0
  67. package/dist/standalone/editor-sidebar.d.ts.map +1 -0
  68. package/dist/standalone/editor-styles.d.ts +12 -0
  69. package/dist/standalone/editor-styles.d.ts.map +1 -0
  70. package/dist/standalone/editor-toolbar.d.ts +89 -0
  71. package/dist/standalone/editor-toolbar.d.ts.map +1 -0
  72. package/dist/standalone/group-node.d.ts +52 -0
  73. package/dist/standalone/group-node.d.ts.map +1 -0
  74. package/dist/standalone/icon-utils.d.ts +19 -0
  75. package/dist/standalone/icon-utils.d.ts.map +1 -0
  76. package/dist/standalone/index.d.ts +9 -0
  77. package/dist/standalone/index.d.ts.map +1 -0
  78. package/dist/standalone/logger.d.ts +35 -0
  79. package/dist/standalone/logger.d.ts.map +1 -0
  80. package/dist/standalone/node-definitions.d.ts +74 -0
  81. package/dist/standalone/node-definitions.d.ts.map +1 -0
  82. package/dist/standalone/node-views-data.d.ts +21 -0
  83. package/dist/standalone/node-views-data.d.ts.map +1 -0
  84. package/dist/standalone/themes.d.ts +54 -0
  85. package/dist/standalone/themes.d.ts.map +1 -0
  86. package/dist/types/component.d.ts +120 -0
  87. package/dist/types/component.d.ts.map +1 -0
  88. package/dist/types/editor.d.ts +246 -0
  89. package/dist/types/editor.d.ts.map +1 -0
  90. package/dist/types/events.d.ts +199 -0
  91. package/dist/types/events.d.ts.map +1 -0
  92. package/dist/types/index.d.ts +12 -0
  93. package/dist/types/index.d.ts.map +1 -0
  94. package/dist/types/rule-chain.d.ts +141 -0
  95. package/dist/types/rule-chain.d.ts.map +1 -0
  96. package/dist/utils/helpers.d.ts +100 -0
  97. package/dist/utils/helpers.d.ts.map +1 -0
  98. package/dist/utils/index.d.ts +6 -0
  99. package/dist/utils/index.d.ts.map +1 -0
  100. package/dist/utils/pinyin-search.d.ts +60 -0
  101. package/dist/utils/pinyin-search.d.ts.map +1 -0
  102. package/package.json +70 -0
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @file ComponentRegistry.ts
3
+ * @description 组件注册表 — 管理所有可用的节点组件
4
+ *
5
+ * 负责:
6
+ * - 注册和管理组件定义 (来自后端 API 或内置默认)
7
+ * - 按分类分组 (filter/transform/action/external/flow)
8
+ * - 提供按 type 快速查询
9
+ * - 适配后端返回的原始数据格式
10
+ * - 合并本地化信息 (标签、描述、图标等)
11
+ *
12
+ * @see default.js - 内置组件定义
13
+ * @see local_zh.js - 中文本地化
14
+ * @see util.js - adapterComponents 转换函数
15
+ */
16
+ import type { ComponentDefinition, ComponentGroup, RawComponentData, ComponentRegistryOptions } from '../types/component';
17
+ /**
18
+ * 组件注册表
19
+ *
20
+ * 管理编辑器中所有可用的节点组件定义。
21
+ * 支持按 type 查找、按 category 分组、动态注册/注销等操作。
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const registry = new ComponentRegistry()
26
+ *
27
+ * // 从后端 API 数据加载组件
28
+ * registry.loadFromRawData(apiData)
29
+ *
30
+ * // 按 type 查找
31
+ * const filterNode = registry.getByType('jsFilter')
32
+ *
33
+ * // 获取分组 (用于侧边栏渲染)
34
+ * const groups = registry.getGroups()
35
+ *
36
+ * // 动态注册自定义组件
37
+ * registry.register({
38
+ * type: 'myCustomNode',
39
+ * category: 'action',
40
+ * label: 'My Custom Node',
41
+ * ...
42
+ * })
43
+ * ```
44
+ */
45
+ export declare class ComponentRegistry {
46
+ /** 组件映射表: type => ComponentDefinition */
47
+ private components;
48
+ /** 自定义分类定义 */
49
+ private categories;
50
+ /** 自定义适配器函数 */
51
+ private adapter?;
52
+ /**
53
+ * 创建组件注册表
54
+ *
55
+ * @param options - 初始化选项
56
+ */
57
+ constructor(options?: ComponentRegistryOptions);
58
+ /**
59
+ * 注册单个组件
60
+ *
61
+ * @param definition - 组件定义
62
+ * @param overwrite - 如果已存在是否覆盖 (默认: true)
63
+ */
64
+ register(definition: ComponentDefinition, overwrite?: boolean): void;
65
+ /**
66
+ * 批量注册组件
67
+ *
68
+ * @param definitions - 组件定义列表
69
+ * @param overwrite - 如果已存在是否覆盖
70
+ */
71
+ registerAll(definitions: ComponentDefinition[], overwrite?: boolean): void;
72
+ /**
73
+ * 注销组件
74
+ *
75
+ * @param type - 组件类型标识
76
+ * @returns 是否成功移除
77
+ */
78
+ unregister(type: string): boolean;
79
+ /**
80
+ * 根据类型获取组件定义
81
+ *
82
+ * @param type - 组件类型标识
83
+ * @returns 组件定义, 不存在返回 undefined
84
+ */
85
+ getByType(type: string): ComponentDefinition | undefined;
86
+ /**
87
+ * 获取所有组件的扁平列表
88
+ *
89
+ * @returns 所有已注册组件的数组
90
+ */
91
+ getAll(): ComponentDefinition[];
92
+ /**
93
+ * 获取组件映射表 (type => definition)
94
+ * 用于快速查找, 对应原版的 nodeComponents 对象
95
+ *
96
+ * @returns type => ComponentDefinition 的映射
97
+ */
98
+ getMap(): Record<string, ComponentDefinition>;
99
+ /**
100
+ * 获取按分类分组的组件列表
101
+ * 用于侧边栏渲染
102
+ *
103
+ * @returns 分组后的组件列表
104
+ */
105
+ getGroups(): ComponentGroup[];
106
+ /**
107
+ * 从后端 API 返回的原始数据加载组件
108
+ *
109
+ * 如果设置了自定义 adapter 则使用自定义逻辑,
110
+ * 否则使用内置的默认适配逻辑。
111
+ *
112
+ * @param rawData - 后端返回的原始组件数据
113
+ * @returns 分组后的组件列表
114
+ */
115
+ loadFromRawData(rawData: RawComponentData): ComponentGroup[];
116
+ /**
117
+ * 注册自定义分类
118
+ *
119
+ * @param category - 分类标识
120
+ * @param info - 分类信息 (标签和颜色)
121
+ */
122
+ registerCategory(category: string, info: {
123
+ label: string;
124
+ color: string;
125
+ }): void;
126
+ /**
127
+ * 获取组件总数
128
+ */
129
+ get size(): number;
130
+ /**
131
+ * 检查组件是否已注册
132
+ *
133
+ * @param type - 组件类型标识
134
+ */
135
+ has(type: string): boolean;
136
+ /**
137
+ * 清空所有已注册组件
138
+ */
139
+ clear(): void;
140
+ }
141
+ //# sourceMappingURL=ComponentRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComponentRegistry.d.ts","sourceRoot":"","sources":["../../src/core/ComponentRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,oBAAoB,CAAA;AAc3B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,iBAAiB;IAC5B,yCAAyC;IACzC,OAAO,CAAC,UAAU,CAA8C;IAChE,cAAc;IACd,OAAO,CAAC,UAAU,CAAkD;IACpE,eAAe;IACf,OAAO,CAAC,OAAO,CAAC,CAA8C;IAE9D;;;;OAIG;gBACS,OAAO,CAAC,EAAE,wBAAwB;IAU9C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,mBAAmB,EAAE,SAAS,UAAO,GAAG,IAAI;IAgBjE;;;;;OAKG;IACH,WAAW,CAAC,WAAW,EAAE,mBAAmB,EAAE,EAAE,SAAS,UAAO,GAAG,IAAI;IAIvE;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;;;OAKG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIxD;;;;OAIG;IACH,MAAM,IAAI,mBAAmB,EAAE;IAI/B;;;;;OAKG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAQ7C;;;;;OAKG;IACH,SAAS,IAAI,cAAc,EAAE;IA8B7B;;;;;;;;OAQG;IACH,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,EAAE;IAgB5D;;;;;OAKG;IACH,gBAAgB,CACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GACrC,IAAI;IAIP;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @file DataAdapter.ts
3
+ * @description 数据格式转换器 — adapterIn / adapterOut
4
+ *
5
+ * 负责 RuleGo JSON 格式 <-> LogicFlow 内部格式 的双向转换。
6
+ *
7
+ * adapterIn: RuleChainData → LogicFlowGraphData (用于渲染)
8
+ * adapterOut: LogicFlowGraphData → RuleChainData (用于保存)
9
+ *
10
+ * 这是原版 RuleGoEditor.vue 中最核心的业务逻辑之一,
11
+ * 从框架层抽取到 core 中后,Vue/React/原生 JS 都可以复用。
12
+ *
13
+ * @see RuleGoEditor.vue 的 lf.adapterIn 和 lf.adapterOut 方法
14
+ */
15
+ import type { RuleChainData, RuleChainConfig, RuleNodeConfig, RuleConnectionConfig } from '../types/rule-chain';
16
+ import type { ComponentDefinition } from '../types/component';
17
+ import type { EditorInternalData } from '../types/editor';
18
+ /**
19
+ * LogicFlow 节点数据
20
+ */
21
+ export interface LFNodeData {
22
+ /** 节点 ID */
23
+ id: string;
24
+ /** 节点类型 (simple-node, start-node, chain-node, group-node) */
25
+ type: string;
26
+ /** X 坐标 */
27
+ x: number;
28
+ /** Y 坐标 */
29
+ y: number;
30
+ /** 节点显示文本 */
31
+ text?: string;
32
+ /** 节点属性 */
33
+ properties: {
34
+ /** RuleGo 节点配置 */
35
+ model?: RuleNodeConfig;
36
+ /** 组件视图定义 */
37
+ view?: ComponentDefinition;
38
+ };
39
+ }
40
+ /**
41
+ * LogicFlow 连接点数据
42
+ */
43
+ export interface LFPoint {
44
+ x: number;
45
+ y: number;
46
+ }
47
+ /**
48
+ * LogicFlow 边数据
49
+ */
50
+ export interface LFEdgeData {
51
+ /** 边 ID */
52
+ id: string;
53
+ /** 边类型 */
54
+ type: string;
55
+ /** 源节点 ID */
56
+ sourceNodeId: string;
57
+ /** 目标节点 ID */
58
+ targetNodeId: string;
59
+ /** 起点坐标 */
60
+ startPoint: LFPoint;
61
+ /** 终点坐标 */
62
+ endPoint: LFPoint;
63
+ /** 显示文本 */
64
+ text?: string;
65
+ /** 边属性 */
66
+ properties: {
67
+ /** 连接配置数据 */
68
+ model: Partial<RuleConnectionConfig> & Record<string, unknown>;
69
+ };
70
+ }
71
+ /**
72
+ * LogicFlow 图数据 (完整的画布数据)
73
+ */
74
+ export interface LFGraphData {
75
+ /** 节点列表 */
76
+ nodes: LFNodeData[];
77
+ /** 边列表 */
78
+ edges: LFEdgeData[];
79
+ }
80
+ /**
81
+ * 数据格式转换器
82
+ * 实现 RuleGo JSON 与 LogicFlow 格式的双向转换
83
+ */
84
+ export declare class DataAdapter {
85
+ /**
86
+ * 将 RuleGo 数据转换为 LogicFlow 格式 (用于渲染)
87
+ *
88
+ * 转换逻辑:
89
+ * 1. 添加固定的 Start 节点
90
+ * 2. 将 metadata.nodes 转换为 LF 节点 (带布局位置)
91
+ * 3. 根据 firstNodeIndex 创建 Start -> 第一个节点的边
92
+ * 4. 将 metadata.connections 转换为 LF 边 (合并同源同目标的多关系)
93
+ *
94
+ * @param userData - RuleGo 规则链 JSON 数据
95
+ * @param nodeComponents - 组件注册表 (type => definition)
96
+ * @param internalData - 编辑器内部运行时数据 (计数器等)
97
+ * @param options - 额外选项 (如起始坐标)
98
+ * @returns LogicFlow 格式的图数据
99
+ */
100
+ adapterIn(userData: RuleChainData, nodeComponents: Record<string, ComponentDefinition>, internalData: EditorInternalData, options: {
101
+ startX: number;
102
+ startY: number;
103
+ }): LFGraphData;
104
+ /**
105
+ * 将 LogicFlow 数据转换回 RuleGo 格式 (用于保存)
106
+ *
107
+ * 转换逻辑:
108
+ * 1. 遍历边, 过滤掉 Start 节点的出边, 将合并的关系类型拆分为多条连接
109
+ * 2. 遍历节点, 过滤掉 Start 节点, 更新布局信息
110
+ * 3. 确定第一个节点 (Start 节点连接的目标节点)
111
+ * 4. 组装 RuleChainData 返回
112
+ *
113
+ * @param logicFlowData - LogicFlow 的图数据
114
+ * @param ruleChain - 当前规则链配置
115
+ * @param internalData - 编辑器内部运行时数据
116
+ * @param getNodeModelById - 从 LogicFlow 获取节点 Model 的函数
117
+ * @returns RuleGo 规则链 JSON 数据
118
+ */
119
+ adapterOut(logicFlowData: LFGraphData, ruleChain: RuleChainConfig, internalData: EditorInternalData, getNodeModelById: (id: string) => LFNodeData | null): RuleChainData;
120
+ /**
121
+ * 根据 LogicFlow 节点 ID 查找对应的 RuleGo 自定义节点 ID
122
+ *
123
+ * @param lfNodeId - LogicFlow 内部节点 ID
124
+ * @param getNodeModelById - 获取节点数据的函数
125
+ * @returns 自定义节点 ID, 找不到返回空字符串
126
+ */
127
+ private lfNodeId2CustomNodeId;
128
+ }
129
+ //# sourceMappingURL=DataAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataAdapter.d.ts","sourceRoot":"","sources":["../../src/core/DataAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAOzD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW;IACX,CAAC,EAAE,MAAM,CAAA;IACT,WAAW;IACX,CAAC,EAAE,MAAM,CAAA;IACT,aAAa;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW;IACX,UAAU,EAAE;QACV,kBAAkB;QAClB,KAAK,CAAC,EAAE,cAAc,CAAA;QACtB,aAAa;QACb,IAAI,CAAC,EAAE,mBAAmB,CAAA;KAC3B,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW;IACX,EAAE,EAAE,MAAM,CAAA;IACV,UAAU;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW;IACX,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW;IACX,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU;IACV,UAAU,EAAE;QACV,aAAa;QACb,KAAK,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC/D,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,WAAW;IACX,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,UAAU;IACV,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAMD;;;GAGG;AACH,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;OAcG;IACH,SAAS,CACP,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACnD,YAAY,EAAE,kBAAkB,EAChC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC1C,WAAW;IA6Md;;;;;;;;;;;;;;OAcG;IACH,UAAU,CACR,aAAa,EAAE,WAAW,EAC1B,SAAS,EAAE,eAAe,EAC1B,YAAY,EAAE,kBAAkB,EAChC,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,GAClD,aAAa;IAkHhB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;CAU9B"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * @file core/EditorCore.ts
3
+ * @description 编辑器核心引擎 — 整合所有子系统的主入口
4
+ *
5
+ * EditorCore 是整个编辑器的中枢, 它:
6
+ * 1. 持有并协调所有子系统 (StateStore, EventBus, ComponentRegistry 等)
7
+ * 2. 管理 LogicFlow 实例的生命周期 (初始化 / 数据加载 / 事件桥接)
8
+ * 3. 提供统一的 API 供框架适配层 (Vue/React/原生 JS) 调用
9
+ * 4. 不包含任何框架特定代码 (无 Vue ref, 无 React useState)
10
+ *
11
+ * 框架适配层职责:
12
+ * - 将 EditorCore 的状态/事件桥接到框架的响应式系统
13
+ * - 渲染 UI 组件 (工具栏、侧边栏、属性面板)
14
+ * - 处理 DOM 挂载/卸载生命周期
15
+ *
16
+ * 使用方式 (原生 JS):
17
+ * ```typescript
18
+ * import { EditorCore } from '@huanban/rulego-editor-core'
19
+ *
20
+ * const editor = new EditorCore({
21
+ * container: document.getElementById('editor'),
22
+ * url: 'http://127.0.0.1:9090', // 通过 url 参数传入实际地址
23
+ * })
24
+ *
25
+ * // 初始化 (DOM 就绪后)
26
+ * editor.init(lfInstance)
27
+ *
28
+ * // 加载规则链数据
29
+ * editor.loadData(ruleChainData)
30
+ *
31
+ * // 导出数据
32
+ * const data = editor.exportData(lfGraphData, getNodeModelById)
33
+ *
34
+ * // 监听事件
35
+ * editor.on('node:click', (data) => { ... })
36
+ *
37
+ * // 销毁
38
+ * editor.destroy()
39
+ * ```
40
+ *
41
+ * 使用方式 (Vue 适配层):
42
+ * ```typescript
43
+ * // 在 @huanban/editor-vue 的 composable 中
44
+ * import { EditorCore } from '@huanban/rulego-editor-core'
45
+ *
46
+ * export function useEditorCore(options) {
47
+ * const core = new EditorCore(options)
48
+ * // 将 core.store 桥接到 Vue 的 reactive/ref
49
+ * // 将 core.eventBus 桥接到 Vue 的 emit
50
+ * return core
51
+ * }
52
+ * ```
53
+ *
54
+ * @see StateStore 状态管理
55
+ * @see EventBus 事件总线
56
+ * @see ComponentRegistry 组件注册表
57
+ * @see DataAdapter 数据格式转换
58
+ * @see HistoryManager 撤销/重做
59
+ * @see ValidationEngine 图验证
60
+ * @see ThemeManager 主题管理
61
+ * @see I18nManager 国际化
62
+ *
63
+ * @see 原版 RuleGoEditor.vue — 所有 initLf / save / deleteSelects 逻辑的来源
64
+ */
65
+ import { StateStore } from './StateStore';
66
+ import { EventBus } from './EventBus';
67
+ import { DataAdapter } from './DataAdapter';
68
+ import type { LFGraphData, LFNodeData } from './DataAdapter';
69
+ import { ComponentRegistry } from './ComponentRegistry';
70
+ import { HistoryManager } from './HistoryManager';
71
+ import { ValidationEngine } from './ValidationEngine';
72
+ import { ThemeManager } from './ThemeManager';
73
+ import { I18nManager } from './I18nManager';
74
+ import type { EditorOptions, EditorInternalData, EditorPlugin } from '../types/editor';
75
+ import type { EditorEventMap, EditorEventName } from '../types/events';
76
+ import type { RuleChainData, RuleChainConfig, RuleNodeConfig, RuleConnectionConfig } from '../types/rule-chain';
77
+ import type { ComponentDefinition, ComponentGroup } from '../types/component';
78
+ /**
79
+ * 编辑器内部使用的状态结构
80
+ *
81
+ * 使用 Record<string, unknown> 兼容的形式,
82
+ * 区别于 types/editor.ts 中严格的 EditorState 接口。
83
+ * 严格类型由框架适配层在包装时保证。
84
+ */
85
+ interface CoreState extends Record<string, unknown> {
86
+ /** 编辑器是否已就绪 */
87
+ isReady: boolean;
88
+ /** 数据是否已修改 (有未保存的更改) */
89
+ isDirty: boolean;
90
+ /** 是否正在加载 */
91
+ isLoading: boolean;
92
+ /** 当前选中的节点数据 */
93
+ selectedNode: RuleNodeConfig | null;
94
+ /** 当前选中的边数据 */
95
+ selectedEdge: RuleConnectionConfig | null;
96
+ /** 规则链配置 */
97
+ ruleChain: RuleChainConfig | null;
98
+ /** 组件注册表 (type => definition 映射) */
99
+ nodeComponents: Record<string, ComponentDefinition>;
100
+ /** 按分类分组的组件列表 */
101
+ componentGroups: ComponentGroup[];
102
+ /** 当前正在编辑的节点视图定义 */
103
+ currentNodeView: ComponentDefinition | null;
104
+ /** 当前正在编辑的节点配置数据 */
105
+ currentNodeModel: Record<string, unknown>;
106
+ /** 当前正在编辑的边配置数据 */
107
+ currentEdgeModel: Record<string, unknown>;
108
+ /** 是否可以撤销 */
109
+ canUndo: boolean;
110
+ /** 是否可以重做 */
111
+ canRedo: boolean;
112
+ }
113
+ /**
114
+ * 编辑器核心引擎
115
+ *
116
+ * 生命周期:
117
+ * 1. constructor — 创建所有子系统
118
+ * 2. init() — 初始化 LogicFlow, 加载组件, 注册事件
119
+ * 3. loadData() — 加载规则链数据并渲染
120
+ * 4. exportData() — 从画布导出数据
121
+ * 5. destroy() — 销毁所有资源
122
+ */
123
+ export declare class EditorCore {
124
+ /** 状态容器 — 编辑器的全局状态 */
125
+ readonly store: StateStore<CoreState>;
126
+ /** 事件总线 — 编辑器级别的事件 */
127
+ readonly eventBus: EventBus;
128
+ /** 数据适配器 — RuleGo JSON ↔ LogicFlow 格式转换 */
129
+ readonly dataAdapter: DataAdapter;
130
+ /** 组件注册表 — 管理可用的节点组件 */
131
+ readonly componentRegistry: ComponentRegistry;
132
+ /** 历史管理器 — 撤销/重做 */
133
+ readonly history: HistoryManager;
134
+ /** 验证引擎 — 图合法性检查 */
135
+ readonly validation: ValidationEngine;
136
+ /** 主题管理器 — 多主题切换 */
137
+ readonly theme: ThemeManager;
138
+ /** 国际化 — 多语言支持 */
139
+ readonly i18n: I18nManager;
140
+ /** 编辑器配置选项 */
141
+ private options;
142
+ /** 内部运行时数据 (计数器、常量配置等) */
143
+ private internalData;
144
+ /** LogicFlow 实例引用 (由外部传入或在 init 时创建) */
145
+ private lfInstance;
146
+ /** 已安装的插件列表 */
147
+ private plugins;
148
+ /** 是否已初始化 */
149
+ private initialized;
150
+ /**
151
+ * 创建编辑器核心实例
152
+ *
153
+ * @param options - 编辑器配置选项
154
+ * @see EditorOptions 完整的配置说明
155
+ */
156
+ constructor(options: EditorOptions);
157
+ /**
158
+ * 初始化编辑器
159
+ *
160
+ * 这个方法在 DOM 容器准备好之后调用 (框架适配层的 mounted/useEffect 中)。
161
+ * 它负责:
162
+ * 1. 保存 LogicFlow 实例引用
163
+ * 2. 应用初始主题
164
+ * 3. 通知插件
165
+ * 4. 触发 editor:ready 事件
166
+ *
167
+ * @param lfInstance - 外部创建的 LogicFlow 实例 (可选)
168
+ */
169
+ init(lfInstance?: unknown): void;
170
+ /**
171
+ * 销毁编辑器, 释放所有资源
172
+ *
173
+ * 必须在组件卸载时调用 (框架适配层的 unmounted/useEffect cleanup 中)
174
+ */
175
+ destroy(): void;
176
+ /**
177
+ * 加载规则链数据并渲染到画布
178
+ *
179
+ * 转换流程:
180
+ * RuleChainData → DataAdapter.adapterIn → LogicFlow.render
181
+ *
182
+ * @param ruleChainData - RuleGo 规则链 JSON 数据
183
+ * @see DataAdapter.adapterIn 数据转换详情
184
+ */
185
+ loadData(ruleChainData: RuleChainData): void;
186
+ /**
187
+ * 从画布导出 RuleGo 格式数据 (用于保存)
188
+ *
189
+ * 转换流程:
190
+ * LogicFlow.getGraphData → DataAdapter.adapterOut → RuleChainData
191
+ *
192
+ * @param lfGraphData - LogicFlow 当前图数据
193
+ * @param getNodeModelById - LogicFlow 节点查询函数
194
+ * @returns RuleGo 格式的规则链数据
195
+ * @see DataAdapter.adapterOut 数据转换详情
196
+ */
197
+ exportData(lfGraphData: LFGraphData, getNodeModelById: (id: string) => LFNodeData | null): RuleChainData;
198
+ /**
199
+ * 验证当前图数据
200
+ *
201
+ * @param lfGraphData - LogicFlow 当前图数据
202
+ * @returns 验证结果
203
+ * @see ValidationEngine.validate
204
+ */
205
+ validateGraph(lfGraphData: LFGraphData): import("./ValidationEngine").ValidationResult;
206
+ /**
207
+ * 监听编辑器事件
208
+ *
209
+ * @param event - 事件名
210
+ * @param handler - 事件处理函数
211
+ * @returns 取消监听函数
212
+ * @see EditorEventMap 所有可监听事件及其载荷类型
213
+ */
214
+ on<K extends EditorEventName>(event: K, handler: (payload: EditorEventMap[K]) => void): () => void;
215
+ /**
216
+ * 触发编辑器事件
217
+ *
218
+ * @param event - 事件名
219
+ * @param args - 事件载荷
220
+ */
221
+ emit<K extends EditorEventName>(event: K, ...args: EditorEventMap[K] extends void ? [] : [EditorEventMap[K]]): void;
222
+ /**
223
+ * 安装插件
224
+ *
225
+ * 插件可以在编辑器生命周期的各个阶段注入自定义逻辑:
226
+ * - onInit: 编辑器初始化后
227
+ * - beforeDataLoad: 数据加载前 (可修改数据)
228
+ * - beforeDataSave: 数据保存前 (可修改数据)
229
+ * - onDestroy: 编辑器销毁前
230
+ *
231
+ * @param plugin - 插件实例
232
+ * @see EditorPlugin 插件接口
233
+ */
234
+ use(plugin: EditorPlugin): void;
235
+ /**
236
+ * 获取内部运行时数据 (只读)
237
+ * 主要供 DataAdapter 和框架适配层使用
238
+ */
239
+ getInternalData(): Readonly<EditorInternalData>;
240
+ /**
241
+ * 获取 LogicFlow 实例引用
242
+ * 供框架适配层在需要直接操作 LogicFlow 时使用
243
+ */
244
+ getLfInstance(): unknown;
245
+ /**
246
+ * 获取编辑器配置选项
247
+ */
248
+ getOptions(): Readonly<EditorOptions>;
249
+ }
250
+ export {};
251
+ //# sourceMappingURL=EditorCore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorCore.d.ts","sourceRoot":"","sources":["../../src/core/EditorCore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @file EventBus.ts
3
+ * @description 类型安全的事件总线
4
+ *
5
+ * 基于 EditorEventMap 提供强类型的事件发布/订阅。
6
+ * 与 LogicFlow 的 eventCenter 分工:
7
+ * - LogicFlow eventCenter: 处理画布级别的原生事件 (node:click, edge:add 等)
8
+ * - EventBus: 处理编辑器业务级别的事件 (editor:save, history:change 等)
9
+ *
10
+ * 特性:
11
+ * - 强类型: 事件名和负载类型在编译期绑定
12
+ * - 一次性监听: once() 方法只触发一次
13
+ * - 安全清理: destroy() 清除所有监听器
14
+ * - 调试模式: 可选事件追踪日志
15
+ */
16
+ import type { EditorEventMap, EditorEventName } from '../types/events';
17
+ /**
18
+ * 事件监听器函数类型
19
+ */
20
+ type Listener<T> = (payload: T) => void;
21
+ /**
22
+ * 类型安全的事件总线
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const bus = new EventBus()
27
+ *
28
+ * // 订阅事件 (有类型提示)
29
+ * bus.on('node:click', (payload) => {
30
+ * // payload 的类型自动推断为 NodeEventPayload
31
+ * console.log(payload.id, payload.type)
32
+ * })
33
+ *
34
+ * // 触发事件
35
+ * bus.emit('node:click', { id: 'node_1', type: 'simple-node', ... })
36
+ *
37
+ * // 取消订阅
38
+ * const off = bus.on('editor:save', handler)
39
+ * off() // 取消
40
+ * ```
41
+ */
42
+ export declare class EventBus {
43
+ /** 事件监听器映射: 事件名 => 监听器列表 */
44
+ private listeners;
45
+ /** 是否启用调试模式 */
46
+ private debug;
47
+ /**
48
+ * 创建事件总线
49
+ * @param debug - 是否启用调试日志 (默认: false)
50
+ */
51
+ constructor(debug?: boolean);
52
+ /**
53
+ * 订阅事件
54
+ *
55
+ * @param event - 事件名称
56
+ * @param callback - 事件回调函数
57
+ * @returns 取消订阅的函数
58
+ */
59
+ on<E extends EditorEventName>(event: E, callback: Listener<EditorEventMap[E]>): () => void;
60
+ /**
61
+ * 一次性订阅事件 (只触发一次后自动取消)
62
+ *
63
+ * @param event - 事件名称
64
+ * @param callback - 事件回调函数
65
+ * @returns 取消订阅的函数
66
+ */
67
+ once<E extends EditorEventName>(event: E, callback: Listener<EditorEventMap[E]>): () => void;
68
+ /**
69
+ * 取消订阅事件
70
+ *
71
+ * @param event - 事件名称
72
+ * @param callback - 要移除的回调函数
73
+ */
74
+ off<E extends EditorEventName>(event: E, callback: Listener<EditorEventMap[E]>): void;
75
+ /**
76
+ * 触发事件,通知所有订阅者
77
+ *
78
+ * @param event - 事件名称
79
+ * @param payload - 事件负载数据
80
+ */
81
+ emit<E extends EditorEventName>(event: E, ...args: EditorEventMap[E] extends void ? [] : [EditorEventMap[E]]): void;
82
+ /**
83
+ * 移除指定事件的所有监听器
84
+ *
85
+ * @param event - 事件名称 (不传则移除所有事件的监听器)
86
+ */
87
+ removeAll(event?: EditorEventName): void;
88
+ /**
89
+ * 获取指定事件的监听器数量 (用于调试)
90
+ *
91
+ * @param event - 事件名称
92
+ * @returns 监听器数量
93
+ */
94
+ listenerCount(event: EditorEventName): number;
95
+ /**
96
+ * 销毁事件总线, 清除所有监听器
97
+ */
98
+ destroy(): void;
99
+ }
100
+ export {};
101
+ //# sourceMappingURL=EventBus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventBus.d.ts","sourceRoot":"","sources":["../../src/core/EventBus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtE;;GAEG;AACH,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;AAYvC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,QAAQ;IACnB,4BAA4B;IAC5B,OAAO,CAAC,SAAS,CAAmD;IACpE,eAAe;IACf,OAAO,CAAC,KAAK,CAAS;IAEtB;;;OAGG;gBACS,KAAK,UAAQ;IAIzB;;;;;;OAMG;IACH,EAAE,CAAC,CAAC,SAAS,eAAe,EAC1B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GACpC,MAAM,IAAI;IAiBb;;;;;;OAMG;IACH,IAAI,CAAC,CAAC,SAAS,eAAe,EAC5B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GACpC,MAAM,IAAI;IAgBb;;;;;OAKG;IACH,GAAG,CAAC,CAAC,SAAS,eAAe,EAC3B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GACpC,IAAI;IAiBP;;;;;OAKG;IACH,IAAI,CAAC,CAAC,SAAS,eAAe,EAC5B,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GACjE,IAAI;IA0CP;;;;OAIG;IACH,SAAS,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI;IAQxC;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAI7C;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}