@diagrammo/dgmo 0.8.3 → 0.8.4
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-diagram-this.md +60 -0
- package/.claude/commands/dgmo-document-project.md +128 -0
- package/.claude/commands/dgmo.md +185 -50
- package/.cursorrules +32 -37
- package/.github/copilot-instructions.md +35 -44
- package/.windsurfrules +32 -37
- package/README.md +4 -4
- package/dist/cli.cjs +153 -153
- package/dist/editor.cjs +336 -0
- package/dist/editor.cjs.map +1 -0
- package/dist/editor.d.cts +27 -0
- package/dist/editor.d.ts +27 -0
- package/dist/editor.js +305 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.cjs +3336 -1055
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3336 -1055
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +30 -29
- package/gallery/fixtures/arc.dgmo +18 -0
- package/gallery/fixtures/area.dgmo +19 -0
- package/gallery/fixtures/bar-stacked.dgmo +10 -0
- package/gallery/fixtures/bar.dgmo +10 -0
- package/gallery/fixtures/c4-full.dgmo +52 -0
- package/gallery/fixtures/c4.dgmo +17 -0
- package/gallery/fixtures/chord.dgmo +12 -0
- package/gallery/fixtures/class-basic.dgmo +14 -0
- package/gallery/fixtures/class-full.dgmo +43 -0
- package/gallery/fixtures/doughnut.dgmo +8 -0
- package/gallery/fixtures/flowchart-basic.dgmo +3 -0
- package/gallery/fixtures/flowchart-colors.dgmo +5 -0
- package/gallery/fixtures/flowchart-complex.dgmo +17 -0
- package/gallery/fixtures/flowchart-decision.dgmo +5 -0
- package/gallery/fixtures/flowchart-full.dgmo +13 -0
- package/gallery/fixtures/flowchart-groups.dgmo +10 -0
- package/gallery/fixtures/flowchart-loop.dgmo +7 -0
- package/gallery/fixtures/flowchart-nested.dgmo +7 -0
- package/gallery/fixtures/flowchart-shapes.dgmo +5 -0
- package/gallery/fixtures/function.dgmo +8 -0
- package/gallery/fixtures/funnel.dgmo +7 -0
- package/gallery/fixtures/gantt-full.dgmo +49 -0
- package/gallery/fixtures/gantt.dgmo +42 -0
- package/gallery/fixtures/heatmap.dgmo +8 -0
- package/gallery/fixtures/infra-full.dgmo +78 -0
- package/gallery/fixtures/infra-overload.dgmo +25 -0
- package/gallery/fixtures/infra.dgmo +47 -0
- package/gallery/fixtures/initiative-status-full.dgmo +46 -0
- package/gallery/fixtures/initiative-status-phases.dgmo +29 -0
- package/gallery/fixtures/initiative-status.dgmo +9 -0
- package/gallery/fixtures/line.dgmo +19 -0
- package/gallery/fixtures/multi-line.dgmo +11 -0
- package/gallery/fixtures/org-basic.dgmo +16 -0
- package/gallery/fixtures/org-full.dgmo +69 -0
- package/gallery/fixtures/org-teams.dgmo +25 -0
- package/gallery/fixtures/pie.dgmo +9 -0
- package/gallery/fixtures/polar-area.dgmo +8 -0
- package/gallery/fixtures/quadrant.dgmo +18 -0
- package/gallery/fixtures/radar.dgmo +8 -0
- package/gallery/fixtures/sankey.dgmo +31 -0
- package/gallery/fixtures/scatter.dgmo +21 -0
- package/gallery/fixtures/sequence-tags-protocols.dgmo +45 -0
- package/gallery/fixtures/sequence-tags.dgmo +41 -0
- package/gallery/fixtures/sequence.dgmo +35 -0
- package/gallery/fixtures/sitemap-basic.dgmo +12 -0
- package/gallery/fixtures/sitemap-full.dgmo +156 -0
- package/gallery/fixtures/slope.dgmo +8 -0
- package/gallery/fixtures/spr-eras.dgmo +62 -0
- package/gallery/fixtures/state.dgmo +30 -0
- package/gallery/fixtures/timeline-intraday.dgmo +14 -0
- package/gallery/fixtures/timeline.dgmo +32 -0
- package/gallery/fixtures/venn.dgmo +10 -0
- package/gallery/fixtures/wordcloud.dgmo +24 -0
- package/package.json +51 -2
- package/src/c4/layout.ts +372 -90
- package/src/c4/parser.ts +100 -55
- package/src/chart.ts +91 -28
- package/src/class/parser.ts +41 -12
- package/src/cli.ts +168 -61
- package/src/completion.ts +378 -183
- package/src/d3.ts +887 -288
- package/src/dgmo-mermaid.ts +16 -13
- package/src/dgmo-router.ts +69 -23
- package/src/echarts.ts +646 -153
- package/src/editor/dgmo.grammar +69 -0
- package/src/editor/dgmo.grammar.d.ts +2 -0
- package/src/editor/dgmo.grammar.js +18 -0
- package/src/editor/dgmo.grammar.terms.d.ts +5 -0
- package/src/editor/dgmo.grammar.terms.js +35 -0
- package/src/editor/highlight.ts +36 -0
- package/src/editor/index.ts +28 -0
- package/src/editor/keywords.ts +220 -0
- package/src/editor/tokens.ts +30 -0
- package/src/er/parser.ts +48 -14
- package/src/er/renderer.ts +112 -53
- package/src/gantt/calculator.ts +91 -29
- package/src/gantt/parser.ts +197 -71
- package/src/gantt/renderer.ts +1120 -350
- package/src/graph/flowchart-parser.ts +46 -25
- package/src/graph/state-parser.ts +47 -17
- package/src/infra/parser.ts +157 -53
- package/src/infra/renderer.ts +723 -271
- package/src/initiative-status/parser.ts +138 -44
- package/src/kanban/parser.ts +25 -14
- package/src/org/layout.ts +111 -44
- package/src/org/parser.ts +69 -22
- package/src/palettes/index.ts +3 -2
- package/src/sequence/parser.ts +193 -61
- package/src/sitemap/parser.ts +65 -29
- package/src/utils/arrows.ts +2 -22
- package/src/utils/duration.ts +39 -21
- package/src/utils/legend-constants.ts +0 -2
- package/src/utils/parsing.ts +75 -31
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@top Document { (newline | Comment | ContentLine)* }
|
|
2
|
+
|
|
3
|
+
ContentLine { contentPart+ newline }
|
|
4
|
+
|
|
5
|
+
contentPart {
|
|
6
|
+
SyncArrow | AsyncArrow |
|
|
7
|
+
Duration | DateLiteral | Percentage | Number |
|
|
8
|
+
SectionMarker |
|
|
9
|
+
Url |
|
|
10
|
+
OpenBracket | CloseBracket | OpenParen | CloseParen | OpenAngle | CloseAngle |
|
|
11
|
+
ColorAnnotation |
|
|
12
|
+
Pipe | Colon | Comma | Plus | Dash | Tilde | Star | Question |
|
|
13
|
+
ChartType |
|
|
14
|
+
TagKeyword | DirectiveKeyword | ControlKeyword | ModifierKeyword |
|
|
15
|
+
Identifier |
|
|
16
|
+
Punct
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@skip { spaces }
|
|
20
|
+
|
|
21
|
+
@tokens {
|
|
22
|
+
spaces { $[ \t]+ }
|
|
23
|
+
newline { "\n" }
|
|
24
|
+
|
|
25
|
+
Comment { "//" ![\n]* }
|
|
26
|
+
|
|
27
|
+
SyncArrow { "->" }
|
|
28
|
+
AsyncArrow { "~>" }
|
|
29
|
+
|
|
30
|
+
Duration { $[0-9]+ ("." $[0-9]+)? ("min" | "bd" | "h" | "d" | "w" | "m" | "q" | "y") "?"? }
|
|
31
|
+
DateLiteral { $[0-9] $[0-9] $[0-9] $[0-9] "-" $[0-9] $[0-9] ("-" $[0-9] $[0-9])? }
|
|
32
|
+
Percentage { $[0-9]+ ("." $[0-9]+)? "%" }
|
|
33
|
+
Number { $[0-9]+ ("." $[0-9]+)? }
|
|
34
|
+
|
|
35
|
+
SectionMarker { "==" }
|
|
36
|
+
Url { "http" "s"? "://" ![ \t\n|,)\]>]+ }
|
|
37
|
+
ColorAnnotation { "(" $[a-z\-]+ ")" }
|
|
38
|
+
|
|
39
|
+
Pipe { "|" }
|
|
40
|
+
Colon { ":" }
|
|
41
|
+
Comma { "," }
|
|
42
|
+
Plus { "+" }
|
|
43
|
+
Dash { "-" }
|
|
44
|
+
Tilde { "~" }
|
|
45
|
+
Star { "*" }
|
|
46
|
+
Question { "?" }
|
|
47
|
+
OpenBracket { "[" }
|
|
48
|
+
CloseBracket { "]" }
|
|
49
|
+
OpenParen { "(" }
|
|
50
|
+
CloseParen { ")" }
|
|
51
|
+
OpenAngle { "<" }
|
|
52
|
+
CloseAngle { ">" }
|
|
53
|
+
|
|
54
|
+
Identifier { $[a-zA-Z_] ($[a-zA-Z0-9_./&?=@#!'+] | "-" $[a-zA-Z_./&?=@#!'+])* }
|
|
55
|
+
|
|
56
|
+
Punct { ![$[ \t\n] }
|
|
57
|
+
|
|
58
|
+
@precedence {
|
|
59
|
+
Comment, SyncArrow, AsyncArrow,
|
|
60
|
+
Duration, DateLiteral, Percentage, Number, SectionMarker, Url, ColorAnnotation,
|
|
61
|
+
Pipe, Colon, Comma, Plus, Dash, Tilde, Star, Question,
|
|
62
|
+
OpenBracket, CloseBracket, OpenParen, CloseParen, OpenAngle, CloseAngle,
|
|
63
|
+
Identifier, Punct
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@external specialize {Identifier} specializeKeyword from "./tokens" {
|
|
68
|
+
ChartType, TagKeyword, DirectiveKeyword, ControlKeyword, ModifierKeyword
|
|
69
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
|
2
|
+
import {LRParser} from "@lezer/lr"
|
|
3
|
+
import {specializeKeyword} from "./tokens"
|
|
4
|
+
export const parser = LRParser.deserialize({
|
|
5
|
+
version: 14,
|
|
6
|
+
states: "!WQVQPOOOOQO'#DU'#DUOOQO'#DP'#DPO%]QPO'#CdOOQO'#DO'#DOQVQPOOOOQO-E6}-E6}OOQO,59O,59OOOQO-E6|-E6|",
|
|
7
|
+
stateData: "&Q~OvOS~OPPOQPORPOSPOTPOVSOXPOYPOZPO[PO]PO^PO_PO`POaPObPOcPOdPOePOfPOgPOhPOiPOjPOkPOlPOmPOnPOoPOpPOqPOwSO~OPPOQPORPOSPOTPOXPOYPOZPO[PO]PO^PO_PO`POaPObPOcPOdPOePOfPOgPOhPOiPOjPOkPOlPOmPOnPOoPOpPOqPO~OwVO~P#]OVXYZ[]^_`ghijklmnoabcdefpqk~",
|
|
8
|
+
goto: "!byPPPPPPPPzPPPPPPPPPPPPPPPPPPPPPPPPP!O!UPPPP!]TSOTQTORWTSROTRURVQORT",
|
|
9
|
+
nodeNames: "⚠ ChartType TagKeyword DirectiveKeyword ControlKeyword ModifierKeyword Document Comment ContentLine SyncArrow AsyncArrow Duration DateLiteral Percentage Number SectionMarker Url OpenBracket CloseBracket OpenParen CloseParen OpenAngle CloseAngle ColorAnnotation Pipe Colon Comma Plus Dash Tilde Star Question Identifier Punct",
|
|
10
|
+
maxTerm: 40,
|
|
11
|
+
skippedNodes: [0],
|
|
12
|
+
repeatNodeCount: 2,
|
|
13
|
+
tokenData: "9q~RxOX#oXY#tYZ$PZp#opq#tqt#oux#oxy$Uyz$tz{${{|%S|}%Z}!O%b!O!P#o!P!Q%q!Q![&b![!],v!]!^#o!^!_,}!_!`-U!`!a-c!a!b-j!b!c#o!c!}-q!}#O0w#O#P#o#P#Q0|#Q#R#o#R#S-q#S#T#o#T#[-q#[#]1T#]#o-q#o#p#o#p#q9T#q#r#o#r#s9[#s;'S#o;'S;=`9k<%lO#o~#tOq~~#yQv~XY#tpq#t~$UOw~~$]Qc~q~}!O$c#T#o$c~$fRyz$o}!O$c#T#o$c~$tOg~~${Od~q~~%SOn~q~~%ZOk~q~~%bOj~q~~%iPl~q~!`!a%l~%qOX~~%vPq~!P!Q%y~&OSV~OY%yZ;'S%y;'S;=`&[<%lO%y~&_P;=`<%l%y~&iY^~q~uv'X!O!P'^!QPY^~uv'X!O!P'^!QtY^~uv'X!O!P'^!Q => (specializeKeyword(value, stack) << 1), external: specializeKeyword}],
|
|
17
|
+
tokenPrec: 204
|
|
18
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
|
2
|
+
export const
|
|
3
|
+
ChartType = 1,
|
|
4
|
+
TagKeyword = 2,
|
|
5
|
+
DirectiveKeyword = 3,
|
|
6
|
+
ControlKeyword = 4,
|
|
7
|
+
ModifierKeyword = 5,
|
|
8
|
+
Document = 6,
|
|
9
|
+
Comment = 7,
|
|
10
|
+
ContentLine = 8,
|
|
11
|
+
SyncArrow = 9,
|
|
12
|
+
AsyncArrow = 10,
|
|
13
|
+
Duration = 11,
|
|
14
|
+
DateLiteral = 12,
|
|
15
|
+
Percentage = 13,
|
|
16
|
+
Number = 14,
|
|
17
|
+
SectionMarker = 15,
|
|
18
|
+
Url = 16,
|
|
19
|
+
OpenBracket = 17,
|
|
20
|
+
CloseBracket = 18,
|
|
21
|
+
OpenParen = 19,
|
|
22
|
+
CloseParen = 20,
|
|
23
|
+
OpenAngle = 21,
|
|
24
|
+
CloseAngle = 22,
|
|
25
|
+
ColorAnnotation = 23,
|
|
26
|
+
Pipe = 24,
|
|
27
|
+
Colon = 25,
|
|
28
|
+
Comma = 26,
|
|
29
|
+
Plus = 27,
|
|
30
|
+
Dash = 28,
|
|
31
|
+
Tilde = 29,
|
|
32
|
+
Star = 30,
|
|
33
|
+
Question = 31,
|
|
34
|
+
Identifier = 32,
|
|
35
|
+
Punct = 33
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { NodePropSource } from '@lezer/common';
|
|
2
|
+
import { styleTags, tags as t } from '@lezer/highlight';
|
|
3
|
+
|
|
4
|
+
/** Maps grammar node names to semantic highlight tags. */
|
|
5
|
+
export const dgmoHighlighting: NodePropSource = styleTags({
|
|
6
|
+
Comment: t.lineComment,
|
|
7
|
+
ChartType: t.typeName,
|
|
8
|
+
TagKeyword: t.definitionKeyword,
|
|
9
|
+
DirectiveKeyword: t.keyword,
|
|
10
|
+
ControlKeyword: t.controlKeyword,
|
|
11
|
+
ModifierKeyword: t.modifier,
|
|
12
|
+
SyncArrow: t.operator,
|
|
13
|
+
AsyncArrow: t.operator,
|
|
14
|
+
Duration: t.number,
|
|
15
|
+
DateLiteral: t.number,
|
|
16
|
+
Number: t.number,
|
|
17
|
+
Percentage: t.number,
|
|
18
|
+
SectionMarker: t.heading,
|
|
19
|
+
OpenBracket: t.squareBracket,
|
|
20
|
+
CloseBracket: t.squareBracket,
|
|
21
|
+
OpenParen: t.paren,
|
|
22
|
+
CloseParen: t.paren,
|
|
23
|
+
OpenAngle: t.angleBracket,
|
|
24
|
+
CloseAngle: t.angleBracket,
|
|
25
|
+
Url: t.url,
|
|
26
|
+
ColorAnnotation: t.atom,
|
|
27
|
+
Pipe: t.separator,
|
|
28
|
+
Colon: t.separator,
|
|
29
|
+
Plus: t.separator,
|
|
30
|
+
Comma: t.punctuation,
|
|
31
|
+
Dash: t.operator,
|
|
32
|
+
Tilde: t.operator,
|
|
33
|
+
Star: t.operator,
|
|
34
|
+
Question: t.operator,
|
|
35
|
+
Punct: t.punctuation,
|
|
36
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LRLanguage, LanguageSupport } from '@codemirror/language';
|
|
2
|
+
import type { Extension } from '@codemirror/state';
|
|
3
|
+
import { parser } from './dgmo.grammar.js';
|
|
4
|
+
import { dgmoHighlighting } from './highlight';
|
|
5
|
+
|
|
6
|
+
export { CHART_TYPES, METADATA_KEYS } from './keywords';
|
|
7
|
+
export { dgmoHighlighting } from './highlight';
|
|
8
|
+
|
|
9
|
+
/** The raw Lezer parser for DGMO. */
|
|
10
|
+
export const dgmoParser = parser.configure({
|
|
11
|
+
props: [dgmoHighlighting],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/** LRLanguage wrapper for CodeMirror. */
|
|
15
|
+
export const dgmoLanguage = LRLanguage.define({
|
|
16
|
+
name: 'dgmo',
|
|
17
|
+
parser: dgmoParser,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/** Full language support (language + extensions). */
|
|
21
|
+
export const dgmoLanguageSupport = new LanguageSupport(dgmoLanguage);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Drop-in replacement for the old dgmoExtension.
|
|
25
|
+
* Consumers should add indentationMarkers() separately if desired
|
|
26
|
+
* (from @replit/codemirror-indentation-markers).
|
|
27
|
+
*/
|
|
28
|
+
export const dgmoExtension: Extension = dgmoLanguageSupport;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/** All supported DGMO chart types. */
|
|
2
|
+
export const CHART_TYPES = new Set([
|
|
3
|
+
// Diagram types
|
|
4
|
+
'sequence',
|
|
5
|
+
'flowchart',
|
|
6
|
+
'class',
|
|
7
|
+
'er',
|
|
8
|
+
'org',
|
|
9
|
+
'kanban',
|
|
10
|
+
'c4',
|
|
11
|
+
'initiative-status',
|
|
12
|
+
'state',
|
|
13
|
+
'sitemap',
|
|
14
|
+
'infra',
|
|
15
|
+
'gantt',
|
|
16
|
+
// Data chart types
|
|
17
|
+
'bar',
|
|
18
|
+
'line',
|
|
19
|
+
'pie',
|
|
20
|
+
'doughnut',
|
|
21
|
+
'area',
|
|
22
|
+
'polar-area',
|
|
23
|
+
'radar',
|
|
24
|
+
'bar-stacked',
|
|
25
|
+
'multi-line',
|
|
26
|
+
'scatter',
|
|
27
|
+
'sankey',
|
|
28
|
+
'chord',
|
|
29
|
+
'function',
|
|
30
|
+
'heatmap',
|
|
31
|
+
'funnel',
|
|
32
|
+
// Visualization types
|
|
33
|
+
'slope',
|
|
34
|
+
'wordcloud',
|
|
35
|
+
'arc',
|
|
36
|
+
'timeline',
|
|
37
|
+
'venn',
|
|
38
|
+
'quadrant',
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
/** Metadata keys recognized across chart types. */
|
|
42
|
+
export const METADATA_KEYS = new Set([
|
|
43
|
+
'title',
|
|
44
|
+
'series',
|
|
45
|
+
'orientation',
|
|
46
|
+
'x-label',
|
|
47
|
+
'y-label',
|
|
48
|
+
'size-label',
|
|
49
|
+
'x',
|
|
50
|
+
'columns',
|
|
51
|
+
'rows',
|
|
52
|
+
'labels',
|
|
53
|
+
'rotate',
|
|
54
|
+
'max',
|
|
55
|
+
'size',
|
|
56
|
+
'order',
|
|
57
|
+
'sort',
|
|
58
|
+
'scale',
|
|
59
|
+
'values',
|
|
60
|
+
'notation',
|
|
61
|
+
'x-axis',
|
|
62
|
+
'y-axis',
|
|
63
|
+
'top-right',
|
|
64
|
+
'top-left',
|
|
65
|
+
'bottom-right',
|
|
66
|
+
'bottom-left',
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
/** Tag declaration keyword. */
|
|
70
|
+
export const TAG_KEYWORD = 'tag';
|
|
71
|
+
|
|
72
|
+
/** Directive keywords — commands that configure chart behavior. */
|
|
73
|
+
export const DIRECTIVE_KEYWORDS = new Set([
|
|
74
|
+
// Gantt
|
|
75
|
+
'start',
|
|
76
|
+
'era',
|
|
77
|
+
'marker',
|
|
78
|
+
'holiday',
|
|
79
|
+
'workweek',
|
|
80
|
+
'today-marker',
|
|
81
|
+
'critical-path',
|
|
82
|
+
'no-dependencies',
|
|
83
|
+
'sort',
|
|
84
|
+
// Tags
|
|
85
|
+
'tags',
|
|
86
|
+
'import',
|
|
87
|
+
'active-tag',
|
|
88
|
+
'hide',
|
|
89
|
+
// ER
|
|
90
|
+
'notation',
|
|
91
|
+
// Class
|
|
92
|
+
'extends',
|
|
93
|
+
'implements',
|
|
94
|
+
'abstract',
|
|
95
|
+
'interface',
|
|
96
|
+
'enum',
|
|
97
|
+
// C4
|
|
98
|
+
'containers',
|
|
99
|
+
'components',
|
|
100
|
+
'deployment',
|
|
101
|
+
// Infra directives
|
|
102
|
+
'sub-node-label',
|
|
103
|
+
'show-sub-node-count',
|
|
104
|
+
'no-auto-color',
|
|
105
|
+
// Infra node properties
|
|
106
|
+
'description',
|
|
107
|
+
'instances',
|
|
108
|
+
'max-rps',
|
|
109
|
+
'latency-ms',
|
|
110
|
+
'uptime',
|
|
111
|
+
'firewall-block',
|
|
112
|
+
'ratelimit-rps',
|
|
113
|
+
'cb-error-threshold',
|
|
114
|
+
'cb-latency-threshold-ms',
|
|
115
|
+
'buffer',
|
|
116
|
+
'drain-rate',
|
|
117
|
+
'retention-hours',
|
|
118
|
+
'partitions',
|
|
119
|
+
'split',
|
|
120
|
+
'slo-p90-latency-ms',
|
|
121
|
+
'slo-availability',
|
|
122
|
+
'cache-hit',
|
|
123
|
+
'concurrency',
|
|
124
|
+
'duration-ms',
|
|
125
|
+
'cold-start-ms',
|
|
126
|
+
'rps',
|
|
127
|
+
// Sequence
|
|
128
|
+
'activations',
|
|
129
|
+
'no-activations',
|
|
130
|
+
'collapse-notes',
|
|
131
|
+
'no-collapse-notes',
|
|
132
|
+
// Data charts
|
|
133
|
+
'stacked',
|
|
134
|
+
'no-label-name',
|
|
135
|
+
'no-label-value',
|
|
136
|
+
'no-label-percent',
|
|
137
|
+
// Quadrant
|
|
138
|
+
'x-axis',
|
|
139
|
+
'y-axis',
|
|
140
|
+
'top-right',
|
|
141
|
+
'top-left',
|
|
142
|
+
'bottom-right',
|
|
143
|
+
'bottom-left',
|
|
144
|
+
// Layout
|
|
145
|
+
'direction-tb',
|
|
146
|
+
'direction-lr',
|
|
147
|
+
// Initiative-status
|
|
148
|
+
'contains',
|
|
149
|
+
// Data chart metadata
|
|
150
|
+
'title',
|
|
151
|
+
'series',
|
|
152
|
+
'orientation',
|
|
153
|
+
'x-label',
|
|
154
|
+
'y-label',
|
|
155
|
+
'size-label',
|
|
156
|
+
'columns',
|
|
157
|
+
'rows',
|
|
158
|
+
'labels',
|
|
159
|
+
'rotate',
|
|
160
|
+
'scale',
|
|
161
|
+
'values',
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
/** Control flow keywords — structural blocks. */
|
|
165
|
+
export const CONTROL_KEYWORDS = new Set([
|
|
166
|
+
'if',
|
|
167
|
+
'else',
|
|
168
|
+
'loop',
|
|
169
|
+
'parallel',
|
|
170
|
+
'note',
|
|
171
|
+
]);
|
|
172
|
+
|
|
173
|
+
/** Status keywords — initiative-status, kanban. */
|
|
174
|
+
export const STATUS_KEYWORDS = new Set([
|
|
175
|
+
'na',
|
|
176
|
+
'todo',
|
|
177
|
+
'wip',
|
|
178
|
+
'done',
|
|
179
|
+
'blocked',
|
|
180
|
+
'in-progress',
|
|
181
|
+
'backlog',
|
|
182
|
+
'ready',
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
/** Modifier keywords — adjust declarations. */
|
|
186
|
+
export const MODIFIER_KEYWORDS = new Set([
|
|
187
|
+
'alias',
|
|
188
|
+
'aka',
|
|
189
|
+
'position',
|
|
190
|
+
'default',
|
|
191
|
+
// Sequence participant types
|
|
192
|
+
'actor',
|
|
193
|
+
'service',
|
|
194
|
+
'database',
|
|
195
|
+
'queue',
|
|
196
|
+
'cache',
|
|
197
|
+
'gateway',
|
|
198
|
+
'external',
|
|
199
|
+
'networking',
|
|
200
|
+
'frontend',
|
|
201
|
+
// C4 element types
|
|
202
|
+
'system',
|
|
203
|
+
'person',
|
|
204
|
+
'container',
|
|
205
|
+
'component',
|
|
206
|
+
// ER column modifiers
|
|
207
|
+
'pk',
|
|
208
|
+
'fk',
|
|
209
|
+
'nullable',
|
|
210
|
+
'unique',
|
|
211
|
+
// ER data types
|
|
212
|
+
'int',
|
|
213
|
+
'varchar',
|
|
214
|
+
'text',
|
|
215
|
+
'boolean',
|
|
216
|
+
'date',
|
|
217
|
+
'timestamp',
|
|
218
|
+
'float',
|
|
219
|
+
'decimal',
|
|
220
|
+
]);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChartType,
|
|
3
|
+
TagKeyword,
|
|
4
|
+
DirectiveKeyword,
|
|
5
|
+
ControlKeyword,
|
|
6
|
+
ModifierKeyword,
|
|
7
|
+
} from './dgmo.grammar.terms.js';
|
|
8
|
+
import {
|
|
9
|
+
CHART_TYPES,
|
|
10
|
+
TAG_KEYWORD,
|
|
11
|
+
DIRECTIVE_KEYWORDS,
|
|
12
|
+
CONTROL_KEYWORDS,
|
|
13
|
+
STATUS_KEYWORDS,
|
|
14
|
+
MODIFIER_KEYWORDS,
|
|
15
|
+
} from './keywords';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Keyword specializer for the Lezer grammar.
|
|
19
|
+
* Called on every Identifier token — returns a specialized term ID
|
|
20
|
+
* or -1 to keep it as a plain Identifier.
|
|
21
|
+
*/
|
|
22
|
+
export function specializeKeyword(value: string): number {
|
|
23
|
+
if (CHART_TYPES.has(value)) return ChartType;
|
|
24
|
+
if (value === TAG_KEYWORD) return TagKeyword;
|
|
25
|
+
if (DIRECTIVE_KEYWORDS.has(value)) return DirectiveKeyword;
|
|
26
|
+
if (CONTROL_KEYWORDS.has(value)) return ControlKeyword;
|
|
27
|
+
if (STATUS_KEYWORDS.has(value)) return ModifierKeyword;
|
|
28
|
+
if (MODIFIER_KEYWORDS.has(value)) return ModifierKeyword;
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
package/src/er/parser.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { resolveColor } from '../colors';
|
|
2
2
|
import type { PaletteColors } from '../palettes';
|
|
3
3
|
import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
measureIndent,
|
|
6
|
+
extractColor,
|
|
7
|
+
parsePipeMetadata,
|
|
8
|
+
parseFirstLine,
|
|
9
|
+
OPTION_NOCOLON_RE,
|
|
10
|
+
} from '../utils/parsing';
|
|
5
11
|
import { matchTagBlockHeading, validateTagValues } from '../utils/tag-groups';
|
|
6
12
|
import type { TagGroup } from '../utils/tag-groups';
|
|
7
13
|
import type {
|
|
@@ -82,7 +88,7 @@ const KEYWORD_TO_SYMBOL: Record<string, string> = {
|
|
|
82
88
|
function parseRelationship(
|
|
83
89
|
trimmed: string,
|
|
84
90
|
lineNumber: number,
|
|
85
|
-
pushError: (line: number, message: string) => void
|
|
91
|
+
pushError: (line: number, message: string) => void
|
|
86
92
|
): {
|
|
87
93
|
source: string;
|
|
88
94
|
target: string;
|
|
@@ -113,7 +119,7 @@ function parseRelationship(
|
|
|
113
119
|
const toSym = KEYWORD_TO_SYMBOL[kw[3].toLowerCase()] ?? kw[3];
|
|
114
120
|
pushError(
|
|
115
121
|
lineNumber,
|
|
116
|
-
`Use symbolic cardinality (1--*, ?--1, *--*) instead of "${kw[2]}-to-${kw[3]}". Example: ${kw[1]} ${fromSym}--${toSym} ${kw[4]}
|
|
122
|
+
`Use symbolic cardinality (1--*, ?--1, *--*) instead of "${kw[2]}-to-${kw[3]}". Example: ${kw[1]} ${fromSym}--${toSym} ${kw[4]}`
|
|
117
123
|
);
|
|
118
124
|
return null;
|
|
119
125
|
}
|
|
@@ -176,7 +182,8 @@ export function parseERDiagram(
|
|
|
176
182
|
error: null,
|
|
177
183
|
};
|
|
178
184
|
|
|
179
|
-
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
186
|
+
const _fail = (line: number, message: string): ParsedERDiagram => {
|
|
180
187
|
const diag = makeDgmoError(line, message);
|
|
181
188
|
result.diagnostics.push(diag);
|
|
182
189
|
result.error = formatDgmoError(diag);
|
|
@@ -254,7 +261,10 @@ export function parseERDiagram(
|
|
|
254
261
|
lineNumber,
|
|
255
262
|
};
|
|
256
263
|
if (tagBlockMatch.alias) {
|
|
257
|
-
aliasMap.set(
|
|
264
|
+
aliasMap.set(
|
|
265
|
+
tagBlockMatch.alias.toLowerCase(),
|
|
266
|
+
tagBlockMatch.name.toLowerCase()
|
|
267
|
+
);
|
|
258
268
|
}
|
|
259
269
|
result.tagGroups.push(currentTagGroup);
|
|
260
270
|
continue;
|
|
@@ -265,8 +275,13 @@ export function parseERDiagram(
|
|
|
265
275
|
if (currentTagGroup && !contentStarted && indent > 0) {
|
|
266
276
|
const { label, color } = extractColor(trimmed, palette);
|
|
267
277
|
if (!color) {
|
|
268
|
-
result.diagnostics.push(
|
|
269
|
-
|
|
278
|
+
result.diagnostics.push(
|
|
279
|
+
makeDgmoError(
|
|
280
|
+
lineNumber,
|
|
281
|
+
`Expected 'Value(color)' in tag group '${currentTagGroup.name}'`,
|
|
282
|
+
'warning'
|
|
283
|
+
)
|
|
284
|
+
);
|
|
270
285
|
continue;
|
|
271
286
|
}
|
|
272
287
|
// First entry becomes the default
|
|
@@ -339,8 +354,8 @@ export function parseERDiagram(
|
|
|
339
354
|
makeDgmoError(
|
|
340
355
|
lineNumber,
|
|
341
356
|
`Relationship "${rel.source} → ${rel.target}" must be indented under the source table "${rel.source}"`,
|
|
342
|
-
'warning'
|
|
343
|
-
)
|
|
357
|
+
'warning'
|
|
358
|
+
)
|
|
344
359
|
);
|
|
345
360
|
continue;
|
|
346
361
|
}
|
|
@@ -367,11 +382,19 @@ export function parseERDiagram(
|
|
|
367
382
|
currentTable = table;
|
|
368
383
|
continue;
|
|
369
384
|
}
|
|
385
|
+
|
|
386
|
+
// Catch-all: nothing matched this line
|
|
387
|
+
result.diagnostics.push(
|
|
388
|
+
makeDgmoError(lineNumber, `Unexpected line: '${trimmed}'.`, 'warning')
|
|
389
|
+
);
|
|
370
390
|
}
|
|
371
391
|
|
|
372
392
|
// Validation
|
|
373
393
|
if (result.tables.length === 0 && !result.error) {
|
|
374
|
-
const diag = makeDgmoError(
|
|
394
|
+
const diag = makeDgmoError(
|
|
395
|
+
1,
|
|
396
|
+
'No tables found. Add table declarations like "users" or "orders (blue)".'
|
|
397
|
+
);
|
|
375
398
|
result.diagnostics.push(diag);
|
|
376
399
|
result.error = formatDgmoError(diag);
|
|
377
400
|
}
|
|
@@ -385,8 +408,9 @@ export function parseERDiagram(
|
|
|
385
408
|
validateTagValues(
|
|
386
409
|
tagEntities,
|
|
387
410
|
result.tagGroups,
|
|
388
|
-
(line, msg) =>
|
|
389
|
-
|
|
411
|
+
(line, msg) =>
|
|
412
|
+
result.diagnostics.push(makeDgmoError(line, msg, 'warning')),
|
|
413
|
+
suggest
|
|
390
414
|
);
|
|
391
415
|
|
|
392
416
|
// Inject defaults for tables without explicit tags
|
|
@@ -402,7 +426,11 @@ export function parseERDiagram(
|
|
|
402
426
|
}
|
|
403
427
|
|
|
404
428
|
// Warn about isolated tables (not in any relationship)
|
|
405
|
-
if (
|
|
429
|
+
if (
|
|
430
|
+
result.tables.length >= 2 &&
|
|
431
|
+
result.relationships.length >= 1 &&
|
|
432
|
+
!result.error
|
|
433
|
+
) {
|
|
406
434
|
const connectedIds = new Set<string>();
|
|
407
435
|
for (const rel of result.relationships) {
|
|
408
436
|
connectedIds.add(rel.source);
|
|
@@ -410,7 +438,13 @@ export function parseERDiagram(
|
|
|
410
438
|
}
|
|
411
439
|
for (const table of result.tables) {
|
|
412
440
|
if (!connectedIds.has(table.id)) {
|
|
413
|
-
result.diagnostics.push(
|
|
441
|
+
result.diagnostics.push(
|
|
442
|
+
makeDgmoError(
|
|
443
|
+
table.lineNumber,
|
|
444
|
+
`Table "${table.name}" is not connected to any other table`,
|
|
445
|
+
'warning'
|
|
446
|
+
)
|
|
447
|
+
);
|
|
414
448
|
}
|
|
415
449
|
}
|
|
416
450
|
}
|