@likec4/language-server 1.2.2 → 1.4.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/package.json +19 -8
- package/src/ast.ts +2 -0
- package/src/generated/ast.ts +157 -123
- package/src/generated/grammar.ts +2 -2
- package/src/generated/module.ts +1 -1
- package/src/like-c4.langium +53 -34
- package/src/logger.ts +21 -7
- package/src/lsp/CompletionProvider.ts +7 -0
- package/src/lsp/SemanticTokenProvider.ts +78 -17
- package/src/lsp/index.ts +1 -0
- package/src/model/model-builder.ts +3 -39
- package/src/model/model-parser.ts +19 -4
- package/src/model-change/ModelChanges.ts +58 -53
- package/src/model-change/changeElementStyle.ts +5 -6
- package/src/model-change/saveManualLayout.ts +43 -0
- package/src/model-graph/LikeC4ModelGraph.ts +304 -0
- package/src/model-graph/compute-view/__test__/fixture.ts +438 -0
- package/src/model-graph/compute-view/compute.ts +430 -0
- package/src/model-graph/compute-view/index.ts +33 -0
- package/src/model-graph/compute-view/predicates.ts +404 -0
- package/src/model-graph/dynamic-view/__test__/fixture.ts +56 -0
- package/src/model-graph/dynamic-view/compute.ts +198 -0
- package/src/model-graph/dynamic-view/index.ts +29 -0
- package/src/model-graph/index.ts +3 -0
- package/src/model-graph/utils/applyElementCustomProperties.ts +49 -0
- package/src/model-graph/utils/applyViewRuleStyles.ts +68 -0
- package/src/model-graph/utils/buildComputeNodes.ts +61 -0
- package/src/model-graph/utils/sortNodes.ts +105 -0
- package/src/module.ts +3 -0
- package/src/protocol.ts +3 -18
- package/src/references/scope-computation.ts +29 -11
- package/src/references/scope-provider.ts +22 -16
- package/src/validation/view.ts +9 -4
- package/src/view-utils/manual-layout.ts +93 -0
- package/contrib/likec4.monarch.ts +0 -41
- package/src/lsp/DocumentLinkProvider.test.ts +0 -66
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ComputedEdge,
|
|
3
|
+
ComputedElementView,
|
|
4
|
+
EdgeId,
|
|
5
|
+
Element,
|
|
6
|
+
ElementView,
|
|
7
|
+
Relation,
|
|
8
|
+
ViewRuleExpression
|
|
9
|
+
} from '@likec4/core'
|
|
10
|
+
import {
|
|
11
|
+
ancestorsFqn,
|
|
12
|
+
commonAncestor,
|
|
13
|
+
compareRelations,
|
|
14
|
+
Expr,
|
|
15
|
+
invariant,
|
|
16
|
+
isAncestor,
|
|
17
|
+
isStrictElementView,
|
|
18
|
+
isViewRuleAutoLayout,
|
|
19
|
+
isViewRuleExpression,
|
|
20
|
+
nonexhaustive,
|
|
21
|
+
parentFqn
|
|
22
|
+
} from '@likec4/core'
|
|
23
|
+
import { hasAtLeast, isTruthy, unique } from 'remeda'
|
|
24
|
+
import type { LikeC4ModelGraph } from '../LikeC4ModelGraph'
|
|
25
|
+
import { applyElementCustomProperties } from '../utils/applyElementCustomProperties'
|
|
26
|
+
import { applyViewRuleStyles } from '../utils/applyViewRuleStyles'
|
|
27
|
+
import { buildComputeNodes } from '../utils/buildComputeNodes'
|
|
28
|
+
import { sortNodes } from '../utils/sortNodes'
|
|
29
|
+
import {
|
|
30
|
+
excludeElementKindOrTag,
|
|
31
|
+
excludeElementRef,
|
|
32
|
+
excludeIncomingExpr,
|
|
33
|
+
excludeInOutExpr,
|
|
34
|
+
excludeOutgoingExpr,
|
|
35
|
+
excludeRelationExpr,
|
|
36
|
+
excludeWildcardRef,
|
|
37
|
+
includeCustomElement,
|
|
38
|
+
includeElementKindOrTag,
|
|
39
|
+
includeElementRef,
|
|
40
|
+
includeExpandedElementExpr,
|
|
41
|
+
includeIncomingExpr,
|
|
42
|
+
includeInOutExpr,
|
|
43
|
+
includeOutgoingExpr,
|
|
44
|
+
includeRelationExpr,
|
|
45
|
+
includeWildcardRef
|
|
46
|
+
} from './predicates'
|
|
47
|
+
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
49
|
+
export namespace ComputeCtx {
|
|
50
|
+
// Intermediate ComputedEdge
|
|
51
|
+
export interface Edge {
|
|
52
|
+
source: Element
|
|
53
|
+
target: Element
|
|
54
|
+
relations: Relation[]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function compareEdges(a: ComputeCtx.Edge, b: ComputeCtx.Edge) {
|
|
59
|
+
return compareRelations(
|
|
60
|
+
{ source: a.source.id, target: a.target.id },
|
|
61
|
+
{ source: b.source.id, target: b.target.id }
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// If there is only one relation and it has same source and target as edge
|
|
66
|
+
function isDirectEdge({ relations: [rel, ...tail], source, target }: ComputeCtx.Edge) {
|
|
67
|
+
if (rel && tail.length === 0) {
|
|
68
|
+
return rel.source === source.id && rel.target === target.id
|
|
69
|
+
}
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class ComputeCtx {
|
|
74
|
+
// Intermediate state
|
|
75
|
+
private explicits = new Set<Element>()
|
|
76
|
+
private implicits = new Set<Element>()
|
|
77
|
+
private ctxEdges = [] as ComputeCtx.Edge[]
|
|
78
|
+
|
|
79
|
+
public static elementView(view: ElementView, graph: LikeC4ModelGraph) {
|
|
80
|
+
return new ComputeCtx(view, graph).compute()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private constructor(
|
|
84
|
+
protected view: ElementView,
|
|
85
|
+
protected graph: LikeC4ModelGraph
|
|
86
|
+
) {}
|
|
87
|
+
|
|
88
|
+
protected compute(): ComputedElementView {
|
|
89
|
+
// reset ctx
|
|
90
|
+
this.reset()
|
|
91
|
+
const { rules, ...view } = this.view
|
|
92
|
+
|
|
93
|
+
const viewPredicates = rules.filter(isViewRuleExpression)
|
|
94
|
+
if (this.root && viewPredicates.length == 0) {
|
|
95
|
+
this.addElement(this.graph.element(this.root))
|
|
96
|
+
}
|
|
97
|
+
this.processPredicates(viewPredicates)
|
|
98
|
+
this.removeRedundantImplicitEdges()
|
|
99
|
+
|
|
100
|
+
const elements = [...this.includedElements]
|
|
101
|
+
const nodesMap = buildComputeNodes(elements)
|
|
102
|
+
|
|
103
|
+
const edges = this.computedEdges.reduce((acc, edge) => {
|
|
104
|
+
const source = nodesMap.get(edge.source)
|
|
105
|
+
const target = nodesMap.get(edge.target)
|
|
106
|
+
invariant(source, `Source node ${edge.source} not found`)
|
|
107
|
+
invariant(target, `Target node ${edge.target} not found`)
|
|
108
|
+
while (edge.parent && !nodesMap.has(edge.parent)) {
|
|
109
|
+
edge.parent = parentFqn(edge.parent)
|
|
110
|
+
}
|
|
111
|
+
source.outEdges.push(edge.id)
|
|
112
|
+
target.inEdges.push(edge.id)
|
|
113
|
+
// Process edge source ancestors
|
|
114
|
+
for (const sourceAncestor of ancestorsFqn(edge.source)) {
|
|
115
|
+
if (sourceAncestor === edge.parent) {
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
nodesMap.get(sourceAncestor)?.outEdges.push(edge.id)
|
|
119
|
+
}
|
|
120
|
+
// Process target hierarchy
|
|
121
|
+
for (const targetAncestor of ancestorsFqn(edge.target)) {
|
|
122
|
+
if (targetAncestor === edge.parent) {
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
nodesMap.get(targetAncestor)?.inEdges.push(edge.id)
|
|
126
|
+
}
|
|
127
|
+
acc.push(edge)
|
|
128
|
+
return acc
|
|
129
|
+
}, [] as ComputedEdge[])
|
|
130
|
+
|
|
131
|
+
// nodesMap sorted hierarchically,
|
|
132
|
+
// but we need to keep the initial sort
|
|
133
|
+
const initialSort = elements.flatMap(e => nodesMap.get(e.id) ?? [])
|
|
134
|
+
|
|
135
|
+
const nodes = applyElementCustomProperties(
|
|
136
|
+
rules,
|
|
137
|
+
applyViewRuleStyles(
|
|
138
|
+
rules,
|
|
139
|
+
// Build graph and apply postorder sort
|
|
140
|
+
sortNodes({
|
|
141
|
+
nodes: initialSort,
|
|
142
|
+
edges
|
|
143
|
+
})
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const edgesMap = new Map<EdgeId, ComputedEdge>(edges.map(e => [e.id, e]))
|
|
148
|
+
|
|
149
|
+
const sortedEdges = new Set([
|
|
150
|
+
...nodes.flatMap(n => n.children.length === 0 ? n.outEdges.flatMap(id => edgesMap.get(id) ?? []) : []),
|
|
151
|
+
...edges
|
|
152
|
+
])
|
|
153
|
+
|
|
154
|
+
const autoLayoutRule = this.view.rules.findLast(isViewRuleAutoLayout)
|
|
155
|
+
return {
|
|
156
|
+
...view,
|
|
157
|
+
autoLayout: autoLayoutRule?.autoLayout ?? 'TB',
|
|
158
|
+
nodes,
|
|
159
|
+
edges: [...sortedEdges]
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
protected get root() {
|
|
164
|
+
return isStrictElementView(this.view) ? this.view.viewOf : null
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
protected get computedEdges(): ComputedEdge[] {
|
|
168
|
+
return this.ctxEdges.map((e): ComputedEdge => {
|
|
169
|
+
invariant(hasAtLeast(e.relations, 1), 'Edge must have at least one relation')
|
|
170
|
+
const relations = [...e.relations].sort(compareRelations)
|
|
171
|
+
const source = e.source.id
|
|
172
|
+
const target = e.target.id
|
|
173
|
+
|
|
174
|
+
const edge: ComputedEdge = {
|
|
175
|
+
id: `${source}:${target}` as EdgeId,
|
|
176
|
+
parent: commonAncestor(source, target),
|
|
177
|
+
source,
|
|
178
|
+
target,
|
|
179
|
+
label: null,
|
|
180
|
+
relations: relations.map(r => r.id)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let relation
|
|
184
|
+
if (relations.length === 1) {
|
|
185
|
+
relation = relations[0]
|
|
186
|
+
} else {
|
|
187
|
+
relation = relations.find(r => r.source === source && r.target === target)
|
|
188
|
+
relation ??= relations.find(r => r.source === source || r.target === target)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// This edge represents mutliple relations
|
|
192
|
+
// We use label if only it is the same for all relations
|
|
193
|
+
if (!relation) {
|
|
194
|
+
const labels = unique(relations.flatMap(r => (isTruthy(r.title) ? r.title : [])))
|
|
195
|
+
if (hasAtLeast(labels, 1)) {
|
|
196
|
+
if (labels.length === 1) {
|
|
197
|
+
edge.label = labels[0]
|
|
198
|
+
} else {
|
|
199
|
+
edge.label = '[...]'
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return edge
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return Object.assign(
|
|
206
|
+
edge,
|
|
207
|
+
isTruthy(relation.title) && { label: relation.title },
|
|
208
|
+
relation.color && { color: relation.color },
|
|
209
|
+
relation.line && { line: relation.line },
|
|
210
|
+
relation.head && { head: relation.head },
|
|
211
|
+
relation.tail && { tail: relation.tail }
|
|
212
|
+
)
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
protected get includedElements() {
|
|
217
|
+
return new Set([
|
|
218
|
+
...this.explicits,
|
|
219
|
+
...this.ctxEdges.flatMap(e => [e.source, e.target])
|
|
220
|
+
]) as ReadonlySet<Element>
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected get resolvedElements() {
|
|
224
|
+
return new Set([
|
|
225
|
+
...this.explicits,
|
|
226
|
+
...this.implicits,
|
|
227
|
+
...this.ctxEdges.flatMap(e => [e.source, e.target])
|
|
228
|
+
]) as ReadonlySet<Element>
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
protected get edges() {
|
|
232
|
+
return this.ctxEdges
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
protected addEdges(edges: ComputeCtx.Edge[]) {
|
|
236
|
+
for (const e of edges) {
|
|
237
|
+
if (!hasAtLeast(e.relations, 1)) {
|
|
238
|
+
continue
|
|
239
|
+
}
|
|
240
|
+
const existing = this.ctxEdges.find(
|
|
241
|
+
_e => _e.source.id === e.source.id && _e.target.id === e.target.id
|
|
242
|
+
)
|
|
243
|
+
if (existing) {
|
|
244
|
+
existing.relations = unique([...existing.relations, ...e.relations])
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
this.ctxEdges.push(e)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Add element explicitly
|
|
253
|
+
* Included even without relationships
|
|
254
|
+
*/
|
|
255
|
+
protected addElement(...el: Element[]) {
|
|
256
|
+
for (const r of el) {
|
|
257
|
+
this.explicits.add(r)
|
|
258
|
+
this.implicits.add(r)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Add element implicitly
|
|
264
|
+
* Included if only has relationships
|
|
265
|
+
*/
|
|
266
|
+
protected addImplicit(...el: Element[]) {
|
|
267
|
+
for (const r of el) {
|
|
268
|
+
this.implicits.add(r)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
protected excludeElement(...excludes: Element[]) {
|
|
273
|
+
for (const el of excludes) {
|
|
274
|
+
this.ctxEdges = this.ctxEdges.filter(e => e.source.id !== el.id && e.target.id !== el.id)
|
|
275
|
+
this.explicits.delete(el)
|
|
276
|
+
this.implicits.delete(el)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
protected excludeImplicit(...excludes: Element[]) {
|
|
281
|
+
for (const el of excludes) {
|
|
282
|
+
this.implicits.delete(el)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
protected excludeRelation(...relations: Relation[]) {
|
|
287
|
+
const excludedImplicits = new Set<Element>()
|
|
288
|
+
for (const relation of relations) {
|
|
289
|
+
let edge
|
|
290
|
+
while ((edge = this.ctxEdges.find(e => e.relations.includes(relation)))) {
|
|
291
|
+
if (edge.relations.length === 1) {
|
|
292
|
+
excludedImplicits.add(edge.source)
|
|
293
|
+
excludedImplicits.add(edge.target)
|
|
294
|
+
this.ctxEdges.splice(this.ctxEdges.indexOf(edge), 1)
|
|
295
|
+
continue
|
|
296
|
+
}
|
|
297
|
+
edge.relations = edge.relations.filter(r => r !== relation)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (excludedImplicits.size === 0) {
|
|
301
|
+
return
|
|
302
|
+
}
|
|
303
|
+
const remaining = this.includedElements
|
|
304
|
+
if (remaining.size === 0) {
|
|
305
|
+
this.implicits.clear()
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
for (const el of excludedImplicits) {
|
|
309
|
+
if (!remaining.has(el)) {
|
|
310
|
+
this.implicits.delete(el)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
protected reset() {
|
|
316
|
+
this.explicits.clear()
|
|
317
|
+
this.implicits.clear()
|
|
318
|
+
this.ctxEdges = []
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Filter out edges if there are edges between descendants
|
|
322
|
+
// i.e. remove implicit edges, derived from childs
|
|
323
|
+
protected removeRedundantImplicitEdges() {
|
|
324
|
+
const processedRelations = new Set<Relation>()
|
|
325
|
+
|
|
326
|
+
// Returns relations, that are not processed/included
|
|
327
|
+
const excludeProcessed = (relations: Relation[]) =>
|
|
328
|
+
relations.reduce((acc, rel) => {
|
|
329
|
+
if (!processedRelations.has(rel)) {
|
|
330
|
+
acc.push(rel)
|
|
331
|
+
processedRelations.add(rel)
|
|
332
|
+
}
|
|
333
|
+
return acc
|
|
334
|
+
}, [] as Relation[])
|
|
335
|
+
|
|
336
|
+
// Returns predicate
|
|
337
|
+
const isNestedEdgeOf = (parent: ComputeCtx.Edge) => {
|
|
338
|
+
const { source, target } = parent
|
|
339
|
+
// Checks if edge is between descendants of source and target of the parent edge
|
|
340
|
+
return (edge: ComputeCtx.Edge) => {
|
|
341
|
+
const isSameSource = source.id === edge.source.id
|
|
342
|
+
const isSameTarget = target.id === edge.target.id
|
|
343
|
+
if (isSameSource && isSameTarget) {
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
const isSourceNested = isAncestor(source.id, edge.source.id)
|
|
347
|
+
const isTargetNested = isAncestor(target.id, edge.target.id)
|
|
348
|
+
return (
|
|
349
|
+
(isSourceNested && isTargetNested)
|
|
350
|
+
|| (isSameSource && isTargetNested)
|
|
351
|
+
|| (isSameTarget && isSourceNested)
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Sort edges from bottom to top (i.e. from more specific edges to implicit or between ancestors)
|
|
357
|
+
const edges = [...this.ctxEdges].sort(compareEdges).reverse()
|
|
358
|
+
this.ctxEdges = edges.reduce((acc, e) => {
|
|
359
|
+
const relations = excludeProcessed(e.relations)
|
|
360
|
+
if (relations.length === 0) {
|
|
361
|
+
return acc
|
|
362
|
+
}
|
|
363
|
+
// If there is an edge between descendants of current edge,
|
|
364
|
+
// then we don't add this edge
|
|
365
|
+
if (acc.length > 0 && acc.some(isNestedEdgeOf(e))) {
|
|
366
|
+
return acc
|
|
367
|
+
}
|
|
368
|
+
acc.push({
|
|
369
|
+
source: e.source,
|
|
370
|
+
target: e.target,
|
|
371
|
+
relations
|
|
372
|
+
})
|
|
373
|
+
return acc
|
|
374
|
+
}, [] as ComputeCtx.Edge[])
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
protected processPredicates(viewRules: ViewRuleExpression[]): this {
|
|
378
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
379
|
+
for (const rule of viewRules) {
|
|
380
|
+
const isInclude = 'include' in rule
|
|
381
|
+
const exprs = rule.include ?? rule.exclude
|
|
382
|
+
for (const expr of exprs) {
|
|
383
|
+
if (Expr.isCustomElement(expr)) {
|
|
384
|
+
if (isInclude) {
|
|
385
|
+
includeCustomElement.call(this, expr)
|
|
386
|
+
}
|
|
387
|
+
continue
|
|
388
|
+
}
|
|
389
|
+
if (Expr.isExpandedElementExpr(expr)) {
|
|
390
|
+
if (isInclude) {
|
|
391
|
+
includeExpandedElementExpr.call(this, expr)
|
|
392
|
+
}
|
|
393
|
+
continue
|
|
394
|
+
}
|
|
395
|
+
if (Expr.isElementKindExpr(expr) || Expr.isElementTagExpr(expr)) {
|
|
396
|
+
isInclude
|
|
397
|
+
? includeElementKindOrTag.call(this, expr)
|
|
398
|
+
: excludeElementKindOrTag.call(this, expr)
|
|
399
|
+
continue
|
|
400
|
+
}
|
|
401
|
+
if (Expr.isElementRef(expr)) {
|
|
402
|
+
isInclude ? includeElementRef.call(this, expr) : excludeElementRef.call(this, expr)
|
|
403
|
+
continue
|
|
404
|
+
}
|
|
405
|
+
if (Expr.isWildcard(expr)) {
|
|
406
|
+
isInclude ? includeWildcardRef.call(this, expr) : excludeWildcardRef.call(this, expr)
|
|
407
|
+
continue
|
|
408
|
+
}
|
|
409
|
+
if (Expr.isIncoming(expr)) {
|
|
410
|
+
isInclude ? includeIncomingExpr.call(this, expr) : excludeIncomingExpr.call(this, expr)
|
|
411
|
+
continue
|
|
412
|
+
}
|
|
413
|
+
if (Expr.isOutgoing(expr)) {
|
|
414
|
+
isInclude ? includeOutgoingExpr.call(this, expr) : excludeOutgoingExpr.call(this, expr)
|
|
415
|
+
continue
|
|
416
|
+
}
|
|
417
|
+
if (Expr.isInOut(expr)) {
|
|
418
|
+
isInclude ? includeInOutExpr.call(this, expr) : excludeInOutExpr.call(this, expr)
|
|
419
|
+
continue
|
|
420
|
+
}
|
|
421
|
+
if (Expr.isRelation(expr)) {
|
|
422
|
+
isInclude ? includeRelationExpr.call(this, expr) : excludeRelationExpr.call(this, expr)
|
|
423
|
+
continue
|
|
424
|
+
}
|
|
425
|
+
nonexhaustive(expr)
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return this
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ComputedElementView, type ElementView } from '@likec4/core'
|
|
2
|
+
import type { LikeC4ModelGraph } from '../LikeC4ModelGraph'
|
|
3
|
+
import { ComputeCtx } from './compute'
|
|
4
|
+
|
|
5
|
+
export function computeElementView(view: ElementView, graph: LikeC4ModelGraph) {
|
|
6
|
+
return ComputeCtx.elementView(view, graph)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type ComputeViewResult =
|
|
10
|
+
| {
|
|
11
|
+
isSuccess: true
|
|
12
|
+
view: ComputedElementView
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
isSuccess: false
|
|
16
|
+
error: Error
|
|
17
|
+
view: undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function computeView(view: ElementView, graph: LikeC4ModelGraph): ComputeViewResult {
|
|
21
|
+
try {
|
|
22
|
+
return {
|
|
23
|
+
isSuccess: true,
|
|
24
|
+
view: computeElementView(view, graph)
|
|
25
|
+
}
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return {
|
|
28
|
+
isSuccess: false,
|
|
29
|
+
error: e instanceof Error ? e : new Error(`Unknown error: ${e}`),
|
|
30
|
+
view: undefined
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|