@diagrammo/dgmo 0.2.5 → 0.2.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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # @diagrammo/dgmo
2
2
 
3
- A unified diagram markup language — parser, config builder, renderer, and color system.
3
+ A diagram markup language — parser, config builder, renderer, and color system.
4
4
 
5
- Write simple, readable `.dgmo` text files and render them as charts, diagrams, and visualizations using ECharts, D3, or Mermaid.
5
+ Write plain-text `.dgmo` files and render them as charts, diagrams, and visualizations. Supports 23 chart types across ECharts, D3, and a built-in sequence renderer. Ships as both a library and a standalone CLI.
6
6
 
7
7
  ## Install
8
8
 
@@ -48,23 +48,13 @@ cat diagram.dgmo | dgmo > out.png # PNG to stdout
48
48
  dgmo diagram.dgmo --theme dark --palette catppuccin
49
49
  ```
50
50
 
51
- **Available options:**
51
+ **Options:**
52
52
 
53
- - `--theme` light, dark, transparent (default: light)
54
- - `--palette` — nord, solarized, catppuccin, rose-pine, gruvbox, tokyo-night, one-dark, bold (default: nord)
55
-
56
- ## How it works
57
-
58
- Every `.dgmo` file is plain text with a `chart: <type>` header followed by metadata and data. The library routes each chart type to the right framework and gives you either:
59
-
60
- - A **framework config object** you render yourself (ECharts, Mermaid)
61
- - A **rendered SVG** via D3 or the built-in sequence renderer
62
-
63
- ```
64
- parse → build config → render
65
- ```
66
-
67
- All parsers are pure functions with no DOM dependency. Renderers that produce SVG accept a container element.
53
+ | Flag | Values | Default |
54
+ |------|--------|---------|
55
+ | `--theme` | `light`, `dark`, `transparent` | `light` |
56
+ | `--palette` | `nord`, `solarized`, `catppuccin`, `rose-pine`, `gruvbox`, `tokyo-night`, `one-dark`, `bold` | `nord` |
57
+ | `-o` | Output file path (`.svg` extension → SVG, otherwise PNG) | `<input>.png` |
68
58
 
69
59
  ## Supported chart types
70
60
 
@@ -73,6 +63,7 @@ All parsers are pure functions with no DOM dependency. Renderers that produce SV
73
63
  | `bar` | ECharts | Vertical/horizontal bar charts |
74
64
  | `bar-stacked` | ECharts | Stacked bar charts |
75
65
  | `line` | ECharts | Line charts with crosshair |
66
+ | `multi-line` | ECharts | Multi-series line charts |
76
67
  | `area` | ECharts | Filled area charts |
77
68
  | `pie` | ECharts | Pie charts with connector labels |
78
69
  | `doughnut` | ECharts | Doughnut charts |
@@ -89,17 +80,32 @@ All parsers are pure functions with no DOM dependency. Renderers that produce SV
89
80
  | `arc` | D3 | Arc/network diagrams |
90
81
  | `timeline` | D3 | Timelines with eras and markers |
91
82
  | `venn` | D3 | Set intersection diagrams |
92
- | `quadrant` | D3/Mermaid | 2D quadrant scatter |
83
+ | `quadrant` | D3 | 2D quadrant scatter (also has a Mermaid output path) |
93
84
  | `sequence` | D3 | Sequence diagrams with type inference |
94
85
 
86
+ ## How it works
87
+
88
+ Every `.dgmo` file is plain text with a `chart: <type>` header followed by metadata and data. The library routes each chart type to the right framework and gives you either:
89
+
90
+ - A **framework config object** you render yourself (ECharts, Mermaid)
91
+ - A **rendered SVG** via D3 or the built-in sequence renderer
92
+
93
+ ```
94
+ parse → build config → render
95
+ ```
96
+
97
+ All parsers are pure functions with no DOM dependency. D3 renderers accept a container element. The CLI sets up jsdom internally for headless rendering.
98
+
95
99
  ## Usage
96
100
 
97
101
  ### Standard charts (bar, line, pie, radar, etc.)
98
102
 
99
103
  ```typescript
100
- import { parseChart, buildEChartsOptionFromChart } from '@diagrammo/dgmo';
104
+ import { parseChart, buildEChartsOptionFromChart, getPalette } from '@diagrammo/dgmo';
101
105
  import * as echarts from 'echarts';
102
106
 
107
+ const colors = getPalette('nord').light;
108
+
103
109
  const content = `
104
110
  chart: bar
105
111
  title: Revenue by Quarter
@@ -112,17 +118,19 @@ Q3: 15
112
118
  Q4: 22
113
119
  `;
114
120
 
115
- const parsed = parseChart(content, palette.light);
116
- const option = buildEChartsOptionFromChart(parsed, palette.light, false);
121
+ const parsed = parseChart(content, colors);
122
+ const option = buildEChartsOptionFromChart(parsed, colors, false);
117
123
  echarts.init(container).setOption(option);
118
124
  ```
119
125
 
120
126
  ### ECharts (scatter, sankey, heatmap, etc.)
121
127
 
122
128
  ```typescript
123
- import { parseEChart, buildEChartsOption } from '@diagrammo/dgmo';
129
+ import { parseEChart, buildEChartsOption, getPalette } from '@diagrammo/dgmo';
124
130
  import * as echarts from 'echarts';
125
131
 
132
+ const colors = getPalette('nord').light;
133
+
126
134
  const content = `
127
135
  chart: sankey
128
136
  title: Energy Flow
@@ -134,14 +142,16 @@ Electricity -> Homes: 35
134
142
  `;
135
143
 
136
144
  const parsed = parseEChart(content);
137
- const option = buildEChartsOption(parsed, palette.light, false);
145
+ const option = buildEChartsOption(parsed, colors, false);
138
146
  echarts.init(container).setOption(option);
139
147
  ```
140
148
 
141
149
  ### D3 (slope, timeline, wordcloud, etc.)
142
150
 
143
151
  ```typescript
144
- import { parseD3, renderTimeline } from '@diagrammo/dgmo';
152
+ import { parseD3, renderTimeline, getPalette } from '@diagrammo/dgmo';
153
+
154
+ const colors = getPalette('nord').light;
145
155
 
146
156
  const content = `
147
157
  chart: timeline
@@ -152,8 +162,8 @@ title: Project Milestones
152
162
  2024-07: Launch
153
163
  `;
154
164
 
155
- const parsed = parseD3(content, palette.light);
156
- renderTimeline(container, parsed, palette.light, false);
165
+ const parsed = parseD3(content, colors);
166
+ renderTimeline(container, parsed, colors, false);
157
167
  ```
158
168
 
159
169
  ### Sequence diagrams
@@ -161,7 +171,9 @@ renderTimeline(container, parsed, palette.light, false);
161
171
  Sequence diagrams use a minimal DSL. Participants are inferred from messages — no declaration blocks needed. Types (service, database, actor, queue, etc.) are inferred from naming conventions.
162
172
 
163
173
  ```typescript
164
- import { parseSequenceDgmo, renderSequenceDiagram } from '@diagrammo/dgmo';
174
+ import { parseSequenceDgmo, renderSequenceDiagram, getPalette } from '@diagrammo/dgmo';
175
+
176
+ const colors = getPalette('nord').light;
165
177
 
166
178
  const content = `
167
179
  title: Login Flow
@@ -173,25 +185,27 @@ AuthService -> User: <- token
173
185
  `;
174
186
 
175
187
  const parsed = parseSequenceDgmo(content);
176
- renderSequenceDiagram(container, parsed, palette.light, false, (lineNum) => {
188
+ renderSequenceDiagram(container, parsed, colors, false, (lineNum) => {
177
189
  // clicked a message — jump to that line in the editor
178
190
  });
179
191
  ```
180
192
 
181
- **Sequence syntax highlights:**
193
+ **Sequence syntax:**
182
194
 
183
195
  - `A -> B: message` — synchronous call
184
196
  - `A ~> B: message` — async/fire-and-forget
185
197
  - `A -> B: method(): returnValue` — call with return
186
- - `if` / `else` / `end`conditional blocks
187
- - `loop` / `end` — loop blocks
198
+ - `B -> A: <- response` — explicit return
199
+ - `if condition` / `else` / `end` — conditional blocks
200
+ - `loop condition` / `end` — loop blocks
188
201
  - `parallel` / `else` / `end` — concurrent branches
189
- - `== Section ==` — horizontal dividers
190
- - `## GroupName(color)` — participant grouping
202
+ - `== Section ==` — horizontal dividers (collapsible in the desktop app)
203
+ - `## GroupName(color)` — participant grouping with optional color
191
204
  - `Name is a database` — explicit type declaration
192
205
  - `Name position 0` — explicit ordering
206
+ - `activations: off` — disable activation bars
193
207
 
194
- **Participant type inference** — 162 rules map names to shapes automatically:
208
+ **Participant type inference** — 104 rules map names to shapes automatically:
195
209
 
196
210
  | Pattern | Inferred type | Shape |
197
211
  |---------|--------------|-------|
@@ -212,7 +226,7 @@ If you don't know the chart type ahead of time, use the router:
212
226
  import { parseDgmoChartType, getDgmoFramework } from '@diagrammo/dgmo';
213
227
 
214
228
  const chartType = parseDgmoChartType(content); // e.g. 'bar'
215
- const framework = getDgmoFramework(chartType); // e.g. 'echart'
229
+ const framework = getDgmoFramework(chartType); // 'echart' | 'd3' | 'mermaid'
216
230
  ```
217
231
 
218
232
  Content with `->` arrows and no `chart:` header is automatically detected as a sequence diagram.
@@ -272,7 +286,7 @@ const all = getAvailablePalettes(); // [{ id, name }, ...]
272
286
  registerPalette({
273
287
  id: 'custom',
274
288
  name: 'My Theme',
275
- light: { bg: '#fff', surface: '#f5f5f5', /* ... 17 more fields */ },
289
+ light: { bg: '#fff', surface: '#f5f5f5', /* ... */ },
276
290
  dark: { bg: '#1a1a1a', surface: '#2a2a2a', /* ... */ },
277
291
  });
278
292
  ```
@@ -299,33 +313,39 @@ const vars = buildMermaidThemeVars(palette.light); // ~121 CSS custom properties
299
313
  const css = buildThemeCSS(palette.light); // complete CSS string
300
314
  ```
301
315
 
302
- ## SVG export
316
+ ## Server-side / headless export
303
317
 
304
- Render any D3-based chart to an SVG string (no visible DOM needed):
318
+ Render any chart to an SVG string without a visible DOM:
305
319
 
306
320
  ```typescript
307
- import { renderD3ForExport } from '@diagrammo/dgmo';
321
+ import { renderD3ForExport, renderEChartsForExport } from '@diagrammo/dgmo';
308
322
 
309
- const svgString = await renderD3ForExport(content, 'light');
323
+ // D3 and sequence charts
324
+ const svg = await renderD3ForExport(content, 'light');
325
+
326
+ // ECharts charts
327
+ const svg = await renderEChartsForExport(content, 'light');
310
328
  ```
311
329
 
330
+ Both accept an optional third argument for a custom `PaletteColors` object (defaults to Nord).
331
+
312
332
  ## API overview
313
333
 
314
334
  ### Router
315
335
 
316
336
  | Export | Description |
317
337
  |--------|-------------|
318
- | `parseDgmoChartType(content)` | Extract chart type from content |
319
- | `getDgmoFramework(type)` | Map chart type to framework |
338
+ | `parseDgmoChartType(content)` | Extract chart type from content (infers `sequence` from arrow syntax) |
339
+ | `getDgmoFramework(type)` | Map chart type `'echart'` \| `'d3'` \| `'mermaid'` |
320
340
  | `DGMO_CHART_TYPE_MAP` | Full type-to-framework registry |
321
341
 
322
342
  ### Parsers
323
343
 
324
344
  | Export | Description |
325
345
  |--------|-------------|
326
- | `parseChart(content, colors)` | Parse standard chart types |
327
- | `parseEChart(content)` | Parse ECharts chart types |
328
- | `parseD3(content, colors)` | Parse D3 chart types |
346
+ | `parseChart(content, colors)` | Parse standard chart types (bar, line, pie, radar, etc.) |
347
+ | `parseEChart(content)` | Parse ECharts-specific types (scatter, sankey, heatmap, etc.) |
348
+ | `parseD3(content, colors)` | Parse D3 chart types (slope, arc, timeline, etc.) |
329
349
  | `parseSequenceDgmo(content)` | Parse sequence diagrams |
330
350
  | `parseQuadrant(content)` | Parse quadrant charts |
331
351
 
@@ -333,11 +353,11 @@ const svgString = await renderD3ForExport(content, 'light');
333
353
 
334
354
  | Export | Description |
335
355
  |--------|-------------|
336
- | `buildEChartsOptionFromChart(parsed, colors, dark)` | ECharts option object |
337
- | `buildEChartsOption(parsed, colors, dark)` | ECharts option object |
338
- | `buildMermaidQuadrant(parsed, colors)` | Mermaid quadrant syntax string |
356
+ | `buildEChartsOptionFromChart(parsed, colors, dark)` | ECharts option from `parseChart` result |
357
+ | `buildEChartsOption(parsed, colors, dark)` | ECharts option from `parseEChart` result |
358
+ | `buildMermaidQuadrant(parsed, colors)` | Mermaid quadrantChart syntax string |
339
359
 
340
- ### D3 renderers
360
+ ### Renderers
341
361
 
342
362
  | Export | Description |
343
363
  |--------|-------------|
@@ -347,29 +367,165 @@ const svgString = await renderD3ForExport(content, 'light');
347
367
  | `renderWordCloud(el, parsed, colors, dark)` | Word cloud SVG |
348
368
  | `renderVenn(el, parsed, colors, dark)` | Venn diagram SVG |
349
369
  | `renderQuadrant(el, parsed, colors, dark)` | Quadrant chart SVG |
350
- | `renderD3ForExport(content, theme)` | Any D3 chart as SVG string |
370
+ | `renderSequenceDiagram(el, parsed, colors, dark, onClick)` | Sequence diagram SVG |
371
+ | `renderD3ForExport(content, theme, palette?)` | Any D3/sequence chart → SVG string |
372
+ | `renderEChartsForExport(content, theme, palette?)` | Any ECharts chart → SVG string |
351
373
 
352
- ### Sequence renderer
374
+ ### Sequence internals
353
375
 
354
376
  | Export | Description |
355
377
  |--------|-------------|
356
- | `renderSequenceDiagram(el, parsed, colors, dark, onClick)` | Sequence diagram SVG |
357
- | `buildRenderSequence(parsed)` | Ordered render steps |
378
+ | `buildRenderSequence(parsed)` | Ordered render steps from parsed diagram |
358
379
  | `computeActivations(steps, participants)` | Activation bar positions |
380
+ | `applyPositionOverrides(participants, parsed)` | Apply `Name position N` overrides |
381
+ | `applyGroupOrdering(participants, groups)` | Reorder participants by group |
382
+ | `groupMessagesBySection(elements)` | Group elements into collapsible sections |
383
+ | `inferParticipantType(name)` | Infer participant type from name |
359
384
 
360
385
  ### Palette & color
361
386
 
362
387
  | Export | Description |
363
388
  |--------|-------------|
364
389
  | `getPalette(id)` | Get palette by ID (falls back to Nord) |
365
- | `getAvailablePalettes()` | List registered palettes |
390
+ | `getAvailablePalettes()` | List registered palettes `[{ id, name }]` |
366
391
  | `registerPalette(config)` | Register a custom palette |
367
- | `resolveColor(name, colors)` | Resolve color name or hex |
392
+ | `resolveColor(name, colors)` | Resolve color name or hex against a palette |
368
393
  | `hexToHSL(hex)` / `hslToHex(h,s,l)` | Color conversion |
369
394
  | `mute(hex)` / `tint(hex, amount)` / `shade(hex, base, amount)` | Color manipulation |
370
395
  | `contrastText(bg, light, dark)` | WCAG contrast text picker |
371
396
  | `buildMermaidThemeVars(colors)` | Mermaid CSS variables |
372
- | `buildThemeCSS(colors)` | Mermaid theme CSS string |
397
+ | `buildThemeCSS(colors)` | Complete Mermaid theme CSS |
398
+
399
+ ## Development
400
+
401
+ ### Prerequisites
402
+
403
+ - Node.js 18+
404
+ - pnpm (`npm install -g pnpm`)
405
+
406
+ ### Setup
407
+
408
+ ```bash
409
+ pnpm install
410
+ pnpm build # tsup → dist/ (ESM + CJS + CLI)
411
+ ```
412
+
413
+ ### Commands
414
+
415
+ ```bash
416
+ pnpm build # Production build (lib + CLI)
417
+ pnpm dev # Watch mode (rebuild on save)
418
+ pnpm test # Run tests (Vitest)
419
+ pnpm test:watch # Tests in watch mode
420
+ pnpm typecheck # TypeScript type checking
421
+ ```
422
+
423
+ ### Quick CLI testing
424
+
425
+ ```bash
426
+ ./test-cli.sh input.dgmo [args...] # Builds and runs in one step
427
+ ```
428
+
429
+ ### Project structure
430
+
431
+ ```
432
+ src/
433
+ ├── index.ts # Public API exports
434
+ ├── cli.ts # CLI entry point → dist/cli.cjs
435
+ ├── dgmo-router.ts # Chart type → framework dispatcher
436
+ ├── chart.ts # Standard chart parser (bar, line, pie, etc.)
437
+ ├── echarts.ts # ECharts parser, config builder, SSR export
438
+ ├── d3.ts # D3 parsers + renderers (slope, arc, timeline, wordcloud, venn, quadrant)
439
+ ├── dgmo-mermaid.ts # Quadrant parser + Mermaid syntax builder
440
+ ├── colors.ts # Named color map, resolve helper
441
+ ├── fonts.ts # Font family constants (Helvetica for resvg)
442
+ ├── sequence/
443
+ │ ├── parser.ts # Sequence diagram DSL parser
444
+ │ ├── renderer.ts # SVG renderer (D3-based)
445
+ │ └── participant-inference.ts # 104-rule name → type engine
446
+ └── palettes/
447
+ ├── types.ts # PaletteConfig, PaletteColors types
448
+ ├── registry.ts # getPalette, registerPalette
449
+ ├── color-utils.ts # HSL conversions, mix(), mute(), tint()
450
+ ├── mermaid-bridge.ts # Mermaid CSS variable builder
451
+ ├── nord.ts # Nord palette
452
+ ├── solarized.ts # Solarized palette
453
+ ├── catppuccin.ts # Catppuccin palette
454
+ ├── rose-pine.ts # Rose Pine palette
455
+ ├── gruvbox.ts # Gruvbox palette
456
+ ├── tokyo-night.ts # Tokyo Night palette
457
+ ├── one-dark.ts # One Dark palette
458
+ └── bold.ts # Bold palette
459
+ ```
460
+
461
+ ### Build output
462
+
463
+ tsup produces:
464
+ - `dist/index.js` + `dist/index.d.ts` (ESM)
465
+ - `dist/index.cjs` + `dist/index.d.cts` (CJS)
466
+ - `dist/cli.cjs` (CLI binary — bundles everything except `@resvg/resvg-js`)
467
+
468
+ ### Testing
469
+
470
+ Tests live in `tests/` and use Vitest with jsdom:
471
+
472
+ ```bash
473
+ pnpm test # Run all tests
474
+ pnpm test -- --reporter verbose # Verbose output
475
+ ```
476
+
477
+ ## Releasing
478
+
479
+ ### npm publish
480
+
481
+ 1. Bump version in `package.json`
482
+ 2. Build and test:
483
+ ```bash
484
+ pnpm build && pnpm test
485
+ ```
486
+ 3. Publish:
487
+ ```bash
488
+ npm publish
489
+ ```
490
+ 4. After publishing, update downstream consumers:
491
+ - **homebrew-dgmo**: Update `Formula/dgmo.rb` with new tarball URL and sha256
492
+ - **obsidian-dgmo**: Update `@diagrammo/dgmo` version in `package.json`
493
+ - **diagrammo-app**: Update submodule ref (`git submodule update --remote`)
494
+
495
+ ### Generating the sha256 for Homebrew
496
+
497
+ ```bash
498
+ VERSION=0.2.7 # new version
499
+ curl -sL "https://registry.npmjs.org/@diagrammo/dgmo/-/dgmo-${VERSION}.tgz" | shasum -a 256
500
+ ```
501
+
502
+ ## Gallery
503
+
504
+ The gallery renders every fixture in `gallery/fixtures/` across all palettes, themes, and formats, producing a filterable HTML page.
505
+
506
+ ```bash
507
+ pnpm gallery # Build CLI + render all combinations
508
+ ```
509
+
510
+ Output lands in `gallery/output/` (gitignored):
511
+
512
+ - `gallery/output/renders/` — individual SVG and PNG files
513
+ - `gallery/output/index.html` — filterable gallery page (open in a browser)
514
+
515
+ ### Filter options
516
+
517
+ ```bash
518
+ pnpm gallery -- --chart bar
519
+ pnpm gallery -- --palette nord
520
+ pnpm gallery -- --theme dark
521
+ pnpm gallery -- --format svg
522
+ pnpm gallery -- --chart sequence --palette catppuccin --theme light --format png
523
+ pnpm gallery -- --concurrency 4 # defaults to CPU count
524
+ ```
525
+
526
+ ### Adding fixtures
527
+
528
+ Drop a new `.dgmo` file into `gallery/fixtures/` and re-run `pnpm gallery`.
373
529
 
374
530
  ## License
375
531