openpuppet-language 2.0__py3-none-any.whl

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 (40) hide show
  1. openpuppet_language-2.0.data/data/share/puppet/conformance/README.md +274 -0
  2. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/binding.json +238 -0
  3. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/capabilities.json +155 -0
  4. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/grammar.json +248 -0
  5. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/interaction.json +220 -0
  6. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/listen.json +133 -0
  7. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/platform.json +274 -0
  8. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/probes.json +117 -0
  9. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/render.json +180 -0
  10. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/tabs.json +39 -0
  11. openpuppet_language-2.0.data/data/share/puppet/conformance/cases/templates.json +143 -0
  12. openpuppet_language-2.0.data/data/share/puppet/conformance/fixtures/capabilities_bad_result.py +11 -0
  13. openpuppet_language-2.0.data/data/share/puppet/conformance/fixtures/capabilities_basic.py +24 -0
  14. openpuppet_language-2.0.data/data/share/puppet/conformance/fixtures/capabilities_deps_mismatch.py +11 -0
  15. openpuppet_language-2.0.data/data/share/puppet/conformance/fixtures/capabilities_no_doc.py +10 -0
  16. openpuppet_language-2.0.data/data/share/puppet/conformance/runner.py +721 -0
  17. openpuppet_language-2.0.data/data/share/puppet/spec/01-grammar.md +283 -0
  18. openpuppet_language-2.0.data/data/share/puppet/spec/02-ir.md +77 -0
  19. openpuppet_language-2.0.data/data/share/puppet/spec/03-semantics.md +167 -0
  20. openpuppet_language-2.0.data/data/share/puppet/spec/04-vocabulary.md +227 -0
  21. openpuppet_language-2.0.data/data/share/puppet/spec/05-render-contract.md +126 -0
  22. openpuppet_language-2.0.data/data/share/puppet/spec/06-diagnostics.md +151 -0
  23. openpuppet_language-2.0.data/data/share/puppet/spec/README.md +73 -0
  24. openpuppet_language-2.0.dist-info/METADATA +50 -0
  25. openpuppet_language-2.0.dist-info/RECORD +40 -0
  26. openpuppet_language-2.0.dist-info/WHEEL +5 -0
  27. openpuppet_language-2.0.dist-info/entry_points.txt +2 -0
  28. openpuppet_language-2.0.dist-info/top_level.txt +1 -0
  29. puppet/__init__.py +19 -0
  30. puppet/adapter.py +112 -0
  31. puppet/capabilities.py +172 -0
  32. puppet/cli.py +132 -0
  33. puppet/diag.py +42 -0
  34. puppet/engine.py +1038 -0
  35. puppet/eval.py +243 -0
  36. puppet/ir.py +538 -0
  37. puppet/lang.py +755 -0
  38. puppet/raster_adapter.py +348 -0
  39. puppet/tk_adapter.py +374 -0
  40. puppet/vocab.py +147 -0
@@ -0,0 +1,248 @@
1
+ [
2
+ {
3
+ "id": "g-minimal",
4
+ "title": "最小程序:根节点为内置节点,结构无诊断",
5
+ "spec": "01-grammar.md 第 5、7.1 节",
6
+ "program": [
7
+ "add #root window #win",
8
+ "add #win col #main"
9
+ ],
10
+ "loadExpect": {
11
+ "noDiagnostics": true,
12
+ "nodes": ["#root", "#win", "#main"]
13
+ },
14
+ "steps": [
15
+ { "expect": { "nodes": ["#main"] } }
16
+ ]
17
+ },
18
+ {
19
+ "id": "g-id-dup",
20
+ "title": "地址重复是错误,且不阻断本批后续语句",
21
+ "spec": "01-grammar.md 第 3 节;03-semantics.md 第 1 节",
22
+ "program": [
23
+ "add #root window #win",
24
+ "add #root window #win",
25
+ "add #win col #main"
26
+ ],
27
+ "loadExpect": {
28
+ "diagnostics": [{ "code": "ID_DUP", "level": "error" }],
29
+ "nodes": ["#win", "#main"]
30
+ },
31
+ "steps": [
32
+ { "expect": { "nodes": ["#main"] } }
33
+ ]
34
+ },
35
+ {
36
+ "id": "g-parent-missing",
37
+ "title": "父地址不存在是错误",
38
+ "spec": "01-grammar.md 第 7.1 节",
39
+ "program": [
40
+ "add #ghost col #c"
41
+ ],
42
+ "loadExpect": {
43
+ "diagnostics": [{ "code": "PARENT_MISSING", "level": "error" }],
44
+ "nodesAbsent": ["#c"]
45
+ },
46
+ "steps": [
47
+ { "expect": { "noDiagnostics": true } }
48
+ ]
49
+ },
50
+ {
51
+ "id": "g-anchor-missing",
52
+ "title": "锚点不存在是错误,且不得静默追加到末尾",
53
+ "spec": "01-grammar.md 第 7.1、7.5 节",
54
+ "program": [
55
+ "add #root window #win",
56
+ "add #win col #a",
57
+ "add #win col #b after #ghost"
58
+ ],
59
+ "loadExpect": {
60
+ "diagnostics": [{ "code": "ANCHOR_MISSING", "level": "error" }],
61
+ "nodes": ["#a"],
62
+ "nodesAbsent": ["#b"]
63
+ },
64
+ "steps": [
65
+ { "expect": { "nodesAbsent": ["#b"] } }
66
+ ]
67
+ },
68
+ {
69
+ "id": "g-del-missing",
70
+ "title": "删除不存在的目标是警告而非错误",
71
+ "spec": "01-grammar.md 第 7.4 节",
72
+ "program": [
73
+ "add #root window #win",
74
+ "del #ghost"
75
+ ],
76
+ "loadExpect": {
77
+ "diagnostics": [{ "code": "DEL_MISSING", "level": "warning" }],
78
+ "forbid": ["TARGET_MISSING"]
79
+ },
80
+ "steps": [
81
+ { "expect": { "nodes": ["#win"] } }
82
+ ]
83
+ },
84
+ {
85
+ "id": "g-move-cycle",
86
+ "title": "移动造成成环是错误",
87
+ "spec": "01-grammar.md 第 7.5 节",
88
+ "program": [
89
+ "add #root window #win",
90
+ "add #win col #a",
91
+ "add #a col #b",
92
+ "move #a #b"
93
+ ],
94
+ "loadExpect": {
95
+ "diagnostics": [{ "code": "MOVE_CYCLE", "level": "error" }],
96
+ "nodes": ["#a", "#b"]
97
+ },
98
+ "steps": [
99
+ { "expect": { "nodes": ["#b"] } }
100
+ ]
101
+ },
102
+ {
103
+ "id": "g-unknown-attr",
104
+ "title": "词汇表外的属性名是警告,不得静默丢弃",
105
+ "spec": "01-grammar.md 第 5 节;04-vocabulary.md 第 1 节",
106
+ "program": [
107
+ "add #root window #win",
108
+ "add #win col #c bgcolr=#ffffff"
109
+ ],
110
+ "loadExpect": {
111
+ "diagnostics": [{ "code": "UNKNOWN_ATTR", "level": "warning" }],
112
+ "nodes": ["#c"]
113
+ },
114
+ "steps": [
115
+ { "expect": { "nodes": ["#c"] } }
116
+ ]
117
+ },
118
+ {
119
+ "id": "g-unknown-type",
120
+ "title": "词汇表外的节点类型是警告,不得渲染成空白",
121
+ "spec": "01-grammar.md 第 5 节;04-vocabulary.md 第 2 节",
122
+ "program": [
123
+ "add #root widget #w"
124
+ ],
125
+ "loadExpect": {
126
+ "diagnostics": [{ "code": "UNKNOWN_TYPE", "level": "warning" }]
127
+ },
128
+ "steps": [
129
+ { "expect": { "noDiagnostics": true } }
130
+ ]
131
+ },
132
+ {
133
+ "id": "g-color-not-address",
134
+ "title": "颜色字面量与地址记号消歧:十六进制即颜色,不产生诊断",
135
+ "spec": "README.md 派生决定 5;01-grammar.md 第 2 节",
136
+ "program": [
137
+ "add #root window #win",
138
+ "add #win col #c bgcolor=#eeeeee fg=#1d4ed8"
139
+ ],
140
+ "loadExpect": {
141
+ "noDiagnostics": true,
142
+ "nodes": ["#c"]
143
+ },
144
+ "steps": [
145
+ { "expect": { "nodes": ["#c"] } }
146
+ ]
147
+ },
148
+ {
149
+ "id": "g-comment-line",
150
+ "title": "双斜杠注释行被忽略,不产生诊断",
151
+ "spec": "01-grammar.md 第 2 节",
152
+ "program": [
153
+ "// 这是一个注释",
154
+ "add #root window #win",
155
+ "add #win col #main"
156
+ ],
157
+ "loadExpect": {
158
+ "noDiagnostics": true,
159
+ "nodes": ["#main"]
160
+ },
161
+ "steps": [
162
+ { "expect": { "nodes": ["#main"] } }
163
+ ]
164
+ },
165
+ {
166
+ "id": "g-template-node",
167
+ "title": "模板是一等节点:拥有地址与子节点,不产生专属节点表",
168
+ "spec": "01-grammar.md 第 8 节",
169
+ "program": [
170
+ "add #root window #win",
171
+ "add #win col #main",
172
+ "add #main list #items source=#todos template=#tpl",
173
+ "add #root template #tpl as t",
174
+ "add #tpl row #r",
175
+ "data #todos = [] of {text: str = \"\"}"
176
+ ],
177
+ "loadExpect": {
178
+ "noDiagnostics": true,
179
+ "nodes": ["#tpl", "#r"]
180
+ },
181
+ "steps": [
182
+ { "expect": { "nodes": ["#tpl", "#r"] } }
183
+ ]
184
+ },
185
+ {
186
+ "id": "g-states-layout-attr",
187
+ "title": "状态外观里出现布局属性是警告",
188
+ "spec": "01-grammar.md 第 9 节;04-vocabulary.md 第 3.6 节",
189
+ "program": [
190
+ "add #root window #win",
191
+ "add #win col #c states={hover: {pad: 8}}"
192
+ ],
193
+ "loadExpect": {
194
+ "diagnostics": [{ "code": "STATE_LAYOUT_ATTR", "level": "warning" }]
195
+ },
196
+ "steps": [
197
+ { "expect": { "noDiagnostics": true } }
198
+ ]
199
+ },
200
+ {
201
+ "id": "g-unknown-event",
202
+ "title": "未识别的事件名是警告",
203
+ "spec": "01-grammar.md 第 7.7 节;04-vocabulary.md 第 5 节",
204
+ "program": [
205
+ "add #root window #win",
206
+ "add #win col #c",
207
+ "on #c hovered: set #c visible=false"
208
+ ],
209
+ "loadExpect": {
210
+ "diagnostics": [{ "code": "UNKNOWN_EVENT", "level": "warning" }]
211
+ },
212
+ "steps": [
213
+ { "expect": { "noDiagnostics": true } }
214
+ ]
215
+ },
216
+ {
217
+ "id": "g-on-body-multiline",
218
+ "title": "行为头之后的缩进体属于它,与单行写法等价",
219
+ "spec": "01-grammar.md 第 1、7.7 节",
220
+ "program": [
221
+ "add #root window #win",
222
+ "add #win button #b text=\"x\"",
223
+ "add #win text #t text=\"\"",
224
+ "on #b click:",
225
+ " set #t text=\"hit\"",
226
+ "on #b focus: set #t text=\"focused\"",
227
+ "",
228
+ "on #b blur:",
229
+ " // 注释行不参与缩进判定",
230
+ " set #t text=\"blurred\""
231
+ ],
232
+ "loadExpect": { "noDiagnostics": true },
233
+ "steps": [
234
+ {
235
+ "fire": { "target": "#b", "event": "click" },
236
+ "expect": { "attrs": { "#t.text": "hit" } }
237
+ },
238
+ {
239
+ "fire": { "target": "#b", "event": "focus" },
240
+ "expect": { "attrs": { "#t.text": "focused" } }
241
+ },
242
+ {
243
+ "fire": { "target": "#b", "event": "blur" },
244
+ "expect": { "attrs": { "#t.text": "blurred" } }
245
+ }
246
+ ]
247
+ }
248
+ ]
@@ -0,0 +1,220 @@
1
+ [
2
+ {
3
+ "id": "i-uncovered-button",
4
+ "title": "按钮的 click 没有处理器是警告:点了没反应必须被说出来",
5
+ "spec": "04-vocabulary.md 第 5.1 节;06-diagnostics.md 第 4.8 节",
6
+ "program": [
7
+ "add #root window #win",
8
+ "add #win button #b text=\"x\""
9
+ ],
10
+ "loadExpect": {
11
+ "diagnostics": [{ "code": "UNCOVERED_INTERACTION", "level": "warning" }]
12
+ },
13
+ "steps": [
14
+ { "expect": { "nodes": ["#b"] } }
15
+ ]
16
+ },
17
+ {
18
+ "id": "i-covered-button",
19
+ "title": "按钮的 click 有处理器即无此警告",
20
+ "spec": "04-vocabulary.md 第 5.1 节",
21
+ "program": [
22
+ "add #root window #win",
23
+ "add #win button #b text=\"x\"",
24
+ "on #b click: set #b text=\"hit\""
25
+ ],
26
+ "loadExpect": { "noDiagnostics": true },
27
+ "steps": [
28
+ {
29
+ "fire": { "target": "#b", "event": "click" },
30
+ "expect": { "attrs": { "#b.text": "hit" } }
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "i-input-has-no-primary-action",
36
+ "title": "输入框不因“没有 change 处理器”而报警告",
37
+ "spec": "04-vocabulary.md 第 5.1 节",
38
+ "program": [
39
+ "add #root window #win",
40
+ "add #win input #q placeholder=\"搜索\""
41
+ ],
42
+ "loadExpect": { "noDiagnostics": true },
43
+ "steps": [
44
+ { "expect": { "nodes": ["#q"] } }
45
+ ]
46
+ },
47
+ {
48
+ "id": "i-template-checkbox-uncovered",
49
+ "title": "模板行内的勾选框没有 change 处理器同样是警告",
50
+ "spec": "04-vocabulary.md 第 5.1 节",
51
+ "program": [
52
+ "add #root window #win",
53
+ "add #win list #items source=#todos template=#tpl",
54
+ "add #root template #tpl as t",
55
+ "add #tpl checkbox #done value=t.done",
56
+ "data #todos = [] of {done: bool = false}"
57
+ ],
58
+ "loadExpect": {
59
+ "diagnostics": [{ "code": "UNCOVERED_INTERACTION", "level": "warning" }]
60
+ },
61
+ "steps": [
62
+ { "expect": { "nodes": ["#done"] } }
63
+ ]
64
+ },
65
+ {
66
+ "id": "i-checkbox-toggle-writes-back",
67
+ "title": "勾选框的 change 处理器把状态写回数据源,绑定随之更新",
68
+ "spec": "03-semantics.md 第 2.7 节;04-vocabulary.md 第 5.1 节",
69
+ "program": [
70
+ "add #root window #win",
71
+ "add #win list #items source=#todos template=#tpl",
72
+ "add #win text #n text=str(count(#todos))",
73
+ "add #root template #tpl as t",
74
+ "add #tpl checkbox #done value=t.done",
75
+ "add #tpl text #label text=t.text",
76
+ "data #todos = [] of {text: str = \"\", done: bool = false}",
77
+ "on #done change as e: update_where #todos as r set done=e.value where r.text == t.text"
78
+ ],
79
+ "loadExpect": { "noDiagnostics": true },
80
+ "steps": [
81
+ {
82
+ "send": ["append #todos item={text: \"a\", done: false}"],
83
+ "expect": { "data": { "#todos": [{ "text": "a", "done": false }] } }
84
+ },
85
+ {
86
+ "fire": { "target": "#done", "event": "change", "row": 0, "value": true },
87
+ "expect": { "data": { "#todos": [{ "text": "a", "done": true }] } }
88
+ },
89
+ {
90
+ "fire": { "target": "#done", "event": "change", "row": 0, "value": false },
91
+ "expect": { "data": { "#todos": [{ "text": "a", "done": false }] } }
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "id": "i-change-payload-value",
97
+ "title": "change 事件的载荷携带新值,处理器据此回写(不必靠取反猜测)",
98
+ "spec": "03-semantics.md 第 2.8 节;01-grammar.md 第 7.7 节",
99
+ "program": [
100
+ "add #root window #win",
101
+ "add #win list #items source=#todos template=#tpl",
102
+ "add #root template #tpl as t",
103
+ "add #tpl checkbox #done value=t.done",
104
+ "add #tpl text #label text=t.text",
105
+ "data #todos = [] of {text: str = \"\", done: bool = false}",
106
+ "on #done change as e: update_where #todos as r set done=e.value where r.text == t.text"
107
+ ],
108
+ "loadExpect": { "noDiagnostics": true },
109
+ "steps": [
110
+ {
111
+ "send": ["append #todos item={text: \"a\", done: false}"],
112
+ "expect": { "data": { "#todos": [{ "text": "a", "done": false }] } }
113
+ },
114
+ {
115
+ "fire": { "target": "#done", "event": "change", "row": 0, "value": true },
116
+ "expect": { "data": { "#todos": [{ "text": "a", "done": true }] } }
117
+ },
118
+ {
119
+ "fire": { "target": "#done", "event": "change", "row": 0, "value": true },
120
+ "expect": { "data": { "#todos": [{ "text": "a", "done": true }] } }
121
+ }
122
+ ]
123
+ },
124
+ {
125
+ "id": "i-bound-value-not-written",
126
+ "title": "值绑定了数据源却没回写:警告(用户的改动会被覆盖)",
127
+ "spec": "03-semantics.md 第 2.8 节;06-diagnostics.md 第 4.8 节",
128
+ "program": [
129
+ "add #root window #win",
130
+ "add #win list #items source=#todos template=#tpl",
131
+ "add #win text #echo text=\"\"",
132
+ "add #root template #tpl as t",
133
+ "add #tpl checkbox #done value=t.done",
134
+ "data #todos = [] of {text: str = \"\", done: bool = false}",
135
+ "on #done change as e: set #echo text=str(e.value)"
136
+ ],
137
+ "loadExpect": {
138
+ "diagnostics": [{ "code": "BOUND_VALUE_NOT_WRITTEN", "level": "warning" }]
139
+ },
140
+ "steps": [
141
+ { "expect": { "nodes": ["#done"] } }
142
+ ]
143
+ },
144
+ {
145
+ "id": "i-change-payload-observed",
146
+ "title": "订阅的 change 事件载荷也带新值",
147
+ "spec": "03-semantics.md 第 6 节",
148
+ "program": [
149
+ "add #root window #win",
150
+ "add #win input #q placeholder=\"搜索\"",
151
+ "add #win text #n text=\"\"",
152
+ "listen #q change",
153
+ "on #q change as e: set #n text=e.value"
154
+ ],
155
+ "loadExpect": { "noDiagnostics": true },
156
+ "steps": [
157
+ {
158
+ "fire": { "target": "#q", "event": "change", "value": "abc" },
159
+ "expect": {
160
+ "events": [{ "target": "#q", "event": "change", "value": "abc" }],
161
+ "attrs": { "#n.text": "abc" }
162
+ }
163
+ }
164
+ ]
165
+ },
166
+ {
167
+ "id": "ir-click-via-renderer",
168
+ "title": "点击经渲染器投递为 click 事件并触发处理器(可观察触发条件)",
169
+ "spec": "05-render-contract.md 第 4 节",
170
+ "requires": ["interaction"],
171
+ "program": [
172
+ "add #root window #win",
173
+ "add #win text #t text=\"\"",
174
+ "add #win button #b text=\"点我\"",
175
+ "on #b click: set #t text=\"clicked\""
176
+ ],
177
+ "loadExpect": { "noDiagnostics": true },
178
+ "steps": [
179
+ {
180
+ "interact": { "target": "#b", "action": "click" },
181
+ "expect": { "attrs": { "#t.text": "clicked" } }
182
+ }
183
+ ]
184
+ },
185
+ {
186
+ "id": "ir-change-writeback-via-renderer",
187
+ "title": "勾选经渲染器投递为 change,受控处理器回写数据源",
188
+ "spec": "05-render-contract.md 第 4 节;03-semantics.md 第 2.8 节",
189
+ "requires": ["interaction"],
190
+ "program": [
191
+ "add #root window #win",
192
+ "data #n = [{v: false}] of {v: bool = false}",
193
+ "add #win checkbox #c value=#n.v",
194
+ "on #c change as e: update_where #n as r set v=e.value where r.v == false"
195
+ ],
196
+ "loadExpect": { "noDiagnostics": true },
197
+ "steps": [
198
+ {
199
+ "interact": { "target": "#c", "action": "change", "value": true },
200
+ "expect": { "data": { "#n": [{ "v": true }] } }
201
+ }
202
+ ]
203
+ },
204
+ {
205
+ "id": "ir-no-renderer-degrades",
206
+ "title": "没有渲染层时用户动作必须可见降级(禁止假装送达)",
207
+ "spec": "05-render-contract.md 第 4 节;06-diagnostics.md 第 4.7 节",
208
+ "program": [
209
+ "add #root window #win",
210
+ "add #win button #b text=\"x\"",
211
+ "on #b click: set #b text=\"hit\""
212
+ ],
213
+ "steps": [
214
+ {
215
+ "interact": { "target": "#b", "action": "click" },
216
+ "expect": { "degraded": ["interaction"] }
217
+ }
218
+ ]
219
+ }
220
+ ]
@@ -0,0 +1,133 @@
1
+ [
2
+ {
3
+ "id": "l-listen-click",
4
+ "title": "listen 把订阅的事件回推给驱动者,与有没有处理器无关",
5
+ "spec": "01-grammar.md 第 7.8 节;03-semantics.md 第 6 节",
6
+ "program": [
7
+ "add #root window #win",
8
+ "add #win button #b text=\"x\"",
9
+ "listen #b click",
10
+ "on #b click: set #b text=\"hit\""
11
+ ],
12
+ "loadExpect": { "noDiagnostics": true },
13
+ "steps": [
14
+ {
15
+ "fire": { "target": "#b", "event": "click" },
16
+ "expect": {
17
+ "events": [{ "target": "#b", "event": "click" }],
18
+ "attrs": { "#b.text": "hit" }
19
+ }
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "id": "l-listen-without-reaction",
25
+ "title": "只订阅不处理:事件照样回推,且不算未覆盖交互",
26
+ "spec": "01-grammar.md 第 7.8 节;04-vocabulary.md 第 5.1 节",
27
+ "program": [
28
+ "add #root window #win",
29
+ "add #win button #b text=\"x\"",
30
+ "listen #b click"
31
+ ],
32
+ "loadExpect": { "noDiagnostics": true },
33
+ "steps": [
34
+ {
35
+ "fire": { "target": "#b", "event": "click" },
36
+ "expect": { "events": [{ "target": "#b", "event": "click" }] }
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ "id": "l-listen-data-change",
42
+ "title": "订阅数据源变化:每次内容变化都回推一条事件",
43
+ "spec": "01-grammar.md 第 7.8 节",
44
+ "program": [
45
+ "add #root window #win",
46
+ "add #win text #n text=str(count(#todos))",
47
+ "data #todos = [] of {text: str = \"\"}",
48
+ "listen #todos change"
49
+ ],
50
+ "loadExpect": { "noDiagnostics": true },
51
+ "steps": [
52
+ {
53
+ "send": ["append #todos item={text: \"a\"}"],
54
+ "expect": { "events": [{ "target": "#todos", "event": "change" }] }
55
+ },
56
+ {
57
+ "send": ["append #todos item={text: \"b\"}"],
58
+ "expect": { "events": [{ "target": "#todos", "event": "change" }] }
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "id": "l-listen-unsubscribed-not-pushed",
64
+ "title": "没被订阅的事件不进观察流",
65
+ "spec": "01-grammar.md 第 7.8 节",
66
+ "program": [
67
+ "add #root window #win",
68
+ "add #win button #b text=\"x\"",
69
+ "on #b click: set #b text=\"hit\""
70
+ ],
71
+ "loadExpect": { "noDiagnostics": true },
72
+ "steps": [
73
+ {
74
+ "fire": { "target": "#b", "event": "click" },
75
+ "expect": { "noEvents": true, "attrs": { "#b.text": "hit" } }
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ "id": "l-listen-row-event",
81
+ "title": "行内订阅事件带行序号",
82
+ "spec": "01-grammar.md 第 7.8、8.1 节",
83
+ "program": [
84
+ "add #root window #win",
85
+ "add #win list #items source=#todos template=#tpl",
86
+ "add #root template #tpl as t",
87
+ "add #tpl button #del text=\"删除\"",
88
+ "listen #del click",
89
+ "data #todos = [] of {text: str = \"\"}",
90
+ "on #del click: append #todos item={text: t.text}"
91
+ ],
92
+ "steps": [
93
+ {
94
+ "send": ["append #todos item={text: \"a\"}"],
95
+ "expect": { "noEvents": true }
96
+ },
97
+ {
98
+ "fire": { "target": "#del", "event": "click", "row": 0 },
99
+ "expect": { "events": [{ "target": "#del", "event": "click", "row": 0 }] }
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ "id": "l-listen-unknown-event",
105
+ "title": "订阅未识别的事件名是警告",
106
+ "spec": "01-grammar.md 第 7.8 节",
107
+ "program": [
108
+ "add #root window #win",
109
+ "add #win button #b text=\"x\"",
110
+ "on #b click: set #b text=\"hit\"",
111
+ "listen #b hovered"
112
+ ],
113
+ "loadExpect": { "diagnostics": [{ "code": "UNKNOWN_EVENT", "level": "warning" }] },
114
+ "steps": [
115
+ { "expect": { "nodes": ["#b"] } }
116
+ ]
117
+ },
118
+ {
119
+ "id": "l-listen-missing-target",
120
+ "title": "订阅不存在的目标是错误",
121
+ "spec": "01-grammar.md 第 7.8 节",
122
+ "program": [
123
+ "add #root window #win",
124
+ "listen #ghost click"
125
+ ],
126
+ "loadExpect": {
127
+ "diagnostics": [{ "code": "TARGET_MISSING", "level": "error" }]
128
+ },
129
+ "steps": [
130
+ { "expect": { "nodes": ["#root"] } }
131
+ ]
132
+ }
133
+ ]