@likec4/language-server 1.8.1 → 1.10.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/contrib/likec4.tmLanguage.json +1 -1
- package/dist/browser.cjs +21 -0
- package/dist/browser.d.cts +22 -0
- package/dist/browser.d.mts +22 -0
- package/dist/browser.d.ts +22 -0
- package/dist/browser.mjs +19 -0
- package/dist/index.cjs +10 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.mjs +1 -0
- package/dist/likec4lib.cjs +961 -0
- package/dist/likec4lib.d.cts +6 -0
- package/dist/likec4lib.d.mts +6 -0
- package/dist/likec4lib.d.ts +6 -0
- package/dist/likec4lib.mjs +957 -0
- package/dist/model-graph/index.cjs +10 -0
- package/dist/model-graph/index.d.cts +79 -0
- package/dist/model-graph/index.d.mts +79 -0
- package/dist/model-graph/index.d.ts +79 -0
- package/dist/model-graph/index.mjs +1 -0
- package/dist/node.cjs +18 -0
- package/dist/node.d.cts +20 -0
- package/dist/node.d.mts +20 -0
- package/dist/node.d.ts +20 -0
- package/dist/node.mjs +16 -0
- package/dist/protocol.cjs +25 -0
- package/dist/protocol.d.cts +43 -0
- package/dist/protocol.d.mts +43 -0
- package/dist/protocol.d.ts +43 -0
- package/dist/protocol.mjs +17 -0
- package/dist/shared/language-server.CjFzaJwI.d.cts +1223 -0
- package/dist/shared/language-server.CtKHXJDD.d.ts +1223 -0
- package/dist/shared/language-server.D-84I33F.d.mts +1223 -0
- package/dist/shared/language-server.DBJJUUgF.mjs +5737 -0
- package/dist/shared/language-server.DtBRb9os.mjs +1656 -0
- package/dist/shared/language-server.DwyCJvXm.cjs +1669 -0
- package/dist/shared/language-server.JWkqVjGv.cjs +5748 -0
- package/package.json +36 -20
- package/src/ast.ts +48 -36
- package/src/browser.ts +0 -3
- package/src/elementRef.ts +1 -1
- package/src/formatting/LikeC4Formatter.ts +388 -0
- package/src/formatting/utils.ts +26 -0
- package/src/generated/ast.ts +170 -12
- package/src/generated/grammar.ts +1 -1
- package/src/generated-lib/icons.ts +1 -1
- package/src/like-c4.langium +49 -8
- package/src/likec4lib.ts +2 -3
- package/src/logger.ts +9 -1
- package/src/lsp/DocumentLinkProvider.ts +27 -15
- package/src/lsp/RenameProvider.ts +8 -0
- package/src/lsp/SemanticTokenProvider.ts +20 -2
- package/src/lsp/index.ts +1 -0
- package/src/model/fqn-computation.ts +33 -23
- package/src/model/fqn-index.ts +5 -21
- package/src/model/model-builder.ts +180 -112
- package/src/model/model-locator.ts +1 -1
- package/src/model/model-parser-where.ts +3 -2
- package/src/model/model-parser.ts +99 -39
- package/src/model-graph/LikeC4ModelGraph.ts +42 -21
- package/src/model-graph/compute-view/__test__/fixture.ts +16 -14
- package/src/model-graph/compute-view/compute.ts +110 -81
- package/src/model-graph/compute-view/predicates.ts +6 -8
- package/src/model-graph/dynamic-view/__test__/fixture.ts +1 -0
- package/src/model-graph/dynamic-view/compute.ts +98 -61
- package/src/model-graph/utils/buildElementNotations.ts +1 -1
- package/src/model-graph/utils/elementExpressionToPredicate.ts +1 -1
- package/src/model-graph/utils/sortNodes.ts +2 -6
- package/src/module.ts +21 -4
- package/src/protocol.ts +4 -5
- package/src/references/scope-computation.ts +10 -1
- package/src/references/scope-provider.ts +2 -1
- package/src/shared/NodeKindProvider.ts +73 -34
- package/src/test/setup.ts +3 -8
- package/src/test/testServices.ts +27 -7
- package/src/utils/graphlib.ts +11 -0
- package/src/validation/index.ts +2 -1
- package/src/validation/property-checks.ts +13 -1
- package/src/validation/specification.ts +3 -3
- package/src/view-utils/manual-layout.ts +1 -1
- package/src/view-utils/resolve-extended-views.ts +19 -10
- package/src/view-utils/resolve-relative-paths.ts +19 -24
- package/src/view-utils/view-hash.ts +1 -1
- package/src/reset.d.ts +0 -2
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import type * as c4 from '@likec4/core'
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
compareRelations,
|
|
4
|
+
computeColorValues,
|
|
5
|
+
type CustomColorDefinitions,
|
|
4
6
|
isElementView,
|
|
5
7
|
isScopedElementView,
|
|
6
8
|
parentFqn,
|
|
7
|
-
|
|
9
|
+
sortByFqnHierarchically,
|
|
8
10
|
type ViewID
|
|
9
11
|
} from '@likec4/core'
|
|
10
12
|
import { deepEqual as eq } from 'fast-equals'
|
|
@@ -12,17 +14,22 @@ import type { Cancellation, LangiumDocument, LangiumDocuments, URI, WorkspaceCac
|
|
|
12
14
|
import { Disposable, DocumentState, interruptAndCheck } from 'langium'
|
|
13
15
|
import {
|
|
14
16
|
filter,
|
|
15
|
-
find,
|
|
16
17
|
flatMap,
|
|
17
18
|
forEach,
|
|
19
|
+
groupBy,
|
|
20
|
+
indexBy,
|
|
21
|
+
isEmpty,
|
|
22
|
+
isNonNullish,
|
|
18
23
|
isNullish,
|
|
19
24
|
isNumber,
|
|
20
25
|
isTruthy,
|
|
21
26
|
map,
|
|
22
27
|
mapToObj,
|
|
28
|
+
mapValues,
|
|
23
29
|
pipe,
|
|
24
30
|
prop,
|
|
25
31
|
reduce,
|
|
32
|
+
reverse,
|
|
26
33
|
sort,
|
|
27
34
|
values
|
|
28
35
|
} from 'remeda'
|
|
@@ -31,7 +38,8 @@ import type {
|
|
|
31
38
|
ParsedAstRelation,
|
|
32
39
|
ParsedAstSpecification,
|
|
33
40
|
ParsedAstView,
|
|
34
|
-
ParsedLikeC4LangiumDocument
|
|
41
|
+
ParsedLikeC4LangiumDocument,
|
|
42
|
+
ParsedLink
|
|
35
43
|
} from '../ast'
|
|
36
44
|
import { isParsedLikeC4LangiumDocument } from '../ast'
|
|
37
45
|
import { logError, logger, logWarnError } from '../logger'
|
|
@@ -40,26 +48,48 @@ import type { LikeC4Services } from '../module'
|
|
|
40
48
|
import { printDocs } from '../utils/printDocs'
|
|
41
49
|
import { assignNavigateTo, resolveRelativePaths, resolveRulesExtendedViews } from '../view-utils'
|
|
42
50
|
|
|
43
|
-
function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[]): c4.
|
|
51
|
+
function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[]): c4.ParsedLikeC4Model {
|
|
44
52
|
const c4Specification: ParsedAstSpecification = {
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
tags: new Set(),
|
|
54
|
+
elements: {},
|
|
55
|
+
relationships: {},
|
|
56
|
+
colors: {}
|
|
47
57
|
}
|
|
48
58
|
forEach(map(docs, prop('c4Specification')), spec => {
|
|
49
|
-
|
|
59
|
+
spec.tags.forEach(t => c4Specification.tags.add(t))
|
|
60
|
+
Object.assign(c4Specification.elements, spec.elements)
|
|
50
61
|
Object.assign(c4Specification.relationships, spec.relationships)
|
|
62
|
+
Object.assign(c4Specification.colors, spec.colors)
|
|
51
63
|
})
|
|
52
|
-
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
function resolveLinks(doc: LangiumDocument, links: c4.NonEmptyArray<ParsedLink>) {
|
|
65
|
+
return map(
|
|
66
|
+
links,
|
|
67
|
+
(link): c4.Link => {
|
|
68
|
+
try {
|
|
69
|
+
const relative = services.lsp.DocumentLinkProvider.relativeLink(doc, link.url)
|
|
70
|
+
if (relative && relative !== link.url) {
|
|
71
|
+
return {
|
|
72
|
+
...link,
|
|
73
|
+
relative
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
logWarnError(e)
|
|
78
|
+
}
|
|
79
|
+
return link
|
|
80
|
+
}
|
|
81
|
+
)
|
|
57
82
|
}
|
|
58
83
|
|
|
59
|
-
const
|
|
84
|
+
const customColorDefinitions: CustomColorDefinitions = mapValues(
|
|
85
|
+
c4Specification.colors,
|
|
86
|
+
c => computeColorValues(c.color)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
function toModelElement(doc: LangiumDocument) {
|
|
60
90
|
return ({
|
|
61
91
|
tags,
|
|
62
|
-
links,
|
|
92
|
+
links: unresolvedLinks,
|
|
63
93
|
style: {
|
|
64
94
|
color,
|
|
65
95
|
shape,
|
|
@@ -75,11 +105,12 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
75
105
|
metadata
|
|
76
106
|
}: ParsedAstElement): c4.Element | null => {
|
|
77
107
|
try {
|
|
78
|
-
const __kind = c4Specification.
|
|
108
|
+
const __kind = c4Specification.elements[kind]
|
|
79
109
|
if (!__kind) {
|
|
80
110
|
logger.warn(`No kind '${kind}' found for ${id}`)
|
|
81
111
|
return null
|
|
82
112
|
}
|
|
113
|
+
const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null
|
|
83
114
|
color ??= __kind.style.color
|
|
84
115
|
shape ??= __kind.style.shape
|
|
85
116
|
icon ??= __kind.style.icon
|
|
@@ -90,13 +121,13 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
90
121
|
...(color && { color }),
|
|
91
122
|
...(shape && { shape }),
|
|
92
123
|
...(icon && { icon }),
|
|
93
|
-
...(metadata && { metadata }),
|
|
124
|
+
...(metadata && !isEmpty(metadata) && { metadata }),
|
|
94
125
|
...(__kind.notation && { notation: __kind.notation }),
|
|
95
126
|
style: {
|
|
96
127
|
...(border && { border }),
|
|
97
128
|
...(isNumber(opacity) && { opacity })
|
|
98
129
|
},
|
|
99
|
-
links
|
|
130
|
+
links,
|
|
100
131
|
tags: tags ?? null,
|
|
101
132
|
technology: technology ?? null,
|
|
102
133
|
description: description ?? null,
|
|
@@ -115,7 +146,9 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
115
146
|
docs,
|
|
116
147
|
flatMap(d => map(d.c4Elements, toModelElement(d))),
|
|
117
148
|
filter(isTruthy),
|
|
118
|
-
sort
|
|
149
|
+
// sort from root elements to nested, so that parent is always present
|
|
150
|
+
// Import to preserve the order from the source
|
|
151
|
+
sortByFqnHierarchically,
|
|
119
152
|
reduce(
|
|
120
153
|
(acc, el) => {
|
|
121
154
|
const parent = parentFqn(el.id)
|
|
@@ -123,25 +156,20 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
123
156
|
logWarnError(`No parent found for ${el.id}`)
|
|
124
157
|
return acc
|
|
125
158
|
}
|
|
126
|
-
if (el.id in acc) {
|
|
127
|
-
// should not happen, as validated
|
|
128
|
-
logWarnError(`Duplicate element id: ${el.id}`)
|
|
129
|
-
return acc
|
|
130
|
-
}
|
|
131
159
|
acc[el.id] = el
|
|
132
160
|
return acc
|
|
133
161
|
},
|
|
134
|
-
{} as c4.
|
|
162
|
+
{} as c4.ParsedLikeC4Model['elements']
|
|
135
163
|
)
|
|
136
164
|
)
|
|
137
165
|
|
|
138
|
-
|
|
166
|
+
function toModelRelation(doc: LangiumDocument) {
|
|
139
167
|
return ({
|
|
140
168
|
astPath,
|
|
141
169
|
source,
|
|
142
170
|
target,
|
|
143
171
|
kind,
|
|
144
|
-
links,
|
|
172
|
+
links: unresolvedLinks,
|
|
145
173
|
id,
|
|
146
174
|
...model
|
|
147
175
|
}: ParsedAstRelation): c4.Relation | null => {
|
|
@@ -151,25 +179,26 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
151
179
|
)
|
|
152
180
|
return null
|
|
153
181
|
}
|
|
182
|
+
const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null
|
|
154
183
|
|
|
155
|
-
if (
|
|
184
|
+
if (isNonNullish(kind) && kind in c4Specification.relationships) {
|
|
156
185
|
return {
|
|
157
|
-
...(links && { links: resolveLinks(doc, links) }),
|
|
158
186
|
...c4Specification.relationships[kind],
|
|
159
187
|
...model,
|
|
188
|
+
...(links && { links }),
|
|
160
189
|
source,
|
|
161
190
|
target,
|
|
162
191
|
kind,
|
|
163
192
|
id
|
|
164
|
-
}
|
|
193
|
+
} satisfies c4.Relation
|
|
165
194
|
}
|
|
166
195
|
return {
|
|
167
|
-
...(links && { links
|
|
196
|
+
...(links && { links }),
|
|
168
197
|
...model,
|
|
169
198
|
source,
|
|
170
199
|
target,
|
|
171
200
|
id
|
|
172
|
-
}
|
|
201
|
+
} satisfies c4.Relation
|
|
173
202
|
}
|
|
174
203
|
}
|
|
175
204
|
|
|
@@ -177,10 +206,12 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
177
206
|
docs,
|
|
178
207
|
flatMap(d => map(d.c4Relations, toModelRelation(d))),
|
|
179
208
|
filter(isTruthy),
|
|
180
|
-
|
|
209
|
+
sort(compareRelations),
|
|
210
|
+
reverse(),
|
|
211
|
+
indexBy(prop('id'))
|
|
181
212
|
)
|
|
182
213
|
|
|
183
|
-
|
|
214
|
+
function toC4View(doc: LangiumDocument) {
|
|
184
215
|
const docUri = doc.uri.toString()
|
|
185
216
|
return (parsedAstView: ParsedAstView): c4.LikeC4View => {
|
|
186
217
|
let {
|
|
@@ -188,11 +219,9 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
188
219
|
title,
|
|
189
220
|
description,
|
|
190
221
|
tags,
|
|
191
|
-
links,
|
|
192
|
-
|
|
222
|
+
links: unresolvedLinks,
|
|
193
223
|
// ignore this property
|
|
194
224
|
astPath: _ignore,
|
|
195
|
-
|
|
196
225
|
// model should include discriminant __
|
|
197
226
|
...model
|
|
198
227
|
} = parsedAstView
|
|
@@ -205,34 +234,32 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
205
234
|
title = 'Landscape view'
|
|
206
235
|
}
|
|
207
236
|
|
|
237
|
+
const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null
|
|
238
|
+
|
|
208
239
|
return {
|
|
209
|
-
|
|
210
|
-
title,
|
|
211
|
-
description,
|
|
240
|
+
...model,
|
|
212
241
|
tags,
|
|
213
|
-
links
|
|
242
|
+
links,
|
|
214
243
|
docUri,
|
|
215
|
-
|
|
244
|
+
description,
|
|
245
|
+
title,
|
|
246
|
+
id,
|
|
247
|
+
customColorDefinitions
|
|
216
248
|
}
|
|
217
249
|
}
|
|
218
250
|
}
|
|
219
251
|
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
mapToObj(v => [v.id, v]),
|
|
225
|
-
resolveRulesExtendedViews
|
|
226
|
-
)
|
|
227
|
-
// add index view if not present
|
|
228
|
-
if (!('index' in views)) {
|
|
229
|
-
views['index' as ViewID] = {
|
|
252
|
+
const parsedViews = docs.flatMap(d => map(d.c4Views, toC4View(d)))
|
|
253
|
+
// Add index view if not present
|
|
254
|
+
if (!parsedViews.some(v => v.id === 'index')) {
|
|
255
|
+
parsedViews.unshift({
|
|
230
256
|
__: 'element',
|
|
231
257
|
id: 'index' as ViewID,
|
|
232
|
-
title: 'Landscape',
|
|
258
|
+
title: 'Landscape view',
|
|
233
259
|
description: null,
|
|
234
260
|
tags: null,
|
|
235
261
|
links: null,
|
|
262
|
+
customColorDefinitions: customColorDefinitions,
|
|
236
263
|
rules: [
|
|
237
264
|
{
|
|
238
265
|
include: [
|
|
@@ -242,17 +269,30 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
242
269
|
]
|
|
243
270
|
}
|
|
244
271
|
]
|
|
245
|
-
}
|
|
272
|
+
})
|
|
246
273
|
}
|
|
247
274
|
|
|
275
|
+
const views = pipe(
|
|
276
|
+
parsedViews,
|
|
277
|
+
resolveRelativePaths,
|
|
278
|
+
indexBy(prop('id')),
|
|
279
|
+
resolveRulesExtendedViews
|
|
280
|
+
)
|
|
281
|
+
|
|
248
282
|
return {
|
|
283
|
+
specification: {
|
|
284
|
+
tags: Array.from(c4Specification.tags),
|
|
285
|
+
elements: c4Specification.elements,
|
|
286
|
+
relationships: c4Specification.relationships
|
|
287
|
+
},
|
|
249
288
|
elements,
|
|
250
289
|
relations,
|
|
251
290
|
views
|
|
252
291
|
}
|
|
253
292
|
}
|
|
254
|
-
|
|
255
|
-
const
|
|
293
|
+
|
|
294
|
+
const CACHE_KEY_PARSED_MODEL = 'ParsedLikeC4Model'
|
|
295
|
+
const CACHE_KEY_COMPUTED_MODEL = 'ComputedLikeC4Model'
|
|
256
296
|
|
|
257
297
|
type ModelParsedListener = (docs: URI[]) => void
|
|
258
298
|
|
|
@@ -274,9 +314,13 @@ export class LikeC4ModelBuilder {
|
|
|
274
314
|
DocumentState.Validated,
|
|
275
315
|
async (docs, _cancelToken) => {
|
|
276
316
|
let parsed = [] as URI[]
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
317
|
+
try {
|
|
318
|
+
logger.debug(`[ModelBuilder] onValidated (${docs.length} docs)\n${printDocs(docs)}`)
|
|
319
|
+
for (const doc of parser.parse(docs)) {
|
|
320
|
+
parsed.push(doc.uri)
|
|
321
|
+
}
|
|
322
|
+
} catch (e) {
|
|
323
|
+
logWarnError(e)
|
|
280
324
|
}
|
|
281
325
|
if (parsed.length > 0) {
|
|
282
326
|
this.notifyListeners(parsed)
|
|
@@ -287,35 +331,82 @@ export class LikeC4ModelBuilder {
|
|
|
287
331
|
logger.debug(`[ModelBuilder] Created`)
|
|
288
332
|
}
|
|
289
333
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
334
|
+
/**
|
|
335
|
+
* WARNING:
|
|
336
|
+
* This method is internal and should to be called only when all documents are known to be parsed.
|
|
337
|
+
* Otherwise, the model may be incomplete.
|
|
338
|
+
*/
|
|
339
|
+
public unsafeSyncBuildModel(): c4.ParsedLikeC4Model | null {
|
|
340
|
+
const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ParsedLikeC4Model | null>
|
|
341
|
+
return cache.get(CACHE_KEY_PARSED_MODEL, () => {
|
|
342
|
+
const docs = this.documents()
|
|
343
|
+
if (docs.length === 0) {
|
|
344
|
+
logger.debug('[ModelBuilder] No documents to build model from')
|
|
345
|
+
return null
|
|
346
|
+
}
|
|
347
|
+
logger.debug(`[ModelBuilder] buildModel from ${docs.length} docs:\n${printDocs(docs)}`)
|
|
348
|
+
return buildModel(this.services, docs)
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public async buildModel(cancelToken?: Cancellation.CancellationToken): Promise<c4.ParsedLikeC4Model | null> {
|
|
353
|
+
const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ParsedLikeC4Model | null>
|
|
354
|
+
if (cache.has(CACHE_KEY_PARSED_MODEL)) {
|
|
355
|
+
return cache.get(CACHE_KEY_PARSED_MODEL)!
|
|
294
356
|
}
|
|
295
357
|
return await this.services.shared.workspace.WorkspaceLock.read(async () => {
|
|
296
358
|
if (cancelToken) {
|
|
297
359
|
await interruptAndCheck(cancelToken)
|
|
298
360
|
}
|
|
299
|
-
return
|
|
300
|
-
const docs = this.documents()
|
|
301
|
-
if (docs.length === 0) {
|
|
302
|
-
logger.debug('[ModelBuilder] No documents to build model from')
|
|
303
|
-
return null
|
|
304
|
-
}
|
|
305
|
-
logger.debug(`[ModelBuilder] buildModel from ${docs.length} docs:\n${printDocs(docs)}`)
|
|
306
|
-
return buildModel(this.services, docs)
|
|
307
|
-
})
|
|
361
|
+
return this.unsafeSyncBuildModel()
|
|
308
362
|
})
|
|
309
363
|
}
|
|
310
364
|
|
|
311
365
|
private previousViews: Record<ViewID, c4.ComputedView> = {}
|
|
312
366
|
|
|
367
|
+
/**
|
|
368
|
+
* WARNING:
|
|
369
|
+
* This method is internal and should to be called only when all documents are known to be parsed.
|
|
370
|
+
* Otherwise, the model may be incomplete.
|
|
371
|
+
*/
|
|
372
|
+
public unsafeSyncBuildComputedModel(model: c4.ParsedLikeC4Model): c4.ComputedLikeC4Model {
|
|
373
|
+
const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedLikeC4Model>
|
|
374
|
+
const viewsCache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedView | null>
|
|
375
|
+
return cache.get(CACHE_KEY_COMPUTED_MODEL, () => {
|
|
376
|
+
const index = new LikeC4ModelGraph(model)
|
|
377
|
+
|
|
378
|
+
const allViews = [] as c4.ComputedView[]
|
|
379
|
+
for (const view of values(model.views)) {
|
|
380
|
+
const result = isElementView(view) ? computeView(view, index) : computeDynamicView(view, index)
|
|
381
|
+
if (!result.isSuccess) {
|
|
382
|
+
logWarnError(result.error)
|
|
383
|
+
continue
|
|
384
|
+
}
|
|
385
|
+
allViews.push(result.view)
|
|
386
|
+
}
|
|
387
|
+
assignNavigateTo(allViews)
|
|
388
|
+
const views = mapToObj(allViews, v => {
|
|
389
|
+
const previous = this.previousViews[v.id]
|
|
390
|
+
const view = previous && eq(v, previous) ? previous : v
|
|
391
|
+
viewsCache.set(computedViewKey(v.id), view)
|
|
392
|
+
return [v.id, view] as const
|
|
393
|
+
})
|
|
394
|
+
this.previousViews = { ...views }
|
|
395
|
+
return {
|
|
396
|
+
specification: model.specification,
|
|
397
|
+
elements: model.elements,
|
|
398
|
+
relations: model.relations,
|
|
399
|
+
views
|
|
400
|
+
}
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
|
|
313
404
|
public async buildComputedModel(
|
|
314
405
|
cancelToken?: Cancellation.CancellationToken
|
|
315
|
-
): Promise<c4.
|
|
316
|
-
const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.
|
|
317
|
-
if (cache.has(
|
|
318
|
-
return cache.get(
|
|
406
|
+
): Promise<c4.ComputedLikeC4Model | null> {
|
|
407
|
+
const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedLikeC4Model | null>
|
|
408
|
+
if (cache.has(CACHE_KEY_COMPUTED_MODEL)) {
|
|
409
|
+
return cache.get(CACHE_KEY_COMPUTED_MODEL)!
|
|
319
410
|
}
|
|
320
411
|
const model = await this.buildModel(cancelToken)
|
|
321
412
|
if (!model) {
|
|
@@ -325,33 +416,7 @@ export class LikeC4ModelBuilder {
|
|
|
325
416
|
if (cancelToken) {
|
|
326
417
|
await interruptAndCheck(cancelToken)
|
|
327
418
|
}
|
|
328
|
-
|
|
329
|
-
return cache.get(MODEL_CACHE, () => {
|
|
330
|
-
const index = new LikeC4ModelGraph(model)
|
|
331
|
-
|
|
332
|
-
const allViews = [] as c4.ComputedView[]
|
|
333
|
-
for (const view of values(model.views)) {
|
|
334
|
-
const result = isElementView(view) ? computeView(view, index) : computeDynamicView(view, index)
|
|
335
|
-
if (!result.isSuccess) {
|
|
336
|
-
logWarnError(result.error)
|
|
337
|
-
continue
|
|
338
|
-
}
|
|
339
|
-
allViews.push(result.view)
|
|
340
|
-
}
|
|
341
|
-
assignNavigateTo(allViews)
|
|
342
|
-
const views = mapToObj(allViews, v => {
|
|
343
|
-
const previous = this.previousViews[v.id]
|
|
344
|
-
const view = previous && eq(v, previous) ? previous : v
|
|
345
|
-
viewsCache.set(computedViewKey(v.id), view)
|
|
346
|
-
return [v.id, view] as const
|
|
347
|
-
})
|
|
348
|
-
this.previousViews = { ...views }
|
|
349
|
-
return {
|
|
350
|
-
elements: model.elements,
|
|
351
|
-
relations: model.relations,
|
|
352
|
-
views
|
|
353
|
-
}
|
|
354
|
-
})
|
|
419
|
+
return this.unsafeSyncBuildComputedModel(model)
|
|
355
420
|
})
|
|
356
421
|
}
|
|
357
422
|
|
|
@@ -383,19 +448,22 @@ export class LikeC4ModelBuilder {
|
|
|
383
448
|
}
|
|
384
449
|
let computedView = result.view
|
|
385
450
|
|
|
386
|
-
const allElementViews =
|
|
387
|
-
|
|
451
|
+
const allElementViews = pipe(
|
|
452
|
+
model.views,
|
|
453
|
+
values(),
|
|
454
|
+
filter(isScopedElementView),
|
|
455
|
+
filter(v => v.id !== viewId),
|
|
456
|
+
groupBy(v => v.viewOf)
|
|
388
457
|
)
|
|
389
458
|
|
|
390
|
-
computedView.nodes
|
|
459
|
+
for (const node of computedView.nodes) {
|
|
391
460
|
if (!node.navigateTo) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
node.navigateTo = navigateTo.id
|
|
461
|
+
const viewsOfNode = allElementViews[node.id]
|
|
462
|
+
if (viewsOfNode) {
|
|
463
|
+
node.navigateTo = viewsOfNode[0].id
|
|
396
464
|
}
|
|
397
465
|
}
|
|
398
|
-
}
|
|
466
|
+
}
|
|
399
467
|
|
|
400
468
|
const previous = this.previousViews[viewId]
|
|
401
469
|
computedView = previous && eq(computedView, previous) ? previous : computedView
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isAndOperator, isOrOperator } from '@likec4/core
|
|
1
|
+
import { invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core'
|
|
2
|
+
import { isAndOperator, isOrOperator } from '@likec4/core'
|
|
3
|
+
import type * as c4 from '@likec4/core'
|
|
3
4
|
import { ast } from '../ast'
|
|
4
5
|
|
|
5
6
|
const parseEquals = (
|