@diagrammo/dgmo 0.8.19 → 0.8.21

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 (74) hide show
  1. package/dist/cli.cjs +92 -131
  2. package/dist/editor.cjs +13 -1
  3. package/dist/editor.cjs.map +1 -1
  4. package/dist/editor.js +13 -1
  5. package/dist/editor.js.map +1 -1
  6. package/dist/highlight.cjs +13 -1
  7. package/dist/highlight.cjs.map +1 -1
  8. package/dist/highlight.js +13 -1
  9. package/dist/highlight.js.map +1 -1
  10. package/dist/index.cjs +4524 -1511
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +427 -186
  13. package/dist/index.d.ts +427 -186
  14. package/dist/index.js +4526 -1503
  15. package/dist/index.js.map +1 -1
  16. package/docs/guide/chart-mindmap.md +198 -0
  17. package/docs/guide/chart-sequence.md +23 -1
  18. package/docs/guide/chart-wireframe.md +100 -0
  19. package/docs/guide/index.md +8 -0
  20. package/docs/language-reference.md +210 -2
  21. package/package.json +22 -9
  22. package/src/boxes-and-lines/collapse.ts +21 -3
  23. package/src/boxes-and-lines/layout.ts +51 -9
  24. package/src/boxes-and-lines/parser.ts +16 -4
  25. package/src/boxes-and-lines/renderer.ts +121 -23
  26. package/src/boxes-and-lines/types.ts +1 -0
  27. package/src/c4/parser.ts +8 -7
  28. package/src/class/parser.ts +6 -0
  29. package/src/cli.ts +1 -9
  30. package/src/completion.ts +26 -0
  31. package/src/d3.ts +169 -266
  32. package/src/dgmo-router.ts +103 -5
  33. package/src/diagnostics.ts +16 -6
  34. package/src/echarts.ts +43 -10
  35. package/src/editor/keywords.ts +12 -0
  36. package/src/er/parser.ts +22 -2
  37. package/src/gantt/renderer.ts +2 -2
  38. package/src/graph/flowchart-parser.ts +89 -52
  39. package/src/graph/layout.ts +73 -9
  40. package/src/graph/state-collapse.ts +78 -0
  41. package/src/graph/state-parser.ts +60 -35
  42. package/src/graph/state-renderer.ts +139 -34
  43. package/src/index.ts +41 -16
  44. package/src/infra/parser.ts +9 -2
  45. package/src/kanban/renderer.ts +305 -59
  46. package/src/mindmap/collapse.ts +88 -0
  47. package/src/mindmap/layout.ts +605 -0
  48. package/src/mindmap/parser.ts +379 -0
  49. package/src/mindmap/renderer.ts +543 -0
  50. package/src/mindmap/text-wrap.ts +207 -0
  51. package/src/mindmap/types.ts +55 -0
  52. package/src/palettes/color-utils.ts +4 -12
  53. package/src/palettes/index.ts +0 -4
  54. package/src/render.ts +31 -20
  55. package/src/sequence/parser.ts +7 -2
  56. package/src/sequence/renderer.ts +141 -21
  57. package/src/sharing.ts +2 -0
  58. package/src/sitemap/layout.ts +35 -12
  59. package/src/sitemap/renderer.ts +1 -6
  60. package/src/utils/arrows.ts +180 -11
  61. package/src/utils/d3-types.ts +4 -0
  62. package/src/utils/export-container.ts +3 -2
  63. package/src/utils/legend-constants.ts +0 -4
  64. package/src/utils/legend-d3.ts +1 -0
  65. package/src/utils/legend-layout.ts +2 -2
  66. package/src/utils/parsing.ts +2 -0
  67. package/src/utils/time-ticks.ts +213 -0
  68. package/src/wireframe/layout.ts +460 -0
  69. package/src/wireframe/parser.ts +956 -0
  70. package/src/wireframe/renderer.ts +1293 -0
  71. package/src/wireframe/types.ts +110 -0
  72. package/src/branding.ts +0 -67
  73. package/src/dgmo-mermaid.ts +0 -262
  74. package/src/palettes/mermaid-bridge.ts +0 -220
@@ -0,0 +1,198 @@
1
+ # Mind Map
2
+
3
+ ```dgmo
4
+ mindmap Product Strategy
5
+
6
+ Research
7
+ User Interviews
8
+ Surveys | description: Quarterly NPS survey
9
+ Focus Groups
10
+ Competitor Analysis
11
+ Feature Matrix
12
+ Pricing Review
13
+ Development
14
+ MVP Features
15
+ Auth System
16
+ description: Handle login, signup, OAuth flows
17
+ Dashboard
18
+ Nice-to-haves | collapsed: true
19
+ Dark Mode
20
+ Export PDF
21
+ Go-to-Market
22
+ Launch Plan
23
+ Blog Post
24
+ Demo Video | description: 2-min product walkthrough
25
+ ```
26
+
27
+ ## Overview
28
+
29
+ Mind maps visualize hierarchical information radiating from a central concept. Each branch represents a subtopic, with deeper nesting for finer detail. Mind maps are useful for brainstorming, project planning, knowledge organization, and breaking down complex topics.
30
+
31
+ **Interactive features:** Click nodes to navigate to their source line. Collapse and expand subtrees by clicking nodes with children. Toggle tag group coloring and depth-based coloring via the legend controls.
32
+
33
+ ## Syntax
34
+
35
+ ```
36
+ mindmap Title
37
+
38
+ Node
39
+ Child Node
40
+ Grandchild
41
+ Another Child
42
+ ```
43
+
44
+ The first line declares the chart type. The title becomes the root node. Indentation establishes the parent-child hierarchy.
45
+
46
+ ## Nodes
47
+
48
+ Every non-blank, non-directive line is a node. Nesting is set by indentation:
49
+
50
+ ```
51
+ mindmap Root
52
+ Level 1a
53
+ Level 2a
54
+ Level 2b
55
+ Level 1b
56
+ ```
57
+
58
+ ### Node Colors
59
+
60
+ Add a color suffix in parentheses:
61
+
62
+ ```
63
+ Important Topic(red)
64
+ Sub-topic(blue)
65
+ ```
66
+
67
+ ### Descriptions
68
+
69
+ Nodes can have descriptions shown as secondary text. Two forms:
70
+
71
+ ```
72
+ // Pipe form (single line)
73
+ Surveys | description: Quarterly NPS survey
74
+
75
+ // Indented form (before children)
76
+ Auth System
77
+ description: Handle login, signup, and OAuth flows
78
+ Login Page
79
+ ```
80
+
81
+ ### Collapse Default
82
+
83
+ Set a node's default collapsed state with pipe metadata:
84
+
85
+ ```
86
+ Nice-to-haves | collapsed: true
87
+ Dark Mode
88
+ Export PDF
89
+ ```
90
+
91
+ Collapsed nodes show a drill-bar indicating hidden children. Click to expand.
92
+
93
+ ## Multi-Root
94
+
95
+ Omit the title to create multiple independent root trees:
96
+
97
+ ```
98
+ mindmap
99
+
100
+ Q1 Goals
101
+ Ship MVP
102
+ Hire designers
103
+ Q2 Goals
104
+ Launch marketing
105
+ Expand team
106
+ ```
107
+
108
+ The diagram title is inferred from the first root's label.
109
+
110
+ ## Pipe Metadata
111
+
112
+ Attach metadata after `|` with comma-separated `key: value` pairs:
113
+
114
+ ```
115
+ Node | priority: High, status: Done
116
+ ```
117
+
118
+ Tag values, descriptions, and `collapsed` are all set via pipe metadata.
119
+
120
+ ## Tag Groups
121
+
122
+ Tag groups define color-coded categories. They appear before content and follow the standard tag syntax:
123
+
124
+ ```
125
+ mindmap Root
126
+
127
+ tag Priority p
128
+ High(red)
129
+ Medium(yellow)
130
+ Low(green)
131
+
132
+ Task A | p: High
133
+ Task B | p: Low
134
+ ```
135
+
136
+ - The alias (`p`) provides a shorthand for metadata keys
137
+ - The active tag group colors nodes by their tag value
138
+ - Click a tag group name in the legend to activate or deactivate it
139
+
140
+ ## Options
141
+
142
+ | Option | Effect |
143
+ |--------|--------|
144
+ | `active-tag GroupName` | Set the default active tag group |
145
+ | `hide-descriptions` | Hide description text on all nodes |
146
+
147
+ Options are placed on their own line before content:
148
+
149
+ ```
150
+ mindmap Root
151
+
152
+ tag Priority p
153
+ High(red)
154
+ Low(green)
155
+
156
+ active-tag Priority
157
+ hide-descriptions
158
+
159
+ Task A | p: High
160
+ ```
161
+
162
+ ## Complete Example
163
+
164
+ ```dgmo
165
+ mindmap Product Strategy(blue)
166
+
167
+ tag Priority p
168
+ High(red)
169
+ Medium(yellow)
170
+ Low(green)
171
+
172
+ tag Department d
173
+ Engineering(blue)
174
+ Design(purple)
175
+ Marketing(orange)
176
+
177
+ active-tag Priority
178
+
179
+ Research | d: Marketing
180
+ User Interviews | p: High
181
+ Surveys | description: Quarterly NPS survey
182
+ Focus Groups
183
+ Competitor Analysis | d: Engineering
184
+ Feature Matrix
185
+ Pricing Review
186
+ Development | p: High, d: Engineering
187
+ MVP Features
188
+ Auth System
189
+ description: Handle login, signup, OAuth flows
190
+ Dashboard
191
+ Nice-to-haves | p: Low, collapsed: true
192
+ Dark Mode
193
+ Export PDF
194
+ Go-to-Market | d: Marketing
195
+ Launch Plan
196
+ Blog Post
197
+ Demo Video | description: 2-min product walkthrough
198
+ ```
@@ -103,7 +103,29 @@ PaymentGW is a networking aka "Payment Gateway"
103
103
  OrderDB position -1
104
104
  ```
105
105
 
106
- Position `0` is leftmost, `-1` is rightmost. Unpositioned participants appear in first-mention order.
106
+ ## Participant Ordering
107
+
108
+ Participants are laid out left-to-right based on **first appearance in messages** — the first participant mentioned gets the leftmost column.
109
+
110
+ **Position values:**
111
+ - `0` = leftmost, `1` = second from left, etc.
112
+ - `-1` = rightmost, `-2` = second from right
113
+ - If two participants target the same slot, the later one shifts to the nearest free position
114
+
115
+ **Groups affect ordering:** members of the same group always stay adjacent (see [Groups](#groups) below). The group is placed where its first member would naturally appear.
116
+
117
+ **Priority (highest wins):**
118
+ 1. Explicit `position N`
119
+ 2. Group adjacency
120
+ 3. First appearance in messages
121
+
122
+ ```
123
+ // Example: force the database to the far right
124
+ sequence
125
+ User -placeOrder-> OrderService
126
+ OrderService -save-> OrderDB
127
+ OrderDB position -1
128
+ ```
107
129
 
108
130
  ## Messages
109
131
 
@@ -0,0 +1,100 @@
1
+ # Wireframe
2
+
3
+ ```dgmo
4
+ wireframe Login Page
5
+
6
+ [Header]
7
+ Acme App
8
+ nav
9
+ Home | active
10
+ About
11
+ Pricing
12
+
13
+ [Main]
14
+ # Sign In
15
+
16
+ Email [user@example.com]
17
+ Password [****] | password
18
+
19
+ <x> Remember me
20
+
21
+ (Sign In)
22
+ (Forgot Password?) | ghost
23
+
24
+ ---
25
+
26
+ New here? (Create Account) | ghost
27
+ ```
28
+
29
+ ## Overview
30
+
31
+ Wireframe diagrams use **visual-mnemonic syntax** where bracket characters communicate the element type. The source text reads as a wireframe even before rendering.
32
+
33
+ ## Elements
34
+
35
+ | Syntax | Element |
36
+ |--------|---------|
37
+ | `[text]` (no children) | Text input |
38
+ | `[Name]` (with children) | Group / region |
39
+ | `(Label)` | Button |
40
+ | `{A \| B \| C}` | Dropdown |
41
+ | `<x>` / `< >` | Checkbox |
42
+ | `(*) Label` / `( ) Label` | Radio button |
43
+ | `# Text` | Heading |
44
+ | `## Text` | Subheading |
45
+ | `---` | Divider |
46
+ | `- text` | List item |
47
+
48
+ ## Keywords
49
+
50
+ `nav`, `tabs`, `table`, `image`, `modal`, `skeleton`, `alert`, `progress`, `chart`
51
+
52
+ - `image round` / `image wide` — shape hints
53
+ - `chart line` / `chart bar` / `chart pie` — chart silhouettes
54
+ - `progress 60` — percentage bar
55
+ - `table 5x4` — skeleton table with dimensions
56
+
57
+ ## States
58
+
59
+ Pipe metadata flags on elements:
60
+
61
+ ```
62
+ (Submit) | disabled
63
+ (Delete) | destructive
64
+ (Cancel) | ghost
65
+ [Email] | password
66
+ [Notes] | textarea
67
+ <x> Dark mode | toggle
68
+ [Cards] | horizontal
69
+ ```
70
+
71
+ ## Layout
72
+
73
+ - **Desktop** (default): 1200px, top-level regions side-by-side
74
+ - **Mobile**: `mobile` keyword, 375px vertical stacking
75
+ - **Smart sizing**: `sidebar` gets ~25%, `main` fills remaining
76
+ - `| horizontal` on any group arranges children in a row
77
+
78
+ ## Multi-Element Lines
79
+
80
+ Two or more spaces between elements on one line:
81
+
82
+ ```
83
+ Email [user@example.com] // label + field
84
+ (-) 1 (+) // inline stepper
85
+ ```
86
+
87
+ ## Tables
88
+
89
+ ```dgmo
90
+ wireframe Data
91
+
92
+ table
93
+ Name, Email, Role
94
+ John, john@, Admin
95
+ Sally, sally@, Editor
96
+
97
+ // Skeleton shorthand:
98
+ table 5x4
99
+ Name, Email, Role, Status
100
+ ```
@@ -4,6 +4,14 @@ Diagrammo is a diagram editor for creating charts and diagrams with a simple pla
4
4
 
5
5
  Learn more at **[diagrammo.app](https://diagrammo.app)**.
6
6
 
7
+ ## DGMO and Diagrammo
8
+
9
+ **DGMO** is the plain-text markup language you write. **Diagrammo** is the app you write it in.
10
+
11
+ Think of it like Markdown and your editor — Markdown is the syntax, and you can write it anywhere. DGMO works the same way: it's a `.dgmo` text file that describes a diagram. You can create and edit `.dgmo` files in the Diagrammo desktop app, the online editor, Obsidian (via plugin), or any text editor. The `dgmo` CLI renders them from the terminal, and the `@diagrammo/dgmo` npm package lets you render them programmatically.
12
+
13
+ The name "DGMO" is shorthand for "Diagrammo" — shorter to type, easier to use as a file extension and command name.
14
+
7
15
  ## Getting Started
8
16
 
9
17
  - **Create a new file** using the file tree on the left, or press **Cmd + N**
@@ -20,7 +20,8 @@
20
20
  14. [Timeline Diagrams](#14-timeline-diagrams)
21
21
  15. [Data Charts](#15-data-charts)
22
22
  16. [Visualizations](#16-visualizations)
23
- 17. [Colon Usage Summary](#17-colon-usage-summary)
23
+ 17. [Wireframe Diagrams](#17-wireframe-diagrams)
24
+ 18. [Colon Usage Summary](#18-colon-usage-summary)
24
25
 
25
26
  ---
26
27
 
@@ -114,6 +115,79 @@ no-option-name // off
114
115
  - Bare keyword = on; `no-` prefix = off
115
116
  - Must appear before diagram content
116
117
 
118
+ ### 1.9 In-Arrow Message Labels
119
+
120
+ An **in-arrow label** is the text embedded inside an arrow between the opening delimiter and the arrow token, as in `A -label-> B`.
121
+
122
+ ```
123
+ A -label-> B
124
+ ^ ^---^ ^^
125
+ | | ||
126
+ | | |+- destination id
127
+ | | +- arrow token
128
+ | +- label text (plain, no markdown)
129
+ +- opening delimiter (matches arrow type)
130
+ ```
131
+
132
+ **Chart types that support in-arrow labels**: sequence, flowchart, state, infra, c4, er, class, boxes-and-lines.
133
+
134
+ #### Cheat sheet
135
+
136
+ ```
137
+ // happy-path: labels are plain text with punctuation allowed
138
+ A -location[]-> B // label = "location[]"
139
+ A -a[b]c-> B // label = "a[b]c"
140
+ A -{json}-> B // label = "{json}"
141
+
142
+ // unicode: all scripts and emoji preserved verbatim
143
+ A -cafƩ-> B
144
+ A -ę—„ęœ¬čŖž-> B
145
+ A -šŸŽ‰-> B
146
+
147
+ // punctuation is literal — no markdown interpretation
148
+ A -(parenthetical)-> B // label = "(parenthetical)" (NOT a color)
149
+ A -*emphasis*-> B // label = "*emphasis*" (NOT bold)
150
+ A -`code`-> B // label = "`code`" (NOT a code span)
151
+
152
+ // forbidden: -> and ~> substrings inside a label
153
+ A -uses -> chain-> B // ERROR (E_ARROW_SUBSTRING_IN_LABEL)
154
+ // migration: move the label to the post-colon form
155
+ A -> B: uses -> chain // works for charts that accept post-colon labels
156
+
157
+ // migration from pre-gauntlet (legacy) syntax
158
+ A -Makes calls [HTTP]-> B // label is now the FULL "Makes calls [HTTP]"
159
+ A -Makes calls-> B | tech: HTTP // preferred: technology on target metadata
160
+ ```
161
+
162
+ #### Character-set contract
163
+
164
+ - **Allowed**: any Unicode codepoint except the forbidden list below. Brackets `[] {} ()`, pipes `|`, quotes `"' `, backticks, punctuation, digits, emoji, ZWJ sequences, combining marks — all pass through as literal characters.
165
+ - **Forbidden substrings**: `->` and `~>`. These terminate the arrow. If you need them inside a label, use the post-colon form (`A -> B: uses -> to chain`) on chart types that support it; there is no escape mechanism.
166
+ - **Forbidden characters**: C0 control characters U+0000–U+001F except U+0009 (tab), and U+007F (DEL). Silent renderer breakage and log-injection surface — no legitimate use case.
167
+ - **Whitespace**: leading and trailing whitespace is trimmed; internal whitespace runs (including tabs, non-breaking spaces, and zero-width spaces) are **preserved**, never collapsed.
168
+ - **Plain text only**: no markdown interpretation. `*foo*` renders as `*foo*`, not italicized. `[label](url)` renders as literal `[label](url)`, not a hyperlink. Clickable URLs belong in notes, not in in-arrow labels.
169
+ - **HTML-safe**: all renderers emit label text as a DOM text node. `<script>alert(1)</script>` renders as literal text — the entire label is a sequence of codepoints, not a markup fragment.
170
+
171
+ #### Color suffix (flowchart and state only)
172
+
173
+ ```
174
+ A -(red)-> B // colored edge, no label
175
+ A -(notacolor)-> B // label = "(notacolor)" (fall-through)
176
+ A -(red) uses-> B // label = "(red) uses" (combined form not supported)
177
+ A -red-> B // label = "red" (bare word is always a label)
178
+ ```
179
+
180
+ A parenthesized palette color is only recognized when the entire label between the opening `-` and the arrow token is exactly `(colorName)` and `colorName` is one of the 11 names in §1.5. Any other content falls through to the label. To combine a color and a label, use the post-colon or pipe-metadata form instead.
181
+
182
+ #### Migrating from pre-gauntlet syntax
183
+
184
+ Two legacy forms changed with this spec:
185
+
186
+ 1. **C4 trailing `[technology]` sugar is removed.** A C4 arrow like `-Makes calls [HTTPS]-> API` used to extract `HTTPS` as the technology annotation. The full `Makes calls [HTTPS]` is now the label. Use the post-colon or pipe form for technology: `-Makes calls-> API | tech: HTTPS`.
187
+ 2. **Bare palette color suffixes are a literal label.** `A -red-> B` on flowchart/state used to be accepted as a bare color suffix in some surfaces. It is now always a label with text `red`. To color an edge, use the `-(red)->` parens form.
188
+
189
+ No code migration is required for in-arrow label character escaping — any label that was valid before remains valid, with one exception: if your label happened to contain the literal substring `->` or `~>`, the parser now rejects it with `E_ARROW_SUBSTRING_IN_LABEL`. Move those labels to the post-colon form.
190
+
117
191
  ---
118
192
 
119
193
  ## 2. Sequence Diagrams
@@ -1253,7 +1327,141 @@ Navigator 0.85 0.8
1253
1327
 
1254
1328
  ---
1255
1329
 
1256
- ## 17. Colon Usage Summary
1330
+ ## 17. Wireframe Diagrams
1331
+
1332
+ Wireframe diagrams use **visual-mnemonic syntax** where bracket characters communicate element type.
1333
+
1334
+ ### Declaration
1335
+
1336
+ ```
1337
+ wireframe Page Title
1338
+ ```
1339
+
1340
+ ### Form Factor
1341
+
1342
+ ```
1343
+ mobile
1344
+ ```
1345
+
1346
+ Switches to narrow vertical layout (375px). Desktop (1200px, horizontal regions) is the default.
1347
+
1348
+ ### Visual-Mnemonic Elements
1349
+
1350
+ | Syntax | Element | Example |
1351
+ |--------|---------|---------|
1352
+ | `[text]` (leaf) | Text input | `[Email address]` |
1353
+ | `[Name]` (with children) | Group/region | `[Sidebar]` + indented children |
1354
+ | `(Label)` | Button | `(Submit)` |
1355
+ | `{A \| B \| C}` | Dropdown/select | `{Small \| Medium \| Large}` |
1356
+ | `<x>` / `< >` | Checkbox | `<x> Remember me` |
1357
+ | `(*) Label` / `( ) Label` | Radio button | `(*) Option A` |
1358
+ | `# Text` / `## Text` | Heading | `# Sign In` |
1359
+ | `---` | Divider | `---` |
1360
+ | `- text` | List item | `- Electronics` |
1361
+ | Bare text | Text/paragraph | `Welcome to our app` |
1362
+
1363
+ ### Keyword Elements
1364
+
1365
+ | Keyword | Type | Parameters |
1366
+ |---------|------|------------|
1367
+ | `nav` | Block | Children are nav items |
1368
+ | `tabs` | Block | Children are tab labels |
1369
+ | `table` | Block | Comma-separated rows; first = header |
1370
+ | `table RxC` | Skeleton table | `table 5x4` + optional header row |
1371
+ | `image` | Leaf | `round`, `wide` hints |
1372
+ | `modal Title` | Block | Rendered as separate panel below |
1373
+ | `skeleton` | Block | Children render as grey placeholders |
1374
+ | `alert` | Block | Optional semantic state |
1375
+ | `progress N` | Leaf | Value 0-100: `progress 60` |
1376
+ | `chart type` | Leaf | `chart line`, `chart bar`, `chart pie` |
1377
+
1378
+ ### Pipe Metadata (States)
1379
+
1380
+ Wireframe uses flag keywords (not `key: value`):
1381
+
1382
+ ```
1383
+ (Submit) | disabled
1384
+ (Delete) | destructive
1385
+ (Cancel) | ghost
1386
+ [Email] | password
1387
+ [Notes] | textarea
1388
+ [Cards] | horizontal
1389
+ [Advanced] | collapsed
1390
+ [Messages] | scrollable
1391
+ <x> Dark mode | toggle
1392
+ ```
1393
+
1394
+ Available states: `disabled`, `active`, `selected`, `empty`, `ghost`, `destructive`, `success`, `warning`, `info`, `scrollable`, `collapsed`, `toggle`, `password`, `textarea`, `horizontal`, `primary`.
1395
+
1396
+ Free-text annotations after states: `[Email] | required, validates email format`.
1397
+
1398
+ ### Multi-Element Lines
1399
+
1400
+ Two or more spaces between segments create separate elements:
1401
+
1402
+ ```
1403
+ Email [user@example.com] // label + field (2 segments)
1404
+ (-) 1 (+) // 3 inline items
1405
+ $299.99 ~~$349.99~~ // 2 inline texts
1406
+ ```
1407
+
1408
+ - **2 segments** (bare text + element): label-for-element pairing
1409
+ - **3+ segments**: inline items, no label pairing
1410
+ - **Single space = same element**: `Cart (3)` is one text element
1411
+
1412
+ ### Group Disambiguation
1413
+
1414
+ - `[Name]` with indented children = group/container
1415
+ - `[Name]` with no children = text input
1416
+ - `[Name] | horizontal/scrollable/collapsed` = group (even without children)
1417
+
1418
+ ### Table Syntax
1419
+
1420
+ Explicit rows (comma-separated, first row = header):
1421
+
1422
+ ```
1423
+ table
1424
+ Name, Email, Role
1425
+ John, john@, Admin
1426
+ Sally, sally@, Editor
1427
+ ```
1428
+
1429
+ Skeleton shorthand:
1430
+
1431
+ ```
1432
+ table 5x4
1433
+ Name, Email, Role, Status
1434
+ ```
1435
+
1436
+ ### Layout Model
1437
+
1438
+ - Desktop: 1200px wide, top-level regions arrange horizontally
1439
+ - Mobile: 375px wide, all regions stack vertically
1440
+ - Smart sizing: `sidebar` → ~25%, `main`/`content` → fill, `header`/`footer` → full width
1441
+ - `| horizontal` on groups arranges children in a row
1442
+
1443
+ ### Example
1444
+
1445
+ ```
1446
+ wireframe Login Page
1447
+
1448
+ [Header]
1449
+ nav
1450
+ Home | active
1451
+ Settings
1452
+
1453
+ [Main]
1454
+ # Sign In
1455
+ Email [user@example.com]
1456
+ Password [****] | password
1457
+ <x> Remember me
1458
+ (Sign In)
1459
+ (Forgot Password?) | ghost
1460
+ ```
1461
+
1462
+ ---
1463
+
1464
+ ## 18. Colon Usage Summary
1257
1465
 
1258
1466
  ### Constructs Where Colons Are REQUIRED
1259
1467
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.8.19",
3
+ "version": "0.8.21",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,10 +55,12 @@
55
55
  ],
56
56
  "sideEffects": false,
57
57
  "scripts": {
58
- "prebuild": "rm -rf dist && lezer-generator src/editor/dgmo.grammar -o src/editor/dgmo.grammar.js",
58
+ "codegen": "lezer-generator src/editor/dgmo.grammar -o src/editor/dgmo.grammar.js",
59
+ "prebuild": "rm -rf dist && pnpm codegen",
59
60
  "build": "tsup",
60
61
  "typecheck": "tsc --noEmit",
61
62
  "dev": "tsup --watch",
63
+ "pretest": "pnpm codegen",
62
64
  "test": "vitest run",
63
65
  "test:watch": "vitest",
64
66
  "gallery": "pnpm build && node scripts/generate-gallery.mjs",
@@ -69,7 +71,13 @@
69
71
  "check:duplication": "jscpd ./src",
70
72
  "check:deadcode": "knip",
71
73
  "check:spelling": "cspell \"src/**/*.ts\" \"tests/**/*.ts\"",
74
+ "check:all": "pnpm check:deadcode && pnpm check:spelling && pnpm check:duplication && pnpm check:circular && pnpm check:deps && pnpm check:security && pnpm build && pnpm check:publish && pnpm check:types",
75
+ "check:circular": "madge --circular --extensions ts src/ --json | node -e \"const c=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const n=c.length; if(n>7){console.error('New circular deps found ('+n+' > 7 known type-only cycles)');process.exit(1)}else if(n>0){console.log(n+' known type-only/dynamic cycles (safe)')}else{console.log('No circular dependencies')}\"",
76
+ "check:deps": "depcheck --ignores='@codemirror/language,@lezer/*,husky,lint-staged,tsup'",
77
+ "check:security": "pnpm audit --prod",
78
+ "check:publish": "publint",
72
79
  "check:size": "pnpm build && du -sh dist/ && echo '---' && ls -lh dist/*.js dist/*.cjs",
80
+ "check:types": "attw --pack . --ignore-rules no-resolution",
73
81
  "postinstall": "node -e \"console.log('\\nšŸ’” Claude Code user? Run: dgmo --install-claude-skill\\n')\"",
74
82
  "prepare": "husky"
75
83
  },
@@ -83,10 +91,11 @@
83
91
  "d3-selection": "^3.0.0",
84
92
  "d3-shape": "^3.2.0",
85
93
  "echarts": "^6.0.0",
86
- "jsdom": "^29.0.1",
94
+ "jsdom": "^29.0.2",
87
95
  "lz-string": "^1.5.0"
88
96
  },
89
97
  "devDependencies": {
98
+ "@arethetypeswrong/cli": "^0.18.2",
90
99
  "@codemirror/language": "^6.12.3",
91
100
  "@eslint/js": "^10.0.1",
92
101
  "@lezer/generator": "^1.8.0",
@@ -97,18 +106,22 @@
97
106
  "@types/d3-selection": "^3.0.11",
98
107
  "@types/d3-shape": "^3.1.8",
99
108
  "@types/jsdom": "^28.0.1",
100
- "cspell": "^9.7.0",
109
+ "cspell": "^10.0.0",
110
+ "depcheck": "^1.4.7",
101
111
  "esbuild": "^0.28.0",
102
112
  "eslint": "^10.2.0",
113
+ "eslint-plugin-security": "^4.0.0",
103
114
  "husky": "^9.1.7",
104
- "jscpd": "^4.0.8",
105
- "knip": "^6.3.0",
115
+ "jscpd": "^4.0.9",
116
+ "knip": "^6.3.1",
106
117
  "lint-staged": "^16.4.0",
107
- "prettier": "^3.8.1",
118
+ "madge": "^8.0.0",
119
+ "prettier": "^3.8.2",
120
+ "publint": "^0.3.18",
108
121
  "tsup": "^8.5.1",
109
122
  "typescript": "^6.0.2",
110
- "typescript-eslint": "^8.58.0",
111
- "vitest": "^4.1.2"
123
+ "typescript-eslint": "^8.58.1",
124
+ "vitest": "^4.1.4"
112
125
  },
113
126
  "lint-staged": {
114
127
  "*.ts": [
@@ -40,12 +40,28 @@ export function collapseBoxesAndLines(
40
40
  const nodeToGroup = new Map<string, string>();
41
41
  const collapsedChildCounts = new Map<string, number>();
42
42
 
43
+ // Recursively collect all descendants of a group (including sub-group children)
44
+ function collectDescendants(groupLabel: string): string[] {
45
+ const group = groupByLabel.get(groupLabel);
46
+ if (!group) return [];
47
+ const descendants: string[] = [];
48
+ for (const child of group.children) {
49
+ descendants.push(child);
50
+ // If child is itself a group, collect its descendants too
51
+ if (groupByLabel.has(child)) {
52
+ descendants.push(...collectDescendants(child));
53
+ }
54
+ }
55
+ return descendants;
56
+ }
57
+
43
58
  for (const groupLabel of collapsedGroups) {
44
59
  const group = groupByLabel.get(groupLabel);
45
60
  if (!group) continue;
46
61
  const groupId = `__group_${groupLabel}`;
47
62
 
48
- for (const child of group.children) {
63
+ const allDescendants = collectDescendants(groupLabel);
64
+ for (const child of allDescendants) {
49
65
  nodeToGroup.set(child, groupId);
50
66
  }
51
67
  collapsedChildCounts.set(groupLabel, group.children.length);
@@ -67,8 +83,10 @@ export function collapseBoxesAndLines(
67
83
  edges.push({ ...edge, source: src, target: tgt });
68
84
  }
69
85
 
70
- // Keep only groups that are not collapsed
71
- const groups = parsed.groups.filter((g) => !collapsedGroups.has(g.label));
86
+ // Keep only groups that are not collapsed and not inside a collapsed group
87
+ const groups = parsed.groups.filter(
88
+ (g) => !collapsedGroups.has(g.label) && !nodeToGroup.has(g.label)
89
+ );
72
90
 
73
91
  return {
74
92
  parsed: { ...parsed, nodes, edges, groups },