triggerix-editor-preset-war3 0.0.5 → 0.0.7
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 +351 -0
- package/dist/index.cjs +119 -119
- package/dist/index.d.cts +46 -46
- package/dist/index.d.mts +46 -46
- package/dist/index.d.ts +46 -46
- package/dist/index.mjs +119 -119
- package/package.json +10 -7
package/README.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# triggerix-editor-preset-war3
|
|
2
|
+
|
|
3
|
+
> **War3-style template editor preset for [Triggerix](https://github.com/triggerix-collective)**
|
|
4
|
+
>
|
|
5
|
+
> 为 Triggerix 提供的「魔兽争霸 III 触发器」风格编辑器预设 —— 用模板字符串 + 槽位的方式声明 Event / Condition / Action,并最终序列化为标准 Trigger JSON。
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/triggerix-editor-preset-war3)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
|
|
11
|
+
## 特性
|
|
12
|
+
|
|
13
|
+
- 🎯 **模板驱动**:用 `"${unit} 发动技能效果"` 这样的自然语言模板声明触发器节点
|
|
14
|
+
- 🧩 **嵌套复合工具 (Composite Tool)**:Tool 可以由其他 Tool 组合,槽位无限嵌套
|
|
15
|
+
- 🪝 **类型安全工厂**:`defineLeafTool` / `defineCompositeTool` / `defineCondition` 提供完整类型推断
|
|
16
|
+
- 🔌 **可插拔预设**:`defineWar3Preset` 一键注入 Event/Action/Condition/Tool 集合
|
|
17
|
+
- 📤 **标准输出**:`toTrigger()` 直接产出 `@triggerix/core` 兼容的 Trigger JSON
|
|
18
|
+
- 🔍 **值来源查询**:`getValueSources(type)` 过滤同类型 Condition / Tool,作为槽位候选项
|
|
19
|
+
- 🪶 **零依赖运行**:仅依赖 `@triggerix/core` 与 `@triggerix/editor`
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add triggerix-editor-preset-war3 @triggerix/core @triggerix/editor
|
|
25
|
+
# 或
|
|
26
|
+
npm install triggerix-editor-preset-war3 @triggerix/core @triggerix/editor
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> 运行时需要 `crypto.randomUUID`(Node 18+ / 现代浏览器);不支持时会回退到基于时间戳的 ID。
|
|
30
|
+
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
createWar3Editor,
|
|
36
|
+
defineCondition,
|
|
37
|
+
defineLeafTool,
|
|
38
|
+
defineWar3Preset
|
|
39
|
+
} from 'triggerix-editor-preset-war3'
|
|
40
|
+
|
|
41
|
+
// 1. 定义工具 (槽位填充器)
|
|
42
|
+
const elementTool = defineLeafTool<string, string>({
|
|
43
|
+
type: 'element',
|
|
44
|
+
label: '元素',
|
|
45
|
+
input: {
|
|
46
|
+
type: 'select',
|
|
47
|
+
options: [
|
|
48
|
+
{ value: '#submit-btn', label: '提交按钮' },
|
|
49
|
+
{ value: '#search-input', label: '搜索框' }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
resolve: v => v
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const eventNameTool = defineLeafTool<string, string>({
|
|
56
|
+
type: 'event-name',
|
|
57
|
+
label: '事件名',
|
|
58
|
+
input: { type: 'text', placeholder: '如 submit-success' },
|
|
59
|
+
resolve: v => v
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const booleanTool = defineLeafTool<boolean, boolean>({
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
label: '开关',
|
|
65
|
+
input: {
|
|
66
|
+
type: 'select',
|
|
67
|
+
options: [
|
|
68
|
+
{ value: true, label: '启用' },
|
|
69
|
+
{ value: false, label: '禁用' }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
resolve: v => v
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// 2. 定义 Condition
|
|
76
|
+
const elementVisible = defineCondition<{ element: string }>({
|
|
77
|
+
id: 'element-visible',
|
|
78
|
+
label: '元素可见',
|
|
79
|
+
template: '${element} 当前可见',
|
|
80
|
+
slots: {
|
|
81
|
+
element: { label: '元素', tools: ['element'] }
|
|
82
|
+
},
|
|
83
|
+
resolve: ({ element }) => ({ element })
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// 3. 定义 Event / Action(结构与 Condition 类似,继承 BaseItemDef)
|
|
87
|
+
// ...
|
|
88
|
+
|
|
89
|
+
// 4. 打包成 Preset
|
|
90
|
+
const preset = defineWar3Preset({
|
|
91
|
+
name: 'my-web-app',
|
|
92
|
+
events: [/* War3EventDef[] */],
|
|
93
|
+
actions: [/* War3ActionDef[] */],
|
|
94
|
+
conditions: [elementVisible],
|
|
95
|
+
tools: {
|
|
96
|
+
element: elementTool,
|
|
97
|
+
'event-name': eventNameTool,
|
|
98
|
+
boolean: booleanTool
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// 5. 创建编辑器并应用 Preset
|
|
103
|
+
const editor = createWar3Editor()
|
|
104
|
+
editor.applyPreset(preset)
|
|
105
|
+
|
|
106
|
+
// 6. 改变状态:监听 #submit-btn 点击后派发 submit-success
|
|
107
|
+
editor.setEvent('element-click')
|
|
108
|
+
editor.addCondition('element-visible')
|
|
109
|
+
editor.setConditionSlot(0, 'element', { tool: 'element', value: '#submit-btn' })
|
|
110
|
+
|
|
111
|
+
editor.addAction('emit-event')
|
|
112
|
+
editor.setActionSlot(0, 'element', { tool: 'element', value: '#submit-btn' })
|
|
113
|
+
editor.setActionSlot(0, 'event', { tool: 'event-name', value: 'submit-success' })
|
|
114
|
+
|
|
115
|
+
// 7. 输出标准 Trigger
|
|
116
|
+
const trigger = editor.toTrigger()
|
|
117
|
+
console.log(JSON.stringify(trigger, null, 2))
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 核心概念
|
|
121
|
+
|
|
122
|
+
| 概念 | 含义 |
|
|
123
|
+
|---|---|
|
|
124
|
+
| **Trigger** | 一条完整的触发器:`{ event, conditions?, actions[] }`,即 `toTrigger()` 的输出 |
|
|
125
|
+
| **Template** | 模板字符串,如 `"${element} 被点击时,发送 ${eventName} 事件"`,`${key}` 为槽位 |
|
|
126
|
+
| **Slot (槽位)** | 模板中的可替换位置,由 `SlotDef` 声明(label + 允许填入的 tool 列表) |
|
|
127
|
+
| **Tool (工具)** | 槽位的填充器;分 `LeafTool`(单值输入)和 `CompositeTool`(由其他 Tool 嵌套) |
|
|
128
|
+
| **Leaf Tool Input** | `text` / `number` / `select`(`select` 携带 `options: { value, label }[]`) |
|
|
129
|
+
| **Segment** | 模板解析后的最小单元:`{ type: 'text', content }` 或 `{ type: 'slot', key, label, tools, value, entry }` |
|
|
130
|
+
| **Item State** | 编辑器运行时状态:`{ id, slotValues: Record<key, SlotValueEntry> }` |
|
|
131
|
+
| **Descriptor** | UI 渲染用:把 Item/Template 解析为 `Segment[]`,附加 `SlotValueEntry` 上下文 |
|
|
132
|
+
| **Value Source** | 同类型的 Condition + Tool 集合,可作为另一个槽位的可选值来源 |
|
|
133
|
+
|
|
134
|
+
### 数据流
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
定义侧 (开发者) 运行侧 (编辑器)
|
|
138
|
+
───────────────── ─────────────────
|
|
139
|
+
War3EventDef / War3ActionDef / editor.applyPreset(preset)
|
|
140
|
+
War3ConditionDef / ToolDef │
|
|
141
|
+
│ ▼
|
|
142
|
+
└── defineWar3Preset ──▶ Preset War3Registry
|
|
143
|
+
│
|
|
144
|
+
状态操作 │ setEvent / addAction / ...
|
|
145
|
+
▼
|
|
146
|
+
War3EditorStateManager
|
|
147
|
+
│
|
|
148
|
+
┌─────────────────────────┼─────────────────────────┐
|
|
149
|
+
▼ ▼ ▼
|
|
150
|
+
parseTemplate resolveSlotDisplayText toTrigger
|
|
151
|
+
(→ ItemDescriptor) (→ 人类可读展示文本) (→ Trigger JSON)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## API 概览
|
|
155
|
+
|
|
156
|
+
### 工厂与预设
|
|
157
|
+
|
|
158
|
+
| 导出 | 说明 |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `createWar3Editor()` | 创建 `War3Editor` 实例(`Editor<War3EditorState>`) |
|
|
161
|
+
| `defineWar3Preset(options)` | 打包为 `Preset<War3Editor>`,批量注册 events / actions / conditions / tools |
|
|
162
|
+
| `defineLeafTool(def)` | 类型安全的叶子工具工厂 |
|
|
163
|
+
| `defineCompositeTool(def)` | 类型安全的复合工具工厂(槽位值类型从 `resolve` 推断) |
|
|
164
|
+
| `defineCondition(def)` | 类型安全的 Condition 工厂 |
|
|
165
|
+
|
|
166
|
+
### `War3Editor` 方法
|
|
167
|
+
|
|
168
|
+
- **注册**:`registerEvent` / `registerAction` / `registerCondition` / `registerTool`
|
|
169
|
+
- **查询**:`getAvailableEvents` / `getAvailableActions` / `getAvailableConditions`
|
|
170
|
+
- **描述符**:`getEventDescriptor` / `getActionDescriptor(index)` / `getConditionDescriptor(index)` / `getToolDescriptor(name, slotValues?)` / `getSlotTools(slotDef)`
|
|
171
|
+
- **状态操作**:
|
|
172
|
+
- Event:`setEvent` / `clearEvent` / `setEventSlot`
|
|
173
|
+
- Action:`addAction` / `removeAction` / `moveAction` / `setActionSlot`
|
|
174
|
+
- Condition:`addCondition` / `removeCondition` / `setConditionSlot`
|
|
175
|
+
- **值来源**:`getValueSources(valueType?)` 返回 `{ conditions, tools }`
|
|
176
|
+
- **生命周期**:`getState` / `onChange` / `reset` / `dispose`
|
|
177
|
+
- **序列化**:`toTrigger(triggerId?)` 输出标准 Trigger;`resolveSlotValue(entry)` 解析单个槽位
|
|
178
|
+
|
|
179
|
+
### 独立函数
|
|
180
|
+
|
|
181
|
+
| 导出 | 说明 |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `parseTemplate(template, slots?, slotValues?)` | 模板 → `Segment[]` |
|
|
184
|
+
| `resolveSlotDisplayText(entry, registry, fallbackLabel)` | `SlotValueEntry` → 可读文本 |
|
|
185
|
+
| `resolveSlotValue(entry, registry)` | `SlotValueEntry` → `Value`(递归) |
|
|
186
|
+
| `getEventDescriptor` / `getActionDescriptor` / `getConditionDescriptor` / `getToolDescriptor` / `getSlotToolDescriptors` | 不走 Editor 的纯函数版本(直接接收 `War3Registry`) |
|
|
187
|
+
|
|
188
|
+
### `toTrigger` 输出结构
|
|
189
|
+
|
|
190
|
+
与 `@triggerix/core` 完全兼容:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
{
|
|
194
|
+
id: string, // 默认 crypto.randomUUID(),可外部传入
|
|
195
|
+
event: { type: string, payload?: Record<string, Value> },
|
|
196
|
+
conditions?: { type: 'and', conditions: Action[] }, // 仅当 conditions 非空时存在
|
|
197
|
+
actions: Action[] // [{ type, params? }]
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
> 注:编辑期 Condition 在内部以 `Action` 形式(`{ type, params }`)存储,序列化为 `and` 分组;Condition ↔ Action 的语义映射由运行时层完成。
|
|
202
|
+
|
|
203
|
+
## 模块结构
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
src/
|
|
207
|
+
├── index.ts # 统一入口
|
|
208
|
+
├── types.ts # 所有类型定义
|
|
209
|
+
├── createWar3Editor.ts # 工厂函数:组装 Registry + State + Serializer
|
|
210
|
+
├── preset.ts # defineWar3Preset → Preset<War3Editor>
|
|
211
|
+
├── registry.ts # War3Registry(继承 BaseRegistry + Tool)
|
|
212
|
+
├── state.ts # War3EditorStateManager(继承 ObservableState)
|
|
213
|
+
├── parser.ts # 模板字符串 → Segment[]
|
|
214
|
+
├── descriptor.ts # Item/Template → ItemDescriptor / ToolDescriptor
|
|
215
|
+
├── display.ts # SlotValueEntry → 人类可读展示文本
|
|
216
|
+
├── serializer.ts # War3EditorState → Trigger JSON
|
|
217
|
+
└── helpers.ts # defineLeafTool / defineCompositeTool / defineCondition
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## 模板系统详解
|
|
221
|
+
|
|
222
|
+
### 模板字符串
|
|
223
|
+
|
|
224
|
+
模板中以 `${key}` 标记槽位,`key` 须为 `SlotDef` 中声明的键:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
{
|
|
228
|
+
id: 'element-focus',
|
|
229
|
+
label: '元素获得焦点',
|
|
230
|
+
template: '${element} 获得焦点时,切换为 ${state}',
|
|
231
|
+
slots: {
|
|
232
|
+
element: { label: '元素', tools: ['element'] },
|
|
233
|
+
state: { label: '状态', tools: ['boolean'] }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
解析后 `Segment[]`:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
[
|
|
242
|
+
{ type: 'slot', key: 'element', label: '元素', tools: ['element'], value: ..., entry: ... },
|
|
243
|
+
{ type: 'text', content: ' 获得焦点时,切换为 ' },
|
|
244
|
+
{ type: 'slot', key: 'state', label: '状态', tools: ['boolean'], value: ..., entry: ... }
|
|
245
|
+
]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
> **未知 `${key}`**:未在 `slots` 中声明的占位符将作为普通文本保留(不抛错),便于迁移期兼容。
|
|
249
|
+
|
|
250
|
+
### Leaf Tool
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
defineLeafTool<boolean, boolean>({
|
|
254
|
+
type: 'boolean', // 语义类型(用于 getValueSources 过滤)
|
|
255
|
+
label: '开关',
|
|
256
|
+
input: {
|
|
257
|
+
type: 'select',
|
|
258
|
+
options: [{ value: true, label: '启用' }]
|
|
259
|
+
},
|
|
260
|
+
resolve: v => v // 序列化为 Trigger.params 时的最终值
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
`resolve` 接收 `input` 类型,返回**最终写入 `params`** 的值(可做单位换算、字符串映射等)。
|
|
265
|
+
|
|
266
|
+
### Composite Tool
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
const emitEventTool = defineCompositeTool<
|
|
270
|
+
{ element: string, event: string },
|
|
271
|
+
{ target: string, type: string }
|
|
272
|
+
>({
|
|
273
|
+
type: 'emit-event',
|
|
274
|
+
label: '发送事件',
|
|
275
|
+
template: '从 ${element} 派发 ${event}',
|
|
276
|
+
slots: {
|
|
277
|
+
element: { label: '元素', tools: ['element'] },
|
|
278
|
+
event: { label: '事件名', tools: ['event-name'] }
|
|
279
|
+
},
|
|
280
|
+
resolve: ({ element, event }) => ({ target: element, type: event })
|
|
281
|
+
})
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- 槽位键 `source` / `target` 会从 `resolve` 参数中推断,保证 `slots` 键与 `resolve` 参数键一致
|
|
285
|
+
- Composite 可无限嵌套(一个 Composite 的槽位可以填入另一个 Composite)
|
|
286
|
+
|
|
287
|
+
## 编辑器状态形状
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
interface War3EditorState {
|
|
291
|
+
event: ItemState | null // 单一事件
|
|
292
|
+
conditions: ItemState[] // 条件列表(AND 语义)
|
|
293
|
+
actions: ItemState[] // 动作列表(顺序敏感)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
interface ItemState {
|
|
297
|
+
id: string // 对应 War3EventDef/Action/Condition 的 id
|
|
298
|
+
slotValues: Record<string, SlotValueEntry> // 各槽位填充值
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
interface SlotValueEntry {
|
|
302
|
+
tool: string | null // 选中的 tool 名
|
|
303
|
+
value: unknown // leaf: 原值; composite: 通常为空对象
|
|
304
|
+
subSlots?: Record<string, SlotValueEntry> // composite 递归结构
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## 监听变化
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
const editor = createWar3Editor()
|
|
312
|
+
const off = editor.onChange((state) => {
|
|
313
|
+
// 触发时机:setEvent / addAction / setActionSlot / reset ...
|
|
314
|
+
console.log('state changed:', state)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
off() // 取消订阅
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
`onChange` 返回的解绑函数也可以在 `dispose()` 后自动失效。
|
|
321
|
+
|
|
322
|
+
## 开发
|
|
323
|
+
|
|
324
|
+
### 命令
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
pnpm install # 安装依赖
|
|
328
|
+
pnpm dev # 监听构建(生成 stub 供本地调试)
|
|
329
|
+
pnpm build # 产出 dist/{index.mjs,index.cjs,index.d.ts}
|
|
330
|
+
pnpm typecheck # tsc --noEmit
|
|
331
|
+
pnpm lint # eslint --cache
|
|
332
|
+
pnpm release # bumpp 交互式升级版本号并打 tag
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### 构建产物
|
|
336
|
+
|
|
337
|
+
- ESM: `dist/index.mjs`
|
|
338
|
+
- CJS: `dist/index.cjs`
|
|
339
|
+
- 类型: `dist/index.d.ts`
|
|
340
|
+
|
|
341
|
+
由 [unbuild](https://github.com/unjs/unbuild) 打包,`@triggerix/core` 与 `@triggerix/editor` 标记为 external。
|
|
342
|
+
|
|
343
|
+
### 质量保障
|
|
344
|
+
|
|
345
|
+
- TypeScript `strict: true` + `declaration: true`
|
|
346
|
+
- ESLint (`@antfu/eslint-config`) + pre-commit (simple-git-hooks + nano-staged)
|
|
347
|
+
- 发布:推送 `v*` tag → GitHub Actions 自动 `changelogithub` + `pnpm publish`
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
[MIT](./LICENSE) © Triggerix Collective
|
package/dist/index.cjs
CHANGED
|
@@ -34,47 +34,6 @@ function parseTemplate(template, slots, slotValues) {
|
|
|
34
34
|
return segments;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function buildDescriptor(def, slotValues) {
|
|
38
|
-
return {
|
|
39
|
-
id: def.id,
|
|
40
|
-
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function getEventDescriptor(registry, id, slotValues) {
|
|
44
|
-
const def = registry.getEvent(id);
|
|
45
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
46
|
-
}
|
|
47
|
-
function getActionDescriptor(registry, id, slotValues) {
|
|
48
|
-
const def = registry.getAction(id);
|
|
49
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
50
|
-
}
|
|
51
|
-
function getConditionDescriptor(registry, id, slotValues) {
|
|
52
|
-
const def = registry.getCondition(id);
|
|
53
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
54
|
-
}
|
|
55
|
-
function getToolDescriptor(registry, toolName, slotValues) {
|
|
56
|
-
const def = registry.getTool(toolName);
|
|
57
|
-
if (!def)
|
|
58
|
-
return null;
|
|
59
|
-
if (def.kind === "leaf") {
|
|
60
|
-
return {
|
|
61
|
-
kind: "leaf",
|
|
62
|
-
name: toolName,
|
|
63
|
-
label: def.label,
|
|
64
|
-
input: def.input
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
kind: "composite",
|
|
69
|
-
name: toolName,
|
|
70
|
-
label: def.label,
|
|
71
|
-
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function getSlotToolDescriptors(registry, slotDef) {
|
|
75
|
-
return slotDef.tools.map((name) => getToolDescriptor(registry, name)).filter((d) => d !== null);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
37
|
class War3Registry extends editor.BaseRegistry {
|
|
79
38
|
tools = /* @__PURE__ */ new Map();
|
|
80
39
|
registerTool(name, def) {
|
|
@@ -97,72 +56,6 @@ class War3Registry extends editor.BaseRegistry {
|
|
|
97
56
|
}
|
|
98
57
|
}
|
|
99
58
|
|
|
100
|
-
function resolveSlotValue(entry, registry) {
|
|
101
|
-
if (!entry.tool)
|
|
102
|
-
return void 0;
|
|
103
|
-
const toolDef = registry.getTool(entry.tool);
|
|
104
|
-
if (!toolDef)
|
|
105
|
-
return void 0;
|
|
106
|
-
if (toolDef.kind === "leaf") {
|
|
107
|
-
return toolDef.resolve(entry.value);
|
|
108
|
-
}
|
|
109
|
-
const resolvedSubSlots = {};
|
|
110
|
-
if (entry.subSlots) {
|
|
111
|
-
for (const [key, subEntry] of Object.entries(entry.subSlots)) {
|
|
112
|
-
resolvedSubSlots[key] = resolveSlotValue(subEntry, registry);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return toolDef.resolve(resolvedSubSlots);
|
|
116
|
-
}
|
|
117
|
-
function resolveItemParams(slotValues, registry) {
|
|
118
|
-
const params = {};
|
|
119
|
-
let hasParams = false;
|
|
120
|
-
for (const [key, entry] of Object.entries(slotValues)) {
|
|
121
|
-
const resolved = resolveSlotValue(entry, registry);
|
|
122
|
-
if (resolved !== void 0) {
|
|
123
|
-
params[key] = resolved;
|
|
124
|
-
hasParams = true;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return hasParams ? params : void 0;
|
|
128
|
-
}
|
|
129
|
-
function serializeItems(items, registry) {
|
|
130
|
-
return items.map((item) => {
|
|
131
|
-
const params = resolveItemParams(item.slotValues, registry);
|
|
132
|
-
const action = { type: item.id };
|
|
133
|
-
if (params) {
|
|
134
|
-
action.params = params;
|
|
135
|
-
}
|
|
136
|
-
return action;
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
function generateRuleId() {
|
|
140
|
-
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
141
|
-
return globalThis.crypto.randomUUID();
|
|
142
|
-
}
|
|
143
|
-
return `rule-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
144
|
-
}
|
|
145
|
-
function toRule(state, registry, ruleId) {
|
|
146
|
-
const eventParams = state.event ? resolveItemParams(state.event.slotValues, registry) : void 0;
|
|
147
|
-
const event = {
|
|
148
|
-
type: state.event?.id ?? "",
|
|
149
|
-
...eventParams ? { payload: eventParams } : {}
|
|
150
|
-
};
|
|
151
|
-
const actions = serializeItems(state.actions, registry);
|
|
152
|
-
const rule = {
|
|
153
|
-
id: ruleId ?? generateRuleId(),
|
|
154
|
-
event,
|
|
155
|
-
actions
|
|
156
|
-
};
|
|
157
|
-
if (state.conditions.length > 0) {
|
|
158
|
-
rule.conditions = {
|
|
159
|
-
type: "and",
|
|
160
|
-
conditions: serializeItems(state.conditions, registry)
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
return rule;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
59
|
const INITIAL_STATE = {
|
|
167
60
|
event: null,
|
|
168
61
|
conditions: [],
|
|
@@ -249,6 +142,113 @@ class War3EditorStateManager extends editor.ObservableState {
|
|
|
249
142
|
}
|
|
250
143
|
}
|
|
251
144
|
|
|
145
|
+
function buildDescriptor(def, slotValues) {
|
|
146
|
+
return {
|
|
147
|
+
id: def.id,
|
|
148
|
+
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function getEventDescriptor(registry, id, slotValues) {
|
|
152
|
+
const def = registry.getEvent(id);
|
|
153
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
154
|
+
}
|
|
155
|
+
function getActionDescriptor(registry, id, slotValues) {
|
|
156
|
+
const def = registry.getAction(id);
|
|
157
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
158
|
+
}
|
|
159
|
+
function getConditionDescriptor(registry, id, slotValues) {
|
|
160
|
+
const def = registry.getCondition(id);
|
|
161
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
162
|
+
}
|
|
163
|
+
function getToolDescriptor(registry, toolName, slotValues) {
|
|
164
|
+
const def = registry.getTool(toolName);
|
|
165
|
+
if (!def)
|
|
166
|
+
return null;
|
|
167
|
+
if (def.kind === "leaf") {
|
|
168
|
+
return {
|
|
169
|
+
kind: "leaf",
|
|
170
|
+
name: toolName,
|
|
171
|
+
label: def.label,
|
|
172
|
+
input: def.input
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
kind: "composite",
|
|
177
|
+
name: toolName,
|
|
178
|
+
label: def.label,
|
|
179
|
+
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function getSlotToolDescriptors(registry, slotDef) {
|
|
183
|
+
return slotDef.tools.map((name) => getToolDescriptor(registry, name)).filter((d) => d !== null);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function resolveSlotValue(entry, registry) {
|
|
187
|
+
if (!entry.tool)
|
|
188
|
+
return void 0;
|
|
189
|
+
const toolDef = registry.getTool(entry.tool);
|
|
190
|
+
if (!toolDef)
|
|
191
|
+
return void 0;
|
|
192
|
+
if (toolDef.kind === "leaf") {
|
|
193
|
+
return toolDef.resolve(entry.value);
|
|
194
|
+
}
|
|
195
|
+
const resolvedSubSlots = {};
|
|
196
|
+
if (entry.subSlots) {
|
|
197
|
+
for (const [key, subEntry] of Object.entries(entry.subSlots)) {
|
|
198
|
+
resolvedSubSlots[key] = resolveSlotValue(subEntry, registry);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return toolDef.resolve(resolvedSubSlots);
|
|
202
|
+
}
|
|
203
|
+
function resolveItemParams(slotValues, registry) {
|
|
204
|
+
const params = {};
|
|
205
|
+
let hasParams = false;
|
|
206
|
+
for (const [key, entry] of Object.entries(slotValues)) {
|
|
207
|
+
const resolved = resolveSlotValue(entry, registry);
|
|
208
|
+
if (resolved !== void 0) {
|
|
209
|
+
params[key] = resolved;
|
|
210
|
+
hasParams = true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return hasParams ? params : void 0;
|
|
214
|
+
}
|
|
215
|
+
function serializeItems(items, registry) {
|
|
216
|
+
return items.map((item) => {
|
|
217
|
+
const params = resolveItemParams(item.slotValues, registry);
|
|
218
|
+
const action = { type: item.id };
|
|
219
|
+
if (params) {
|
|
220
|
+
action.params = params;
|
|
221
|
+
}
|
|
222
|
+
return action;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function generateTriggerId() {
|
|
226
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
227
|
+
return globalThis.crypto.randomUUID();
|
|
228
|
+
}
|
|
229
|
+
return `trigger-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
230
|
+
}
|
|
231
|
+
function toTrigger(state, registry, triggerId) {
|
|
232
|
+
const eventParams = state.event ? resolveItemParams(state.event.slotValues, registry) : void 0;
|
|
233
|
+
const event = {
|
|
234
|
+
type: state.event?.id ?? "",
|
|
235
|
+
...eventParams ? { payload: eventParams } : {}
|
|
236
|
+
};
|
|
237
|
+
const actions = serializeItems(state.actions, registry);
|
|
238
|
+
const trigger = {
|
|
239
|
+
id: triggerId ?? generateTriggerId(),
|
|
240
|
+
event,
|
|
241
|
+
actions
|
|
242
|
+
};
|
|
243
|
+
if (state.conditions.length > 0) {
|
|
244
|
+
trigger.conditions = {
|
|
245
|
+
type: "and",
|
|
246
|
+
conditions: serializeItems(state.conditions, registry)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return trigger;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
252
|
function createWar3Editor() {
|
|
253
253
|
const registry = new War3Registry();
|
|
254
254
|
const stateManager = new War3EditorStateManager();
|
|
@@ -256,7 +256,7 @@ function createWar3Editor() {
|
|
|
256
256
|
// --- Editor 接口 ---
|
|
257
257
|
getState: () => stateManager.getState(),
|
|
258
258
|
onChange: (listener) => stateManager.onChange(listener),
|
|
259
|
-
|
|
259
|
+
toTrigger: (triggerId) => toTrigger(stateManager.getState(), registry, triggerId),
|
|
260
260
|
reset: () => stateManager.reset(),
|
|
261
261
|
dispose: () => stateManager.dispose(),
|
|
262
262
|
// --- 注册 ---
|
|
@@ -316,6 +316,16 @@ function createWar3Editor() {
|
|
|
316
316
|
return editor;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
function defineLeafTool(def) {
|
|
320
|
+
return { ...def, kind: "leaf" };
|
|
321
|
+
}
|
|
322
|
+
function defineCompositeTool(def) {
|
|
323
|
+
return { ...def, kind: "composite" };
|
|
324
|
+
}
|
|
325
|
+
function defineCondition(def) {
|
|
326
|
+
return def;
|
|
327
|
+
}
|
|
328
|
+
|
|
319
329
|
function valueEquals(a, b) {
|
|
320
330
|
if (a === b)
|
|
321
331
|
return true;
|
|
@@ -368,16 +378,6 @@ function resolveSlotDisplayText(entry, registry, fallbackLabel) {
|
|
|
368
378
|
}).join("");
|
|
369
379
|
}
|
|
370
380
|
|
|
371
|
-
function defineLeafTool(def) {
|
|
372
|
-
return { ...def, kind: "leaf" };
|
|
373
|
-
}
|
|
374
|
-
function defineCompositeTool(def) {
|
|
375
|
-
return { ...def, kind: "composite" };
|
|
376
|
-
}
|
|
377
|
-
function defineCondition(def) {
|
|
378
|
-
return def;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
381
|
function defineWar3Preset(options) {
|
|
382
382
|
return {
|
|
383
383
|
name: options.name,
|
|
@@ -409,4 +409,4 @@ exports.getToolDescriptor = getToolDescriptor;
|
|
|
409
409
|
exports.parseTemplate = parseTemplate;
|
|
410
410
|
exports.resolveSlotDisplayText = resolveSlotDisplayText;
|
|
411
411
|
exports.resolveSlotValue = resolveSlotValue;
|
|
412
|
-
exports.
|
|
412
|
+
exports.toTrigger = toTrigger;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseItemDef, BaseRegistry, Editor, Preset
|
|
1
|
+
import { BaseItemDef, BaseRegistry, ObservableState, Editor, Preset } from '@triggerix/editor';
|
|
2
2
|
export { BaseItemDef, Preset } from '@triggerix/editor';
|
|
3
|
-
import { Value,
|
|
3
|
+
import { Value, Trigger } from '@triggerix/core';
|
|
4
4
|
|
|
5
5
|
interface SlotDef {
|
|
6
6
|
label: string;
|
|
@@ -93,6 +93,12 @@ interface War3PresetOptions {
|
|
|
93
93
|
tools?: Record<string, ToolDef>;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* 解析模板字符串为 Segment 数组
|
|
98
|
+
* 模板格式: "普通文本${slotKey}更多文本"
|
|
99
|
+
*/
|
|
100
|
+
declare function parseTemplate(template: string, slots?: Record<string, SlotDef>, slotValues?: Record<string, SlotValueEntry>): Segment[];
|
|
101
|
+
|
|
96
102
|
/**
|
|
97
103
|
* War3 注册表 - 继承 BaseRegistry,增加 Tool 注册能力
|
|
98
104
|
*/
|
|
@@ -107,6 +113,26 @@ declare class War3Registry extends BaseRegistry<War3EventDef, War3ActionDef, War
|
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* War3 编辑器状态管理
|
|
118
|
+
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
119
|
+
*/
|
|
120
|
+
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
121
|
+
constructor();
|
|
122
|
+
setEvent(id: string): void;
|
|
123
|
+
clearEvent(): void;
|
|
124
|
+
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
125
|
+
addAction(id: string): void;
|
|
126
|
+
removeAction(index: number): void;
|
|
127
|
+
moveAction(from: number, to: number): void;
|
|
128
|
+
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
129
|
+
addCondition(id: string): void;
|
|
130
|
+
removeCondition(index: number): void;
|
|
131
|
+
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
132
|
+
reset(): void;
|
|
133
|
+
private setItemSlot;
|
|
134
|
+
}
|
|
135
|
+
|
|
110
136
|
interface War3Editor extends Editor<War3EditorState> {
|
|
111
137
|
registerEvent: (def: War3EventDef) => void;
|
|
112
138
|
registerAction: (def: War3ActionDef) => void;
|
|
@@ -140,24 +166,6 @@ interface War3Editor extends Editor<War3EditorState> {
|
|
|
140
166
|
}
|
|
141
167
|
declare function createWar3Editor(): War3Editor;
|
|
142
168
|
|
|
143
|
-
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
144
|
-
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
145
|
-
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
146
|
-
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
147
|
-
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
151
|
-
*
|
|
152
|
-
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
153
|
-
* - 如果 tool 为 leaf:
|
|
154
|
-
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
155
|
-
* - 其它类型:返回 value 的字符串形式
|
|
156
|
-
* - 若 value 为空:返回 fallbackLabel
|
|
157
|
-
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
158
|
-
*/
|
|
159
|
-
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
160
|
-
|
|
161
169
|
/**
|
|
162
170
|
* Type-safe LeafTool definition.
|
|
163
171
|
* Input type comes from the resolve callback annotation; output is inferred.
|
|
@@ -192,11 +200,23 @@ declare function defineCondition<TSlotValues extends Record<string, unknown> = R
|
|
|
192
200
|
resolve?: (slotValues: TSlotValues) => unknown;
|
|
193
201
|
}): War3ConditionDef;
|
|
194
202
|
|
|
203
|
+
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
204
|
+
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
205
|
+
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
206
|
+
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
207
|
+
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
208
|
+
|
|
195
209
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
210
|
+
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
211
|
+
*
|
|
212
|
+
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
213
|
+
* - 如果 tool 为 leaf:
|
|
214
|
+
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
215
|
+
* - 其它类型:返回 value 的字符串形式
|
|
216
|
+
* - 若 value 为空:返回 fallbackLabel
|
|
217
|
+
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
198
218
|
*/
|
|
199
|
-
declare function
|
|
219
|
+
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
200
220
|
|
|
201
221
|
declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor>;
|
|
202
222
|
|
|
@@ -205,7 +225,7 @@ declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor
|
|
|
205
225
|
*/
|
|
206
226
|
declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry): Value | undefined;
|
|
207
227
|
/**
|
|
208
|
-
* Serialize editor state into a standard
|
|
228
|
+
* Serialize editor state into a standard Trigger JSON.
|
|
209
229
|
*
|
|
210
230
|
* Output shape (compatible with @triggerix/core):
|
|
211
231
|
* {
|
|
@@ -213,27 +233,7 @@ declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry)
|
|
|
213
233
|
* actions: [{ type, params? }]
|
|
214
234
|
* }
|
|
215
235
|
*/
|
|
216
|
-
declare function
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* War3 编辑器状态管理
|
|
220
|
-
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
221
|
-
*/
|
|
222
|
-
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
223
|
-
constructor();
|
|
224
|
-
setEvent(id: string): void;
|
|
225
|
-
clearEvent(): void;
|
|
226
|
-
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
227
|
-
addAction(id: string): void;
|
|
228
|
-
removeAction(index: number): void;
|
|
229
|
-
moveAction(from: number, to: number): void;
|
|
230
|
-
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
231
|
-
addCondition(id: string): void;
|
|
232
|
-
removeCondition(index: number): void;
|
|
233
|
-
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
234
|
-
reset(): void;
|
|
235
|
-
private setItemSlot;
|
|
236
|
-
}
|
|
236
|
+
declare function toTrigger(state: War3EditorState, registry: War3Registry, triggerId?: string): Trigger;
|
|
237
237
|
|
|
238
|
-
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue,
|
|
238
|
+
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue, toTrigger };
|
|
239
239
|
export type { CompositeToolDef, CompositeToolDescriptor, ItemDescriptor, ItemState, LeafToolDef, LeafToolDescriptor, LeafToolInput, Segment, SlotDef, SlotValueEntry, ToolDef, ToolDescriptor, War3ActionDef, War3ConditionDef, War3Editor, War3EditorState, War3EventDef, War3PresetOptions };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseItemDef, BaseRegistry, Editor, Preset
|
|
1
|
+
import { BaseItemDef, BaseRegistry, ObservableState, Editor, Preset } from '@triggerix/editor';
|
|
2
2
|
export { BaseItemDef, Preset } from '@triggerix/editor';
|
|
3
|
-
import { Value,
|
|
3
|
+
import { Value, Trigger } from '@triggerix/core';
|
|
4
4
|
|
|
5
5
|
interface SlotDef {
|
|
6
6
|
label: string;
|
|
@@ -93,6 +93,12 @@ interface War3PresetOptions {
|
|
|
93
93
|
tools?: Record<string, ToolDef>;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* 解析模板字符串为 Segment 数组
|
|
98
|
+
* 模板格式: "普通文本${slotKey}更多文本"
|
|
99
|
+
*/
|
|
100
|
+
declare function parseTemplate(template: string, slots?: Record<string, SlotDef>, slotValues?: Record<string, SlotValueEntry>): Segment[];
|
|
101
|
+
|
|
96
102
|
/**
|
|
97
103
|
* War3 注册表 - 继承 BaseRegistry,增加 Tool 注册能力
|
|
98
104
|
*/
|
|
@@ -107,6 +113,26 @@ declare class War3Registry extends BaseRegistry<War3EventDef, War3ActionDef, War
|
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* War3 编辑器状态管理
|
|
118
|
+
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
119
|
+
*/
|
|
120
|
+
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
121
|
+
constructor();
|
|
122
|
+
setEvent(id: string): void;
|
|
123
|
+
clearEvent(): void;
|
|
124
|
+
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
125
|
+
addAction(id: string): void;
|
|
126
|
+
removeAction(index: number): void;
|
|
127
|
+
moveAction(from: number, to: number): void;
|
|
128
|
+
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
129
|
+
addCondition(id: string): void;
|
|
130
|
+
removeCondition(index: number): void;
|
|
131
|
+
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
132
|
+
reset(): void;
|
|
133
|
+
private setItemSlot;
|
|
134
|
+
}
|
|
135
|
+
|
|
110
136
|
interface War3Editor extends Editor<War3EditorState> {
|
|
111
137
|
registerEvent: (def: War3EventDef) => void;
|
|
112
138
|
registerAction: (def: War3ActionDef) => void;
|
|
@@ -140,24 +166,6 @@ interface War3Editor extends Editor<War3EditorState> {
|
|
|
140
166
|
}
|
|
141
167
|
declare function createWar3Editor(): War3Editor;
|
|
142
168
|
|
|
143
|
-
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
144
|
-
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
145
|
-
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
146
|
-
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
147
|
-
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
151
|
-
*
|
|
152
|
-
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
153
|
-
* - 如果 tool 为 leaf:
|
|
154
|
-
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
155
|
-
* - 其它类型:返回 value 的字符串形式
|
|
156
|
-
* - 若 value 为空:返回 fallbackLabel
|
|
157
|
-
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
158
|
-
*/
|
|
159
|
-
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
160
|
-
|
|
161
169
|
/**
|
|
162
170
|
* Type-safe LeafTool definition.
|
|
163
171
|
* Input type comes from the resolve callback annotation; output is inferred.
|
|
@@ -192,11 +200,23 @@ declare function defineCondition<TSlotValues extends Record<string, unknown> = R
|
|
|
192
200
|
resolve?: (slotValues: TSlotValues) => unknown;
|
|
193
201
|
}): War3ConditionDef;
|
|
194
202
|
|
|
203
|
+
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
204
|
+
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
205
|
+
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
206
|
+
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
207
|
+
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
208
|
+
|
|
195
209
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
210
|
+
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
211
|
+
*
|
|
212
|
+
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
213
|
+
* - 如果 tool 为 leaf:
|
|
214
|
+
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
215
|
+
* - 其它类型:返回 value 的字符串形式
|
|
216
|
+
* - 若 value 为空:返回 fallbackLabel
|
|
217
|
+
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
198
218
|
*/
|
|
199
|
-
declare function
|
|
219
|
+
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
200
220
|
|
|
201
221
|
declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor>;
|
|
202
222
|
|
|
@@ -205,7 +225,7 @@ declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor
|
|
|
205
225
|
*/
|
|
206
226
|
declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry): Value | undefined;
|
|
207
227
|
/**
|
|
208
|
-
* Serialize editor state into a standard
|
|
228
|
+
* Serialize editor state into a standard Trigger JSON.
|
|
209
229
|
*
|
|
210
230
|
* Output shape (compatible with @triggerix/core):
|
|
211
231
|
* {
|
|
@@ -213,27 +233,7 @@ declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry)
|
|
|
213
233
|
* actions: [{ type, params? }]
|
|
214
234
|
* }
|
|
215
235
|
*/
|
|
216
|
-
declare function
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* War3 编辑器状态管理
|
|
220
|
-
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
221
|
-
*/
|
|
222
|
-
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
223
|
-
constructor();
|
|
224
|
-
setEvent(id: string): void;
|
|
225
|
-
clearEvent(): void;
|
|
226
|
-
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
227
|
-
addAction(id: string): void;
|
|
228
|
-
removeAction(index: number): void;
|
|
229
|
-
moveAction(from: number, to: number): void;
|
|
230
|
-
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
231
|
-
addCondition(id: string): void;
|
|
232
|
-
removeCondition(index: number): void;
|
|
233
|
-
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
234
|
-
reset(): void;
|
|
235
|
-
private setItemSlot;
|
|
236
|
-
}
|
|
236
|
+
declare function toTrigger(state: War3EditorState, registry: War3Registry, triggerId?: string): Trigger;
|
|
237
237
|
|
|
238
|
-
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue,
|
|
238
|
+
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue, toTrigger };
|
|
239
239
|
export type { CompositeToolDef, CompositeToolDescriptor, ItemDescriptor, ItemState, LeafToolDef, LeafToolDescriptor, LeafToolInput, Segment, SlotDef, SlotValueEntry, ToolDef, ToolDescriptor, War3ActionDef, War3ConditionDef, War3Editor, War3EditorState, War3EventDef, War3PresetOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseItemDef, BaseRegistry, Editor, Preset
|
|
1
|
+
import { BaseItemDef, BaseRegistry, ObservableState, Editor, Preset } from '@triggerix/editor';
|
|
2
2
|
export { BaseItemDef, Preset } from '@triggerix/editor';
|
|
3
|
-
import { Value,
|
|
3
|
+
import { Value, Trigger } from '@triggerix/core';
|
|
4
4
|
|
|
5
5
|
interface SlotDef {
|
|
6
6
|
label: string;
|
|
@@ -93,6 +93,12 @@ interface War3PresetOptions {
|
|
|
93
93
|
tools?: Record<string, ToolDef>;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* 解析模板字符串为 Segment 数组
|
|
98
|
+
* 模板格式: "普通文本${slotKey}更多文本"
|
|
99
|
+
*/
|
|
100
|
+
declare function parseTemplate(template: string, slots?: Record<string, SlotDef>, slotValues?: Record<string, SlotValueEntry>): Segment[];
|
|
101
|
+
|
|
96
102
|
/**
|
|
97
103
|
* War3 注册表 - 继承 BaseRegistry,增加 Tool 注册能力
|
|
98
104
|
*/
|
|
@@ -107,6 +113,26 @@ declare class War3Registry extends BaseRegistry<War3EventDef, War3ActionDef, War
|
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* War3 编辑器状态管理
|
|
118
|
+
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
119
|
+
*/
|
|
120
|
+
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
121
|
+
constructor();
|
|
122
|
+
setEvent(id: string): void;
|
|
123
|
+
clearEvent(): void;
|
|
124
|
+
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
125
|
+
addAction(id: string): void;
|
|
126
|
+
removeAction(index: number): void;
|
|
127
|
+
moveAction(from: number, to: number): void;
|
|
128
|
+
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
129
|
+
addCondition(id: string): void;
|
|
130
|
+
removeCondition(index: number): void;
|
|
131
|
+
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
132
|
+
reset(): void;
|
|
133
|
+
private setItemSlot;
|
|
134
|
+
}
|
|
135
|
+
|
|
110
136
|
interface War3Editor extends Editor<War3EditorState> {
|
|
111
137
|
registerEvent: (def: War3EventDef) => void;
|
|
112
138
|
registerAction: (def: War3ActionDef) => void;
|
|
@@ -140,24 +166,6 @@ interface War3Editor extends Editor<War3EditorState> {
|
|
|
140
166
|
}
|
|
141
167
|
declare function createWar3Editor(): War3Editor;
|
|
142
168
|
|
|
143
|
-
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
144
|
-
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
145
|
-
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
146
|
-
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
147
|
-
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
151
|
-
*
|
|
152
|
-
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
153
|
-
* - 如果 tool 为 leaf:
|
|
154
|
-
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
155
|
-
* - 其它类型:返回 value 的字符串形式
|
|
156
|
-
* - 若 value 为空:返回 fallbackLabel
|
|
157
|
-
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
158
|
-
*/
|
|
159
|
-
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
160
|
-
|
|
161
169
|
/**
|
|
162
170
|
* Type-safe LeafTool definition.
|
|
163
171
|
* Input type comes from the resolve callback annotation; output is inferred.
|
|
@@ -192,11 +200,23 @@ declare function defineCondition<TSlotValues extends Record<string, unknown> = R
|
|
|
192
200
|
resolve?: (slotValues: TSlotValues) => unknown;
|
|
193
201
|
}): War3ConditionDef;
|
|
194
202
|
|
|
203
|
+
declare function getEventDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
204
|
+
declare function getActionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
205
|
+
declare function getConditionDescriptor(registry: War3Registry, id: string, slotValues?: Record<string, SlotValueEntry>): ItemDescriptor | null;
|
|
206
|
+
declare function getToolDescriptor(registry: War3Registry, toolName: string, slotValues?: Record<string, SlotValueEntry>): ToolDescriptor | null;
|
|
207
|
+
declare function getSlotToolDescriptors(registry: War3Registry, slotDef: SlotDef): ToolDescriptor[];
|
|
208
|
+
|
|
195
209
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
210
|
+
* 递归解析 SlotValueEntry 为人类可读的展示文本
|
|
211
|
+
*
|
|
212
|
+
* - 如果 entry 为 null/undefined 或未选择 tool,返回 fallbackLabel(slot 占位文案)
|
|
213
|
+
* - 如果 tool 为 leaf:
|
|
214
|
+
* - select 类型:尝试匹配 options 找到对应 label(支持对象值的深比较)
|
|
215
|
+
* - 其它类型:返回 value 的字符串形式
|
|
216
|
+
* - 若 value 为空:返回 fallbackLabel
|
|
217
|
+
* - 如果 tool 为 composite:使用 tool 的 template 递归展开
|
|
198
218
|
*/
|
|
199
|
-
declare function
|
|
219
|
+
declare function resolveSlotDisplayText(entry: SlotValueEntry | null | undefined, registry: War3Registry, fallbackLabel: string): string;
|
|
200
220
|
|
|
201
221
|
declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor>;
|
|
202
222
|
|
|
@@ -205,7 +225,7 @@ declare function defineWar3Preset(options: War3PresetOptions): Preset<War3Editor
|
|
|
205
225
|
*/
|
|
206
226
|
declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry): Value | undefined;
|
|
207
227
|
/**
|
|
208
|
-
* Serialize editor state into a standard
|
|
228
|
+
* Serialize editor state into a standard Trigger JSON.
|
|
209
229
|
*
|
|
210
230
|
* Output shape (compatible with @triggerix/core):
|
|
211
231
|
* {
|
|
@@ -213,27 +233,7 @@ declare function resolveSlotValue(entry: SlotValueEntry, registry: War3Registry)
|
|
|
213
233
|
* actions: [{ type, params? }]
|
|
214
234
|
* }
|
|
215
235
|
*/
|
|
216
|
-
declare function
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* War3 编辑器状态管理
|
|
220
|
-
* 继承 ObservableState,提供模板模式特有的状态操作
|
|
221
|
-
*/
|
|
222
|
-
declare class War3EditorStateManager extends ObservableState<War3EditorState> {
|
|
223
|
-
constructor();
|
|
224
|
-
setEvent(id: string): void;
|
|
225
|
-
clearEvent(): void;
|
|
226
|
-
setEventSlot(key: string, entry: SlotValueEntry): void;
|
|
227
|
-
addAction(id: string): void;
|
|
228
|
-
removeAction(index: number): void;
|
|
229
|
-
moveAction(from: number, to: number): void;
|
|
230
|
-
setActionSlot(actionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
231
|
-
addCondition(id: string): void;
|
|
232
|
-
removeCondition(index: number): void;
|
|
233
|
-
setConditionSlot(conditionIndex: number, key: string, entry: SlotValueEntry): void;
|
|
234
|
-
reset(): void;
|
|
235
|
-
private setItemSlot;
|
|
236
|
-
}
|
|
236
|
+
declare function toTrigger(state: War3EditorState, registry: War3Registry, triggerId?: string): Trigger;
|
|
237
237
|
|
|
238
|
-
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue,
|
|
238
|
+
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue, toTrigger };
|
|
239
239
|
export type { CompositeToolDef, CompositeToolDescriptor, ItemDescriptor, ItemState, LeafToolDef, LeafToolDescriptor, LeafToolInput, Segment, SlotDef, SlotValueEntry, ToolDef, ToolDescriptor, War3ActionDef, War3ConditionDef, War3Editor, War3EditorState, War3EventDef, War3PresetOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -32,47 +32,6 @@ function parseTemplate(template, slots, slotValues) {
|
|
|
32
32
|
return segments;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function buildDescriptor(def, slotValues) {
|
|
36
|
-
return {
|
|
37
|
-
id: def.id,
|
|
38
|
-
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function getEventDescriptor(registry, id, slotValues) {
|
|
42
|
-
const def = registry.getEvent(id);
|
|
43
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
44
|
-
}
|
|
45
|
-
function getActionDescriptor(registry, id, slotValues) {
|
|
46
|
-
const def = registry.getAction(id);
|
|
47
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
48
|
-
}
|
|
49
|
-
function getConditionDescriptor(registry, id, slotValues) {
|
|
50
|
-
const def = registry.getCondition(id);
|
|
51
|
-
return def ? buildDescriptor(def, slotValues) : null;
|
|
52
|
-
}
|
|
53
|
-
function getToolDescriptor(registry, toolName, slotValues) {
|
|
54
|
-
const def = registry.getTool(toolName);
|
|
55
|
-
if (!def)
|
|
56
|
-
return null;
|
|
57
|
-
if (def.kind === "leaf") {
|
|
58
|
-
return {
|
|
59
|
-
kind: "leaf",
|
|
60
|
-
name: toolName,
|
|
61
|
-
label: def.label,
|
|
62
|
-
input: def.input
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
kind: "composite",
|
|
67
|
-
name: toolName,
|
|
68
|
-
label: def.label,
|
|
69
|
-
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
function getSlotToolDescriptors(registry, slotDef) {
|
|
73
|
-
return slotDef.tools.map((name) => getToolDescriptor(registry, name)).filter((d) => d !== null);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
35
|
class War3Registry extends BaseRegistry {
|
|
77
36
|
tools = /* @__PURE__ */ new Map();
|
|
78
37
|
registerTool(name, def) {
|
|
@@ -95,72 +54,6 @@ class War3Registry extends BaseRegistry {
|
|
|
95
54
|
}
|
|
96
55
|
}
|
|
97
56
|
|
|
98
|
-
function resolveSlotValue(entry, registry) {
|
|
99
|
-
if (!entry.tool)
|
|
100
|
-
return void 0;
|
|
101
|
-
const toolDef = registry.getTool(entry.tool);
|
|
102
|
-
if (!toolDef)
|
|
103
|
-
return void 0;
|
|
104
|
-
if (toolDef.kind === "leaf") {
|
|
105
|
-
return toolDef.resolve(entry.value);
|
|
106
|
-
}
|
|
107
|
-
const resolvedSubSlots = {};
|
|
108
|
-
if (entry.subSlots) {
|
|
109
|
-
for (const [key, subEntry] of Object.entries(entry.subSlots)) {
|
|
110
|
-
resolvedSubSlots[key] = resolveSlotValue(subEntry, registry);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return toolDef.resolve(resolvedSubSlots);
|
|
114
|
-
}
|
|
115
|
-
function resolveItemParams(slotValues, registry) {
|
|
116
|
-
const params = {};
|
|
117
|
-
let hasParams = false;
|
|
118
|
-
for (const [key, entry] of Object.entries(slotValues)) {
|
|
119
|
-
const resolved = resolveSlotValue(entry, registry);
|
|
120
|
-
if (resolved !== void 0) {
|
|
121
|
-
params[key] = resolved;
|
|
122
|
-
hasParams = true;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return hasParams ? params : void 0;
|
|
126
|
-
}
|
|
127
|
-
function serializeItems(items, registry) {
|
|
128
|
-
return items.map((item) => {
|
|
129
|
-
const params = resolveItemParams(item.slotValues, registry);
|
|
130
|
-
const action = { type: item.id };
|
|
131
|
-
if (params) {
|
|
132
|
-
action.params = params;
|
|
133
|
-
}
|
|
134
|
-
return action;
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
function generateRuleId() {
|
|
138
|
-
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
139
|
-
return globalThis.crypto.randomUUID();
|
|
140
|
-
}
|
|
141
|
-
return `rule-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
142
|
-
}
|
|
143
|
-
function toRule(state, registry, ruleId) {
|
|
144
|
-
const eventParams = state.event ? resolveItemParams(state.event.slotValues, registry) : void 0;
|
|
145
|
-
const event = {
|
|
146
|
-
type: state.event?.id ?? "",
|
|
147
|
-
...eventParams ? { payload: eventParams } : {}
|
|
148
|
-
};
|
|
149
|
-
const actions = serializeItems(state.actions, registry);
|
|
150
|
-
const rule = {
|
|
151
|
-
id: ruleId ?? generateRuleId(),
|
|
152
|
-
event,
|
|
153
|
-
actions
|
|
154
|
-
};
|
|
155
|
-
if (state.conditions.length > 0) {
|
|
156
|
-
rule.conditions = {
|
|
157
|
-
type: "and",
|
|
158
|
-
conditions: serializeItems(state.conditions, registry)
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
return rule;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
57
|
const INITIAL_STATE = {
|
|
165
58
|
event: null,
|
|
166
59
|
conditions: [],
|
|
@@ -247,6 +140,113 @@ class War3EditorStateManager extends ObservableState {
|
|
|
247
140
|
}
|
|
248
141
|
}
|
|
249
142
|
|
|
143
|
+
function buildDescriptor(def, slotValues) {
|
|
144
|
+
return {
|
|
145
|
+
id: def.id,
|
|
146
|
+
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function getEventDescriptor(registry, id, slotValues) {
|
|
150
|
+
const def = registry.getEvent(id);
|
|
151
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
152
|
+
}
|
|
153
|
+
function getActionDescriptor(registry, id, slotValues) {
|
|
154
|
+
const def = registry.getAction(id);
|
|
155
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
156
|
+
}
|
|
157
|
+
function getConditionDescriptor(registry, id, slotValues) {
|
|
158
|
+
const def = registry.getCondition(id);
|
|
159
|
+
return def ? buildDescriptor(def, slotValues) : null;
|
|
160
|
+
}
|
|
161
|
+
function getToolDescriptor(registry, toolName, slotValues) {
|
|
162
|
+
const def = registry.getTool(toolName);
|
|
163
|
+
if (!def)
|
|
164
|
+
return null;
|
|
165
|
+
if (def.kind === "leaf") {
|
|
166
|
+
return {
|
|
167
|
+
kind: "leaf",
|
|
168
|
+
name: toolName,
|
|
169
|
+
label: def.label,
|
|
170
|
+
input: def.input
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
kind: "composite",
|
|
175
|
+
name: toolName,
|
|
176
|
+
label: def.label,
|
|
177
|
+
segments: parseTemplate(def.template, def.slots, slotValues)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function getSlotToolDescriptors(registry, slotDef) {
|
|
181
|
+
return slotDef.tools.map((name) => getToolDescriptor(registry, name)).filter((d) => d !== null);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function resolveSlotValue(entry, registry) {
|
|
185
|
+
if (!entry.tool)
|
|
186
|
+
return void 0;
|
|
187
|
+
const toolDef = registry.getTool(entry.tool);
|
|
188
|
+
if (!toolDef)
|
|
189
|
+
return void 0;
|
|
190
|
+
if (toolDef.kind === "leaf") {
|
|
191
|
+
return toolDef.resolve(entry.value);
|
|
192
|
+
}
|
|
193
|
+
const resolvedSubSlots = {};
|
|
194
|
+
if (entry.subSlots) {
|
|
195
|
+
for (const [key, subEntry] of Object.entries(entry.subSlots)) {
|
|
196
|
+
resolvedSubSlots[key] = resolveSlotValue(subEntry, registry);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return toolDef.resolve(resolvedSubSlots);
|
|
200
|
+
}
|
|
201
|
+
function resolveItemParams(slotValues, registry) {
|
|
202
|
+
const params = {};
|
|
203
|
+
let hasParams = false;
|
|
204
|
+
for (const [key, entry] of Object.entries(slotValues)) {
|
|
205
|
+
const resolved = resolveSlotValue(entry, registry);
|
|
206
|
+
if (resolved !== void 0) {
|
|
207
|
+
params[key] = resolved;
|
|
208
|
+
hasParams = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return hasParams ? params : void 0;
|
|
212
|
+
}
|
|
213
|
+
function serializeItems(items, registry) {
|
|
214
|
+
return items.map((item) => {
|
|
215
|
+
const params = resolveItemParams(item.slotValues, registry);
|
|
216
|
+
const action = { type: item.id };
|
|
217
|
+
if (params) {
|
|
218
|
+
action.params = params;
|
|
219
|
+
}
|
|
220
|
+
return action;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function generateTriggerId() {
|
|
224
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
225
|
+
return globalThis.crypto.randomUUID();
|
|
226
|
+
}
|
|
227
|
+
return `trigger-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
228
|
+
}
|
|
229
|
+
function toTrigger(state, registry, triggerId) {
|
|
230
|
+
const eventParams = state.event ? resolveItemParams(state.event.slotValues, registry) : void 0;
|
|
231
|
+
const event = {
|
|
232
|
+
type: state.event?.id ?? "",
|
|
233
|
+
...eventParams ? { payload: eventParams } : {}
|
|
234
|
+
};
|
|
235
|
+
const actions = serializeItems(state.actions, registry);
|
|
236
|
+
const trigger = {
|
|
237
|
+
id: triggerId ?? generateTriggerId(),
|
|
238
|
+
event,
|
|
239
|
+
actions
|
|
240
|
+
};
|
|
241
|
+
if (state.conditions.length > 0) {
|
|
242
|
+
trigger.conditions = {
|
|
243
|
+
type: "and",
|
|
244
|
+
conditions: serializeItems(state.conditions, registry)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return trigger;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
250
|
function createWar3Editor() {
|
|
251
251
|
const registry = new War3Registry();
|
|
252
252
|
const stateManager = new War3EditorStateManager();
|
|
@@ -254,7 +254,7 @@ function createWar3Editor() {
|
|
|
254
254
|
// --- Editor 接口 ---
|
|
255
255
|
getState: () => stateManager.getState(),
|
|
256
256
|
onChange: (listener) => stateManager.onChange(listener),
|
|
257
|
-
|
|
257
|
+
toTrigger: (triggerId) => toTrigger(stateManager.getState(), registry, triggerId),
|
|
258
258
|
reset: () => stateManager.reset(),
|
|
259
259
|
dispose: () => stateManager.dispose(),
|
|
260
260
|
// --- 注册 ---
|
|
@@ -314,6 +314,16 @@ function createWar3Editor() {
|
|
|
314
314
|
return editor;
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
function defineLeafTool(def) {
|
|
318
|
+
return { ...def, kind: "leaf" };
|
|
319
|
+
}
|
|
320
|
+
function defineCompositeTool(def) {
|
|
321
|
+
return { ...def, kind: "composite" };
|
|
322
|
+
}
|
|
323
|
+
function defineCondition(def) {
|
|
324
|
+
return def;
|
|
325
|
+
}
|
|
326
|
+
|
|
317
327
|
function valueEquals(a, b) {
|
|
318
328
|
if (a === b)
|
|
319
329
|
return true;
|
|
@@ -366,16 +376,6 @@ function resolveSlotDisplayText(entry, registry, fallbackLabel) {
|
|
|
366
376
|
}).join("");
|
|
367
377
|
}
|
|
368
378
|
|
|
369
|
-
function defineLeafTool(def) {
|
|
370
|
-
return { ...def, kind: "leaf" };
|
|
371
|
-
}
|
|
372
|
-
function defineCompositeTool(def) {
|
|
373
|
-
return { ...def, kind: "composite" };
|
|
374
|
-
}
|
|
375
|
-
function defineCondition(def) {
|
|
376
|
-
return def;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
379
|
function defineWar3Preset(options) {
|
|
380
380
|
return {
|
|
381
381
|
name: options.name,
|
|
@@ -392,4 +392,4 @@ function defineWar3Preset(options) {
|
|
|
392
392
|
};
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue,
|
|
395
|
+
export { War3EditorStateManager, War3Registry, createWar3Editor, defineCompositeTool, defineCondition, defineLeafTool, defineWar3Preset, getActionDescriptor, getConditionDescriptor, getEventDescriptor, getSlotToolDescriptors, getToolDescriptor, parseTemplate, resolveSlotDisplayText, resolveSlotValue, toTrigger };
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "triggerix-editor-preset-war3",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.7",
|
|
5
5
|
"description": "War3-style template editor preset for Triggerix",
|
|
6
|
-
"homepage": "https://github.com/triggerix-
|
|
6
|
+
"homepage": "https://github.com/triggerix-collective/triggerix-editor-preset-war3#readme",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git@github.com:triggerix-
|
|
9
|
+
"url": "git@github.com:triggerix-collective/triggerix-editor-preset-war3.git"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/triggerix-
|
|
12
|
+
"url": "https://github.com/triggerix-collective/triggerix-editor-preset-war3/issues"
|
|
13
13
|
},
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@triggerix/core": "^0.0.
|
|
29
|
-
"@triggerix/editor": "^0.0.
|
|
28
|
+
"@triggerix/core": "^0.0.8",
|
|
29
|
+
"@triggerix/editor": "^0.0.8"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@antfu/eslint-config": "^9.0.0",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"nano-staged": "^1.0.2",
|
|
37
37
|
"simple-git-hooks": "^2.13.1",
|
|
38
38
|
"typescript": "^6.0.3",
|
|
39
|
-
"unbuild": "^3.6.1"
|
|
39
|
+
"unbuild": "^3.6.1",
|
|
40
|
+
"vitest": "^4.1.9"
|
|
40
41
|
},
|
|
41
42
|
"simple-git-hooks": {
|
|
42
43
|
"pre-commit": "pnpm nano-staged"
|
|
@@ -49,6 +50,8 @@
|
|
|
49
50
|
"dev": "unbuild --stub",
|
|
50
51
|
"lint": "eslint --cache",
|
|
51
52
|
"typecheck": "tsc --noEmit",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:watch": "vitest",
|
|
52
55
|
"release": "bumpp"
|
|
53
56
|
}
|
|
54
57
|
}
|