@likec4/language-server 1.9.0 → 1.10.1
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 +1 -1
- package/dist/browser.d.cts +3 -4
- package/dist/browser.d.mts +3 -4
- package/dist/browser.d.ts +3 -4
- package/dist/browser.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/model-graph/index.cjs +1 -1
- package/dist/model-graph/index.mjs +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.d.cts +3 -4
- package/dist/node.d.mts +3 -4
- package/dist/node.d.ts +3 -4
- package/dist/node.mjs +1 -1
- package/dist/shared/{language-server.Q-wtPShM.mjs → language-server.BFBeyvV8.mjs} +486 -108
- package/dist/shared/{language-server.86lmJ8ZN.d.cts → language-server.BGy3FJPJ.d.cts} +43 -14
- package/dist/shared/{language-server.B1TZgyoH.cjs → language-server.Bfc-5M8A.cjs} +482 -104
- package/dist/shared/{language-server.CCB4ESN5.mjs → language-server.CbqwHp7Q.mjs} +184 -120
- package/dist/shared/{language-server.RjhrBZS0.d.ts → language-server.CnVuAxDh.d.ts} +43 -14
- package/dist/shared/{language-server.CFTY6j4e.d.mts → language-server.DEK39RmI.d.mts} +43 -14
- package/dist/shared/{language-server.D0bOlrCi.cjs → language-server.DJhoJBWh.cjs} +180 -116
- package/package.json +13 -11
- package/src/ast.ts +8 -6
- package/src/formatting/LikeC4Formatter.ts +390 -0
- package/src/formatting/utils.ts +26 -0
- package/src/generated/ast.ts +203 -11
- package/src/generated/grammar.ts +2 -2
- package/src/generated/module.ts +1 -1
- package/src/like-c4.langium +34 -7
- package/src/lsp/CompletionProvider.ts +1 -1
- package/src/lsp/DocumentLinkProvider.ts +27 -15
- package/src/lsp/SemanticTokenProvider.ts +1 -1
- package/src/lsp/index.ts +1 -1
- package/src/model/fqn-index.ts +0 -1
- package/src/model/model-builder.ts +43 -32
- package/src/model/model-parser.ts +43 -21
- package/src/model-graph/compute-view/compute.ts +111 -80
- package/src/model-graph/compute-view/predicates.ts +3 -5
- package/src/model-graph/dynamic-view/compute.ts +96 -60
- package/src/model-graph/utils/buildElementNotations.ts +1 -1
- package/src/model-graph/utils/uniqueTags.test.ts +42 -0
- package/src/model-graph/utils/uniqueTags.ts +19 -0
- package/src/module.ts +6 -9
- package/src/test/testServices.ts +27 -7
- 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/resolve-relative-paths.ts +14 -17
package/src/generated/module.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/******************************************************************************
|
|
2
|
-
* This file was generated by langium-cli 3.
|
|
2
|
+
* This file was generated by langium-cli 3.2.0.
|
|
3
3
|
* DO NOT EDIT MANUALLY!
|
|
4
4
|
******************************************************************************/
|
|
5
5
|
|
package/src/like-c4.langium
CHANGED
|
@@ -162,7 +162,12 @@ RelationBody: '{'
|
|
|
162
162
|
;
|
|
163
163
|
|
|
164
164
|
RelationProperty:
|
|
165
|
-
RelationStringProperty |
|
|
165
|
+
RelationStringProperty |
|
|
166
|
+
RelationNavigateToProperty |
|
|
167
|
+
RelationStyleProperty |
|
|
168
|
+
LinkProperty |
|
|
169
|
+
MetadataProperty
|
|
170
|
+
;
|
|
166
171
|
|
|
167
172
|
RelationStringProperty:
|
|
168
173
|
key=('title' | 'technology' | 'description') ':'? value=String ';'?;
|
|
@@ -183,7 +188,7 @@ MetadataBody: '{'
|
|
|
183
188
|
;
|
|
184
189
|
|
|
185
190
|
MetadataAttribute:
|
|
186
|
-
key=IdTerminal value=String
|
|
191
|
+
key=IdTerminal ':'? value=String ';'?
|
|
187
192
|
;
|
|
188
193
|
|
|
189
194
|
// Views -------------------------------------
|
|
@@ -215,6 +220,9 @@ ViewRef:
|
|
|
215
220
|
ElementViewRef:
|
|
216
221
|
view=[ElementView];
|
|
217
222
|
|
|
223
|
+
DynamicViewRef:
|
|
224
|
+
view=[DynamicView];
|
|
225
|
+
|
|
218
226
|
ElementViewBody: '{'
|
|
219
227
|
tags=Tags?
|
|
220
228
|
props+=ViewProperty*
|
|
@@ -225,8 +233,11 @@ ElementViewBody: '{'
|
|
|
225
233
|
DynamicViewBody: '{'
|
|
226
234
|
tags=Tags?
|
|
227
235
|
props+=ViewProperty*
|
|
228
|
-
(
|
|
229
|
-
|
|
236
|
+
(
|
|
237
|
+
steps+=(DynamicViewParallelSteps | DynamicViewStep) |
|
|
238
|
+
rules+=DynamicViewRule
|
|
239
|
+
)*
|
|
240
|
+
'}'
|
|
230
241
|
;
|
|
231
242
|
|
|
232
243
|
|
|
@@ -237,7 +248,8 @@ type StringProperty =
|
|
|
237
248
|
MetadataAttribute |
|
|
238
249
|
SpecificationElementStringProperty |
|
|
239
250
|
SpecificationRelationshipStringProperty |
|
|
240
|
-
NotationProperty
|
|
251
|
+
NotationProperty |
|
|
252
|
+
NotesProperty
|
|
241
253
|
;
|
|
242
254
|
|
|
243
255
|
ViewProperty:
|
|
@@ -262,6 +274,12 @@ DynamicViewRule:
|
|
|
262
274
|
ViewRuleAutoLayout
|
|
263
275
|
;
|
|
264
276
|
|
|
277
|
+
DynamicViewParallelSteps:
|
|
278
|
+
('parallel'|'par') '{'
|
|
279
|
+
(steps+=DynamicViewStep)*
|
|
280
|
+
'}'
|
|
281
|
+
;
|
|
282
|
+
|
|
265
283
|
DynamicViewStep:
|
|
266
284
|
source=ElementRef
|
|
267
285
|
(isBackward?='<-' | '->' | '-[' kind=[RelationshipKind] ']->' | kind=[RelationshipKind:DotId] )
|
|
@@ -426,6 +444,9 @@ ViewRuleAutoLayout:
|
|
|
426
444
|
NotationProperty:
|
|
427
445
|
key='notation' ':'? value=String ';'?
|
|
428
446
|
;
|
|
447
|
+
NotesProperty:
|
|
448
|
+
key='notes' ':'? value=String ';'?
|
|
449
|
+
;
|
|
429
450
|
|
|
430
451
|
CustomElementProperties: '{'
|
|
431
452
|
props+=(
|
|
@@ -439,8 +460,10 @@ CustomElementProperties: '{'
|
|
|
439
460
|
|
|
440
461
|
CustomRelationProperties: '{'
|
|
441
462
|
props+=(
|
|
463
|
+
RelationNavigateToProperty |
|
|
442
464
|
RelationStringProperty |
|
|
443
465
|
NotationProperty |
|
|
466
|
+
NotesProperty |
|
|
444
467
|
RelationshipStyleProperty
|
|
445
468
|
)*
|
|
446
469
|
'}'
|
|
@@ -449,6 +472,9 @@ CustomRelationProperties: '{'
|
|
|
449
472
|
NavigateToProperty:
|
|
450
473
|
key='navigateTo' value=ViewRef;
|
|
451
474
|
|
|
475
|
+
RelationNavigateToProperty:
|
|
476
|
+
key='navigateTo' value=DynamicViewRef;
|
|
477
|
+
|
|
452
478
|
// Common properties -------------------------------------
|
|
453
479
|
|
|
454
480
|
LinkProperty:
|
|
@@ -565,7 +591,8 @@ fragment IsEqual:
|
|
|
565
591
|
// Comments
|
|
566
592
|
hidden terminal BLOCK_COMMENT: /\/\*[\s\S]*?\*\//;
|
|
567
593
|
hidden terminal LINE_COMMENT: /\/\/[^\n\r]*/;
|
|
568
|
-
hidden terminal WS:
|
|
594
|
+
hidden terminal WS: /[\t ]+/;
|
|
595
|
+
hidden terminal NL: /[\r\n]+/;
|
|
569
596
|
|
|
570
597
|
// -----------------------------------
|
|
571
598
|
// Terminals
|
|
@@ -593,4 +620,4 @@ terminal String: /"[^"]*"|'[^']*'/;
|
|
|
593
620
|
// terminal TagId: HASH LETTER (LETTER | DIGIT | UNDERSCORE | DASH)*;
|
|
594
621
|
// terminal IdTerminal: (LETTER | UNDERSCORE+ (LETTER | DIGIT)) (LETTER | DIGIT | UNDERSCORE | DASH)*;
|
|
595
622
|
terminal IdTerminal: /[_]*[a-zA-Z][-\w]*/;
|
|
596
|
-
terminal Hex: /[a-zA-Z0-9]+/;
|
|
623
|
+
terminal Hex: /[a-zA-Z0-9]+/;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CompletionProviderOptions, DefaultCompletionProvider } from 'langium/lsp'
|
|
2
2
|
|
|
3
3
|
export class LikeC4CompletionProvider extends DefaultCompletionProvider {
|
|
4
|
-
readonly completionOptions = {
|
|
4
|
+
override readonly completionOptions = {
|
|
5
5
|
triggerCharacters: ['.']
|
|
6
6
|
} satisfies CompletionProviderOptions
|
|
7
7
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { LangiumDocument, MaybePromise } from 'langium'
|
|
2
2
|
import { AstUtils, GrammarUtils } from 'langium'
|
|
3
3
|
import type { DocumentLinkProvider } from 'langium/lsp'
|
|
4
|
-
import { hasProtocol, isRelative,
|
|
4
|
+
import { hasLeadingSlash, hasProtocol, isRelative, withoutBase, withoutLeadingSlash } from 'ufo'
|
|
5
5
|
import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver'
|
|
6
6
|
import { ast, isParsedLikeC4LangiumDocument } from '../ast'
|
|
7
|
-
import {
|
|
7
|
+
import { logWarnError } from '../logger'
|
|
8
8
|
import type { LikeC4Services } from '../module'
|
|
9
9
|
|
|
10
10
|
export class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
|
|
@@ -20,34 +20,46 @@ export class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
|
|
|
20
20
|
}
|
|
21
21
|
return AstUtils.streamAllContents(doc.parseResult.value)
|
|
22
22
|
.filter(ast.isLinkProperty)
|
|
23
|
-
.
|
|
23
|
+
.map((n): DocumentLink | null => {
|
|
24
24
|
try {
|
|
25
25
|
const range = GrammarUtils.findNodeForProperty(n.$cstNode, 'value')?.range
|
|
26
|
-
if (!range) {
|
|
27
|
-
return []
|
|
28
|
-
}
|
|
29
26
|
const target = this.resolveLink(doc, n.value)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
if (range && hasProtocol(target)) {
|
|
28
|
+
return {
|
|
29
|
+
range,
|
|
30
|
+
target
|
|
31
|
+
}
|
|
33
32
|
}
|
|
34
33
|
} catch (e) {
|
|
35
|
-
|
|
36
|
-
return []
|
|
34
|
+
logWarnError(e)
|
|
37
35
|
}
|
|
36
|
+
return null
|
|
38
37
|
})
|
|
38
|
+
.nonNullable()
|
|
39
39
|
.toArray()
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
resolveLink(doc: LangiumDocument, link: string): string {
|
|
43
|
-
if (hasProtocol(link)) {
|
|
43
|
+
if (hasProtocol(link) || hasLeadingSlash(link)) {
|
|
44
44
|
return link
|
|
45
45
|
}
|
|
46
|
+
const base = isRelative(link)
|
|
47
|
+
? new URL(doc.uri.toString(true))
|
|
48
|
+
: this.services.shared.workspace.WorkspaceManager.workspaceURL
|
|
49
|
+
return new URL(link, base).toString()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
relativeLink(doc: LangiumDocument, link: string): string | null {
|
|
53
|
+
if (hasLeadingSlash(link)) {
|
|
54
|
+
return withoutLeadingSlash(link)
|
|
55
|
+
}
|
|
46
56
|
if (isRelative(link)) {
|
|
47
57
|
const base = new URL(doc.uri.toString(true))
|
|
48
|
-
|
|
58
|
+
const linkURL = new URL(link, base).toString()
|
|
59
|
+
return withoutLeadingSlash(
|
|
60
|
+
withoutBase(linkURL, this.services.shared.workspace.WorkspaceManager.workspaceURL.toString())
|
|
61
|
+
)
|
|
49
62
|
}
|
|
50
|
-
|
|
51
|
-
return withBase(link, workspace.toString())
|
|
63
|
+
return null
|
|
52
64
|
}
|
|
53
65
|
}
|
|
@@ -42,7 +42,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
42
42
|
type: SemanticTokenTypes.function
|
|
43
43
|
})
|
|
44
44
|
}
|
|
45
|
-
if (ast.isNavigateToProperty(node)) {
|
|
45
|
+
if (ast.isNavigateToProperty(node) || ast.isRelationNavigateToProperty(node)) {
|
|
46
46
|
acceptor({
|
|
47
47
|
node,
|
|
48
48
|
property: 'key',
|
package/src/lsp/index.ts
CHANGED
|
@@ -4,5 +4,5 @@ export * from './DocumentHighlightProvider'
|
|
|
4
4
|
export * from './DocumentLinkProvider'
|
|
5
5
|
export * from './DocumentSymbolProvider'
|
|
6
6
|
export * from './HoverProvider'
|
|
7
|
-
export * from './RenameProvider'
|
|
7
|
+
// export * from './RenameProvider'
|
|
8
8
|
export * from './SemanticTokenProvider'
|
package/src/model/fqn-index.ts
CHANGED
|
@@ -26,7 +26,6 @@ export class FqnIndex {
|
|
|
26
26
|
services.shared.workspace.DocumentBuilder.onBuildPhase(
|
|
27
27
|
DocumentState.IndexedContent,
|
|
28
28
|
async (docs, _cancelToken) => {
|
|
29
|
-
logger.debug(`[FqnIndex] onIndexedContent ${docs.length}:\n` + printDocs(docs))
|
|
30
29
|
for (const doc of docs) {
|
|
31
30
|
if (isLikeC4LangiumDocument(doc)) {
|
|
32
31
|
delete doc.c4fqnIndex
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
+
import type * as c4 from '@likec4/core'
|
|
1
2
|
import {
|
|
2
|
-
compareByFqnHierarchically,
|
|
3
3
|
compareRelations,
|
|
4
4
|
computeColorValues,
|
|
5
5
|
type CustomColorDefinitions,
|
|
6
6
|
isElementView,
|
|
7
7
|
isScopedElementView,
|
|
8
8
|
parentFqn,
|
|
9
|
-
|
|
9
|
+
sortByFqnHierarchically,
|
|
10
10
|
type ViewID
|
|
11
11
|
} from '@likec4/core'
|
|
12
|
-
import type * as c4 from '@likec4/core'
|
|
13
12
|
import { deepEqual as eq } from 'fast-equals'
|
|
14
13
|
import type { Cancellation, LangiumDocument, LangiumDocuments, URI, WorkspaceCache } from 'langium'
|
|
15
14
|
import { Disposable, DocumentState, interruptAndCheck } from 'langium'
|
|
16
15
|
import {
|
|
17
16
|
filter,
|
|
18
|
-
find,
|
|
19
17
|
flatMap,
|
|
20
18
|
forEach,
|
|
19
|
+
groupBy,
|
|
21
20
|
indexBy,
|
|
21
|
+
isEmpty,
|
|
22
22
|
isNonNullish,
|
|
23
23
|
isNullish,
|
|
24
24
|
isNumber,
|
|
@@ -38,7 +38,8 @@ import type {
|
|
|
38
38
|
ParsedAstRelation,
|
|
39
39
|
ParsedAstSpecification,
|
|
40
40
|
ParsedAstView,
|
|
41
|
-
ParsedLikeC4LangiumDocument
|
|
41
|
+
ParsedLikeC4LangiumDocument,
|
|
42
|
+
ParsedLink
|
|
42
43
|
} from '../ast'
|
|
43
44
|
import { isParsedLikeC4LangiumDocument } from '../ast'
|
|
44
45
|
import { logError, logger, logWarnError } from '../logger'
|
|
@@ -60,16 +61,24 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
60
61
|
Object.assign(c4Specification.relationships, spec.relationships)
|
|
61
62
|
Object.assign(c4Specification.colors, spec.colors)
|
|
62
63
|
})
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
+
)
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
const customColorDefinitions: CustomColorDefinitions = mapValues(
|
|
@@ -77,7 +86,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
77
86
|
c => computeColorValues(c.color)
|
|
78
87
|
)
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
function toModelElement(doc: LangiumDocument) {
|
|
81
90
|
return ({
|
|
82
91
|
tags,
|
|
83
92
|
links: unresolvedLinks,
|
|
@@ -112,7 +121,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
112
121
|
...(color && { color }),
|
|
113
122
|
...(shape && { shape }),
|
|
114
123
|
...(icon && { icon }),
|
|
115
|
-
...(metadata && { metadata }),
|
|
124
|
+
...(metadata && !isEmpty(metadata) && { metadata }),
|
|
116
125
|
...(__kind.notation && { notation: __kind.notation }),
|
|
117
126
|
style: {
|
|
118
127
|
...(border && { border }),
|
|
@@ -138,7 +147,8 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
138
147
|
flatMap(d => map(d.c4Elements, toModelElement(d))),
|
|
139
148
|
filter(isTruthy),
|
|
140
149
|
// sort from root elements to nested, so that parent is always present
|
|
141
|
-
|
|
150
|
+
// Import to preserve the order from the source
|
|
151
|
+
sortByFqnHierarchically,
|
|
142
152
|
reduce(
|
|
143
153
|
(acc, el) => {
|
|
144
154
|
const parent = parentFqn(el.id)
|
|
@@ -153,7 +163,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
153
163
|
)
|
|
154
164
|
)
|
|
155
165
|
|
|
156
|
-
|
|
166
|
+
function toModelRelation(doc: LangiumDocument) {
|
|
157
167
|
return ({
|
|
158
168
|
astPath,
|
|
159
169
|
source,
|
|
@@ -180,7 +190,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
180
190
|
target,
|
|
181
191
|
kind,
|
|
182
192
|
id
|
|
183
|
-
}
|
|
193
|
+
} satisfies c4.Relation
|
|
184
194
|
}
|
|
185
195
|
return {
|
|
186
196
|
...(links && { links }),
|
|
@@ -188,7 +198,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
188
198
|
source,
|
|
189
199
|
target,
|
|
190
200
|
id
|
|
191
|
-
}
|
|
201
|
+
} satisfies c4.Relation
|
|
192
202
|
}
|
|
193
203
|
}
|
|
194
204
|
|
|
@@ -201,7 +211,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
201
211
|
indexBy(prop('id'))
|
|
202
212
|
)
|
|
203
213
|
|
|
204
|
-
|
|
214
|
+
function toC4View(doc: LangiumDocument) {
|
|
205
215
|
const docUri = doc.uri.toString()
|
|
206
216
|
return (parsedAstView: ParsedAstView): c4.LikeC4View => {
|
|
207
217
|
let {
|
|
@@ -210,10 +220,8 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
210
220
|
description,
|
|
211
221
|
tags,
|
|
212
222
|
links: unresolvedLinks,
|
|
213
|
-
|
|
214
223
|
// ignore this property
|
|
215
224
|
astPath: _ignore,
|
|
216
|
-
|
|
217
225
|
// model should include discriminant __
|
|
218
226
|
...model
|
|
219
227
|
} = parsedAstView
|
|
@@ -440,19 +448,22 @@ export class LikeC4ModelBuilder {
|
|
|
440
448
|
}
|
|
441
449
|
let computedView = result.view
|
|
442
450
|
|
|
443
|
-
const allElementViews =
|
|
444
|
-
|
|
451
|
+
const allElementViews = pipe(
|
|
452
|
+
model.views,
|
|
453
|
+
values(),
|
|
454
|
+
filter(isScopedElementView),
|
|
455
|
+
filter(v => v.id !== viewId),
|
|
456
|
+
groupBy(v => v.viewOf)
|
|
445
457
|
)
|
|
446
458
|
|
|
447
|
-
computedView.nodes
|
|
459
|
+
for (const node of computedView.nodes) {
|
|
448
460
|
if (!node.navigateTo) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
node.navigateTo = navigateTo.id
|
|
461
|
+
const viewsOfNode = allElementViews[node.id]
|
|
462
|
+
if (viewsOfNode) {
|
|
463
|
+
node.navigateTo = viewsOfNode[0].id
|
|
453
464
|
}
|
|
454
465
|
}
|
|
455
|
-
}
|
|
466
|
+
}
|
|
456
467
|
|
|
457
468
|
const previous = this.previousViews[viewId]
|
|
458
469
|
computedView = previous && eq(computedView, previous) ? previous : computedView
|
|
@@ -2,7 +2,7 @@ import { type HexColorLiteral, invariant, isNonEmptyArray, nonexhaustive } from
|
|
|
2
2
|
import type * as c4 from '@likec4/core'
|
|
3
3
|
import type { AstNode, LangiumDocument } from 'langium'
|
|
4
4
|
import { AstUtils, CstUtils } from 'langium'
|
|
5
|
-
import { filter, flatMap, isDefined, isNonNullish, isTruthy, mapToObj, pipe } from 'remeda'
|
|
5
|
+
import { filter, first, flatMap, isDefined, isNonNullish, isTruthy, map, mapToObj, pipe } from 'remeda'
|
|
6
6
|
import stripIndent from 'strip-indent'
|
|
7
7
|
import type { Writable } from 'type-fest'
|
|
8
8
|
import type {
|
|
@@ -247,6 +247,14 @@ export class LikeC4ModelParser {
|
|
|
247
247
|
p => [p.key, p.value]
|
|
248
248
|
)
|
|
249
249
|
|
|
250
|
+
const navigateTo = pipe(
|
|
251
|
+
astNode.body?.props ?? [],
|
|
252
|
+
filter(ast.isRelationNavigateToProperty),
|
|
253
|
+
map(p => p.value.view.ref?.name),
|
|
254
|
+
filter(isTruthy),
|
|
255
|
+
first()
|
|
256
|
+
)
|
|
257
|
+
|
|
250
258
|
const title = removeIndent(astNode.title ?? bodyProps.title) ?? ''
|
|
251
259
|
const description = removeIndent(bodyProps.description)
|
|
252
260
|
const technology = removeIndent(astNode.technology) ?? toSingleLine(bodyProps.technology)
|
|
@@ -269,7 +277,8 @@ export class LikeC4ModelParser {
|
|
|
269
277
|
...(kind && { kind }),
|
|
270
278
|
...(tags && { tags }),
|
|
271
279
|
...(isNonEmptyArray(links) && { links }),
|
|
272
|
-
...toRelationshipStyleExcludeDefaults(styleProp?.props)
|
|
280
|
+
...toRelationshipStyleExcludeDefaults(styleProp?.props),
|
|
281
|
+
...(navigateTo && { navigateTo: navigateTo as c4.ViewID })
|
|
273
282
|
}
|
|
274
283
|
}
|
|
275
284
|
|
|
@@ -514,7 +523,7 @@ export class LikeC4ModelParser {
|
|
|
514
523
|
const props = astNode.custom?.props ?? []
|
|
515
524
|
return props.reduce(
|
|
516
525
|
(acc, prop) => {
|
|
517
|
-
if (ast.isRelationStringProperty(prop)) {
|
|
526
|
+
if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
|
|
518
527
|
if (isDefined(prop.value)) {
|
|
519
528
|
acc.customRelation[prop.key] = removeIndent(prop.value) ?? ''
|
|
520
529
|
}
|
|
@@ -539,9 +548,10 @@ export class LikeC4ModelParser {
|
|
|
539
548
|
}
|
|
540
549
|
return acc
|
|
541
550
|
}
|
|
542
|
-
if (ast.
|
|
543
|
-
|
|
544
|
-
|
|
551
|
+
if (ast.isRelationNavigateToProperty(prop)) {
|
|
552
|
+
const viewId = prop.value.view.ref?.name
|
|
553
|
+
if (isTruthy(viewId)) {
|
|
554
|
+
acc.customRelation.navigateTo = viewId as c4.ViewID
|
|
545
555
|
}
|
|
546
556
|
return acc
|
|
547
557
|
}
|
|
@@ -624,6 +634,12 @@ export class LikeC4ModelParser {
|
|
|
624
634
|
}
|
|
625
635
|
}
|
|
626
636
|
|
|
637
|
+
private parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps {
|
|
638
|
+
return {
|
|
639
|
+
__parallel: node.steps.map(step => this.parseDynamicStep(step))
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
627
643
|
private parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep {
|
|
628
644
|
const sourceEl = elementRef(node.source)
|
|
629
645
|
if (!sourceEl) {
|
|
@@ -635,9 +651,7 @@ export class LikeC4ModelParser {
|
|
|
635
651
|
}
|
|
636
652
|
let source = this.resolveFqn(sourceEl)
|
|
637
653
|
let target = this.resolveFqn(targetEl)
|
|
638
|
-
const title = removeIndent(
|
|
639
|
-
node.title ?? node.custom?.props.find((p): p is ast.RelationStringProperty => p.key === 'title')?.value
|
|
640
|
-
) ?? ''
|
|
654
|
+
const title = removeIndent(node.title) ?? null
|
|
641
655
|
|
|
642
656
|
let step: Writable<c4.DynamicViewStep> = {
|
|
643
657
|
source,
|
|
@@ -655,31 +669,35 @@ export class LikeC4ModelParser {
|
|
|
655
669
|
if (Array.isArray(node.custom?.props)) {
|
|
656
670
|
for (const prop of node.custom.props) {
|
|
657
671
|
try {
|
|
658
|
-
if (ast.isRelationStringProperty(prop)) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
step[prop.key] = value
|
|
672
|
+
if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
|
|
673
|
+
if (isDefined(prop.value)) {
|
|
674
|
+
step[prop.key] = removeIndent(prop.value) ?? ''
|
|
662
675
|
}
|
|
663
676
|
continue
|
|
664
677
|
}
|
|
665
678
|
if (ast.isArrowProperty(prop)) {
|
|
666
|
-
|
|
679
|
+
if (isDefined(prop.value)) {
|
|
680
|
+
step[prop.key] = prop.value
|
|
681
|
+
}
|
|
667
682
|
continue
|
|
668
683
|
}
|
|
669
684
|
if (ast.isColorProperty(prop)) {
|
|
670
685
|
const value = toColor(prop)
|
|
671
|
-
if (
|
|
686
|
+
if (isDefined(value)) {
|
|
672
687
|
step[prop.key] = value
|
|
673
688
|
}
|
|
674
689
|
continue
|
|
675
690
|
}
|
|
676
691
|
if (ast.isLineProperty(prop)) {
|
|
677
|
-
|
|
692
|
+
if (isDefined(prop.value)) {
|
|
693
|
+
step[prop.key] = prop.value
|
|
694
|
+
}
|
|
678
695
|
continue
|
|
679
696
|
}
|
|
680
|
-
if (ast.
|
|
681
|
-
|
|
682
|
-
|
|
697
|
+
if (ast.isRelationNavigateToProperty(prop)) {
|
|
698
|
+
const viewId = prop.value.view.ref?.name
|
|
699
|
+
if (isTruthy(viewId)) {
|
|
700
|
+
step.navigateTo = viewId as c4.ViewID
|
|
683
701
|
}
|
|
684
702
|
continue
|
|
685
703
|
}
|
|
@@ -845,13 +863,17 @@ export class LikeC4ModelParser {
|
|
|
845
863
|
steps: body.steps.reduce((acc, n) => {
|
|
846
864
|
try {
|
|
847
865
|
if (isValid(n)) {
|
|
848
|
-
|
|
866
|
+
if (ast.isDynamicViewParallelSteps(n)) {
|
|
867
|
+
acc.push(this.parseDynamicParallelSteps(n))
|
|
868
|
+
} else {
|
|
869
|
+
acc.push(this.parseDynamicStep(n))
|
|
870
|
+
}
|
|
849
871
|
}
|
|
850
872
|
} catch (e) {
|
|
851
873
|
logWarnError(e)
|
|
852
874
|
}
|
|
853
875
|
return acc
|
|
854
|
-
}, [] as c4.
|
|
876
|
+
}, [] as c4.DynamicViewStepOrParallel[]),
|
|
855
877
|
...(manualLayout && { manualLayout })
|
|
856
878
|
}
|
|
857
879
|
}
|