@naiv/swan 0.0.1
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/SWAN-DSL.md +832 -0
- package/dist/SWANServer.d.ts +26 -0
- package/dist/SWANServer.d.ts.map +1 -0
- package/dist/SWANServer.js +158 -0
- package/dist/SWANServer.js.map +1 -0
- package/dist/agent-mode/agent-capability.d.ts +28 -0
- package/dist/agent-mode/agent-capability.d.ts.map +1 -0
- package/dist/agent-mode/agent-capability.js +82 -0
- package/dist/agent-mode/agent-capability.js.map +1 -0
- package/dist/agent-mode/plan-execution-and-next.d.ts +3 -0
- package/dist/agent-mode/plan-execution-and-next.d.ts.map +1 -0
- package/dist/agent-mode/plan-execution-and-next.js +33 -0
- package/dist/agent-mode/plan-execution-and-next.js.map +1 -0
- package/dist/agent-mode/plan-preparation.d.ts +11 -0
- package/dist/agent-mode/plan-preparation.d.ts.map +1 -0
- package/dist/agent-mode/plan-preparation.js +98 -0
- package/dist/agent-mode/plan-preparation.js.map +1 -0
- package/dist/command/cmd-chat.d.ts +2 -0
- package/dist/command/cmd-chat.d.ts.map +1 -0
- package/dist/command/cmd-chat.js +137 -0
- package/dist/command/cmd-chat.js.map +1 -0
- package/dist/command/cmd-run.d.ts +2 -0
- package/dist/command/cmd-run.d.ts.map +1 -0
- package/dist/command/cmd-run.js +42 -0
- package/dist/command/cmd-run.js.map +1 -0
- package/dist/exec.d.ts +3 -0
- package/dist/exec.d.ts.map +1 -0
- package/dist/exec.js +78 -0
- package/dist/exec.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/prompt.d.ts +7 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +90 -0
- package/dist/prompt.js.map +1 -0
- package/dist/sample-page.d.ts +3 -0
- package/dist/sample-page.d.ts.map +1 -0
- package/dist/sample-page.js +144 -0
- package/dist/sample-page.js.map +1 -0
- package/package.json +50 -0
package/SWAN-DSL.md
ADDED
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
# SWAN DSL — a UI Interaction DSL Full Specification
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 1. Purpose
|
|
6
|
+
|
|
7
|
+
This DSL describes:
|
|
8
|
+
|
|
9
|
+
> **User interfaces as hierarchical interaction graphs with explicit navigation states.**
|
|
10
|
+
|
|
11
|
+
It is designed to:
|
|
12
|
+
|
|
13
|
+
* Model pages, components, and flows
|
|
14
|
+
* Separate navigation from interaction
|
|
15
|
+
* Enable compilation to web/mobile frameworks
|
|
16
|
+
* Support visualization and verification
|
|
17
|
+
|
|
18
|
+
It is **declarative**, **state-oriented**, and **framework-agnostic**.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# 2. Core Concepts
|
|
23
|
+
|
|
24
|
+
## 2.1 Application
|
|
25
|
+
|
|
26
|
+
An application is the top-level container.
|
|
27
|
+
|
|
28
|
+
It defines:
|
|
29
|
+
|
|
30
|
+
* identity
|
|
31
|
+
* entry point
|
|
32
|
+
* owned pages and components
|
|
33
|
+
|
|
34
|
+
```dsl
|
|
35
|
+
app MyApp {
|
|
36
|
+
entry Home
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2.2 Pages (Navigation States)
|
|
43
|
+
|
|
44
|
+
A `page` represents a **reachable navigation state**.
|
|
45
|
+
|
|
46
|
+
Properties:
|
|
47
|
+
|
|
48
|
+
| Property | Value |
|
|
49
|
+
| ----------- | ----- |
|
|
50
|
+
| Addressable | Yes |
|
|
51
|
+
| Routable | Yes |
|
|
52
|
+
| Reusable | No |
|
|
53
|
+
| Stateful | Yes |
|
|
54
|
+
|
|
55
|
+
Pages:
|
|
56
|
+
|
|
57
|
+
* may contain UI
|
|
58
|
+
* may contain components
|
|
59
|
+
* may emit navigation
|
|
60
|
+
* may be navigation targets
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2.3 Components (Interaction Units)
|
|
65
|
+
|
|
66
|
+
A `component` represents a **reusable interaction unit**.
|
|
67
|
+
|
|
68
|
+
Properties:
|
|
69
|
+
|
|
70
|
+
| Property | Value |
|
|
71
|
+
| ----------- | ------------------- |
|
|
72
|
+
| Addressable | No |
|
|
73
|
+
| Routable | No |
|
|
74
|
+
| Reusable | Yes |
|
|
75
|
+
| Stateful | No (locally scoped) |
|
|
76
|
+
|
|
77
|
+
Components:
|
|
78
|
+
|
|
79
|
+
* may contain components
|
|
80
|
+
* may contain logic
|
|
81
|
+
* may emit navigation
|
|
82
|
+
* may not be targets
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 2.4 Navigation
|
|
87
|
+
|
|
88
|
+
Navigation is the transition between pages.
|
|
89
|
+
|
|
90
|
+
Only pages may be navigation destinations.
|
|
91
|
+
|
|
92
|
+
```dsl
|
|
93
|
+
-> Dashboard // valid
|
|
94
|
+
-> LoginForm // invalid
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Navigation events bubble upward.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# 3. Structural Model
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Application
|
|
105
|
+
├── Pages (graph nodes)
|
|
106
|
+
└── Components (hierarchical tree)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
* Pages form a directed graph
|
|
110
|
+
* Components form a tree
|
|
111
|
+
* Navigation edges connect pages
|
|
112
|
+
|
|
113
|
+
No cycles restriction is imposed.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
# 4. Lexical Elements
|
|
118
|
+
|
|
119
|
+
## 4.1 Identifiers
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Identifier ::= Letter (Letter | Digit | "_")*
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Case-sensitive.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 4.2 Literals
|
|
130
|
+
|
|
131
|
+
### String
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
"Any UTF-8 text"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Number
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
123 | 45.67
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Boolean
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
true | false
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
# 5. Top-Level Grammar (EBNF)
|
|
152
|
+
|
|
153
|
+
```ebnf
|
|
154
|
+
Program ::= AppDecl { PageDecl | ComponentDecl }
|
|
155
|
+
|
|
156
|
+
AppDecl ::= "app" Identifier "{" "entry" Identifier "}"
|
|
157
|
+
|
|
158
|
+
PageDecl ::= "page" Identifier Block
|
|
159
|
+
|
|
160
|
+
ComponentDecl ::= "component" Identifier Block
|
|
161
|
+
|
|
162
|
+
Block ::= "{" { Statement } "}"
|
|
163
|
+
|
|
164
|
+
QueryDecl ::= "query" Identifier [ ":" Type ] [ "=" Literal ]
|
|
165
|
+
|
|
166
|
+
Type ::= "string" | "number" | "boolean"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
# 6. Statements
|
|
172
|
+
|
|
173
|
+
```ebnf
|
|
174
|
+
Statement ::=
|
|
175
|
+
UIStatement
|
|
176
|
+
| UseStatement
|
|
177
|
+
| ActionStatement
|
|
178
|
+
| HandlerStatement
|
|
179
|
+
| ConditionalStatement
|
|
180
|
+
| QueryStatement
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 6.1 UI Statements
|
|
186
|
+
|
|
187
|
+
```ebnf
|
|
188
|
+
UIStatement ::=
|
|
189
|
+
"header" String
|
|
190
|
+
| "text" String
|
|
191
|
+
| "button" String NavTarget
|
|
192
|
+
| "link" String NavTarget
|
|
193
|
+
| "field" Identifier
|
|
194
|
+
| "input" Identifier
|
|
195
|
+
| TableStatement
|
|
196
|
+
| ChartStatement
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
|
|
201
|
+
```dsl
|
|
202
|
+
header "Login"
|
|
203
|
+
text "Welcome back"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 6.7 Table Statement
|
|
209
|
+
|
|
210
|
+
A `table` statement renders **tabular data** with named columns.
|
|
211
|
+
|
|
212
|
+
Each row is a fixed-width list of values that must match the declared columns.
|
|
213
|
+
|
|
214
|
+
```ebnf
|
|
215
|
+
TableStatement ::= "table" Identifier "{" TableColumns TableRows "}"
|
|
216
|
+
|
|
217
|
+
TableColumns ::= "columns" "[" ColumnName { "," ColumnName } "]"
|
|
218
|
+
|
|
219
|
+
ColumnName ::= String
|
|
220
|
+
|
|
221
|
+
TableRows ::= { TableRow }
|
|
222
|
+
|
|
223
|
+
TableRow ::= "row" "[" CellValue { "," CellValue } "]"
|
|
224
|
+
|
|
225
|
+
CellValue ::= Literal | Expression
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Example:
|
|
229
|
+
|
|
230
|
+
```dsl
|
|
231
|
+
table UserList {
|
|
232
|
+
columns ["Name", "Role", "Status"]
|
|
233
|
+
row ["Alice", "Admin", "Active"]
|
|
234
|
+
row ["Bob", "Viewer", "Inactive"]
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The table identifier (`UserList`) names the table for semantic checking. It does **not** introduce a navigable scope.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 6.8 Chart Statement
|
|
243
|
+
|
|
244
|
+
A `chart` statement renders **visual data** using a specified chart type.
|
|
245
|
+
|
|
246
|
+
Each `series` is a named data sequence. Each `point` is a single `x, y` data pair.
|
|
247
|
+
|
|
248
|
+
```ebnf
|
|
249
|
+
ChartStatement ::= "chart" Identifier ChartType "{" { SeriesDecl } "}"
|
|
250
|
+
|
|
251
|
+
ChartType ::= "bar" | "line" | "pie" | "area" | "scatter"
|
|
252
|
+
|
|
253
|
+
SeriesDecl ::= "series" String "{" { DataPoint } "}"
|
|
254
|
+
|
|
255
|
+
DataPoint ::= "point" CellValue "," CellValue
|
|
256
|
+
|
|
257
|
+
CellValue ::= Literal | Expression
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Part | Required | Description |
|
|
261
|
+
| -------------- | -------- | ---------------------------------------- |
|
|
262
|
+
| Identifier | Yes | Chart name (unique within scope) |
|
|
263
|
+
| ChartType | Yes | Visual style: bar, line, pie, area, scatter |
|
|
264
|
+
| `series` block | Yes (≥1) | Named sequence of data points |
|
|
265
|
+
| `point` x, y | Yes (≥1) | Single (x, y) coordinate or category |
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
|
|
269
|
+
```dsl
|
|
270
|
+
chart MonthlySales line {
|
|
271
|
+
series "Revenue" {
|
|
272
|
+
point "Jan", 4200
|
|
273
|
+
point "Feb", 5800
|
|
274
|
+
point "Mar", 7100
|
|
275
|
+
}
|
|
276
|
+
series "Cost" {
|
|
277
|
+
point "Jan", 2100
|
|
278
|
+
point "Feb", 3000
|
|
279
|
+
point "Mar", 3500
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Pie charts use label/value pairs:
|
|
285
|
+
|
|
286
|
+
```dsl
|
|
287
|
+
chart TrafficSource pie {
|
|
288
|
+
series "Sources" {
|
|
289
|
+
point "Organic", 65
|
|
290
|
+
point "Paid", 20
|
|
291
|
+
point "Direct", 15
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## 6.2 Component Composition
|
|
299
|
+
|
|
300
|
+
```ebnf
|
|
301
|
+
UseStatement ::= "use" Identifier
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
|
|
306
|
+
```dsl
|
|
307
|
+
use LoginForm
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 6.3 Actions
|
|
313
|
+
|
|
314
|
+
Actions represent named interaction events.
|
|
315
|
+
|
|
316
|
+
```ebnf
|
|
317
|
+
ActionStatement ::=
|
|
318
|
+
"submit" String "->" Identifier
|
|
319
|
+
| "click" String "->" Identifier
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Example:
|
|
323
|
+
|
|
324
|
+
```dsl
|
|
325
|
+
submit "Continue" -> authenticate
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Here `authenticate` is an action identifier.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 6.4 Event Handlers
|
|
333
|
+
|
|
334
|
+
Handlers define control flow.
|
|
335
|
+
|
|
336
|
+
```ebnf
|
|
337
|
+
HandlerStatement ::=
|
|
338
|
+
"on" Identifier "{" { OutcomeClause } "}"
|
|
339
|
+
|
|
340
|
+
OutcomeClause ::=
|
|
341
|
+
Identifier "->" Identifier
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Example:
|
|
345
|
+
|
|
346
|
+
```dsl
|
|
347
|
+
on authenticate {
|
|
348
|
+
success -> Dashboard
|
|
349
|
+
error -> LoginError
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 6.5 Conditionals
|
|
356
|
+
|
|
357
|
+
```ebnf
|
|
358
|
+
ConditionalStatement ::=
|
|
359
|
+
"if" Expression Block
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Example:
|
|
363
|
+
|
|
364
|
+
```dsl
|
|
365
|
+
if user.role == "admin" {
|
|
366
|
+
button "Admin" -> AdminPanel
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 6.6 Page Query Statement
|
|
373
|
+
|
|
374
|
+
A `query` statement declares a **URL query parameter** accepted by a page.
|
|
375
|
+
It maps directly to the query string portion of the URL (e.g. `/search?q=hello&page=2`).
|
|
376
|
+
|
|
377
|
+
Only valid inside a `page` block — **not** inside components.
|
|
378
|
+
|
|
379
|
+
```ebnf
|
|
380
|
+
QueryStatement ::=
|
|
381
|
+
"query" Identifier [ ":" Type ] [ "=" Literal ]
|
|
382
|
+
|
|
383
|
+
Type ::= "string" | "number" | "boolean"
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
| Part | Required | Description |
|
|
387
|
+
| ----------- | -------- | ---------------------------------------- |
|
|
388
|
+
| Identifier | Yes | Query parameter key (maps to URL `?key`) |
|
|
389
|
+
| `:` Type | No | Expected value type (default: `string`) |
|
|
390
|
+
| `=` Literal | No | Default value when parameter is absent |
|
|
391
|
+
|
|
392
|
+
Example:
|
|
393
|
+
|
|
394
|
+
```dsl
|
|
395
|
+
page Search {
|
|
396
|
+
query q // ?q=<any string>
|
|
397
|
+
query page : number = 1 // ?page=2 (default: 1)
|
|
398
|
+
query active : boolean // ?active=true
|
|
399
|
+
|
|
400
|
+
header "Search Results"
|
|
401
|
+
text "Showing results for query"
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Runtime behaviour:
|
|
406
|
+
|
|
407
|
+
* Query values are read from the URL on page entry.
|
|
408
|
+
* If a parameter is absent and a default is declared, the default is used.
|
|
409
|
+
* If a parameter is absent and no default is declared, the value is `null`.
|
|
410
|
+
* Query values are available in expressions via the `query` scope:
|
|
411
|
+
|
|
412
|
+
```dsl
|
|
413
|
+
if query.active == true {
|
|
414
|
+
text "Showing active items only"
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
# 7. Expressions
|
|
421
|
+
|
|
422
|
+
```ebnf
|
|
423
|
+
Expression ::=
|
|
424
|
+
Identifier
|
|
425
|
+
| Literal
|
|
426
|
+
| Expression Operator Expression
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Operators:
|
|
430
|
+
|
|
431
|
+
```
|
|
432
|
+
== != < > <= >= && || !
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Scope:
|
|
436
|
+
|
|
437
|
+
* `user`
|
|
438
|
+
* `session`
|
|
439
|
+
* `env`
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
# 8. Navigation Targets
|
|
444
|
+
|
|
445
|
+
```ebnf
|
|
446
|
+
NavTarget ::= "->" Identifier [ QueryArgs ]
|
|
447
|
+
|
|
448
|
+
QueryArgs ::= "?" QueryArg { "&" QueryArg }
|
|
449
|
+
|
|
450
|
+
QueryArg ::= Identifier "=" Expression
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Semantics:
|
|
454
|
+
|
|
455
|
+
* Identifier must resolve to a `page`
|
|
456
|
+
* Resolution is static
|
|
457
|
+
* `QueryArgs` are optional; they set query parameter values on the target page
|
|
458
|
+
* Each key in `QueryArgs` must match a `query` declaration on the target page
|
|
459
|
+
|
|
460
|
+
Example:
|
|
461
|
+
|
|
462
|
+
```dsl
|
|
463
|
+
button "Next Page" -> Search?q="hello"&page=2
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
# 9. Semantic Rules (Static)
|
|
469
|
+
|
|
470
|
+
### SR-1: Single Entry Point
|
|
471
|
+
|
|
472
|
+
```
|
|
473
|
+
app must define exactly one entry page
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### SR-2: Valid Entry
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
entry must reference a page
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### SR-3: Valid Targets
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
All navigation targets must be pages
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### SR-4: No Orphan Pages
|
|
489
|
+
|
|
490
|
+
```
|
|
491
|
+
All pages must be reachable from entry
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
(optional strict mode)
|
|
495
|
+
|
|
496
|
+
### SR-5: No Cyclic Components
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
Component composition graph must be acyclic
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### SR-6: Unique Names
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
Identifiers are unique per namespace
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Namespaces:
|
|
509
|
+
|
|
510
|
+
* pages
|
|
511
|
+
* components
|
|
512
|
+
* actions
|
|
513
|
+
* tables (within a page or component block)
|
|
514
|
+
* charts (within a page or component block)
|
|
515
|
+
|
|
516
|
+
### SR-7: Query in Pages Only
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
query statements are only valid inside page blocks
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### SR-8: Unique Query Keys
|
|
523
|
+
|
|
524
|
+
```
|
|
525
|
+
Query parameter identifiers must be unique within a page
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### SR-9: Valid Query Args in Navigation
|
|
529
|
+
|
|
530
|
+
```
|
|
531
|
+
Each key in a navigation QueryArgs list must match
|
|
532
|
+
a query declaration on the target page
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### SR-10: Table Column Count Consistency
|
|
536
|
+
|
|
537
|
+
```
|
|
538
|
+
Every row in a table must have exactly as many cells
|
|
539
|
+
as there are declared columns
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Example of a violation:
|
|
543
|
+
|
|
544
|
+
```dsl
|
|
545
|
+
table Bad {
|
|
546
|
+
columns ["A", "B", "C"]
|
|
547
|
+
row ["x", "y"] // error: 2 cells, 3 columns expected
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### SR-11: Table Must Have Columns
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
A table block must declare at least one column
|
|
555
|
+
and at least one row
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### SR-12: Chart Must Have at Least One Series
|
|
559
|
+
|
|
560
|
+
```
|
|
561
|
+
A chart block must contain at least one series declaration
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### SR-13: Series Must Have at Least One Point
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
Each series block must contain at least one data point
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### SR-14: Pie Chart Single Series
|
|
571
|
+
|
|
572
|
+
```
|
|
573
|
+
A pie chart may only contain a single series
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Pie charts represent a whole divided into parts. Multiple series on a pie chart are undefined and rejected.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
# 10. Runtime Semantics
|
|
581
|
+
|
|
582
|
+
## 10.1 Rendering
|
|
583
|
+
|
|
584
|
+
Rendering is recursive:
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
Render(Page):
|
|
588
|
+
render local UI
|
|
589
|
+
render used components
|
|
590
|
+
|
|
591
|
+
Render(Component):
|
|
592
|
+
render UI
|
|
593
|
+
render children
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## 10.2 Event Propagation
|
|
599
|
+
|
|
600
|
+
1. User triggers event
|
|
601
|
+
2. Component handles if defined
|
|
602
|
+
3. Otherwise bubbles up
|
|
603
|
+
4. Page resolves navigation
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## 10.3 Navigation Resolution
|
|
608
|
+
|
|
609
|
+
When a navigation intent occurs:
|
|
610
|
+
|
|
611
|
+
```
|
|
612
|
+
-> TargetPage
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Runtime:
|
|
616
|
+
|
|
617
|
+
```
|
|
618
|
+
currentPage := TargetPage
|
|
619
|
+
re-render
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
State is reset unless persisted.
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## 10.4 Table Rendering
|
|
627
|
+
|
|
628
|
+
A table is rendered as a **two-dimensional grid**:
|
|
629
|
+
|
|
630
|
+
```
|
|
631
|
+
Render(Table):
|
|
632
|
+
render header row from columns[]
|
|
633
|
+
for each row:
|
|
634
|
+
render cells left-to-right
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
Cell values are evaluated lazily at render time. If a cell contains an expression, it is resolved against the current scope (`user`, `session`, `env`, `query`).
|
|
638
|
+
|
|
639
|
+
---
|
|
640
|
+
|
|
641
|
+
## 10.5 Chart Rendering
|
|
642
|
+
|
|
643
|
+
A chart is rendered as a **visual data graphic** delegated to the compilation target:
|
|
644
|
+
|
|
645
|
+
```
|
|
646
|
+
Render(Chart):
|
|
647
|
+
resolve all point values
|
|
648
|
+
emit chart type + series data to target backend
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
The DSL does not prescribe pixel layout — that is the responsibility of the compilation target (e.g., React renders a `<Chart>` component; HTML emits a `<canvas>` block).
|
|
652
|
+
|
|
653
|
+
Point values:
|
|
654
|
+
|
|
655
|
+
* `x` axis — category label (String) or numeric position (Number)
|
|
656
|
+
* `y` axis — numeric value (Number)
|
|
657
|
+
|
|
658
|
+
For pie charts the `x` value is the **slice label** and `y` is the **slice size**.
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
# 11. Flow Semantics
|
|
663
|
+
|
|
664
|
+
Each action defines a mini-state machine.
|
|
665
|
+
|
|
666
|
+
Example:
|
|
667
|
+
|
|
668
|
+
```dsl
|
|
669
|
+
submit -> auth
|
|
670
|
+
|
|
671
|
+
on auth {
|
|
672
|
+
success -> Dashboard
|
|
673
|
+
error -> LoginError
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
Equivalent to:
|
|
678
|
+
|
|
679
|
+
```
|
|
680
|
+
Idle → Submitting → {Success, Error}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
# 12. Validation Phases
|
|
686
|
+
|
|
687
|
+
## Phase 1: Parsing
|
|
688
|
+
|
|
689
|
+
* Grammar conformance
|
|
690
|
+
|
|
691
|
+
## Phase 2: Name Resolution
|
|
692
|
+
|
|
693
|
+
* Link identifiers
|
|
694
|
+
* Build symbol tables
|
|
695
|
+
|
|
696
|
+
## Phase 3: Flow Analysis
|
|
697
|
+
|
|
698
|
+
* Build navigation graph
|
|
699
|
+
* Check reachability
|
|
700
|
+
|
|
701
|
+
## Phase 4: Type Checking (optional)
|
|
702
|
+
|
|
703
|
+
* Validate expressions
|
|
704
|
+
* Validate fields
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
# 13. Compilation Targets
|
|
709
|
+
|
|
710
|
+
The DSL is target-independent.
|
|
711
|
+
|
|
712
|
+
Possible backends:
|
|
713
|
+
|
|
714
|
+
| Target | Page / Component Mapping | Table Mapping | Chart Mapping |
|
|
715
|
+
| ------- | ------------------------ | ------------------- | -------------------------- |
|
|
716
|
+
| HTML | Routes + templates | `<table>` element | `<canvas>` + Chart.js |
|
|
717
|
+
| React | Router + components | `<Table>` component | `<Chart>` component |
|
|
718
|
+
| Flutter | Navigator + Widgets | `DataTable` widget | `fl_chart` widget |
|
|
719
|
+
| SwiftUI | NavigationStack | `Table` view | `Swift Charts` view |
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
# 14. Example (Complete Program)
|
|
724
|
+
|
|
725
|
+
```dsl
|
|
726
|
+
app MyApp {
|
|
727
|
+
entry Home
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
page Home {
|
|
731
|
+
header "Welcome"
|
|
732
|
+
button "Log in" -> Login
|
|
733
|
+
button "Search" -> Search?q=""&page=1
|
|
734
|
+
button "Dashboard" -> Dashboard
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
component LoginForm {
|
|
738
|
+
field email
|
|
739
|
+
field password
|
|
740
|
+
|
|
741
|
+
submit "Continue" -> auth
|
|
742
|
+
|
|
743
|
+
on auth {
|
|
744
|
+
success -> Dashboard
|
|
745
|
+
error -> LoginError
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
page Login {
|
|
750
|
+
header "Login"
|
|
751
|
+
use LoginForm
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
page LoginError {
|
|
755
|
+
text "Invalid credentials"
|
|
756
|
+
button "Retry" -> Login
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
page Dashboard {
|
|
760
|
+
header "Dashboard"
|
|
761
|
+
text "Hello!"
|
|
762
|
+
button "Logout" -> Home
|
|
763
|
+
button "Search Items" -> Search?q=""&page=1
|
|
764
|
+
|
|
765
|
+
// Recent users table
|
|
766
|
+
table RecentUsers {
|
|
767
|
+
columns ["Name", "Role", "Last Seen"]
|
|
768
|
+
row ["Alice", "Admin", "2 mins ago"]
|
|
769
|
+
row ["Bob", "Viewer", "1 hour ago"]
|
|
770
|
+
row ["Carol", "Editor", "Yesterday"]
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Monthly activity chart
|
|
774
|
+
chart MonthlyLogins line {
|
|
775
|
+
series "Logins" {
|
|
776
|
+
point "Jan", 320
|
|
777
|
+
point "Feb", 410
|
|
778
|
+
point "Mar", 390
|
|
779
|
+
point "Apr", 520
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Traffic breakdown (pie)
|
|
784
|
+
chart TrafficSource pie {
|
|
785
|
+
series "Sources" {
|
|
786
|
+
point "Organic", 58
|
|
787
|
+
point "Paid", 27
|
|
788
|
+
point "Direct", 15
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
page Search {
|
|
794
|
+
query q : string = ""
|
|
795
|
+
query page : number = 1
|
|
796
|
+
query active : boolean
|
|
797
|
+
|
|
798
|
+
header "Search"
|
|
799
|
+
text "Showing results"
|
|
800
|
+
|
|
801
|
+
if query.active == true {
|
|
802
|
+
text "(active items only)"
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
button "Next" -> Search?q=query.q&page=query.page+1
|
|
806
|
+
button "Home" -> Home
|
|
807
|
+
}
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
---
|
|
811
|
+
|
|
812
|
+
# 15. Design Guarantees
|
|
813
|
+
|
|
814
|
+
This DSL guarantees:
|
|
815
|
+
|
|
816
|
+
✅ Explicit navigation graph
|
|
817
|
+
✅ No hidden routes
|
|
818
|
+
✅ Predictable composition
|
|
819
|
+
✅ Static analyzability
|
|
820
|
+
✅ Framework independence
|
|
821
|
+
✅ AI-safe generation
|
|
822
|
+
✅ Schema-checked tabular data
|
|
823
|
+
✅ Declarative, backend-agnostic charts
|
|
824
|
+
|
|
825
|
+
---
|
|
826
|
+
|
|
827
|
+
# 16. Design Philosophy
|
|
828
|
+
|
|
829
|
+
> Pages are states.
|
|
830
|
+
> Components are behavior.
|
|
831
|
+
> Flows are explicit.
|
|
832
|
+
> Navigation is centralized.
|