@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.
Files changed (171) hide show
  1. package/dist/lib/chunk-parse.mjs +9406 -0
  2. package/dist/lib/chunk-parse.mjs.map +1 -0
  3. package/dist/lib/extension.mjs +204 -0
  4. package/dist/lib/extension.mjs.map +1 -0
  5. package/dist/lib/index.mjs +497 -2846
  6. package/dist/lib/index.mjs.map +1 -1
  7. package/dist/types/src/aesthetics.d.ts +12 -0
  8. package/dist/types/src/aesthetics.d.ts.map +1 -0
  9. package/dist/types/src/aesthetics.test.d.ts +2 -0
  10. package/dist/types/src/aesthetics.test.d.ts.map +1 -0
  11. package/dist/types/src/appeal.d.ts +55 -0
  12. package/dist/types/src/appeal.d.ts.map +1 -0
  13. package/dist/types/src/appeal.test.d.ts +2 -0
  14. package/dist/types/src/appeal.test.d.ts.map +1 -0
  15. package/dist/types/src/architecture.d.ts +86 -0
  16. package/dist/types/src/architecture.d.ts.map +1 -0
  17. package/dist/types/src/architecture.test.d.ts +2 -0
  18. package/dist/types/src/architecture.test.d.ts.map +1 -0
  19. package/dist/types/src/compact.d.ts +39 -0
  20. package/dist/types/src/compact.d.ts.map +1 -0
  21. package/dist/types/src/compact.test.d.ts +2 -0
  22. package/dist/types/src/compact.test.d.ts.map +1 -0
  23. package/dist/types/src/diagnostics.d.ts +70 -3
  24. package/dist/types/src/diagnostics.d.ts.map +1 -1
  25. package/dist/types/src/dsl/cli.d.ts +2 -0
  26. package/dist/types/src/dsl/cli.d.ts.map +1 -0
  27. package/dist/types/src/dsl/compile.d.ts +12 -0
  28. package/dist/types/src/dsl/compile.d.ts.map +1 -0
  29. package/dist/types/src/dsl/convert.d.ts +45 -0
  30. package/dist/types/src/dsl/convert.d.ts.map +1 -0
  31. package/dist/types/src/dsl/convert.test.d.ts +2 -0
  32. package/dist/types/src/dsl/convert.test.d.ts.map +1 -0
  33. package/dist/types/src/dsl/dsl.test.d.ts +2 -0
  34. package/dist/types/src/dsl/dsl.test.d.ts.map +1 -0
  35. package/dist/types/src/dsl/gen/diagram.d.ts +3 -0
  36. package/dist/types/src/dsl/gen/diagram.d.ts.map +1 -0
  37. package/dist/types/src/dsl/index.d.ts +7 -0
  38. package/dist/types/src/dsl/index.d.ts.map +1 -0
  39. package/dist/types/src/dsl/parse.d.ts +49 -0
  40. package/dist/types/src/dsl/parse.d.ts.map +1 -0
  41. package/dist/types/src/dsl/print.d.ts +19 -0
  42. package/dist/types/src/dsl/print.d.ts.map +1 -0
  43. package/dist/types/src/dsl/semantic.test.d.ts +2 -0
  44. package/dist/types/src/dsl/semantic.test.d.ts.map +1 -0
  45. package/dist/types/src/dsl/vocabulary.d.ts +61 -0
  46. package/dist/types/src/dsl/vocabulary.d.ts.map +1 -0
  47. package/dist/types/src/dx-svg.d.ts +12 -0
  48. package/dist/types/src/dx-svg.d.ts.map +1 -0
  49. package/dist/types/src/dx-svg.test.d.ts +2 -0
  50. package/dist/types/src/dx-svg.test.d.ts.map +1 -0
  51. package/dist/types/src/extension/complete.d.ts +3 -0
  52. package/dist/types/src/extension/complete.d.ts.map +1 -0
  53. package/dist/types/src/extension/extension.test.d.ts +2 -0
  54. package/dist/types/src/extension/extension.test.d.ts.map +1 -0
  55. package/dist/types/src/extension/highlight.d.ts +14 -0
  56. package/dist/types/src/extension/highlight.d.ts.map +1 -0
  57. package/dist/types/src/extension/index.d.ts +6 -0
  58. package/dist/types/src/extension/index.d.ts.map +1 -0
  59. package/dist/types/src/extension/language.d.ts +13 -0
  60. package/dist/types/src/extension/language.d.ts.map +1 -0
  61. package/dist/types/src/extension/lint.d.ts +21 -0
  62. package/dist/types/src/extension/lint.d.ts.map +1 -0
  63. package/dist/types/src/extension/syntax.d.ts +3 -0
  64. package/dist/types/src/extension/syntax.d.ts.map +1 -0
  65. package/dist/types/src/index.d.ts +14 -0
  66. package/dist/types/src/index.d.ts.map +1 -1
  67. package/dist/types/src/mermaid-engine.d.ts +40 -1
  68. package/dist/types/src/mermaid-engine.d.ts.map +1 -1
  69. package/dist/types/src/mermaid.d.ts +3 -3
  70. package/dist/types/src/mermaid.d.ts.map +1 -1
  71. package/dist/types/src/nudge.d.ts +30 -0
  72. package/dist/types/src/nudge.d.ts.map +1 -0
  73. package/dist/types/src/nudge.test.d.ts +2 -0
  74. package/dist/types/src/nudge.test.d.ts.map +1 -0
  75. package/dist/types/src/objective.d.ts +4 -0
  76. package/dist/types/src/objective.d.ts.map +1 -1
  77. package/dist/types/src/ortho-router.d.ts +13 -1
  78. package/dist/types/src/ortho-router.d.ts.map +1 -1
  79. package/dist/types/src/ports.d.ts +40 -0
  80. package/dist/types/src/ports.d.ts.map +1 -0
  81. package/dist/types/src/ports.test.d.ts +2 -0
  82. package/dist/types/src/ports.test.d.ts.map +1 -0
  83. package/dist/types/src/relations.test.d.ts +2 -0
  84. package/dist/types/src/relations.test.d.ts.map +1 -0
  85. package/dist/types/src/rules.d.ts +30 -0
  86. package/dist/types/src/rules.d.ts.map +1 -0
  87. package/dist/types/src/scene.d.ts +108 -74
  88. package/dist/types/src/scene.d.ts.map +1 -1
  89. package/dist/types/src/score.d.ts +54 -0
  90. package/dist/types/src/score.d.ts.map +1 -0
  91. package/dist/types/src/score.test.d.ts +2 -0
  92. package/dist/types/src/score.test.d.ts.map +1 -0
  93. package/dist/types/src/semantic-engine.d.ts +41 -0
  94. package/dist/types/src/semantic-engine.d.ts.map +1 -0
  95. package/dist/types/src/semantic-engine.test.d.ts +2 -0
  96. package/dist/types/src/semantic-engine.test.d.ts.map +1 -0
  97. package/dist/types/src/semantic-place.d.ts +81 -0
  98. package/dist/types/src/semantic-place.d.ts.map +1 -0
  99. package/dist/types/src/semantic-route.d.ts +133 -0
  100. package/dist/types/src/semantic-route.d.ts.map +1 -0
  101. package/dist/types/src/semantic.d.ts +164 -0
  102. package/dist/types/src/semantic.d.ts.map +1 -0
  103. package/dist/types/src/uml-grid.d.ts.map +1 -1
  104. package/dist/types/src/uml.d.ts +3 -5
  105. package/dist/types/src/uml.d.ts.map +1 -1
  106. package/dist/types/src/view.d.ts +53 -0
  107. package/dist/types/src/view.d.ts.map +1 -0
  108. package/dist/types/src/view.test.d.ts +2 -0
  109. package/dist/types/src/view.test.d.ts.map +1 -0
  110. package/dist/types/tsconfig.tsbuildinfo +1 -1
  111. package/package.json +23 -5
  112. package/rules/DIAGRAM.mdl +388 -0
  113. package/src/aesthetics.test.ts +89 -0
  114. package/src/aesthetics.ts +148 -0
  115. package/src/appeal.test.ts +144 -0
  116. package/src/appeal.ts +586 -0
  117. package/src/architecture.test.ts +94 -0
  118. package/src/architecture.ts +215 -0
  119. package/src/compact.test.ts +67 -0
  120. package/src/compact.ts +219 -0
  121. package/src/diagnostics.test.ts +207 -1
  122. package/src/diagnostics.ts +481 -37
  123. package/src/dsl/cli.ts +46 -0
  124. package/src/dsl/compile.ts +28 -0
  125. package/src/dsl/convert.test.ts +51 -0
  126. package/src/dsl/convert.ts +98 -0
  127. package/src/dsl/diagram.grammar +195 -0
  128. package/src/dsl/dsl.test.ts +286 -0
  129. package/src/dsl/gen/diagram.ts +22 -0
  130. package/src/dsl/index.ts +44 -0
  131. package/src/dsl/parse.ts +1054 -0
  132. package/src/dsl/print.ts +198 -0
  133. package/src/dsl/semantic.test.ts +216 -0
  134. package/src/dsl/vocabulary.ts +150 -0
  135. package/src/dx-svg.test.ts +44 -0
  136. package/src/dx-svg.ts +77 -0
  137. package/src/extension/complete.ts +105 -0
  138. package/src/extension/extension.test.ts +135 -0
  139. package/src/extension/highlight.ts +23 -0
  140. package/src/extension/index.ts +9 -0
  141. package/src/extension/language.ts +31 -0
  142. package/src/extension/lint.ts +60 -0
  143. package/src/extension/syntax.ts +62 -0
  144. package/src/index.ts +14 -0
  145. package/src/mermaid-engine.test.ts +6 -6
  146. package/src/mermaid-engine.ts +569 -119
  147. package/src/mermaid.test.ts +17 -1
  148. package/src/mermaid.ts +30 -18
  149. package/src/nudge.test.ts +186 -0
  150. package/src/nudge.ts +387 -0
  151. package/src/objective.test.ts +2 -0
  152. package/src/objective.ts +17 -1
  153. package/src/ortho-router.ts +240 -80
  154. package/src/ports.test.ts +157 -0
  155. package/src/ports.ts +186 -0
  156. package/src/relations.test.ts +98 -0
  157. package/src/rules.ts +117 -0
  158. package/src/scene.ts +66 -5
  159. package/src/score.test.ts +64 -0
  160. package/src/score.ts +130 -0
  161. package/src/semantic-engine.test.ts +635 -0
  162. package/src/semantic-engine.ts +891 -0
  163. package/src/semantic-place.ts +1508 -0
  164. package/src/semantic-route.ts +1136 -0
  165. package/src/semantic.ts +278 -0
  166. package/src/typings.d.ts +8 -0
  167. package/src/uml-grid.ts +6 -1
  168. package/src/uml.test.ts +5 -1
  169. package/src/uml.ts +24 -11
  170. package/src/view.test.ts +139 -0
  171. package/src/view.ts +376 -0
@@ -0,0 +1,204 @@
1
+ import { G as analyze, _ as ELEMENT_KINDS, b as OBJECT_ATTRS, g as ELEMENT_ATTRS, h as EDGE_ATTRS, i as toScene, m as DIAGRAM_ATTRS, o as parser, r as read, t as parse, v as GROUP_ATTRS, w as STATEMENT_KEYWORDS, x as RELATION_WORDS, y as NODE_ATTRS } from "./chunk-parse.mjs";
2
+ import { HighlightStyle, LRLanguage, LanguageDescription, LanguageSupport, syntaxHighlighting, syntaxTree } from "@codemirror/language";
3
+ import { autocompletion } from "@codemirror/autocomplete";
4
+ import { styleTags, tags } from "@lezer/highlight";
5
+ import { linter } from "@codemirror/lint";
6
+ //#region src/extension/complete.ts
7
+ /** What a semantic statement accepts after its id: attributes, plus relations or edge clauses. */
8
+ var SEMANTIC = {
9
+ DiagramDecl: {
10
+ attrs: DIAGRAM_ATTRS,
11
+ words: []
12
+ },
13
+ GroupDecl: {
14
+ attrs: GROUP_ATTRS,
15
+ words: [...RELATION_WORDS, "compact"]
16
+ },
17
+ NodeDecl: {
18
+ attrs: NODE_ATTRS,
19
+ words: RELATION_WORDS
20
+ },
21
+ EdgeDecl: {
22
+ attrs: EDGE_ATTRS,
23
+ words: ["via", "bus"]
24
+ }
25
+ };
26
+ var attributeOptions = (attrs) => attrs.map(({ name, type }) => ({
27
+ label: name,
28
+ type: "property",
29
+ detail: type === "enum" ? void 0 : type,
30
+ apply: `${name}=`
31
+ }));
32
+ /** The element kind a completion is inside, read off the tree rather than re-lexing the line. */
33
+ var enclosingKind = (context, pos) => {
34
+ let node = syntaxTree(context.state).resolveInner(pos, -1);
35
+ while (node.parent) {
36
+ if (node.name === "Element") {
37
+ const shape = node.firstChild;
38
+ const keyword = shape && (shape.getChild("BoxKind") ?? shape.getChild("PathKind"))?.firstChild;
39
+ const word = context.state.doc.sliceString((keyword ?? shape?.firstChild)?.from ?? 0, (keyword ?? shape?.firstChild)?.to ?? 0);
40
+ return ELEMENT_KINDS.find((kind) => kind === word);
41
+ }
42
+ if (node.name === "ObjectDecl" || node.name === "ElementsDecl") return;
43
+ node = node.parent;
44
+ }
45
+ };
46
+ /** Node names from the cursor out to the document, so a position is classified by where it sits. */
47
+ var ancestorsOf = (context, pos) => {
48
+ const names = [];
49
+ for (let node = syntaxTree(context.state).resolveInner(pos, -1); node; node = node.parent) names.push(node.name);
50
+ return names;
51
+ };
52
+ var source = (context) => {
53
+ const word = context.matchBefore(/[\w-]*/);
54
+ if (!word || word.from === word.to && !context.explicit) return null;
55
+ const ancestors = ancestorsOf(context, context.pos);
56
+ const innermost = ancestors.find((name) => name in SEMANTIC || name === "GroupBody");
57
+ if (innermost === "GroupBody") return {
58
+ from: word.from,
59
+ options: ["node", "edge"].map((label) => ({
60
+ label,
61
+ type: "keyword"
62
+ }))
63
+ };
64
+ if (innermost) {
65
+ const { attrs, words } = SEMANTIC[innermost];
66
+ return {
67
+ from: word.from,
68
+ options: [...words.map((label) => ({
69
+ label,
70
+ type: "keyword"
71
+ })), ...attributeOptions(attrs)]
72
+ };
73
+ }
74
+ if (!ancestors.includes("ObjectDecl") && !ancestors.includes("ElementsDecl")) return {
75
+ from: word.from,
76
+ options: STATEMENT_KEYWORDS.map((label) => ({
77
+ label,
78
+ type: "keyword"
79
+ }))
80
+ };
81
+ const kind = enclosingKind(context, context.pos);
82
+ if (!kind && ancestors.includes("Body")) return {
83
+ from: word.from,
84
+ options: ELEMENT_KINDS.map((label) => ({
85
+ label,
86
+ type: "keyword"
87
+ }))
88
+ };
89
+ return {
90
+ from: word.from,
91
+ options: attributeOptions(kind ? ELEMENT_ATTRS[kind] : OBJECT_ATTRS)
92
+ };
93
+ };
94
+ var diagramComplete = autocompletion({ override: [source] });
95
+ //#endregion
96
+ //#region src/extension/highlight.ts
97
+ /**
98
+ * Fills the gaps the editor's own highlight style leaves. The grammar emits standard
99
+ * `@lezer/highlight` tags, so most of a document is coloured by whatever style the theme installs
100
+ * and inherits its palette — but `vscodeLightStyle`/`vscodeDarkStyle` define neither
101
+ * `attributeValue` nor `null`, which in this language are the enum values (`grey`, `dashed`,
102
+ * `triangle`) and the unbound arrow end. Those are the most scannable part of a diagram, so
103
+ * leaving them uncoloured is the one thing worth overriding.
104
+ *
105
+ * Classes are semantic theme tokens rather than hues, as in `mermaidHighlightStyle`, so light and
106
+ * dark follow the palette.
107
+ */
108
+ var diagramHighlightStyle = () => HighlightStyle.define([{
109
+ tag: tags.attributeValue,
110
+ class: "text-accent"
111
+ }, {
112
+ tag: tags.null,
113
+ class: "text-fg-subtle"
114
+ }]);
115
+ //#endregion
116
+ //#region src/extension/lint.ts
117
+ /**
118
+ * What is wrong with a document: everything `parse` found, and optionally everything
119
+ * `Diagnostics.analyze` finds in the scene it produced, each carrying the range of the statement
120
+ * or element that produced it — a layout error is only actionable when it points at the box it is
121
+ * about. Separate from the CodeMirror wrapper so it needs no editor, which is also how the
122
+ * agent-facing path reports the same problems.
123
+ */
124
+ var diagramDiagnostics = (text, { layout = false } = {}) => {
125
+ const { commands, problems, ranges } = layout ? parse(text) : read(text);
126
+ const clamp = (value) => Math.max(0, Math.min(value, text.length));
127
+ const diagnostics = problems.map(({ severity, message, from, to }) => ({
128
+ severity,
129
+ message,
130
+ from: clamp(from),
131
+ to: clamp(to)
132
+ }));
133
+ if (layout && !problems.some(({ severity }) => severity === "error")) for (const diagnostic of analyze(toScene(commands).objects).diagnostics) {
134
+ const range = diagnostic.refs.flatMap((ref) => ranges.get(ref) ?? []).at(0);
135
+ diagnostics.push({
136
+ severity: diagnostic.severity,
137
+ source: diagnostic.code,
138
+ message: diagnostic.message,
139
+ from: clamp(range?.from ?? 0),
140
+ to: clamp(range?.to ?? Math.min(1, text.length))
141
+ });
142
+ }
143
+ return diagnostics.sort((left, right) => left.from - right.from);
144
+ };
145
+ /** The CodeMirror linter over {@link diagramDiagnostics}. */
146
+ var diagramLint = (options = {}) => linter((view) => diagramDiagnostics(view.state.doc.toString(), options));
147
+ //#endregion
148
+ //#region src/extension/syntax.ts
149
+ var diagramLanguage = LRLanguage.define({
150
+ name: "diagram",
151
+ parser: parser.configure({ props: [styleTags({
152
+ "object elements move remove diagram group node edge": tags.definitionKeyword,
153
+ "cell via bus compact": tags.keyword,
154
+ "RelationKind Side": tags.keyword,
155
+ "Soft": tags.modifier,
156
+ "rect ellipse diamond triangle circle line curve arc text arrow portal": tags.keyword,
157
+ "Id/String": tags.variableName,
158
+ "Id": tags.variableName,
159
+ "Ref": tags.propertyName,
160
+ "Label": tags.string,
161
+ "String": tags.string,
162
+ "Number": tags.number,
163
+ "Size": tags.number,
164
+ "Ratio": tags.number,
165
+ "AttrName": tags.attributeName,
166
+ "Word": tags.attributeValue,
167
+ "Word/object Word/elements Word/move Word/remove Word/rect Word/ellipse Word/diamond Word/triangle Word/circle Word/line Word/curve Word/arc Word/text Word/arrow Word/portal Word/diagram Word/group Word/node Word/edge Word/cell Word/via Word/bus Word/compact": tags.attributeValue,
168
+ "_": tags.null,
169
+ "Comment": tags.lineComment,
170
+ "-> <-> -- @ .. : | ~": tags.operator,
171
+ "( )": tags.paren,
172
+ "=": tags.definitionOperator,
173
+ ",": tags.separator,
174
+ "{ }": tags.brace
175
+ })] }),
176
+ languageData: {
177
+ commentTokens: { line: "#" },
178
+ closeBrackets: { brackets: ["{", "\""] }
179
+ }
180
+ });
181
+ //#endregion
182
+ //#region src/extension/language.ts
183
+ /**
184
+ * The fence dispatch point. Pass this alongside deus's `mdlBlockDescription` in
185
+ * `createMarkdownExtensions({ codeLanguages: [...] })` and a ```diagram block inside a `.mdl`
186
+ * document parses with the diagram grammar — a sibling of MDL's, not a nesting inside it. See
187
+ * `docs/DSL.md`.
188
+ */
189
+ var diagramBlockDescription = LanguageDescription.of({
190
+ name: "diagram",
191
+ alias: ["dxd"],
192
+ support: new LanguageSupport(diagramLanguage)
193
+ });
194
+ /** The whole editing surface for a standalone DSL buffer: mode, highlighting, completion, lint. */
195
+ var diagram = (options = {}) => [
196
+ new LanguageSupport(diagramLanguage),
197
+ syntaxHighlighting(diagramHighlightStyle()),
198
+ diagramComplete,
199
+ diagramLint(options)
200
+ ];
201
+ //#endregion
202
+ export { diagram, diagramBlockDescription, diagramComplete, diagramDiagnostics, diagramHighlightStyle, diagramLanguage, diagramLint };
203
+
204
+ //# sourceMappingURL=extension.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../src/extension/complete.ts","../../src/extension/highlight.ts","../../src/extension/lint.ts","../../src/extension/syntax.ts","../../src/extension/language.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { type CompletionContext, type CompletionResult, autocompletion } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\nimport { type SyntaxNode } from '@lezer/common';\n\nimport {\n type AttrSpec,\n DIAGRAM_ATTRS,\n EDGE_ATTRS,\n ELEMENT_ATTRS,\n ELEMENT_KINDS,\n type ElementKind,\n GROUP_ATTRS,\n NODE_ATTRS,\n OBJECT_ATTRS,\n RELATION_WORDS,\n STATEMENT_KEYWORDS,\n} from '../dsl/vocabulary.ts';\n\n/** What a semantic statement accepts after its id: attributes, plus relations or edge clauses. */\nconst SEMANTIC: Record<string, { attrs: readonly AttrSpec[]; words: readonly string[] }> = {\n DiagramDecl: { attrs: DIAGRAM_ATTRS, words: [] },\n GroupDecl: { attrs: GROUP_ATTRS, words: [...RELATION_WORDS, 'compact'] },\n NodeDecl: { attrs: NODE_ATTRS, words: RELATION_WORDS },\n EdgeDecl: { attrs: EDGE_ATTRS, words: ['via', 'bus'] },\n};\n\nconst attributeOptions = (attrs: readonly AttrSpec[]) =>\n attrs.map(({ name, type }) => ({\n label: name,\n type: 'property',\n detail: type === 'enum' ? undefined : type,\n apply: `${name}=`,\n }));\n\n/** The element kind a completion is inside, read off the tree rather than re-lexing the line. */\nconst enclosingKind = (context: CompletionContext, pos: number): ElementKind | undefined => {\n let node = syntaxTree(context.state).resolveInner(pos, -1);\n while (node.parent) {\n if (node.name === 'Element') {\n const shape = node.firstChild;\n const keyword = shape && (shape.getChild('BoxKind') ?? shape.getChild('PathKind'))?.firstChild;\n const word = context.state.doc.sliceString(\n (keyword ?? shape?.firstChild)?.from ?? 0,\n (keyword ?? shape?.firstChild)?.to ?? 0,\n );\n return ELEMENT_KINDS.find((kind) => kind === word);\n }\n if (node.name === 'ObjectDecl' || node.name === 'ElementsDecl') {\n // Inside the declaration but outside any element: the object's own attributes.\n return undefined;\n }\n node = node.parent;\n }\n return undefined;\n};\n\n/** Node names from the cursor out to the document, so a position is classified by where it sits. */\nconst ancestorsOf = (context: CompletionContext, pos: number): string[] => {\n const names: string[] = [];\n for (let node: SyntaxNode | null = syntaxTree(context.state).resolveInner(pos, -1); node; node = node.parent) {\n names.push(node.name);\n }\n return names;\n};\n\nconst source = (context: CompletionContext): CompletionResult | null => {\n const word = context.matchBefore(/[\\w-]*/);\n if (!word || (word.from === word.to && !context.explicit)) {\n return null;\n }\n\n const ancestors = ancestorsOf(context, context.pos);\n // Inside a semantic statement the innermost one decides; a group's body holds nodes and edges.\n const innermost = ancestors.find((name) => name in SEMANTIC || name === 'GroupBody');\n if (innermost === 'GroupBody') {\n return { from: word.from, options: ['node', 'edge'].map((label) => ({ label, type: 'keyword' })) };\n }\n if (innermost) {\n const { attrs, words } = SEMANTIC[innermost];\n return {\n from: word.from,\n options: [...words.map((label) => ({ label, type: 'keyword' })), ...attributeOptions(attrs)],\n };\n }\n // Outside any declaration only a statement can start.\n if (!ancestors.includes('ObjectDecl') && !ancestors.includes('ElementsDecl')) {\n return { from: word.from, options: STATEMENT_KEYWORDS.map((label) => ({ label, type: 'keyword' })) };\n }\n\n // A `Body` holds elements and nothing else, so an empty position in one wants a kind; inside an\n // element it wants that kind's attributes, and in the header it wants the object's.\n const kind = enclosingKind(context, context.pos);\n if (!kind && ancestors.includes('Body')) {\n return { from: word.from, options: ELEMENT_KINDS.map((label) => ({ label, type: 'keyword' })) };\n }\n\n return { from: word.from, options: attributeOptions(kind ? ELEMENT_ATTRS[kind] : OBJECT_ATTRS) };\n};\n\nexport const diagramComplete: Extension = autocompletion({ override: [source] });\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { HighlightStyle } from '@codemirror/language';\nimport { tags } from '@lezer/highlight';\n\n/**\n * Fills the gaps the editor's own highlight style leaves. The grammar emits standard\n * `@lezer/highlight` tags, so most of a document is coloured by whatever style the theme installs\n * and inherits its palette — but `vscodeLightStyle`/`vscodeDarkStyle` define neither\n * `attributeValue` nor `null`, which in this language are the enum values (`grey`, `dashed`,\n * `triangle`) and the unbound arrow end. Those are the most scannable part of a diagram, so\n * leaving them uncoloured is the one thing worth overriding.\n *\n * Classes are semantic theme tokens rather than hues, as in `mermaidHighlightStyle`, so light and\n * dark follow the palette.\n */\nexport const diagramHighlightStyle = () =>\n HighlightStyle.define([\n { tag: tags.attributeValue, class: 'text-accent' },\n { tag: tags.null, class: 'text-fg-subtle' },\n ]);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Diagnostic, linter } from '@codemirror/lint';\nimport { type Extension } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\n\nimport * as Diagnostics from '../diagnostics.ts';\nimport { parse, read, toScene } from '../dsl/parse.ts';\n\nexport type LintOptions = {\n /**\n * Also report the layout diagnostics — overlaps, a connector through a node, a label that does\n * not fit. Off by default because a document being typed is briefly nonsense; the bench and the\n * agent loop both want it on.\n */\n layout?: boolean;\n};\n\n/**\n * What is wrong with a document: everything `parse` found, and optionally everything\n * `Diagnostics.analyze` finds in the scene it produced, each carrying the range of the statement\n * or element that produced it — a layout error is only actionable when it points at the box it is\n * about. Separate from the CodeMirror wrapper so it needs no editor, which is also how the\n * agent-facing path reports the same problems.\n */\nexport const diagramDiagnostics = (text: string, { layout = false }: LintOptions = {}): Diagnostic[] => {\n // Laying out semantic statements is a search; without the layout report only the reading is needed.\n const { commands, problems, ranges } = layout ? parse(text) : read(text);\n const clamp = (value: number) => Math.max(0, Math.min(value, text.length));\n\n const diagnostics: Diagnostic[] = problems.map(({ severity, message, from, to }) => ({\n severity,\n message,\n from: clamp(from),\n to: clamp(to),\n }));\n\n // A document with a syntax error has a scene that is missing pieces, so its layout report would\n // be noise on top of an error the author is already fixing.\n if (layout && !problems.some(({ severity }) => severity === 'error')) {\n for (const diagnostic of Diagnostics.analyze(toScene(commands).objects).diagnostics) {\n const range = diagnostic.refs.flatMap((ref) => ranges.get(ref) ?? []).at(0);\n diagnostics.push({\n severity: diagnostic.severity,\n source: diagnostic.code,\n message: diagnostic.message,\n from: clamp(range?.from ?? 0),\n to: clamp(range?.to ?? Math.min(1, text.length)),\n });\n }\n }\n\n return diagnostics.sort((left, right) => left.from - right.from);\n};\n\n/** The CodeMirror linter over {@link diagramDiagnostics}. */\nexport const diagramLint = (options: LintOptions = {}): Extension =>\n linter((view: EditorView): Diagnostic[] => diagramDiagnostics(view.state.doc.toString(), options));\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { LRLanguage } from '@codemirror/language';\nimport { styleTags, tags } from '@lezer/highlight';\n\nimport { parser } from '../dsl/gen/diagram.ts';\n\n//\n// Unlike deus's MDL mode — which keeps highlighting on a regex ViewPlugin so prose inside a block\n// cannot trip LR error recovery — the diagram grammar covers its whole input, so highlighting comes\n// off the tree. The tags are the standard ones, so most of a document inherits the editor's own\n// palette; `highlight.ts` covers only the two the theme leaves undefined.\n//\n\nexport const diagramLanguage = LRLanguage.define({\n name: 'diagram',\n parser: parser.configure({\n props: [\n styleTags({\n 'object elements move remove diagram group node edge': tags.definitionKeyword,\n 'cell via bus compact': tags.keyword,\n // Relation words and sides are plain names the reader checks, so they are tagged by position.\n 'RelationKind Side': tags.keyword,\n 'Soft': tags.modifier,\n 'rect ellipse diamond triangle circle line curve arc text arrow portal': tags.keyword,\n // A quoted id is still an id, not a string.\n 'Id/String': tags.variableName,\n 'Id': tags.variableName,\n 'Ref': tags.propertyName,\n 'Label': tags.string,\n 'String': tags.string,\n 'Number': tags.number,\n 'Size': tags.number,\n 'Ratio': tags.number,\n 'AttrName': tags.attributeName,\n // On the leaf, not on `AttrValue`/`Unbound`: a named child with no tag of its own does not\n // inherit its parent's, so tagging the wrapper colours nothing. A numeric or quoted value\n // keeps its own number/string tag; this is the bare enum word (`grey`, `dashed`).\n 'Word': tags.attributeValue,\n // `head=triangle`, `head=arrow`, `tail=circle`: schema literals that are also element-kind\n // keywords, so without the path they would colour as keywords while every other enum value\n // colours as a value. Listed in full, like the grammar's own `Word` alternation, so a\n // literal that starts colliding later is already covered.\n 'Word/object Word/elements Word/move Word/remove Word/rect Word/ellipse Word/diamond Word/triangle Word/circle Word/line Word/curve Word/arc Word/text Word/arrow Word/portal Word/diagram Word/group Word/node Word/edge Word/cell Word/via Word/bus Word/compact':\n tags.attributeValue,\n '_': tags.null,\n 'Comment': tags.lineComment,\n '-> <-> -- @ .. : | ~': tags.operator,\n '( )': tags.paren,\n '=': tags.definitionOperator,\n ',': tags.separator,\n '{ }': tags.brace,\n }),\n ],\n }),\n languageData: {\n commentTokens: { line: '#' },\n closeBrackets: { brackets: ['{', '\"'] },\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { LanguageDescription, LanguageSupport, syntaxHighlighting } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\n\nimport { diagramComplete } from './complete.ts';\nimport { diagramHighlightStyle } from './highlight.ts';\nimport { type LintOptions, diagramLint } from './lint.ts';\nimport { diagramLanguage } from './syntax.ts';\n\n/**\n * The fence dispatch point. Pass this alongside deus's `mdlBlockDescription` in\n * `createMarkdownExtensions({ codeLanguages: [...] })` and a ```diagram block inside a `.mdl`\n * document parses with the diagram grammar — a sibling of MDL's, not a nesting inside it. See\n * `docs/DSL.md`.\n */\nexport const diagramBlockDescription = LanguageDescription.of({\n name: 'diagram',\n alias: ['dxd'],\n support: new LanguageSupport(diagramLanguage),\n});\n\n/** The whole editing surface for a standalone DSL buffer: mode, highlighting, completion, lint. */\nexport const diagram = (options: LintOptions = {}): Extension => [\n new LanguageSupport(diagramLanguage),\n syntaxHighlighting(diagramHighlightStyle()),\n diagramComplete,\n diagramLint(options),\n];\n"],"mappings":"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"}