@diagrammo/dgmo 0.11.2 → 0.12.0

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.
@@ -1967,25 +1967,6 @@ Phase headers accept pipe metadata for per-phase styling:
1967
1967
 
1968
1968
  The phase bar tints to a soft mix of the color over the background. Phases without metadata fall back to the neutral gray bar.
1969
1969
 
1970
- ### Diagnostic codes
1971
-
1972
- | Code | Severity | Fires when |
1973
- |------|----------|------------|
1974
- | `E_RACI_MULTI_ACCOUNTABLE` | error | RACI/RASCI task has more than one A |
1975
- | `E_DACI_MULTI_DRIVER` | error | DACI task has more than one D |
1976
- | `E_DACI_MULTI_ACCOUNTABLE` | error | DACI task has more than one A |
1977
- | `E_RACI_INVALID_MARKER` | error | Marker isn't in the resolved variant's alphabet |
1978
- | `E_RACI_UNEXPECTED_LINE` | error | Free-text line appears after the first role assignment |
1979
- | `E_RACI_MIXED_VARIANTS` | error | Both `D` and `S` markers appear without a `variant-*` lock |
1980
- | `E_RACI_DUPLICATE_VARIANT` | error | More than one `variant-*` directive in the chart |
1981
- | `W_RACI_MISSING_ACCOUNTABLE` | warning | RACI/RASCI task has no A |
1982
- | `W_RACI_MISSING_RESPONSIBLE` | warning | RACI/RASCI task has no R |
1983
- | `W_DACI_MISSING_DRIVER` | warning | DACI task has no D |
1984
- | `W_DACI_MISSING_ACCOUNTABLE` | warning | DACI task has no A |
1985
- | `W_RACI_UNKNOWN_ROLE` | warning | Role used without being declared in `roles` |
1986
-
1987
- Warnings are non-blocking; there is no source-level suppression mechanism — by design, source should not silently mute the linter.
1988
-
1989
1970
  ### Display vs source ordering
1990
1971
 
1991
1972
  Markers in cells are always **rendered in canonical alphabet order** (`R A C I`, `R A S C I`, `D A C I`) regardless of source order. Source casing and order are preserved in the file; mutations operate on source order to keep round-trips byte-stable except for the cell that changed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.11.2",
3
+ "version": "0.12.0",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/completion.ts CHANGED
@@ -164,6 +164,15 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
164
164
  'no-value': { description: 'Hide value labels at each point' },
165
165
  }),
166
166
  ],
167
+ [
168
+ 'multi-line',
169
+ withGlobals({
170
+ series: { description: 'Series name(s)' },
171
+ 'x-label': { description: 'X-axis label' },
172
+ 'y-label': { description: 'Y-axis label' },
173
+ 'no-value': { description: 'Hide value labels at each point' },
174
+ }),
175
+ ],
167
176
  [
168
177
  'polar-area',
169
178
  withGlobals({
@@ -270,8 +279,15 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
270
279
  ],
271
280
  [
272
281
  'flowchart',
282
+ // Spec §5 §4.6: direction-lr, orientation-vertical, no-color, solid-fill
273
283
  withGlobals({
274
284
  'direction-lr': { description: 'Switch to left-to-right layout' },
285
+ 'orientation-vertical': {
286
+ description: 'Use vertical orientation for ranks',
287
+ },
288
+ 'no-color': {
289
+ description: 'Resolve all nodes to muted neutral fill',
290
+ },
275
291
  }),
276
292
  ],
277
293
  [
@@ -284,88 +300,76 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
284
300
  ],
285
301
  [
286
302
  'er',
303
+ // Spec §9 §8.5: notation (chen/crow), active-tag.
287
304
  withGlobals({
305
+ notation: {
306
+ description: 'ER notation style',
307
+ values: ['chen', 'crow'],
308
+ },
288
309
  'active-tag': { description: 'Active tag group name' },
289
310
  }),
290
311
  ],
291
312
  [
292
313
  'org',
314
+ // Spec §7 §6.5: direction-tb, sub-node-label, show-sub-node-count,
315
+ // hide, active-tag. solid-fill via SOLID_FILL_CAPABLE.
293
316
  withGlobals({
317
+ 'direction-tb': { description: 'Switch to top-to-bottom layout' },
294
318
  'sub-node-label': { description: 'Label for sub-nodes' },
295
319
  'show-sub-node-count': { description: 'Show sub-node counts' },
320
+ hide: { description: 'Hide tag:value pairs' },
296
321
  'active-tag': { description: 'Active tag group name' },
297
322
  }),
298
323
  ],
299
324
  [
300
325
  'kanban',
326
+ // Spec §11 §10.4: no-auto-color, hide, active-tag.
301
327
  withGlobals({
302
328
  'no-auto-color': { description: 'Disable automatic card coloring' },
329
+ hide: { description: 'Hide tag:value pairs' },
303
330
  'active-tag': { description: 'Active tag group name' },
304
331
  }),
305
332
  ],
306
- // RACI / RASCI / DACI — three chart-type ids, one parser, same directives.
333
+ // RACI / RASCI / DACI — one chart type (`raci`), variant inferred from
334
+ // markers or locked via `variant-*` bare directive. `rasci`/`daci` are
335
+ // not first-line keywords so they get no separate registry entry.
307
336
  [
308
337
  'raci',
309
338
  withGlobals({
310
- variant: {
311
- description: 'Variant rule set',
312
- values: ['raci', 'rasci', 'daci'],
339
+ 'variant-raci': {
340
+ description: 'Lock chart to RACI variant (R / A / C / I markers)',
313
341
  },
314
- roles: {
342
+ 'variant-rasci': {
315
343
  description:
316
- 'Comma-separated role list (declares column order; enables unknown-role linting)',
317
- },
318
- draft: {
319
- description: 'Suppress missing-A / missing-R warnings during authoring',
344
+ 'Lock chart to RASCI variant (adds Support R / A / S / C / I)',
320
345
  },
321
- 'active-tag': { description: 'Active tag group name' },
322
- }),
323
- ],
324
- [
325
- 'rasci',
326
- withGlobals({
327
- variant: {
328
- description: 'Variant rule set',
329
- values: ['raci', 'rasci', 'daci'],
330
- },
331
- roles: {
346
+ 'variant-daci': {
332
347
  description:
333
- 'Comma-separated role list (declares column order; enables unknown-role linting)',
334
- },
335
- draft: {
336
- description: 'Suppress missing-A / missing-R warnings during authoring',
337
- },
338
- 'active-tag': { description: 'Active tag group name' },
339
- }),
340
- ],
341
- [
342
- 'daci',
343
- withGlobals({
344
- variant: {
345
- description: 'Variant rule set',
346
- values: ['raci', 'rasci', 'daci'],
348
+ 'Lock chart to DACI variant (Driver / Approver / Contributor / Informed)',
347
349
  },
348
350
  roles: {
349
351
  description:
350
- 'Comma-separated role list (declares column order; enables unknown-role linting)',
351
- },
352
- draft: {
353
- description: 'Suppress missing-A / missing-R warnings during authoring',
352
+ 'Declare role column order (inline `roles A, B, C` or indented block with per-role pipe metadata)',
354
353
  },
355
354
  'active-tag': { description: 'Active tag group name' },
356
355
  }),
357
356
  ],
358
357
  [
359
358
  'c4',
359
+ // Spec §8 §7.7: direction-tb, active-tag.
360
360
  withGlobals({
361
+ 'direction-tb': { description: 'Switch to top-to-bottom layout' },
361
362
  'active-tag': { description: 'Active tag group name' },
362
363
  }),
363
364
  ],
364
365
  [
365
366
  'state',
367
+ // Spec §6 §5.5: direction-tb, no-color, solid-fill.
366
368
  withGlobals({
367
369
  'direction-tb': { description: 'Switch to top-to-bottom layout' },
368
- color: { description: 'Color mode', values: ['off'] },
370
+ 'no-color': {
371
+ description: 'Resolve all states to muted neutral fill',
372
+ },
369
373
  }),
370
374
  ],
371
375
  [
@@ -392,6 +396,7 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
392
396
  ],
393
397
  [
394
398
  'gantt',
399
+ // Spec §13 §12.2 Options.
395
400
  withGlobals({
396
401
  start: { description: 'Project start date (YYYY-MM-DD)' },
397
402
  'today-marker': {
@@ -399,8 +404,14 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
399
404
  },
400
405
  sort: { description: 'Sort order', values: ['time', 'group', 'tag'] },
401
406
  'critical-path': { description: 'Show critical path' },
402
- dependencies: { description: 'Show dependencies' },
407
+ 'no-dependencies': { description: 'Hide dependency arrows' },
408
+ 'sprint-length': { description: 'Sprint duration (e.g. 2w)' },
409
+ 'sprint-number': { description: 'Starting sprint number' },
410
+ 'sprint-start': { description: 'Sprint start date (YYYY-MM-DD)' },
403
411
  'active-tag': { description: 'Active tag group name' },
412
+ // Legacy positive form `dependencies` — kept for back-compat. Use
413
+ // `no-dependencies` to suppress dependency arrows in new code.
414
+ dependencies: { description: 'Show dependencies (legacy form)' },
404
415
  }),
405
416
  ],
406
417
  [
@@ -427,15 +438,13 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
427
438
  ],
428
439
  [
429
440
  'tech-radar',
441
+ // Spec §20 documents one directive: `show-blip-legend`. `rings` is a
442
+ // structural block keyword; quadrant/ring/trend/color are pipe metadata
443
+ // that live in PIPE_METADATA.
430
444
  withGlobals({
431
- rings: { description: 'Ring names block (innermost to outermost)' },
432
- quadrant: {
433
- description:
434
- 'Quadrant position (top-left, top-right, bottom-left, bottom-right)',
445
+ 'show-blip-legend': {
446
+ description: 'Render the four-column blip listing alongside the radar',
435
447
  },
436
- ring: { description: 'Ring assignment for a blip' },
437
- trend: { description: 'Blip trend (new, up, down, stable)' },
438
- color: { description: 'Override quadrant color' },
439
448
  }),
440
449
  ],
441
450
  [
@@ -452,30 +461,29 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
452
461
  ],
453
462
  [
454
463
  'journey-map',
464
+ // Spec §22 directives: `no-legend`, `active-tag`. `persona` is a
465
+ // structural keyword (like `tag` / `roles`), not a directive.
466
+ // `solid-fill` is added via SOLID_FILL_CAPABLE below.
455
467
  withGlobals({
456
468
  'no-legend': { description: 'Hide the score legend' },
457
- persona: { description: 'Define the journey persona' },
469
+ 'active-tag': { description: 'Active tag group name' },
458
470
  }),
459
471
  ],
460
472
  [
461
473
  'pyramid',
474
+ // Spec §23.5 documents `inverted`; `solid-fill` is added via
475
+ // SOLID_FILL_CAPABLE below (working but not yet in spec §23.5).
476
+ // `color`/`description` are layer pipe-metadata, not directives.
462
477
  withGlobals({
463
478
  inverted: { description: 'Flip apex to the bottom (funnel orientation)' },
464
- color: { description: 'Override layer color (pipe metadata)' },
465
- description: { description: 'Layer description (pipe or indented body)' },
466
479
  }),
467
480
  ],
468
481
  [
469
482
  'ring',
470
- withGlobals({
471
- color: {
472
- description:
473
- 'Override ring color (pipe metadata; closed set of 11 named colors)',
474
- },
475
- description: {
476
- description: 'Ring description (pipe shorthand or indented body)',
477
- },
478
- }),
483
+ // Per spec §24.5 the only chart-specific directive is `solid-fill`,
484
+ // applied via SOLID_FILL_CAPABLE below. `color`/`description` are
485
+ // layer pipe-metadata, not directives — they live in PIPE_METADATA.
486
+ withGlobals({}),
479
487
  ],
480
488
  ]);
481
489
 
@@ -576,19 +584,28 @@ export interface PipeKeySpec {
576
584
 
577
585
  /**
578
586
  * Pipe metadata keys for inline `| key value` on data lines.
579
- * Keyed by chart type → { node: ..., edge: ... }.
587
+ * Keyed by chart type → { context-name: keys }.
588
+ *
589
+ * Contexts are open-ended. The two universal ones are:
590
+ * - `node` — the default for any non-arrow line
591
+ * - `edge` — lines containing an arrow (`->`, `--`)
592
+ *
593
+ * Charts with richer line types declare additional contexts:
594
+ * - raci: `role`, `phase`, `assignment`
595
+ * - ring / pyramid: `layer`
596
+ * - tech-radar: `quadrant`, `blip`
597
+ * - journey-map: `step`
598
+ *
599
+ * Consumers that don't classify lines beyond node/edge can fall back to
600
+ * the union of all contexts via `unionPipeKeys(spec)` below.
580
601
  *
581
602
  * IMPORTANT: NEVER add 'sequence' here. The `|` character in sequence
582
603
  * diagrams separates display names from identifiers and tag metadata.
583
604
  * Adding sequence would trigger false pipe-metadata completions on every `|`.
584
605
  */
585
- export const PIPE_METADATA = new Map<
586
- string,
587
- {
588
- node: Record<string, PipeKeySpec>;
589
- edge: Record<string, PipeKeySpec>;
590
- }
591
- >([
606
+ export type PipeContextMap = Record<string, Record<string, PipeKeySpec>>;
607
+
608
+ export const PIPE_METADATA = new Map<string, PipeContextMap>([
592
609
  [
593
610
  'infra',
594
611
  {
@@ -667,21 +684,25 @@ export const PIPE_METADATA = new Map<
667
684
  },
668
685
  ],
669
686
  [
687
+ // Tech-radar pipe metadata (spec §20). Two contexts:
688
+ // - quadrant: top-level quadrant headers (`Tools | quadrant: top-left, color: blue`)
689
+ // - blip: indented blip lines (` Vite | ring: Adopt, trend: up`)
670
690
  'tech-radar',
671
691
  {
672
- node: {
692
+ quadrant: {
673
693
  quadrant: {
674
694
  description: 'Quadrant position',
675
695
  values: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
676
696
  },
677
- ring: { description: 'Ring assignment for blip' },
697
+ color: { description: 'Override quadrant color' },
698
+ },
699
+ blip: {
700
+ ring: { description: 'Ring assignment (must match a declared ring)' },
678
701
  trend: {
679
702
  description: 'Blip trend indicator',
680
703
  values: ['new', 'up', 'down', 'stable'],
681
704
  },
682
- color: { description: 'Override quadrant color' },
683
705
  },
684
- edge: {},
685
706
  },
686
707
  ],
687
708
  [
@@ -698,8 +719,69 @@ export const PIPE_METADATA = new Map<
698
719
  },
699
720
  },
700
721
  ],
722
+ [
723
+ // RACI pipe metadata (spec §24A). Two contexts:
724
+ // - role: declarations inside the `roles` block (`Cap | color: red`)
725
+ // - phase: bracketed phase headers (`[Departure] | color: teal`)
726
+ 'raci',
727
+ {
728
+ role: {
729
+ color: { description: 'Role column tint (palette name)' },
730
+ },
731
+ phase: {
732
+ color: { description: 'Phase bar tint (palette name)' },
733
+ },
734
+ },
735
+ ],
736
+ [
737
+ // Ring layer pipe metadata (spec §24.4). One context: `layer`.
738
+ 'ring',
739
+ {
740
+ layer: {
741
+ color: { description: 'Ring color (palette name)' },
742
+ description: { description: 'Layer description (one-liner shorthand)' },
743
+ },
744
+ },
745
+ ],
746
+ [
747
+ // Pyramid layer pipe metadata (spec §23.4). Identical surface to ring.
748
+ 'pyramid',
749
+ {
750
+ layer: {
751
+ color: { description: 'Layer color (palette name)' },
752
+ description: { description: 'Layer description (one-liner shorthand)' },
753
+ },
754
+ },
755
+ ],
756
+ [
757
+ // Journey-map step pipe metadata (spec §22). One static key: `score`.
758
+ // Tag aliases (e.g. `ch: Web`) are user-defined via the `tag` block
759
+ // and resolved dynamically — not part of the static map.
760
+ 'journey-map',
761
+ {
762
+ step: {
763
+ score: { description: 'Step score (1–5 integer; high = good)' },
764
+ },
765
+ },
766
+ ],
701
767
  ]);
702
768
 
769
+ /**
770
+ * Union of all pipe-metadata keys across every context for a chart.
771
+ * Use this when a consumer can't precisely classify which line context
772
+ * the cursor is on (e.g. raci role vs phase) and wants to surface every
773
+ * potentially-valid key. Returns an empty record for unknown chart types.
774
+ */
775
+ export function unionPipeKeys(chartType: string): Record<string, PipeKeySpec> {
776
+ const spec = PIPE_METADATA.get(chartType);
777
+ if (!spec) return {};
778
+ const merged: Record<string, PipeKeySpec> = {};
779
+ for (const ctx of Object.values(spec)) {
780
+ Object.assign(merged, ctx);
781
+ }
782
+ return merged;
783
+ }
784
+
703
785
  // ============================================================
704
786
  // Derived metadata key set
705
787
  // ============================================================