@dxos/diagram 0.11.1 → 0.14.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.
- package/dist/lib/chunk-parse.mjs +9406 -0
- package/dist/lib/chunk-parse.mjs.map +1 -0
- package/dist/lib/extension.mjs +204 -0
- package/dist/lib/extension.mjs.map +1 -0
- package/dist/lib/index.mjs +497 -2846
- package/dist/lib/index.mjs.map +1 -1
- package/dist/types/src/aesthetics.d.ts +12 -0
- package/dist/types/src/aesthetics.d.ts.map +1 -0
- package/dist/types/src/aesthetics.test.d.ts +2 -0
- package/dist/types/src/aesthetics.test.d.ts.map +1 -0
- package/dist/types/src/appeal.d.ts +55 -0
- package/dist/types/src/appeal.d.ts.map +1 -0
- package/dist/types/src/appeal.test.d.ts +2 -0
- package/dist/types/src/appeal.test.d.ts.map +1 -0
- package/dist/types/src/architecture.d.ts +86 -0
- package/dist/types/src/architecture.d.ts.map +1 -0
- package/dist/types/src/architecture.test.d.ts +2 -0
- package/dist/types/src/architecture.test.d.ts.map +1 -0
- package/dist/types/src/compact.d.ts +39 -0
- package/dist/types/src/compact.d.ts.map +1 -0
- package/dist/types/src/compact.test.d.ts +2 -0
- package/dist/types/src/compact.test.d.ts.map +1 -0
- package/dist/types/src/diagnostics.d.ts +70 -3
- package/dist/types/src/diagnostics.d.ts.map +1 -1
- package/dist/types/src/dsl/cli.d.ts +2 -0
- package/dist/types/src/dsl/cli.d.ts.map +1 -0
- package/dist/types/src/dsl/compile.d.ts +12 -0
- package/dist/types/src/dsl/compile.d.ts.map +1 -0
- package/dist/types/src/dsl/convert.d.ts +45 -0
- package/dist/types/src/dsl/convert.d.ts.map +1 -0
- package/dist/types/src/dsl/convert.test.d.ts +2 -0
- package/dist/types/src/dsl/convert.test.d.ts.map +1 -0
- package/dist/types/src/dsl/dsl.test.d.ts +2 -0
- package/dist/types/src/dsl/dsl.test.d.ts.map +1 -0
- package/dist/types/src/dsl/gen/diagram.d.ts +3 -0
- package/dist/types/src/dsl/gen/diagram.d.ts.map +1 -0
- package/dist/types/src/dsl/index.d.ts +7 -0
- package/dist/types/src/dsl/index.d.ts.map +1 -0
- package/dist/types/src/dsl/parse.d.ts +49 -0
- package/dist/types/src/dsl/parse.d.ts.map +1 -0
- package/dist/types/src/dsl/print.d.ts +19 -0
- package/dist/types/src/dsl/print.d.ts.map +1 -0
- package/dist/types/src/dsl/semantic.test.d.ts +2 -0
- package/dist/types/src/dsl/semantic.test.d.ts.map +1 -0
- package/dist/types/src/dsl/vocabulary.d.ts +61 -0
- package/dist/types/src/dsl/vocabulary.d.ts.map +1 -0
- package/dist/types/src/dx-svg.d.ts +12 -0
- package/dist/types/src/dx-svg.d.ts.map +1 -0
- package/dist/types/src/dx-svg.test.d.ts +2 -0
- package/dist/types/src/dx-svg.test.d.ts.map +1 -0
- package/dist/types/src/extension/complete.d.ts +3 -0
- package/dist/types/src/extension/complete.d.ts.map +1 -0
- package/dist/types/src/extension/extension.test.d.ts +2 -0
- package/dist/types/src/extension/extension.test.d.ts.map +1 -0
- package/dist/types/src/extension/highlight.d.ts +14 -0
- package/dist/types/src/extension/highlight.d.ts.map +1 -0
- package/dist/types/src/extension/index.d.ts +6 -0
- package/dist/types/src/extension/index.d.ts.map +1 -0
- package/dist/types/src/extension/language.d.ts +13 -0
- package/dist/types/src/extension/language.d.ts.map +1 -0
- package/dist/types/src/extension/lint.d.ts +21 -0
- package/dist/types/src/extension/lint.d.ts.map +1 -0
- package/dist/types/src/extension/syntax.d.ts +3 -0
- package/dist/types/src/extension/syntax.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +14 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/mermaid-engine.d.ts +40 -1
- package/dist/types/src/mermaid-engine.d.ts.map +1 -1
- package/dist/types/src/mermaid.d.ts +3 -3
- package/dist/types/src/mermaid.d.ts.map +1 -1
- package/dist/types/src/nudge.d.ts +30 -0
- package/dist/types/src/nudge.d.ts.map +1 -0
- package/dist/types/src/nudge.test.d.ts +2 -0
- package/dist/types/src/nudge.test.d.ts.map +1 -0
- package/dist/types/src/objective.d.ts +4 -0
- package/dist/types/src/objective.d.ts.map +1 -1
- package/dist/types/src/ortho-router.d.ts +13 -1
- package/dist/types/src/ortho-router.d.ts.map +1 -1
- package/dist/types/src/ports.d.ts +40 -0
- package/dist/types/src/ports.d.ts.map +1 -0
- package/dist/types/src/ports.test.d.ts +2 -0
- package/dist/types/src/ports.test.d.ts.map +1 -0
- package/dist/types/src/relations.test.d.ts +2 -0
- package/dist/types/src/relations.test.d.ts.map +1 -0
- package/dist/types/src/rules.d.ts +30 -0
- package/dist/types/src/rules.d.ts.map +1 -0
- package/dist/types/src/scene.d.ts +108 -74
- package/dist/types/src/scene.d.ts.map +1 -1
- package/dist/types/src/score.d.ts +54 -0
- package/dist/types/src/score.d.ts.map +1 -0
- package/dist/types/src/score.test.d.ts +2 -0
- package/dist/types/src/score.test.d.ts.map +1 -0
- package/dist/types/src/semantic-engine.d.ts +41 -0
- package/dist/types/src/semantic-engine.d.ts.map +1 -0
- package/dist/types/src/semantic-engine.test.d.ts +2 -0
- package/dist/types/src/semantic-engine.test.d.ts.map +1 -0
- package/dist/types/src/semantic-place.d.ts +81 -0
- package/dist/types/src/semantic-place.d.ts.map +1 -0
- package/dist/types/src/semantic-route.d.ts +133 -0
- package/dist/types/src/semantic-route.d.ts.map +1 -0
- package/dist/types/src/semantic.d.ts +164 -0
- package/dist/types/src/semantic.d.ts.map +1 -0
- package/dist/types/src/uml-grid.d.ts.map +1 -1
- package/dist/types/src/uml.d.ts +3 -5
- package/dist/types/src/uml.d.ts.map +1 -1
- package/dist/types/src/view.d.ts +53 -0
- package/dist/types/src/view.d.ts.map +1 -0
- package/dist/types/src/view.test.d.ts +2 -0
- package/dist/types/src/view.test.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -5
- package/rules/DIAGRAM.mdl +388 -0
- package/src/aesthetics.test.ts +89 -0
- package/src/aesthetics.ts +148 -0
- package/src/appeal.test.ts +144 -0
- package/src/appeal.ts +586 -0
- package/src/architecture.test.ts +94 -0
- package/src/architecture.ts +215 -0
- package/src/compact.test.ts +67 -0
- package/src/compact.ts +219 -0
- package/src/diagnostics.test.ts +207 -1
- package/src/diagnostics.ts +481 -37
- package/src/dsl/cli.ts +46 -0
- package/src/dsl/compile.ts +28 -0
- package/src/dsl/convert.test.ts +51 -0
- package/src/dsl/convert.ts +98 -0
- package/src/dsl/diagram.grammar +195 -0
- package/src/dsl/dsl.test.ts +286 -0
- package/src/dsl/gen/diagram.ts +22 -0
- package/src/dsl/index.ts +44 -0
- package/src/dsl/parse.ts +1054 -0
- package/src/dsl/print.ts +198 -0
- package/src/dsl/semantic.test.ts +216 -0
- package/src/dsl/vocabulary.ts +150 -0
- package/src/dx-svg.test.ts +44 -0
- package/src/dx-svg.ts +77 -0
- package/src/extension/complete.ts +105 -0
- package/src/extension/extension.test.ts +135 -0
- package/src/extension/highlight.ts +23 -0
- package/src/extension/index.ts +9 -0
- package/src/extension/language.ts +31 -0
- package/src/extension/lint.ts +60 -0
- package/src/extension/syntax.ts +62 -0
- package/src/index.ts +14 -0
- package/src/mermaid-engine.test.ts +6 -6
- package/src/mermaid-engine.ts +569 -119
- package/src/mermaid.test.ts +17 -1
- package/src/mermaid.ts +30 -18
- package/src/nudge.test.ts +186 -0
- package/src/nudge.ts +387 -0
- package/src/objective.test.ts +2 -0
- package/src/objective.ts +17 -1
- package/src/ortho-router.ts +240 -80
- package/src/ports.test.ts +157 -0
- package/src/ports.ts +186 -0
- package/src/relations.test.ts +98 -0
- package/src/rules.ts +117 -0
- package/src/scene.ts +66 -5
- package/src/score.test.ts +64 -0
- package/src/score.ts +130 -0
- package/src/semantic-engine.test.ts +635 -0
- package/src/semantic-engine.ts +891 -0
- package/src/semantic-place.ts +1508 -0
- package/src/semantic-route.ts +1136 -0
- package/src/semantic.ts +278 -0
- package/src/typings.d.ts +8 -0
- package/src/uml-grid.ts +6 -1
- package/src/uml.test.ts +5 -1
- package/src/uml.ts +24 -11
- package/src/view.test.ts +139 -0
- package/src/view.ts +376 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import * as MermaidEngine from '../mermaid-engine.ts';
|
|
8
|
+
import type * as Scene from '../scene.ts';
|
|
9
|
+
import { BASIC } from '../testing.ts';
|
|
10
|
+
import { parse, parseScene, toScene } from './parse.ts';
|
|
11
|
+
import { print, printCommands } from './print.ts';
|
|
12
|
+
|
|
13
|
+
/** Every element kind, every attribute family, in canonical form. */
|
|
14
|
+
const KITCHEN_SINK = `object pkgA @ -24,-24 scale=2 index="a1" ref="dxn:echo:@:01ABC" {
|
|
15
|
+
rect frame 0,0 248x172 "Package A" rotation=45 corners=top color=grey stroke=dashed
|
|
16
|
+
ellipse blob 4,4 20x10 fill=pattern
|
|
17
|
+
diamond gate 0,0 30x30
|
|
18
|
+
triangle warn 0,0 30x30 weight=xl
|
|
19
|
+
circle dot 10,10 4 "o" color=red
|
|
20
|
+
line path 0,0 10,10 20,0 closed=true stroke=dotted
|
|
21
|
+
curve wave 0,0 10,10 20,0
|
|
22
|
+
arc smile 50,50 20 0..180
|
|
23
|
+
text note 4,4 "A label" w=120 weight=s
|
|
24
|
+
arrow bound A/box -> B/box#left "extends" head=triangle tail=circle
|
|
25
|
+
arrow free 10,20 -> 30,40
|
|
26
|
+
arrow half A/box -> _
|
|
27
|
+
portal inner 0,0 240x160 "Inner" ref="dxn:echo:@:01XYZ"
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const COMMANDS = `object A @ 0,0 {
|
|
32
|
+
rect box 0,0 100x50 "A"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
elements A {
|
|
36
|
+
rect extra 0,0 5x5
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
move A @ 10,20
|
|
40
|
+
|
|
41
|
+
remove elements A extra
|
|
42
|
+
|
|
43
|
+
remove object A
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
/** Ids the grammar reserves or cannot lex bare; the printer has to quote them back. */
|
|
47
|
+
const AWKWARD_IDS = `object "1st" @ 0,0 {
|
|
48
|
+
rect "rect" 0,0 10x10 "quote \\" and \\\\ and \\n"
|
|
49
|
+
rect "has space" 0,0 10x10
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const NEGATIVES = `object neg @ -1.5,-2 scale=0.25 {
|
|
54
|
+
rect box -10,-20 -30x-40
|
|
55
|
+
arc back 0,0 5 -90..270
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const roundTrip = (source: string) => printCommands(parse(source).commands);
|
|
60
|
+
|
|
61
|
+
describe('dsl round trip', () => {
|
|
62
|
+
for (const [name, source] of Object.entries({ KITCHEN_SINK, COMMANDS, AWKWARD_IDS, NEGATIVES })) {
|
|
63
|
+
test(`print(parse(x)) === x — ${name}`, ({ expect }) => {
|
|
64
|
+
expect(parse(source).problems).toEqual([]);
|
|
65
|
+
expect(roundTrip(source)).toEqual(source);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
test('an empty document is empty', ({ expect }) => {
|
|
70
|
+
expect(roundTrip('')).toEqual('');
|
|
71
|
+
expect(roundTrip('# just a comment\n')).toEqual('');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('comments parse and are dropped, as documented', ({ expect }) => {
|
|
75
|
+
const { commands, problems } = parse(`
|
|
76
|
+
# leading
|
|
77
|
+
object A @ 0,0 { # trailing
|
|
78
|
+
rect box 0,0 10x10
|
|
79
|
+
}
|
|
80
|
+
`);
|
|
81
|
+
expect(problems).toEqual([]);
|
|
82
|
+
expect(print(toScene(commands))).toEqual('object A @ 0,0 {\n rect box 0,0 10x10\n}\n');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('whitespace is insignificant', ({ expect }) => {
|
|
86
|
+
const dense = 'object A @ 0,0 {rect box 0,0 10x10 "hi" color=red}';
|
|
87
|
+
const loose = 'object A\n @ 0 , 0\n{\n rect\n box\n 0,0\n 10x10\n "hi"\n color=red\n}\n';
|
|
88
|
+
expect(roundTrip(dense)).toEqual(roundTrip(loose));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('dsl scene mapping', () => {
|
|
93
|
+
test('bound arrow ends survive, with ports', ({ expect }) => {
|
|
94
|
+
const { scene } = parseScene('object e @ 0,0 {\n arrow a A/box#left -> B/box\n}\n');
|
|
95
|
+
const [arrow] = scene.objects[0].elements;
|
|
96
|
+
expect(arrow).toEqual({ kind: 'arrow', id: 'a', from: 'A/box#left', to: 'B/box' });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('an unbound end is absent, not a point', ({ expect }) => {
|
|
100
|
+
const { scene } = parseScene('object e @ 0,0 {\n arrow a _ -> 1,2\n}\n');
|
|
101
|
+
expect(scene.objects[0].elements[0]).toEqual({ kind: 'arrow', id: 'a', end: { x: 1, y: 2 } });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('a portal carries its target', ({ expect }) => {
|
|
105
|
+
const { scene } = parseScene('object p @ 0,0 {\n portal win 0,0 10x10 "T" ref="dxn:echo:@:01"\n}\n');
|
|
106
|
+
expect(scene.objects[0].elements[0]).toEqual({
|
|
107
|
+
kind: 'portal',
|
|
108
|
+
id: 'win',
|
|
109
|
+
x: 0,
|
|
110
|
+
y: 0,
|
|
111
|
+
w: 10,
|
|
112
|
+
h: 10,
|
|
113
|
+
ref: 'dxn:echo:@:01',
|
|
114
|
+
text: 'T',
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('omitting @ leaves the object where it is', ({ expect }) => {
|
|
119
|
+
const { scene } = parseScene('object A {\n rect box 0,0 10x10\n}\n');
|
|
120
|
+
expect(scene.objects[0].origin).toBeUndefined();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('commands apply in order', ({ expect }) => {
|
|
124
|
+
const { scene } = parseScene(COMMANDS);
|
|
125
|
+
expect(scene.objects).toEqual([]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('upsert-elements replaces by id and keeps the rest', ({ expect }) => {
|
|
129
|
+
const { scene } = parseScene(
|
|
130
|
+
'object A @ 0,0 {\n rect a 0,0 1x1\n rect b 0,0 1x1\n}\n\nelements A {\n rect b 5,5 2x2\n}\n',
|
|
131
|
+
);
|
|
132
|
+
expect(scene.objects[0].elements.map((element) => element.id)).toEqual(['a', 'b']);
|
|
133
|
+
expect(scene.objects[0].elements[1]).toMatchObject({ x: 5, y: 5, w: 2, h: 2 });
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('dsl diagnostics', () => {
|
|
138
|
+
test('an unknown attribute is reported, not fatal', ({ expect }) => {
|
|
139
|
+
const { commands, problems } = parse('object A @ 0,0 {\n rect box 0,0 10x10 colour=red\n}\n');
|
|
140
|
+
expect(problems).toHaveLength(1);
|
|
141
|
+
expect(problems[0].message).toContain('Unknown attribute "colour"');
|
|
142
|
+
expect(commands).toHaveLength(1);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('a value outside the schema literals is reported', ({ expect }) => {
|
|
146
|
+
const { problems } = parse('object A @ 0,0 {\n rect box 0,0 10x10 color=puce\n}\n');
|
|
147
|
+
expect(problems).toHaveLength(1);
|
|
148
|
+
expect(problems[0].message).toContain('"color" takes one of');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('a portal without a ref is reported', ({ expect }) => {
|
|
152
|
+
const { problems } = parse('object A @ 0,0 {\n portal p 0,0 10x10\n}\n');
|
|
153
|
+
expect(problems.map(({ message }) => message)).toContain(
|
|
154
|
+
'portal "p" needs ref="<dxn>": it is the drawing shown inside the frame.',
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('ranges point at the statement and the element a layout report names', ({ expect }) => {
|
|
159
|
+
const source = 'object A @ 0,0 {\n rect box 0,0 10x10\n}\n';
|
|
160
|
+
const { ranges } = parse(source);
|
|
161
|
+
expect(source.slice(ranges.get('A')!.from, ranges.get('A')!.to)).toEqual(
|
|
162
|
+
'object A @ 0,0 {\n rect box 0,0 10x10\n}',
|
|
163
|
+
);
|
|
164
|
+
expect(source.slice(ranges.get('A/box')!.from, ranges.get('A/box')!.to)).toEqual('rect box 0,0 10x10');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
//
|
|
168
|
+
// Recovered nodes can hold one number where the grammar wants two. Every one of these threw a
|
|
169
|
+
// TypeError out of `parse` before the readers were guarded, which would have broken the promise
|
|
170
|
+
// that `parse` reports rather than throws.
|
|
171
|
+
//
|
|
172
|
+
for (const [name, source] of Object.entries({
|
|
173
|
+
'half a point': 'object A @ 0, {\n rect b 0,0 1x1\n}\n',
|
|
174
|
+
'half an element point': 'object A @ 0,0 {\n rect b 0, 1x1\n}\n',
|
|
175
|
+
'half a range': 'object A @ 0,0 {\n arc a 0,0 5 90..\n}\n',
|
|
176
|
+
'half a move': 'move A @ 1,\n',
|
|
177
|
+
'half a line point': 'object A @ 0,0 {\n line l 0,0 10,\n}\n',
|
|
178
|
+
})) {
|
|
179
|
+
test(`an incomplete ${name} reports instead of throwing`, ({ expect }) => {
|
|
180
|
+
const { problems } = parse(source);
|
|
181
|
+
expect(problems.length).toBeGreaterThan(0);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
test('a syntax error is located', ({ expect }) => {
|
|
186
|
+
const { problems } = parse('object A @ 0,0 {\n rect box 0,0\n}\n');
|
|
187
|
+
expect(problems.length).toBeGreaterThan(0);
|
|
188
|
+
expect(problems[0].to).toBeGreaterThan(problems[0].from);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe('dsl round-trip hazards', () => {
|
|
193
|
+
test('an upsert without @ keeps the position the object already had', ({ expect }) => {
|
|
194
|
+
const { scene } = parseScene('object A @ 10,20 {\n rect b 0,0 1x1\n}\n\nobject A {\n rect b 0,0 2x2\n}\n');
|
|
195
|
+
// `WorldObject.origin` says "omit on upsert to keep the current position".
|
|
196
|
+
expect(scene.objects[0].origin).toEqual({ x: 10, y: 20 });
|
|
197
|
+
expect(scene.objects[0].elements[0]).toMatchObject({ w: 2, h: 2 });
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('a ref whose id cannot lex bare round-trips quoted', ({ expect }) => {
|
|
201
|
+
// Mermaid ids may start with a digit, so `1st/box` is reachable from a real dialect.
|
|
202
|
+
const scene: Scene.Scene = {
|
|
203
|
+
objects: [{ id: 'edges', origin: { x: 0, y: 0 }, elements: [{ kind: 'arrow', id: 'e', from: '1st/box' }] }],
|
|
204
|
+
};
|
|
205
|
+
const text = print(scene);
|
|
206
|
+
expect(text).toContain('"1st/box"');
|
|
207
|
+
expect(parse(text).problems).toEqual([]);
|
|
208
|
+
expect(toScene(parse(text).commands)).toEqual(scene);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('exponent notation survives the round trip', ({ expect }) => {
|
|
212
|
+
// `String(1e-7)` is "1e-7", which the grammar had to learn to read back.
|
|
213
|
+
const scene: Scene.Scene = {
|
|
214
|
+
objects: [
|
|
215
|
+
{ id: 'A', origin: { x: 1e-7, y: 1e21 }, elements: [{ kind: 'rect', id: 'b', x: 0, y: 0, w: 1, h: 1 }] },
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
const text = print(scene);
|
|
219
|
+
expect(parse(text).problems).toEqual([]);
|
|
220
|
+
expect(toScene(parse(text).commands)).toEqual(scene);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
//
|
|
224
|
+
// The exponent support the printer needs also admits `1e309`, which `parseFloat` turns into
|
|
225
|
+
// Infinity — an infinite coordinate poisons layout and cannot be printed back, so `parse` must
|
|
226
|
+
// refuse what `print` refuses.
|
|
227
|
+
//
|
|
228
|
+
for (const [name, source] of Object.entries({
|
|
229
|
+
origin: 'object A @ 1e309,0 {\n rect b 0,0 1x1\n}\n',
|
|
230
|
+
size: 'object A @ 0,0 {\n rect b 0,0 1e309x1\n}\n',
|
|
231
|
+
radius: 'object A @ 0,0 {\n circle c 0,0 1e309\n}\n',
|
|
232
|
+
range: 'object A @ 0,0 {\n arc a 0,0 5 0..1e309\n}\n',
|
|
233
|
+
attribute: 'object A @ 0,0 {\n rect b 0,0 1x1 rotation=1e309\n}\n',
|
|
234
|
+
})) {
|
|
235
|
+
test(`an overflowing ${name} is reported, not silently Infinity`, ({ expect }) => {
|
|
236
|
+
const { commands, problems } = parse(source);
|
|
237
|
+
expect(problems.length).toBeGreaterThan(0);
|
|
238
|
+
// Nothing infinite may reach a command, since `Draw` would apply it and `print` could not
|
|
239
|
+
// write it back.
|
|
240
|
+
expect(JSON.stringify(commands)).not.toContain('null');
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
test('a non-finite coordinate is refused rather than printed unreadably', ({ expect }) => {
|
|
245
|
+
const scene: Scene.Scene = {
|
|
246
|
+
objects: [{ id: 'A', origin: { x: Number.NaN, y: 0 }, elements: [] }],
|
|
247
|
+
};
|
|
248
|
+
expect(() => print(scene)).toThrow(TypeError);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('dsl over the reference fixture', () => {
|
|
253
|
+
test('BASIC survives a mermaid compile, a print, and a reparse', async ({ expect }) => {
|
|
254
|
+
const commands = await MermaidEngine.compile(BASIC.trim());
|
|
255
|
+
const upserts = commands.filter((command) => command.op === 'upsert-object');
|
|
256
|
+
expect(upserts).toHaveLength(commands.length);
|
|
257
|
+
|
|
258
|
+
const text = printCommands(commands);
|
|
259
|
+
const { commands: reparsed, problems } = parse(text);
|
|
260
|
+
expect(problems).toEqual([]);
|
|
261
|
+
|
|
262
|
+
// Text identity: the printed form is canonical, so a second pass changes nothing.
|
|
263
|
+
expect(printCommands(reparsed)).toEqual(text);
|
|
264
|
+
// Scene identity: the model survives the text, not merely its formatting.
|
|
265
|
+
expect(toScene(reparsed)).toEqual(toScene(commands));
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('BASIC prints objects a reviewer can read', async ({ expect }) => {
|
|
269
|
+
const text = printCommands(await MermaidEngine.compile(BASIC.trim()));
|
|
270
|
+
// The frames, the type boxes, and the one `edges` object holding the routes.
|
|
271
|
+
expect(text).toMatch(/^object pkgA @ /m);
|
|
272
|
+
expect(text).toMatch(/^ {2}rect frame 0,0 \d/m);
|
|
273
|
+
expect(text).toMatch(/^object edges @ /m);
|
|
274
|
+
expect(text).toMatch(/ -> /);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
describe('dsl scene printing', () => {
|
|
279
|
+
test('print emits only object statements', ({ expect }) => {
|
|
280
|
+
const scene: Scene.Scene = {
|
|
281
|
+
objects: [{ id: 'A', origin: { x: 1, y: 2 }, elements: [{ kind: 'rect', id: 'box', x: 0, y: 0, w: 3, h: 4 }] }],
|
|
282
|
+
};
|
|
283
|
+
expect(print(scene)).toEqual('object A @ 1,2 {\n rect box 0,0 3x4\n}\n');
|
|
284
|
+
expect(toScene(parse(print(scene)).commands)).toEqual(scene);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
|
2
|
+
import {LRParser} from "@lezer/lr"
|
|
3
|
+
const spec_name = {__proto__:null,object:8, elements:42, move:44, remove:46, rect:48, ellipse:50, diamond:52, triangle:54, circle:56, line:58, curve:60, arc:62, text:64, arrow:66, portal:68, diagram:70, group:72, node:74, edge:76, cell:78, via:80, bus:82, compact:84, _:124}
|
|
4
|
+
export const parser = LRParser.deserialize({
|
|
5
|
+
version: 14,
|
|
6
|
+
states: ":WQYQPOOOOQO'#Eq'#EqOOQO'#E`'#E`QYQPOOOtQPO'#C_OtQPO'#DoOtQPO'#DpO|QPO'#DqO!UQPO'#DsOtQPO'#D{OtQPO'#EROtQPO'#DtOOQO-E8^-E8^OOQO'#Ca'#CaO!yQPO,58yO#UQPO,5:ZO#ZQPO,5:[OtQPO,5:]OtQPO,5:^O#`QPO'#CdOOQO'#Cj'#CjO#eQPO'#CiOOQO'#Ef'#EfO#jQPO,5:_O$_QPO,5:gO%]QPO'#ETO&jQPO'#ESO'tQPO,5:mO(SQPO,5:`OOQO'#Cc'#CcOOQO'#Ea'#EaO!yQPO1G.eO)YQPO'#DZOOQO1G.e1G.eOOQO1G/u1G/uOOQO1G/v1G/vOOQO1G/w1G/wOtQPO1G/xOOQO'#Cg'#CgO)aQPO'#CfOOQO,59O,59OO)fQPO,59TOOQO-E8d-E8dO+]QPO'#CjOOQO'#D_'#D_OOQO'#Dv'#DvOtQPO'#DuO+hQPO'#DuO+mQPO'#D|OOQO'#Ei'#EiO+uQPO1G0RO+uQPO1G0RO,pQPO,5:oOtQPO'#EkO,xQPO,5:nOOQO'#E['#E[OOQO'#EX'#EXOtQPO1G0XOOQO'#Eg'#EgO(VQPO1G/zO.SQPO'#DzOOQO'#Dy'#DyOOQO1G/z1G/zO(VQPO1G/zOOQO-E8_-E8_OOQO7+$P7+$POtQPO'#D]OtQPO'#DaOOQO'#D['#D[OOQO'#Eb'#EbO.bQPO,59uOOQO,59u,59uOOQO'#D^'#D^OtQPO'#D`OOQO'#Db'#DbOtQPO'#DcOtQPO'#DfOtQPO'#DgOtQPO'#DnOOQO'#Ee'#EeO.iQPO7+%dO#`QPO,59QOOQO'#Cm'#CmO/^QPO'#ClOOQO'#Cp'#CpOOQO'#Cl'#ClOOQO1G.o1G.oOOQO,5:a,5:aOOQO'#Dx'#DxOtQPO,5:aOOQO,5:h,5:hO1ZQPO'#EOOOQO-E8g-E8gO1`QPO7+%mOOQO'#EV'#EVO2ZQPO'#EUOOQO1G0Z1G0ZO,sQPO1G0ZOOQO,5;V,5;VOOQO-E8i-E8iO3hQPO7+%sOOQO-E8e-E8eOOQO7+%f7+%fOOQO'#Eh'#EhO4fQPO,5:fOOQO,5:f,5:fO(VQPO7+%fO#`QPO,59wO#`QPO,59{OOQO-E8`-E8`OOQO1G/a1G/aO#`QPO,59zO#`QPO,59}O#`QPO,5:QO4tQPO,5:RO#`QPO,5:YOOQO-E8c-E8cOOQO1G.l1G.lO#`QPO,59YOOQO1G/{1G/{O5SQPO,5:jO,sQPO'#EjO5[QPO,5:pOOQO7+%u7+%uOOQO'#El'#ElO6iQPO<<I_O7dQPO'#E]O7oQPO'#E_O6iQPO<<I_OOQO-E8f-E8fOOQO1G0Q1G0QOOQO<<IQ<<IQO+WQPO1G/cO#`QPO1G/gO#`QPO1G/fO#`QPO1G/iO8mQPO1G/lOOQO'#Dj'#DjOOQO'#Di'#DiO8rQPO'#DhOOQO'#Dk'#DkO8wQPO1G/mO+WQPO1G/tOOQO1G.t1G.tOOQO'#EQ'#EQO9uQPO1G0UOOQO,5;U,5;UOOQO-E8h-E8hOOQO-E8j-E8jO9zQPO'#E^OOQO'#E^'#E^OOQO'#Em'#EmO:PQPO,5:wOtQPO,5:yO;TQPOAN>yO<OQPO7+$}OOQO'#Ed'#EdO<|QPO7+%RO=zQPO7+%QO#`QPO7+%TO>xQPO7+%WO4tQPO,5:SOOQO'#Ec'#EcO?sQPO7+%XO?sQPO7+%XO@nQPO7+%`O5SQPO7+%pO5SQPO,5:xOOQO-E8k-E8kOOQO1G0e1G0eOAlQPO<<HiOAlQPO<<HiOBgQPO<<HmOOQO-E8b-E8bOCbQPO<<HlOCbQPO<<HlOD]QPO'#DdODbQPO<<HoOE]QPO<<HrOOQO1G/n1G/nOOQO-E8a-E8aOFWQPO<<HsOGRQPO<<HzOGRQPO<<HzOG|QPO<<I[OOQO1G0d1G0dOHRQPOAN>TOH|QPOAN>WO#`QPO,5:OOIwQPOAN>ZOJrQPOAN>fOOQOAN>vAN>vOOQO1G/j1G/j",
|
|
7
|
+
stateData: "Ks~O#dOSPOS~OSSOeTOfUOgVOsWOtZOuXOvYO~OU]O#f]O~OSaOebO~OXcO#fdOS!gXe!gXf!gXg!gXs!gXt!gXu!gXv!gX#b!gX~OXcO|pO#fdO~O|pO~OXcO~O#gvO~O_yO~OXcO#fdOS!gae!gaf!gag!gas!gat!gau!gav!ga#b!ga~OU|OX!QO!k}O#f{OS!oae!oaf!oag!oas!oat!oau!oav!oa#b!oa{!oa~Oc!UO[!wX!a!wX!|!wX!}!wX#f!wXS!wXU!wXe!wXf!wXg!wXs!wXt!wXu!wXv!wXx!wXy!wX#b!wX{!wX~O[!VO!a!vX!|!vX!}!vX#f!vXS!vXU!vXe!vXf!vXg!vXs!vXt!vXu!vXv!vXx!vXy!vX#b!vX{!vX~O!a!YO!|!YO!}!YO#f!XO~OU|Oz!_O|!^O!k}O#f{O~Oh!jOi!jOj!jOk!jOl!kOm!lOn!lOo!mOp!nOq!oOr!pO~O{!iO~P(eO[!sO~OS!vOU!wOe!vOf!vOg!vOh!vOi!vOj!vOk!vOl!vOm!vOn!vOo!vOp!vOq!vOr!vOs!vOt!vOu!vOv!vOw!vOx!vOy!vOz!vO#f!vO#gvO#h!tO~OU!lX_^X#f!lX~O#f!zO~Ow!}O#gvO~OX!QO!k}O#f{OS!oie!oif!oig!ois!oit!oiu!oiv!oi#b!oi{!oi~O!k}O#f#QO~O[!VO!a!va!|!va!}!va#f!vaS!vaU!vae!vaf!vag!vas!vat!vau!vav!vax!vay!va#b!va{!va~OtZOuXOvYO{#]O~O{#bO~P(eOU]O#f]OS!fqe!fqf!fqg!fqs!fqt!fqu!fqv!fq#b!fq~Oc#jOS`XX`Xe`Xf`Xg`Xs`Xt`Xu`Xv`X#b`X#f`X|`X!k`Xz`Xx`Xy`X{`Xh`Xi`Xj`Xk`Xl`Xm`Xn`Xo`Xp`Xq`Xr`X~O!s#lO~OX!QO!k}O#f{OS!oqe!oqf!oqg!oqs!oqt!oqu!oqv!oq#b!oq{!oq~O!z#mO[!xX!a!xX!|!xX!}!xX#f!xXS!xXU!xXe!xXf!xXg!xXs!xXt!xXu!xXv!xXx!xXy!xX#b!xX{!xX~OU|Ox#rOy#sO#fdOS!uqe!uqf!uqg!uqs!uqt!uqu!uqv!uq#b!uq{!uq~OtZOuXOvYO{#vO~OU#}O!`$QO#f#}O#gvO~O!`$QO#gvO~O!z#mO[!xa!a!xa!|!xa!}!xa#f!xaS!xaU!xae!xaf!xag!xas!xat!xau!xav!xax!xay!xa#b!xa{!xa~Ox#rOy#sO#fdOS!uye!uyf!uyg!uys!uyt!uyu!uyv!uy#b!uy{!uy~Ow!}O!`$QO#gvO~O_$_OS#RXe#RXf#RXg#RXs#RXt#RXu#RXv#RXx#RXy#RX#b#RX#f#RX{#RX~OU|O~O!a$gO~OU|O#fdOh!Zii!Zij!Zik!Zil!Zim!Zin!Zio!Zip!Ziq!Zir!Zi{!Zi~O[$lO~O[$mO~Ow!}O!`$QO#gvOS#Pae#Paf#Pag#Pas#Pat#Pau#Pav#Pax#Pay#Pa#b#Pa#f#Pa{#Pa~Ox#rOy#sO#fdOS!u!Re!u!Rf!u!Rg!u!Rs!u!Rt!u!Ru!u!Rv!u!R#b!u!R{!u!R~OU|O#fdOh!Pqi!Pqj!Pqk!Pql!Pqm!Pqn!Pqo!Pqp!Pqq!Pqr!Pq{!Pq~O#fdO#gvOh!Tqi!Tqj!Tqk!Tql!Tqm!Tqn!Tqo!Tqp!Tqq!Tqr!Tq{!Tq~OU|O#fdOh!Sqi!Sqj!Sqk!Sql!Sqm!Sqn!Sqo!Sqp!Sqq!Sqr!Sq{!Sq~O#fdOh!Yqi!Yqj!Yqk!Yql!Yqm!Yqn!Yqo!Yqp!Yqq!Yqr!Yq{!Yq~O#fdOh!Zqi!Zqj!Zqk!Zql!Zqm!Zqn!Zqo!Zqp!Zqq!Zqr!Zq{!Zq~OU|O#fdOh!bqi!bqj!bqk!bql!bqm!bqn!bqo!bqp!bqq!bqr!bq{!bq~O#fdOh!Pyi!Pyj!Pyk!Pyl!Pym!Pyn!Pyo!Pyp!Pyq!Pyr!Py{!Py~O#fdOh!Tyi!Tyj!Tyk!Tyl!Tym!Tyn!Tyo!Typ!Tyq!Tyr!Ty{!Ty~O#fdOh!Syi!Syj!Syk!Syl!Sym!Syn!Syo!Syp!Syq!Syr!Sy{!Sy~O!X%SO~O#fdOh!Vyi!Vyj!Vyk!Vyl!Vym!Vyn!Vyo!Vyp!Vyq!Vyr!Vy{!Vy~O#fdOh!Yyi!Yyj!Yyk!Yyl!Yym!Yyn!Yyo!Yyp!Yyq!Yyr!Yy{!Yy~O#fdOh!Zyi!Zyj!Zyk!Zyl!Zym!Zyn!Zyo!Zyp!Zyq!Zyr!Zy{!Zy~O#fdOh!byi!byj!byk!byl!bym!byn!byo!byp!byq!byr!by{!by~O!q%VO~O#fdOh!P!Ri!P!Rj!P!Rk!P!Rl!P!Rm!P!Rn!P!Ro!P!Rp!P!Rq!P!Rr!P!R{!P!R~O#fdOh!S!Ri!S!Rj!S!Rk!S!Rl!S!Rm!S!Rn!S!Ro!S!Rp!S!Rq!S!Rr!S!R{!S!R~O#fdOh!V!Ri!V!Rj!V!Rk!V!Rl!V!Rm!V!Rn!V!Ro!V!Rp!V!Rq!V!Rr!V!R{!V!R~O#fdOh!b!Ri!b!Rj!b!Rk!b!Rl!b!Rm!b!Rn!b!Ro!b!Rp!b!Rq!b!Rr!b!R{!b!R~O#h#g#fP#f~",
|
|
8
|
+
goto: "0g#fPPP#gP#kP$y$}P%Y%zP&v'zP(t(w)QP)QPPPPPPPPPPPPPPPPPPPPPPPP)T)^)b)f)j)b)b*S)b*WP)b)b*Z*^*d*hPP)b#g#g#g#g#g*s*{+XP+f+R+s*s+}P,TP,[*s,i,o,v,|P-TPP-W-Z-a-Z-e-k-q-w.w.}/T/Z/e/k/u/{0R0]PPP0cTPORQ^SQ_TQ`UQhXUiY!V!ZQlZQtaQubS!qu!rQ!y!OQ#_!dQ#`!eQ#c!kQ#d!mQ#e!nQ#f!oQ#g!pQ#k!{R$o$_Tn^oSfWgSm^oRs`QxcQ!|!QQ#x#_Q#y#`Q#z#cQ#{#dQ#|#eS$O#f$gQ$S#gT$b#y$chwc!Q#_#`#c#d#e#f#g#y$c$gQ!uyQ#i!sQ$T#jY$U#l#r$^$l$mQ$d#zQ$e#{Q$v$eR%W%SSfWgSm^oW!Rh!S!T#PW![l!]!a#^W#p#W#q#t$`}$h$R$a$c$d$f$i$j$k$p$q$r$t$u$w$x${$|$}%Q%R%T%U!oeW^ghlo!S!T!]!a#P#W#^#q#t$R$`$a$c$d$f$i$j$k$p$q$r$t$u$w$x${$|$}%Q%R%T%UR!xyQ!wyQ$a#xR$k$SR!wyQq^Qr_R!coT!gp!hT!fp!hT!dp!hQ!ThQ!alQ#t#WQ$f#|Q$j$RQ$q$aQ$u$dR$}$kT!ep!hR$w$eR$R#fQ$P#fR$y$gT$O#f$gS$O#f$gZ$U#l#r$^$l$mSPORT#Z!^#[W!Rh!S!T#PX![l!]!a#^`!Phl!S!T!]!a#P#^R#T!U`!Ohl!S!T!]!a#P#^R!{!PQ!`lS#Y!]!aR#w#^X!Rh!S!T#PQ!|!QT$[#r$^Q$V#lS$Z#r$^Q%O$lR%P$mQkYR#W!ZSjY!ZR#U!VQ#S!UR#o#TS#R!U#TR$W#mR!ZkR!YkX#p#W#q#t$`T$]#r$^QROR[RQo^R!boQ!hpR#a!hQ$i$RQ$p$aQ$r$cQ$t$dQ$x$ff$z$i$p$r$t$x${$|%Q%R%T%UQ${$jQ$|$kQ%Q$qQ%R$uQ%T$wR%U$}Q$c#yR$s$cQ!ruR#h!rQgWRzgQ!]lS#X!]#^R#^!aQ#[!^R#u#[Q!ShS#O!S#PR#P!TQ#n#RR$X#nQ!WjR#V!WQ#q#WS$Y#q$`R$`#tQ$^#rR$n$^TQOR",
|
|
9
|
+
nodeNames: "⚠ Comment Document ObjectDecl object Id String ObjectAttr Origin @ Point Number , Attribute AttrName = AttrValue Size Ratio : Word elements move remove rect ellipse diamond triangle circle line curve arc text arrow portal diagram group node edge cell via bus compact } { Body Element BoxElement BoxKind Label CircleElement PathElement PathKind ArcElement Range .. TextElement ArrowElement Connection Endpoint Ref Unbound _ -> PortalElement ElementsDecl MoveStmt RemoveObjectStmt RemoveElementsStmt DiagramDecl GroupDecl Relation Soft ~ RelationKind Compact GroupBody NodeDecl Pin ) CellRef ( Coord EdgeDecl EndList EdgeEnd SideList Side | EdgeOp <-> -- RelationWord Via Waypoint Bus",
|
|
10
|
+
maxTerm: 116,
|
|
11
|
+
nodeProps: [
|
|
12
|
+
["openedBy", 43,"{"],
|
|
13
|
+
["closedBy", 44,"}"]
|
|
14
|
+
],
|
|
15
|
+
skippedNodes: [0,1],
|
|
16
|
+
repeatNodeCount: 14,
|
|
17
|
+
tokenData: ",g~RgXY!jYZ!j]^!jpq!jrs!{st$ixy%Qyz%V|}%[}!O%a!O!P)T!Q![%r![!])`!^!_)e!_!`)v!b!c){!c!}*Q#R#S*Q#T#o*Q#o#p,R#p#q,W#q#r,]#r#s,b~!oS#d~XY!jYZ!j]^!jpq!j~#OVOr!{rs#es#O!{#O#P#j#P;'S!{;'S;=`$c<%lO!{~#jOU~~#mRO;'S!{;'S;=`#v;=`O!{~#yWOr!{rs#es#O!{#O#P#j#P;'S!{;'S;=`$c;=`<%l!{<%lO!{~$fP;=`<%l!{~$nSP~OY$iZ;'S$i;'S;=`$z<%lO$i~$}P;=`<%l$i~%VO!s~~%[O!q~~%aO[~~%dR}!O%m!Q![%r!`!a)O~%rO!}~~%wT#g~!O!P&W!Q![%r!g!h&o#X#Y&o#l#m'^~&ZP!Q![&^~&cS#g~!Q![&^!g!h&o#X#Y&o#l#m'^~&rR{|&{}!O&{!Q!['R~'OP!Q!['R~'WQ#g~!Q!['R#l#m'^~'aQ}!O'g!Q!['m~'jP!Q!['m~'rS#h~!O!P(O!Q!['m!g!h(d#X#Y(d~(RP!Q![(U~(ZR#h~!Q![(U!g!h(d#X#Y(d~(gR{|(p}!O(p!Q![(v~(sP!Q![(v~({P#h~!Q![(v~)TO!a~~)WP!O!P)Z~)`O!X~~)eOc~~)hP}!O)k~)nP!`!a)q~)vO!|~~){O_~~*QOX~~*VV#f~st*l}!O*Q!P!Q+^!Q![*Q!c!}*Q#R#S*Q#T#o*Q~*oR!c!}*x#R#S*x#T#o*x~*}T#f~}!O*x!Q![*x!c!}*x#R#S*x#T#o*x~+aR!c!}+j#R#S+j#T#o+j~+oU#f~st*l}!O+j!Q![+j!c!}+j#R#S+j#T#o+j~,WO|~~,]O!z~~,bO{~~,gO!k~",
|
|
18
|
+
tokenizers: [0],
|
|
19
|
+
topRules: {"Document":[0,2]},
|
|
20
|
+
specialized: [{term: 114, get: (value: keyof typeof spec_name) => spec_name[value] || -1}],
|
|
21
|
+
tokenPrec: 1961
|
|
22
|
+
})
|
package/src/dsl/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
type ConvertOptions,
|
|
7
|
+
type Source,
|
|
8
|
+
SOURCES,
|
|
9
|
+
UndetectedSourceError,
|
|
10
|
+
UnknownSourceError,
|
|
11
|
+
convert,
|
|
12
|
+
detect,
|
|
13
|
+
} from './convert.ts';
|
|
14
|
+
export { type CompileOptions, compile } from './compile.ts';
|
|
15
|
+
export {
|
|
16
|
+
type ParseResult,
|
|
17
|
+
type Problem,
|
|
18
|
+
type Range,
|
|
19
|
+
type Reading,
|
|
20
|
+
parse,
|
|
21
|
+
parseScene,
|
|
22
|
+
read,
|
|
23
|
+
toScene,
|
|
24
|
+
withLayout,
|
|
25
|
+
} from './parse.ts';
|
|
26
|
+
export { formatCommand, formatElement, formatId, formatObject, formatString, print, printCommands } from './print.ts';
|
|
27
|
+
export {
|
|
28
|
+
type AttrSpec,
|
|
29
|
+
type AttrType,
|
|
30
|
+
CLAUSE_KEYWORDS,
|
|
31
|
+
DIAGRAM_ATTRS,
|
|
32
|
+
EDGE_ATTRS,
|
|
33
|
+
ELEMENT_ATTRS,
|
|
34
|
+
ELEMENT_KINDS,
|
|
35
|
+
type ElementKind,
|
|
36
|
+
GROUP_ATTRS,
|
|
37
|
+
NODE_ATTRS,
|
|
38
|
+
OBJECT_ATTRS,
|
|
39
|
+
RELATION_WORDS,
|
|
40
|
+
RESERVED,
|
|
41
|
+
SEMANTIC_KEYWORDS,
|
|
42
|
+
STATEMENT_KEYWORDS,
|
|
43
|
+
} from './vocabulary.ts';
|
|
44
|
+
export { parser } from './gen/diagram.ts';
|