@diagrammo/dgmo 0.8.23 → 0.8.25
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/.claude/commands/dgmo.md +60 -72
- package/dist/cli.cjs +119 -114
- package/dist/editor.cjs +0 -2
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +0 -2
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +0 -2
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +0 -2
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +690 -278
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -18
- package/dist/index.d.ts +105 -18
- package/dist/index.js +680 -277
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +348 -51
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +93 -5
- package/dist/internal.d.ts +93 -5
- package/dist/internal.js +334 -38
- package/dist/internal.js.map +1 -1
- package/docs/guide/chart-area.md +17 -17
- package/docs/guide/chart-bar-stacked.md +12 -12
- package/docs/guide/chart-doughnut.md +10 -10
- package/docs/guide/chart-funnel.md +9 -9
- package/docs/guide/chart-heatmap.md +10 -10
- package/docs/guide/chart-kanban.md +2 -0
- package/docs/guide/chart-line.md +19 -19
- package/docs/guide/chart-multi-line.md +16 -16
- package/docs/guide/chart-pie.md +11 -11
- package/docs/guide/chart-polar-area.md +10 -10
- package/docs/guide/chart-radar.md +9 -9
- package/docs/guide/chart-scatter.md +24 -27
- package/docs/guide/index.md +3 -3
- package/docs/language-reference.md +46 -25
- package/fonts/Inter-Bold.ttf +0 -0
- package/fonts/Inter-Regular.ttf +0 -0
- package/fonts/LICENSE-Inter.txt +92 -0
- package/gallery/fixtures/bar-stacked.dgmo +12 -6
- package/gallery/fixtures/heatmap.dgmo +12 -6
- package/gallery/fixtures/multi-line.dgmo +11 -7
- package/gallery/fixtures/quadrant.dgmo +8 -8
- package/gallery/fixtures/scatter.dgmo +12 -12
- package/package.json +4 -2
- package/src/boxes-and-lines/parser.ts +13 -2
- package/src/boxes-and-lines/renderer.ts +22 -13
- package/src/chart-type-scoring.ts +162 -0
- package/src/chart-types.ts +437 -0
- package/src/cli.ts +147 -66
- package/src/completion.ts +0 -4
- package/src/d3.ts +9 -2
- package/src/dgmo-router.ts +85 -130
- package/src/editor/keywords.ts +0 -2
- package/src/fonts.ts +3 -2
- package/src/gantt/parser.ts +5 -1
- package/src/index.ts +24 -1
- package/src/infra/parser.ts +1 -1
- package/src/internal.ts +6 -2
- package/src/journey-map/layout.ts +7 -3
- package/src/journey-map/parser.ts +5 -1
- package/src/kanban/parser.ts +5 -1
- package/src/org/collapse.ts +1 -4
- package/src/org/parser.ts +1 -1
- package/src/org/renderer.ts +26 -17
- package/src/sequence/parser.ts +2 -2
- package/src/sequence/participant-inference.ts +0 -1
- package/src/sequence/renderer.ts +95 -263
- package/src/sharing.ts +0 -1
- package/src/sitemap/parser.ts +1 -1
- package/src/utils/tag-groups.ts +35 -5
- package/src/wireframe/parser.ts +3 -1
package/src/cli.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
import { homedir } from 'node:os';
|
|
4
|
+
import { homedir, platform } from 'node:os';
|
|
5
5
|
import { resolve, join, basename, extname } from 'node:path';
|
|
6
6
|
import { createInterface } from 'node:readline';
|
|
7
7
|
import { Resvg } from '@resvg/resvg-js';
|
|
@@ -467,10 +467,6 @@ Options:
|
|
|
467
467
|
With stdin and no -o, PNG is written to stdout
|
|
468
468
|
--theme <theme> Theme: ${THEMES.join(', ')} (default: light)
|
|
469
469
|
--palette <name> Palette: ${PALETTES.join(', ')} (default: nord)
|
|
470
|
-
--c4-level <level> C4 render level: context (default), containers, components, deployment
|
|
471
|
-
--c4-system <name> System to drill into (with --c4-level containers or components)
|
|
472
|
-
--c4-container <name> Container to drill into (with --c4-level components)
|
|
473
|
-
--tag-group <name> Pre-select a tag group for static export coloring
|
|
474
470
|
--copy Copy URL to clipboard (only with -o url)
|
|
475
471
|
--json Output structured JSON to stdout
|
|
476
472
|
--chart-types List all supported chart types
|
|
@@ -482,6 +478,11 @@ Options:
|
|
|
482
478
|
--install-codex-integration
|
|
483
479
|
Full Codex CLI setup: write AGENTS.md to the project and configure
|
|
484
480
|
the dgmo MCP server in .codex/config.toml (project) or ~/.codex/config.toml (global)
|
|
481
|
+
--install-claude-desktop-integration
|
|
482
|
+
Full Claude Desktop setup: install @diagrammo/dgmo-mcp if needed,
|
|
483
|
+
then merge the dgmo MCP entry into Claude Desktop's config file
|
|
484
|
+
(~/Library/Application Support/Claude/claude_desktop_config.json on macOS,
|
|
485
|
+
%APPDATA%/Claude/... on Windows, ~/.config/Claude/... on Linux)
|
|
485
486
|
--help Show this help
|
|
486
487
|
--version Show version`);
|
|
487
488
|
}
|
|
@@ -508,10 +509,7 @@ function parseArgs(argv: string[]): {
|
|
|
508
509
|
installClaudeSkill: boolean;
|
|
509
510
|
installClaudeCodeIntegration: boolean;
|
|
510
511
|
installCodexIntegration: boolean;
|
|
511
|
-
|
|
512
|
-
c4System: string | undefined;
|
|
513
|
-
c4Container: string | undefined;
|
|
514
|
-
tagGroup: string | undefined;
|
|
512
|
+
installClaudeDesktopIntegration: boolean;
|
|
515
513
|
} {
|
|
516
514
|
const result = {
|
|
517
515
|
input: undefined as string | undefined,
|
|
@@ -528,14 +526,7 @@ function parseArgs(argv: string[]): {
|
|
|
528
526
|
installClaudeSkill: false,
|
|
529
527
|
installClaudeCodeIntegration: false,
|
|
530
528
|
installCodexIntegration: false,
|
|
531
|
-
|
|
532
|
-
| 'context'
|
|
533
|
-
| 'containers'
|
|
534
|
-
| 'components'
|
|
535
|
-
| 'deployment',
|
|
536
|
-
c4System: undefined as string | undefined,
|
|
537
|
-
c4Container: undefined as string | undefined,
|
|
538
|
-
tagGroup: undefined as string | undefined,
|
|
529
|
+
installClaudeDesktopIntegration: false,
|
|
539
530
|
};
|
|
540
531
|
|
|
541
532
|
const args = argv.slice(2); // skip node + script
|
|
@@ -579,30 +570,6 @@ function parseArgs(argv: string[]): {
|
|
|
579
570
|
}
|
|
580
571
|
result.palette = val;
|
|
581
572
|
i++;
|
|
582
|
-
} else if (arg === '--c4-level') {
|
|
583
|
-
const val = args[++i];
|
|
584
|
-
if (
|
|
585
|
-
val !== 'context' &&
|
|
586
|
-
val !== 'containers' &&
|
|
587
|
-
val !== 'components' &&
|
|
588
|
-
val !== 'deployment'
|
|
589
|
-
) {
|
|
590
|
-
console.error(
|
|
591
|
-
`Error: Invalid C4 level "${val}". Valid levels: context, containers, components, deployment`
|
|
592
|
-
);
|
|
593
|
-
process.exit(1);
|
|
594
|
-
}
|
|
595
|
-
result.c4Level = val;
|
|
596
|
-
i++;
|
|
597
|
-
} else if (arg === '--c4-system') {
|
|
598
|
-
result.c4System = args[++i];
|
|
599
|
-
i++;
|
|
600
|
-
} else if (arg === '--c4-container') {
|
|
601
|
-
result.c4Container = args[++i];
|
|
602
|
-
i++;
|
|
603
|
-
} else if (arg === '--tag-group') {
|
|
604
|
-
result.tagGroup = args[++i];
|
|
605
|
-
i++;
|
|
606
573
|
} else if (arg === '--json') {
|
|
607
574
|
result.json = true;
|
|
608
575
|
i++;
|
|
@@ -618,6 +585,9 @@ function parseArgs(argv: string[]): {
|
|
|
618
585
|
} else if (arg === '--install-codex-integration') {
|
|
619
586
|
result.installCodexIntegration = true;
|
|
620
587
|
i++;
|
|
588
|
+
} else if (arg === '--install-claude-desktop-integration') {
|
|
589
|
+
result.installClaudeDesktopIntegration = true;
|
|
590
|
+
i++;
|
|
621
591
|
} else if (arg === '--copy') {
|
|
622
592
|
result.copy = true;
|
|
623
593
|
i++;
|
|
@@ -643,12 +613,19 @@ function inferFormat(outputPath: string | undefined): 'svg' | 'png' | 'url' {
|
|
|
643
613
|
return 'png';
|
|
644
614
|
}
|
|
645
615
|
|
|
616
|
+
const BUNDLED_FONTS = [
|
|
617
|
+
join(__dirname, '..', 'fonts', 'Inter-Regular.ttf'),
|
|
618
|
+
join(__dirname, '..', 'fonts', 'Inter-Bold.ttf'),
|
|
619
|
+
];
|
|
620
|
+
|
|
646
621
|
function svgToPng(svg: string, background?: string): Buffer {
|
|
622
|
+
const fontFiles = BUNDLED_FONTS.filter((f) => existsSync(f));
|
|
647
623
|
const resvg = new Resvg(svg, {
|
|
648
624
|
fitTo: { mode: 'zoom', value: 2 },
|
|
649
625
|
...(background ? { background } : {}),
|
|
650
626
|
font: {
|
|
651
|
-
loadSystemFonts:
|
|
627
|
+
loadSystemFonts: fontFiles.length === 0,
|
|
628
|
+
...(fontFiles.length > 0 ? { fontFiles } : {}),
|
|
652
629
|
defaultFontFamily: DEFAULT_FONT_NAME,
|
|
653
630
|
sansSerifFamily: DEFAULT_FONT_NAME,
|
|
654
631
|
},
|
|
@@ -715,7 +692,7 @@ async function main(): Promise<void> {
|
|
|
715
692
|
} else {
|
|
716
693
|
for (const id of types) {
|
|
717
694
|
const desc = CHART_TYPE_DESCRIPTIONS[id];
|
|
718
|
-
console.log(desc ? `${id} — ${desc
|
|
695
|
+
console.log(desc ? `${id} — ${desc}` : id);
|
|
719
696
|
}
|
|
720
697
|
}
|
|
721
698
|
return;
|
|
@@ -1038,6 +1015,133 @@ async function main(): Promise<void> {
|
|
|
1038
1015
|
return;
|
|
1039
1016
|
}
|
|
1040
1017
|
|
|
1018
|
+
if (opts.installClaudeDesktopIntegration) {
|
|
1019
|
+
const ask = (prompt: string): Promise<string> =>
|
|
1020
|
+
new Promise((resolve) => {
|
|
1021
|
+
const rl = createInterface({
|
|
1022
|
+
input: process.stdin,
|
|
1023
|
+
output: process.stdout,
|
|
1024
|
+
});
|
|
1025
|
+
rl.question(prompt, (answer) => {
|
|
1026
|
+
rl.close();
|
|
1027
|
+
resolve(answer);
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
// Check / install dgmo-mcp binary
|
|
1032
|
+
let dgmoMcpInstalled = false;
|
|
1033
|
+
try {
|
|
1034
|
+
execSync('which dgmo-mcp', { stdio: 'pipe' });
|
|
1035
|
+
dgmoMcpInstalled = true;
|
|
1036
|
+
} catch {
|
|
1037
|
+
/* not found */
|
|
1038
|
+
}
|
|
1039
|
+
if (!dgmoMcpInstalled) {
|
|
1040
|
+
const ans = await ask(
|
|
1041
|
+
'\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] '
|
|
1042
|
+
);
|
|
1043
|
+
const yes =
|
|
1044
|
+
ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
|
|
1045
|
+
if (yes) {
|
|
1046
|
+
console.log('Installing @diagrammo/dgmo-mcp...');
|
|
1047
|
+
try {
|
|
1048
|
+
execSync('npm install -g @diagrammo/dgmo-mcp', { stdio: 'inherit' });
|
|
1049
|
+
console.log('✓ @diagrammo/dgmo-mcp installed');
|
|
1050
|
+
} catch {
|
|
1051
|
+
console.error('Error: Failed to install @diagrammo/dgmo-mcp.');
|
|
1052
|
+
console.error('Try manually: npm install -g @diagrammo/dgmo-mcp');
|
|
1053
|
+
}
|
|
1054
|
+
} else {
|
|
1055
|
+
console.log(
|
|
1056
|
+
' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp'
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
} else {
|
|
1060
|
+
console.log('✓ dgmo-mcp already installed');
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Resolve the Claude Desktop config path for the current platform.
|
|
1064
|
+
// macOS and Windows use the documented Claude Desktop paths; Linux
|
|
1065
|
+
// doesn't have a first-party build yet, but community installs follow
|
|
1066
|
+
// the XDG config convention.
|
|
1067
|
+
const os = platform();
|
|
1068
|
+
let configPath: string;
|
|
1069
|
+
if (os === 'darwin') {
|
|
1070
|
+
configPath = join(
|
|
1071
|
+
homedir(),
|
|
1072
|
+
'Library',
|
|
1073
|
+
'Application Support',
|
|
1074
|
+
'Claude',
|
|
1075
|
+
'claude_desktop_config.json'
|
|
1076
|
+
);
|
|
1077
|
+
} else if (os === 'win32') {
|
|
1078
|
+
const appData =
|
|
1079
|
+
process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming');
|
|
1080
|
+
configPath = join(appData, 'Claude', 'claude_desktop_config.json');
|
|
1081
|
+
} else {
|
|
1082
|
+
configPath = join(
|
|
1083
|
+
homedir(),
|
|
1084
|
+
'.config',
|
|
1085
|
+
'Claude',
|
|
1086
|
+
'claude_desktop_config.json'
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// Read existing config (or start fresh). Non-JSON contents are treated
|
|
1091
|
+
// as corruption and we bail — the user needs to resolve it manually so
|
|
1092
|
+
// we don't silently overwrite something they care about.
|
|
1093
|
+
type ClaudeDesktopConfig = {
|
|
1094
|
+
mcpServers?: Record<
|
|
1095
|
+
string,
|
|
1096
|
+
{ command: string; args?: string[]; env?: Record<string, string> }
|
|
1097
|
+
>;
|
|
1098
|
+
[key: string]: unknown;
|
|
1099
|
+
};
|
|
1100
|
+
let config: ClaudeDesktopConfig = {};
|
|
1101
|
+
if (existsSync(configPath)) {
|
|
1102
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
1103
|
+
if (raw.trim().length > 0) {
|
|
1104
|
+
try {
|
|
1105
|
+
config = JSON.parse(raw) as ClaudeDesktopConfig;
|
|
1106
|
+
} catch {
|
|
1107
|
+
console.error(
|
|
1108
|
+
`Error: ${configPath} exists but is not valid JSON. Fix it manually and re-run, or remove the file to regenerate.`
|
|
1109
|
+
);
|
|
1110
|
+
process.exit(1);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
const existingDgmo = config.mcpServers?.dgmo;
|
|
1116
|
+
if (existingDgmo && existingDgmo.command === 'dgmo-mcp') {
|
|
1117
|
+
console.log(`✓ dgmo MCP server already configured in ${configPath}`);
|
|
1118
|
+
} else {
|
|
1119
|
+
if (existingDgmo) {
|
|
1120
|
+
const ans = await ask(
|
|
1121
|
+
`\nA "dgmo" entry already exists in ${configPath}. Overwrite? [y/N] `
|
|
1122
|
+
);
|
|
1123
|
+
if (ans.toLowerCase() !== 'y' && ans.toLowerCase() !== 'yes') {
|
|
1124
|
+
console.log(' Skipped.');
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
config.mcpServers = {
|
|
1129
|
+
...(config.mcpServers ?? {}),
|
|
1130
|
+
dgmo: { command: 'dgmo-mcp' },
|
|
1131
|
+
};
|
|
1132
|
+
mkdirSync(join(configPath, '..'), { recursive: true });
|
|
1133
|
+
writeFileSync(
|
|
1134
|
+
configPath,
|
|
1135
|
+
JSON.stringify(config, null, 2) + '\n',
|
|
1136
|
+
'utf-8'
|
|
1137
|
+
);
|
|
1138
|
+
console.log(`✓ dgmo MCP server configured: ${configPath}`);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
console.log('\nRestart Claude Desktop to activate the MCP server.');
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1041
1145
|
// Determine input source
|
|
1042
1146
|
let content: string;
|
|
1043
1147
|
let inputBasename: string | undefined;
|
|
@@ -1195,32 +1299,9 @@ async function main(): Promise<void> {
|
|
|
1195
1299
|
}
|
|
1196
1300
|
}
|
|
1197
1301
|
|
|
1198
|
-
// Validate C4 options
|
|
1199
|
-
if (opts.c4Level === 'containers' && !opts.c4System) {
|
|
1200
|
-
exitWithJsonError(
|
|
1201
|
-
'Error: --c4-system is required when --c4-level is containers'
|
|
1202
|
-
);
|
|
1203
|
-
}
|
|
1204
|
-
if (opts.c4Level === 'components') {
|
|
1205
|
-
if (!opts.c4System) {
|
|
1206
|
-
exitWithJsonError(
|
|
1207
|
-
'Error: --c4-system is required when --c4-level is components'
|
|
1208
|
-
);
|
|
1209
|
-
}
|
|
1210
|
-
if (!opts.c4Container) {
|
|
1211
|
-
exitWithJsonError(
|
|
1212
|
-
'Error: --c4-container is required when --c4-level is components'
|
|
1213
|
-
);
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
1302
|
const { svg } = await render(content, {
|
|
1218
1303
|
theme: opts.theme,
|
|
1219
1304
|
palette: opts.palette,
|
|
1220
|
-
c4Level: opts.c4Level,
|
|
1221
|
-
c4System: opts.c4System,
|
|
1222
|
-
c4Container: opts.c4Container,
|
|
1223
|
-
tagGroup: opts.tagGroup,
|
|
1224
1305
|
});
|
|
1225
1306
|
|
|
1226
1307
|
if (!svg) {
|
package/src/completion.ts
CHANGED
|
@@ -238,10 +238,6 @@ export const COMPLETION_REGISTRY = new Map<string, DirectiveSpec>([
|
|
|
238
238
|
description: 'Show activation bars',
|
|
239
239
|
values: ['on', 'off'],
|
|
240
240
|
},
|
|
241
|
-
'collapse-notes': {
|
|
242
|
-
description: 'Collapse note blocks',
|
|
243
|
-
values: ['yes', 'no'],
|
|
244
|
-
},
|
|
245
241
|
'active-tag': { description: 'Active tag group name' },
|
|
246
242
|
}),
|
|
247
243
|
],
|
package/src/d3.ts
CHANGED
|
@@ -1506,8 +1506,15 @@ export function parseVisualization(
|
|
|
1506
1506
|
result.diagnostics.push(makeDgmoError(line, msg, 'warning')),
|
|
1507
1507
|
suggest
|
|
1508
1508
|
);
|
|
1509
|
-
validateTagGroupNames(
|
|
1510
|
-
result.
|
|
1509
|
+
validateTagGroupNames(
|
|
1510
|
+
result.timelineTagGroups,
|
|
1511
|
+
(line, msg) =>
|
|
1512
|
+
result.diagnostics.push(makeDgmoError(line, msg, 'warning')),
|
|
1513
|
+
(line, msg) => {
|
|
1514
|
+
const diag = makeDgmoError(line, msg);
|
|
1515
|
+
result.diagnostics.push(diag);
|
|
1516
|
+
if (!result.error) result.error = formatDgmoError(diag);
|
|
1517
|
+
}
|
|
1511
1518
|
);
|
|
1512
1519
|
for (const group of result.timelineTagGroups) {
|
|
1513
1520
|
if (!group.defaultValue) continue;
|
package/src/dgmo-router.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { parsePyramid } from './pyramid/parser';
|
|
|
26
26
|
import { parseFirstLine } from './utils/parsing';
|
|
27
27
|
import { makeDgmoError, suggest } from './diagnostics';
|
|
28
28
|
import type { DgmoError } from './diagnostics';
|
|
29
|
+
import { chartTypes } from './chart-types';
|
|
29
30
|
|
|
30
31
|
// ============================================================
|
|
31
32
|
// Content-based chart type inference helpers
|
|
@@ -192,129 +193,98 @@ export function isExtendedChartType(chartType: string): boolean {
|
|
|
192
193
|
return EXTENDED_CHART_TYPES.has(chartType.toLowerCase());
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
/** Standard chart types parsed by parseChart (then rendered via ECharts). Internal use. */
|
|
196
|
-
const STANDARD_CHART_TYPES = new Set([
|
|
197
|
-
'bar',
|
|
198
|
-
'line',
|
|
199
|
-
'multi-line',
|
|
200
|
-
'area',
|
|
201
|
-
'pie',
|
|
202
|
-
'doughnut',
|
|
203
|
-
'radar',
|
|
204
|
-
'polar-area',
|
|
205
|
-
'bar-stacked',
|
|
206
|
-
]);
|
|
207
|
-
|
|
208
196
|
/**
|
|
209
|
-
* Returns all supported chart type identifiers
|
|
210
|
-
*
|
|
197
|
+
* Returns all supported chart type identifiers in canonical (tier) order,
|
|
198
|
+
* derived from `chartTypes`. Consumers that need alphabetical order should
|
|
199
|
+
* call `.sort()` explicitly.
|
|
211
200
|
*/
|
|
212
201
|
export function getAllChartTypes(): string[] {
|
|
213
|
-
return
|
|
202
|
+
return chartTypes.map((c) => c.id);
|
|
214
203
|
}
|
|
215
204
|
|
|
216
205
|
/**
|
|
217
|
-
* Canonical descriptions for every supported chart type.
|
|
218
|
-
*
|
|
219
|
-
*
|
|
206
|
+
* Canonical descriptions for every supported chart type. Derived from
|
|
207
|
+
* `chartTypes` so there is exactly one place to update when adding a new
|
|
208
|
+
* type. Consumed by the CLI `--chart-types` flag, the editor autocomplete
|
|
209
|
+
* popup, and the MCP `list_chart_types` tool.
|
|
220
210
|
*/
|
|
221
|
-
export const CHART_TYPE_DESCRIPTIONS: Record<string, string> =
|
|
222
|
-
|
|
223
|
-
line: 'Line chart — trends over time; supports era bands (era start -> end Label (color)) for annotating named periods',
|
|
224
|
-
'multi-line':
|
|
225
|
-
'Multi-line chart — multiple series trends over time; supports era bands',
|
|
226
|
-
area: 'Area chart — filled line chart; supports era bands',
|
|
227
|
-
pie: 'Pie chart — part-to-whole proportions',
|
|
228
|
-
doughnut: 'Doughnut chart — ring-style pie chart',
|
|
229
|
-
radar: 'Radar chart — multi-dimensional metrics',
|
|
230
|
-
'polar-area': 'Polar area chart — radial bar chart',
|
|
231
|
-
'bar-stacked': 'Stacked bar chart — multi-series categorical',
|
|
232
|
-
scatter: 'Scatter plot — 2D data points or bubble chart',
|
|
233
|
-
sankey: 'Sankey diagram — flow/allocation visualization',
|
|
234
|
-
chord: 'Chord diagram — circular flow relationships',
|
|
235
|
-
function: 'Function plot — mathematical expressions',
|
|
236
|
-
heatmap: 'Heatmap — matrix intensity visualization',
|
|
237
|
-
funnel: 'Funnel chart — conversion pipeline',
|
|
238
|
-
slope: 'Slope chart — change between two periods',
|
|
239
|
-
wordcloud: 'Word cloud — term frequency visualization',
|
|
240
|
-
arc: 'Arc diagram — network relationships',
|
|
241
|
-
timeline: 'Timeline — events, eras, and date ranges',
|
|
242
|
-
venn: 'Venn diagram — set overlaps',
|
|
243
|
-
quadrant: 'Quadrant chart — 2x2 positioning matrix',
|
|
244
|
-
'tech-radar':
|
|
245
|
-
'Tech radar — technology adoption quadrants (adopt/trial/assess/hold)',
|
|
246
|
-
cycle:
|
|
247
|
-
'Cycle diagram — cyclical process visualization (PDCA, OODA, DevOps loops)',
|
|
248
|
-
sequence: 'Sequence diagram — message/interaction flows',
|
|
249
|
-
flowchart: 'Flowchart — decision trees and process flows',
|
|
250
|
-
class: 'Class diagram — UML class hierarchies',
|
|
251
|
-
er: 'ER diagram — database schemas and relationships',
|
|
252
|
-
org: 'Org chart — hierarchical tree structures',
|
|
253
|
-
kanban: 'Kanban board — task/workflow columns',
|
|
254
|
-
c4: 'C4 diagram — system architecture (context, container, component, deployment)',
|
|
255
|
-
state: 'State diagram — state machine / lifecycle transitions',
|
|
256
|
-
sitemap:
|
|
257
|
-
'Sitemap — navigable UI structure with pages, groups, and cross-link arrows',
|
|
258
|
-
infra:
|
|
259
|
-
'Infrastructure diagram — traffic flow with RPS computation, capacity modeling, and latency analysis',
|
|
260
|
-
gantt:
|
|
261
|
-
'Gantt chart — project scheduling with task dependencies and milestones',
|
|
262
|
-
'boxes-and-lines':
|
|
263
|
-
'Boxes and lines — general-purpose node-edge diagrams with nested groups, tags, and shape inference',
|
|
264
|
-
mindmap: 'Mindmap — radial hierarchy of ideas branching from a central topic',
|
|
265
|
-
wireframe:
|
|
266
|
-
'Wireframe — low-fidelity UI layout with panels, controls, and annotations',
|
|
267
|
-
'journey-map':
|
|
268
|
-
'Journey map — user experience flow with emotion scores, phases, and annotations',
|
|
269
|
-
pyramid:
|
|
270
|
-
'Pyramid — hierarchical layered pyramid (Maslow, DIKW, learning pyramid); inverted for funnel-of-learning style',
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// ECharts-native types parsed by parseExtendedChart
|
|
274
|
-
const ECHART_TYPES = new Set([
|
|
275
|
-
'scatter',
|
|
276
|
-
'sankey',
|
|
277
|
-
'chord',
|
|
278
|
-
'function',
|
|
279
|
-
'heatmap',
|
|
280
|
-
'funnel',
|
|
281
|
-
]);
|
|
211
|
+
export const CHART_TYPE_DESCRIPTIONS: Record<string, string> =
|
|
212
|
+
Object.fromEntries(chartTypes.map((c) => [c.id, c.description]));
|
|
282
213
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
['flowchart', (c) => parseFlowchart(c)],
|
|
290
|
-
['class', (c) => parseClassDiagram(c)],
|
|
291
|
-
['er', (c) => parseERDiagram(c)],
|
|
292
|
-
['org', (c) => parseOrg(c)],
|
|
293
|
-
['kanban', (c) => parseKanban(c)],
|
|
294
|
-
['c4', (c) => parseC4(c)],
|
|
295
|
-
['state', (c) => parseState(c)],
|
|
296
|
-
['sitemap', (c) => parseSitemap(c)],
|
|
297
|
-
['infra', (c) => parseInfra(c)],
|
|
298
|
-
['gantt', (c) => parseGantt(c)],
|
|
299
|
-
['boxes-and-lines', (c) => parseBoxesAndLines(c)],
|
|
300
|
-
['mindmap', (c) => parseMindmap(c)],
|
|
301
|
-
['wireframe', (c) => parseWireframe(c)],
|
|
302
|
-
['tech-radar', (c) => parseTechRadar(c)],
|
|
303
|
-
['cycle', (c) => parseCycle(c)],
|
|
304
|
-
['journey-map', (c) => parseJourneyMap(c)],
|
|
305
|
-
['pyramid', (c) => parsePyramid(c)],
|
|
306
|
-
]);
|
|
214
|
+
// ============================================================
|
|
215
|
+
// Parser registry — single source of truth for id → parser
|
|
216
|
+
// ============================================================
|
|
217
|
+
|
|
218
|
+
type ParseResult = { diagnostics: DgmoError[] };
|
|
219
|
+
type ParseFn = (content: string) => ParseResult;
|
|
307
220
|
|
|
308
221
|
/**
|
|
309
|
-
*
|
|
310
|
-
*
|
|
222
|
+
* Maps every chart-type id to the parser that handles it. Adding a new
|
|
223
|
+
* chart type means:
|
|
224
|
+
* 1. Add an entry here.
|
|
225
|
+
* 2. Add an entry to `chartTypes` in `chart-types.ts`.
|
|
226
|
+
*
|
|
227
|
+
* The `chart-types.test.ts` cross-check asserts both sets are identical;
|
|
228
|
+
* forgetting either side trips the test.
|
|
311
229
|
*/
|
|
230
|
+
export const chartTypeParsers: ReadonlyArray<readonly [string, ParseFn]> = [
|
|
231
|
+
// Structured diagrams (direct parsers)
|
|
232
|
+
['sequence', parseSequenceDgmo],
|
|
233
|
+
['flowchart', parseFlowchart],
|
|
234
|
+
['class', parseClassDiagram],
|
|
235
|
+
['er', parseERDiagram],
|
|
236
|
+
['state', parseState],
|
|
237
|
+
['org', parseOrg],
|
|
238
|
+
['kanban', parseKanban],
|
|
239
|
+
['c4', parseC4],
|
|
240
|
+
['sitemap', parseSitemap],
|
|
241
|
+
['infra', parseInfra],
|
|
242
|
+
['gantt', parseGantt],
|
|
243
|
+
['boxes-and-lines', parseBoxesAndLines],
|
|
244
|
+
['mindmap', parseMindmap],
|
|
245
|
+
['wireframe', parseWireframe],
|
|
246
|
+
['tech-radar', parseTechRadar],
|
|
247
|
+
['cycle', parseCycle],
|
|
248
|
+
['journey-map', parseJourneyMap],
|
|
249
|
+
['pyramid', parsePyramid],
|
|
250
|
+
|
|
251
|
+
// Standard ECharts charts (parseChart)
|
|
252
|
+
['bar', parseChart],
|
|
253
|
+
['line', parseChart],
|
|
254
|
+
['multi-line', parseChart],
|
|
255
|
+
['area', parseChart],
|
|
256
|
+
['pie', parseChart],
|
|
257
|
+
['doughnut', parseChart],
|
|
258
|
+
['radar', parseChart],
|
|
259
|
+
['polar-area', parseChart],
|
|
260
|
+
['bar-stacked', parseChart],
|
|
261
|
+
|
|
262
|
+
// Extended ECharts charts (parseExtendedChart)
|
|
263
|
+
['scatter', parseExtendedChart],
|
|
264
|
+
['sankey', parseExtendedChart],
|
|
265
|
+
['chord', parseExtendedChart],
|
|
266
|
+
['function', parseExtendedChart],
|
|
267
|
+
['heatmap', parseExtendedChart],
|
|
268
|
+
['funnel', parseExtendedChart],
|
|
269
|
+
|
|
270
|
+
// D3 visualizations (parseVisualization)
|
|
271
|
+
['slope', parseVisualization],
|
|
272
|
+
['wordcloud', parseVisualization],
|
|
273
|
+
['arc', parseVisualization],
|
|
274
|
+
['timeline', parseVisualization],
|
|
275
|
+
['venn', parseVisualization],
|
|
276
|
+
['quadrant', parseVisualization],
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
/** Ids in the same order as `chartTypeParsers`; used for cross-checks. */
|
|
280
|
+
export const knownChartTypeIds: readonly string[] = chartTypeParsers.map(
|
|
281
|
+
([id]) => id
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const PARSER_BY_ID: Map<string, ParseFn> = new Map(chartTypeParsers);
|
|
285
|
+
|
|
312
286
|
/** All known chart type names for colon-pattern detection. */
|
|
313
|
-
const ALL_KNOWN_TYPES = new Set(
|
|
314
|
-
...DATA_CHART_TYPES,
|
|
315
|
-
...VISUALIZATION_TYPES,
|
|
316
|
-
...DIAGRAM_TYPES,
|
|
317
|
-
]);
|
|
287
|
+
const ALL_KNOWN_TYPES: ReadonlySet<string> = new Set(knownChartTypeIds);
|
|
318
288
|
|
|
319
289
|
/**
|
|
320
290
|
* Parse DGMO content and return diagnostics without rendering.
|
|
@@ -341,31 +311,16 @@ export function parseDgmo(content: string): {
|
|
|
341
311
|
};
|
|
342
312
|
}
|
|
343
313
|
|
|
344
|
-
const
|
|
345
|
-
if (
|
|
346
|
-
const result =
|
|
347
|
-
return {
|
|
348
|
-
diagnostics: [...result.diagnostics, ...detectEmptyContent(content)],
|
|
349
|
-
chartType,
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
if (STANDARD_CHART_TYPES.has(chartType)) {
|
|
354
|
-
const result = parseChart(content);
|
|
355
|
-
return {
|
|
356
|
-
diagnostics: [...result.diagnostics, ...detectEmptyContent(content)],
|
|
357
|
-
chartType,
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
if (ECHART_TYPES.has(chartType)) {
|
|
361
|
-
const result = parseExtendedChart(content);
|
|
314
|
+
const parser = PARSER_BY_ID.get(chartType);
|
|
315
|
+
if (parser) {
|
|
316
|
+
const result = parser(content);
|
|
362
317
|
return {
|
|
363
318
|
diagnostics: [...result.diagnostics, ...detectEmptyContent(content)],
|
|
364
319
|
chartType,
|
|
365
320
|
};
|
|
366
321
|
}
|
|
367
322
|
|
|
368
|
-
//
|
|
323
|
+
// Unknown id (defensive): fall through to visualization parser.
|
|
369
324
|
const result = parseVisualization(content);
|
|
370
325
|
return {
|
|
371
326
|
diagnostics: [...result.diagnostics, ...detectEmptyContent(content)],
|
package/src/editor/keywords.ts
CHANGED
package/src/fonts.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export const FONT_FAMILY =
|
|
2
|
-
|
|
1
|
+
export const FONT_FAMILY =
|
|
2
|
+
'Inter, system-ui, Avenir, Helvetica, Arial, sans-serif';
|
|
3
|
+
export const DEFAULT_FONT_NAME = 'Inter';
|
package/src/gantt/parser.ts
CHANGED
|
@@ -926,7 +926,11 @@ export function parseGantt(
|
|
|
926
926
|
result.options.sort = 'default';
|
|
927
927
|
}
|
|
928
928
|
|
|
929
|
-
validateTagGroupNames(result.tagGroups, warn)
|
|
929
|
+
validateTagGroupNames(result.tagGroups, warn, (line, msg) => {
|
|
930
|
+
const diag = makeDgmoError(line, msg);
|
|
931
|
+
diagnostics.push(diag);
|
|
932
|
+
if (!result.error) result.error = formatDgmoError(diag);
|
|
933
|
+
});
|
|
930
934
|
|
|
931
935
|
// ── Sprint mode detection ──────────────────────────────
|
|
932
936
|
const hasSprintOption =
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,28 @@ export type { ParseInArrowLabelResult } from './utils/arrows';
|
|
|
23
23
|
|
|
24
24
|
export { render } from './render';
|
|
25
25
|
|
|
26
|
+
// ============================================================
|
|
27
|
+
// Chart-type registry (single source of truth)
|
|
28
|
+
// ============================================================
|
|
29
|
+
|
|
30
|
+
export { chartTypes } from './chart-types';
|
|
31
|
+
export type { ChartTypeMeta } from './chart-types';
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
normalize as normalizeChartTypePrompt,
|
|
35
|
+
matchesContiguously,
|
|
36
|
+
scoreChartType,
|
|
37
|
+
confidence as chartTypeConfidence,
|
|
38
|
+
suggestChartTypes,
|
|
39
|
+
MIN_PRIMARY_SCORE,
|
|
40
|
+
AMBIGUITY_THRESHOLD,
|
|
41
|
+
} from './chart-type-scoring';
|
|
42
|
+
export type {
|
|
43
|
+
ChartTypeScore,
|
|
44
|
+
Confidence as ChartTypeConfidence,
|
|
45
|
+
SuggestionResult as ChartTypeSuggestionResult,
|
|
46
|
+
} from './chart-type-scoring';
|
|
47
|
+
|
|
26
48
|
// ============================================================
|
|
27
49
|
// Router
|
|
28
50
|
// ============================================================
|
|
@@ -34,6 +56,8 @@ export {
|
|
|
34
56
|
isExtendedChartType,
|
|
35
57
|
getAllChartTypes,
|
|
36
58
|
CHART_TYPE_DESCRIPTIONS,
|
|
59
|
+
chartTypeParsers,
|
|
60
|
+
knownChartTypeIds,
|
|
37
61
|
} from './dgmo-router';
|
|
38
62
|
export type { RenderCategory } from './dgmo-router';
|
|
39
63
|
|
|
@@ -496,7 +520,6 @@ export {
|
|
|
496
520
|
applyGroupOrdering,
|
|
497
521
|
groupMessagesBySection,
|
|
498
522
|
buildNoteMessageMap,
|
|
499
|
-
collectNoteLineNumbers,
|
|
500
523
|
} from './sequence/renderer';
|
|
501
524
|
export type {
|
|
502
525
|
RenderStep,
|
package/src/infra/parser.ts
CHANGED
package/src/internal.ts
CHANGED
|
@@ -10,7 +10,11 @@ export {
|
|
|
10
10
|
isArchiveColumn,
|
|
11
11
|
} from './kanban/mutations';
|
|
12
12
|
export {
|
|
13
|
-
|
|
13
|
+
applyGroupOrdering,
|
|
14
|
+
applyPositionOverrides,
|
|
14
15
|
buildNoteMessageMap,
|
|
15
|
-
|
|
16
|
+
buildRenderSequence,
|
|
17
|
+
computeActivations,
|
|
18
|
+
groupMessagesBySection,
|
|
16
19
|
} from './sequence/renderer';
|
|
20
|
+
export { orderArcNodes } from './d3';
|