@likec4/language-server 1.17.1 → 1.18.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 +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.mjs +2 -2
- 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 +2 -2
- package/dist/protocol.d.cts +8 -5
- package/dist/protocol.d.mts +8 -5
- package/dist/protocol.d.ts +8 -5
- package/dist/shared/{language-server.DKV_FdPN.cjs → language-server.CO_nmHiL.cjs} +5598 -4213
- package/dist/shared/{language-server.BQRvVmE0.d.cts → language-server.Da6ey08o.d.cts} +390 -74
- package/dist/shared/{language-server.BysPcTxr.d.ts → language-server.De7S3e5Z.d.ts} +390 -74
- package/dist/shared/{language-server._wkyPgso.d.mts → language-server.Dj4iDjtB.d.mts} +390 -74
- package/dist/shared/{language-server.BIbAD1T-.mjs → language-server.oO_9JoAG.mjs} +5604 -4230
- package/package.json +11 -25
- package/src/Rpc.ts +6 -3
- package/src/ast.ts +124 -71
- package/src/generated/ast.ts +655 -39
- package/src/generated/grammar.ts +1 -1
- package/src/index.ts +1 -0
- package/src/like-c4.langium +170 -22
- package/src/logger.ts +7 -2
- package/src/lsp/CodeLensProvider.ts +0 -1
- package/src/lsp/CompletionProvider.ts +17 -2
- package/src/lsp/DocumentSymbolProvider.ts +5 -2
- package/src/lsp/HoverProvider.ts +34 -2
- package/src/lsp/SemanticTokenProvider.ts +58 -32
- package/src/model/deployments-index.ts +218 -0
- package/src/model/fqn-computation.ts +1 -1
- package/src/model/fqn-index.ts +0 -1
- package/src/model/index.ts +1 -0
- package/src/model/model-builder.ts +172 -37
- package/src/model/model-locator.ts +36 -7
- package/src/model/model-parser.ts +554 -92
- package/src/model-change/changeViewLayout.ts +2 -2
- package/src/module.ts +10 -4
- package/src/protocol.ts +10 -6
- package/src/references/index.ts +1 -0
- package/src/references/name-provider.ts +37 -0
- package/src/references/scope-computation.ts +130 -21
- package/src/references/scope-provider.ts +63 -36
- package/src/shared/NodeKindProvider.ts +15 -3
- package/src/utils/deploymentRef.ts +31 -0
- package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
- package/src/utils/stringHash.ts +2 -2
- package/src/validation/_shared.ts +7 -5
- package/src/validation/deployment-checks.ts +144 -0
- package/src/validation/dynamic-view-step.ts +1 -1
- package/src/validation/index.ts +7 -0
- package/src/validation/relation.ts +1 -1
- package/src/validation/view-predicates/deployments.ts +56 -0
- package/src/validation/view-predicates/index.ts +1 -0
- package/src/view-utils/assignNavigateTo.ts +6 -5
- package/src/view-utils/index.ts +0 -1
- package/dist/model-graph/index.cjs +0 -10
- package/dist/model-graph/index.d.cts +0 -81
- package/dist/model-graph/index.d.mts +0 -81
- package/dist/model-graph/index.d.ts +0 -81
- package/dist/model-graph/index.mjs +0 -1
- package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
- package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
- package/src/model-graph/LikeC4ModelGraph.ts +0 -338
- package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
- package/src/model-graph/compute-view/compute.ts +0 -788
- package/src/model-graph/compute-view/index.ts +0 -33
- package/src/model-graph/compute-view/predicates.ts +0 -509
- package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
- package/src/model-graph/dynamic-view/compute.ts +0 -313
- package/src/model-graph/dynamic-view/index.ts +0 -29
- package/src/model-graph/index.ts +0 -3
- package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
- package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
- package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
- package/src/model-graph/utils/buildComputeNodes.ts +0 -113
- package/src/model-graph/utils/buildElementNotations.ts +0 -63
- package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
- package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
- package/src/model-graph/utils/sortNodes.ts +0 -105
- package/src/model-graph/utils/uniqueTags.test.ts +0 -42
- package/src/model-graph/utils/uniqueTags.ts +0 -19
- package/src/utils/graphlib.ts +0 -9
- package/src/view-utils/resolve-extended-views.ts +0 -66
- package/src/view-utils/resolve-global-rules.ts +0 -88
- package/src/view-utils/view-hash.ts +0 -27
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { invariant, type ViewChange } from '@likec4/core'
|
|
2
2
|
import { GrammarUtils } from 'langium'
|
|
3
|
-
import { isNumber } from 'remeda'
|
|
3
|
+
import { findLast, isNumber } from 'remeda'
|
|
4
4
|
import { TextEdit } from 'vscode-languageserver-types'
|
|
5
5
|
import { ast, type ParsedAstView, type ParsedLikeC4LangiumDocument, toAstViewLayoutDirection } from '../ast'
|
|
6
6
|
import type { LikeC4Services } from '../module'
|
|
@@ -24,7 +24,7 @@ export function changeViewLayout(_services: LikeC4Services, {
|
|
|
24
24
|
const viewCstNode = viewAst.$cstNode
|
|
25
25
|
invariant(viewCstNode, 'viewCstNode')
|
|
26
26
|
const newdirection = toAstViewLayoutDirection(layout.direction)
|
|
27
|
-
const existingRule = viewAst.body.rules
|
|
27
|
+
const existingRule = findLast(viewAst.body.rules, ast.isViewRuleAutoLayout) as ast.ViewRuleAutoLayout | undefined
|
|
28
28
|
|
|
29
29
|
let newRule = `autoLayout ${newdirection}`
|
|
30
30
|
|
package/src/module.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EmptyFileSystem, inject, type Module, WorkspaceCache } from 'langium'
|
|
1
|
+
import { DocumentCache, EmptyFileSystem, inject, type Module, WorkspaceCache } from 'langium'
|
|
2
2
|
import {
|
|
3
3
|
createDefaultModule,
|
|
4
4
|
createDefaultSharedModule,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type PartialLangiumServices,
|
|
9
9
|
type PartialLangiumSharedServices
|
|
10
10
|
} from 'langium/lsp'
|
|
11
|
+
import { LikeC4Formatter } from './formatting/LikeC4Formatter'
|
|
11
12
|
import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module'
|
|
12
13
|
import { logErrorToTelemetry, logToLspConnection } from './logger'
|
|
13
14
|
import {
|
|
@@ -19,13 +20,12 @@ import {
|
|
|
19
20
|
LikeC4HoverProvider,
|
|
20
21
|
LikeC4SemanticTokenProvider
|
|
21
22
|
} from './lsp'
|
|
22
|
-
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model'
|
|
23
|
+
import { DeploymentsIndex, FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model'
|
|
23
24
|
import { LikeC4ModelChanges } from './model-change/ModelChanges'
|
|
24
|
-
import { LikeC4ScopeComputation, LikeC4ScopeProvider } from './references'
|
|
25
|
+
import { LikeC4NameProvider, LikeC4ScopeComputation, LikeC4ScopeProvider } from './references'
|
|
25
26
|
import { Rpc } from './Rpc'
|
|
26
27
|
import { LikeC4WorkspaceManager, NodeKindProvider, WorkspaceSymbolProvider } from './shared'
|
|
27
28
|
import { registerValidationChecks } from './validation'
|
|
28
|
-
import { LikeC4Formatter } from './formatting/LikeC4Formatter'
|
|
29
29
|
|
|
30
30
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
31
|
type Constructor<T, Arguments extends unknown[] = any[]> = new(...arguments_: Arguments) => T
|
|
@@ -61,8 +61,10 @@ const LikeC4SharedModule: Module<
|
|
|
61
61
|
export interface LikeC4AddedServices {
|
|
62
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
63
|
WorkspaceCache: WorkspaceCache<string, any>
|
|
64
|
+
DocumentCache: DocumentCache<string, any>
|
|
64
65
|
Rpc: Rpc
|
|
65
66
|
likec4: {
|
|
67
|
+
DeploymentsIndex: DeploymentsIndex
|
|
66
68
|
FqnIndex: FqnIndex
|
|
67
69
|
ModelParser: LikeC4ModelParser
|
|
68
70
|
ModelBuilder: LikeC4ModelBuilder
|
|
@@ -80,6 +82,7 @@ export interface LikeC4AddedServices {
|
|
|
80
82
|
DocumentLinkProvider: LikeC4DocumentLinkProvider
|
|
81
83
|
}
|
|
82
84
|
references: {
|
|
85
|
+
NameProvider: LikeC4NameProvider
|
|
83
86
|
ScopeComputation: LikeC4ScopeComputation
|
|
84
87
|
ScopeProvider: LikeC4ScopeProvider
|
|
85
88
|
}
|
|
@@ -94,8 +97,10 @@ function bind<T>(Type: Constructor<T, [LikeC4Services]>) {
|
|
|
94
97
|
|
|
95
98
|
export const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC4AddedServices> = {
|
|
96
99
|
WorkspaceCache: (services: LikeC4Services) => new WorkspaceCache(services.shared),
|
|
100
|
+
DocumentCache: (services: LikeC4Services) => new DocumentCache(services.shared),
|
|
97
101
|
Rpc: bind(Rpc),
|
|
98
102
|
likec4: {
|
|
103
|
+
DeploymentsIndex: bind(DeploymentsIndex),
|
|
99
104
|
ModelChanges: bind(LikeC4ModelChanges),
|
|
100
105
|
FqnIndex: bind(FqnIndex),
|
|
101
106
|
ModelParser: bind(LikeC4ModelParser),
|
|
@@ -114,6 +119,7 @@ export const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC
|
|
|
114
119
|
Formatter: bind(LikeC4Formatter)
|
|
115
120
|
},
|
|
116
121
|
references: {
|
|
122
|
+
NameProvider: bind(LikeC4NameProvider),
|
|
117
123
|
ScopeComputation: bind(LikeC4ScopeComputation),
|
|
118
124
|
ScopeProvider: bind(LikeC4ScopeProvider)
|
|
119
125
|
}
|
package/src/protocol.ts
CHANGED
|
@@ -3,9 +3,9 @@ import type {
|
|
|
3
3
|
ComputedView,
|
|
4
4
|
Fqn,
|
|
5
5
|
ParsedLikeC4Model,
|
|
6
|
-
|
|
6
|
+
RelationId,
|
|
7
7
|
ViewChange,
|
|
8
|
-
|
|
8
|
+
ViewId
|
|
9
9
|
} from '@likec4/core'
|
|
10
10
|
import { NotificationType, RequestType, RequestType0 } from 'vscode-jsonrpc'
|
|
11
11
|
import type { DocumentUri, Location } from 'vscode-languageserver-types'
|
|
@@ -30,7 +30,7 @@ export const fetchComputedModel = new RequestType<
|
|
|
30
30
|
)
|
|
31
31
|
export type FetchComputedModelRequest = typeof fetchComputedModel
|
|
32
32
|
|
|
33
|
-
export const computeView = new RequestType<{ viewId:
|
|
33
|
+
export const computeView = new RequestType<{ viewId: ViewId }, { view: ComputedView | null }, void>(
|
|
34
34
|
'likec4/computeView'
|
|
35
35
|
)
|
|
36
36
|
export type ComputeViewRequest = typeof computeView
|
|
@@ -47,17 +47,21 @@ export type LocateParams =
|
|
|
47
47
|
property?: string
|
|
48
48
|
}
|
|
49
49
|
| {
|
|
50
|
-
relation:
|
|
50
|
+
relation: RelationId
|
|
51
51
|
}
|
|
52
52
|
| {
|
|
53
|
-
|
|
53
|
+
deployment: Fqn
|
|
54
|
+
property?: string
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
view: ViewId
|
|
54
58
|
}
|
|
55
59
|
export const locate = new RequestType<LocateParams, Location | null, void>('likec4/locate')
|
|
56
60
|
export type LocateRequest = typeof locate
|
|
57
61
|
// #endregion
|
|
58
62
|
|
|
59
63
|
export interface ChangeViewRequestParams {
|
|
60
|
-
viewId:
|
|
64
|
+
viewId: ViewId
|
|
61
65
|
change: ViewChange
|
|
62
66
|
}
|
|
63
67
|
export const changeView = new RequestType<ChangeViewRequestParams, Location | null, void>('likec4/change-view')
|
package/src/references/index.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { nonNullable } from '@likec4/core'
|
|
2
|
+
import { type AstNode, type CstNode, DefaultNameProvider, isNamed, type NamedAstNode } from 'langium'
|
|
3
|
+
import { ast } from '../ast'
|
|
4
|
+
import type { LikeC4Services } from '../module'
|
|
5
|
+
|
|
6
|
+
export class LikeC4NameProvider extends DefaultNameProvider {
|
|
7
|
+
constructor(protected services: LikeC4Services) {
|
|
8
|
+
super()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public getNameStrict(node: AstNode): string {
|
|
12
|
+
return nonNullable(
|
|
13
|
+
this.getName(node),
|
|
14
|
+
`Failed getName for ${this.services.workspace.AstNodeLocator.getAstNodePath(node)}`
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override getName(node: AstNode): string | undefined {
|
|
19
|
+
if (isNamed(node)) {
|
|
20
|
+
return node.name
|
|
21
|
+
}
|
|
22
|
+
if (ast.isDeployedInstance(node)) {
|
|
23
|
+
return node.element.el.$refText
|
|
24
|
+
}
|
|
25
|
+
return undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override getNameNode(node: AstNode): CstNode | undefined {
|
|
29
|
+
if (isNamed(node)) {
|
|
30
|
+
return super.getNameNode(node)
|
|
31
|
+
}
|
|
32
|
+
if (ast.isDeployedInstance(node)) {
|
|
33
|
+
return node.element.el.$refNode
|
|
34
|
+
}
|
|
35
|
+
return undefined
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -6,21 +6,38 @@ import {
|
|
|
6
6
|
MultiMap,
|
|
7
7
|
type PrecomputedScopes
|
|
8
8
|
} from 'langium'
|
|
9
|
-
import { isNullish, isTruthy } from 'remeda'
|
|
9
|
+
import { entries, filter, flatMap, forEach, forEachObj, groupBy, isNullish, isTruthy, pipe } from 'remeda'
|
|
10
10
|
import type { CancellationToken } from 'vscode-languageserver'
|
|
11
11
|
import { ast, type LikeC4LangiumDocument } from '../ast'
|
|
12
|
-
import { logError } from '../logger'
|
|
12
|
+
import { logError, logWarnError } from '../logger'
|
|
13
|
+
import type { LikeC4Services } from '../module'
|
|
13
14
|
|
|
14
15
|
type ElementsContainer = ast.Model | ast.ElementBody | ast.ExtendElementBody
|
|
16
|
+
type DeploymentsContainer = ast.ModelDeployments | ast.DeploymentNodeBody
|
|
17
|
+
|
|
18
|
+
function uniqueDescriptions(
|
|
19
|
+
descs: AstNodeDescription[]
|
|
20
|
+
): AstNodeDescription[] {
|
|
21
|
+
return pipe(
|
|
22
|
+
descs,
|
|
23
|
+
groupBy(desc => `${desc.type}.${desc.name}`),
|
|
24
|
+
entries(),
|
|
25
|
+
flatMap(([_, descs]) => descs.length === 1 ? descs : [])
|
|
26
|
+
)
|
|
27
|
+
}
|
|
15
28
|
|
|
16
29
|
export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
30
|
+
constructor(services: LikeC4Services) {
|
|
31
|
+
super(services)
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
override async computeExports(
|
|
18
35
|
document: LikeC4LangiumDocument,
|
|
19
36
|
_cancelToken?: CancellationToken
|
|
20
37
|
): Promise<AstNodeDescription[]> {
|
|
21
38
|
const docExports: AstNodeDescription[] = []
|
|
22
39
|
try {
|
|
23
|
-
const { specifications, models, views, globals, likec4lib } = document.parseResult.value
|
|
40
|
+
const { specifications, models, views, globals, likec4lib, deployments } = document.parseResult.value
|
|
24
41
|
|
|
25
42
|
// Process library
|
|
26
43
|
this.exportLibrary(likec4lib, docExports, document)
|
|
@@ -36,6 +53,8 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
36
53
|
|
|
37
54
|
// Process global
|
|
38
55
|
this.exportGlobals(globals, docExports, document)
|
|
56
|
+
|
|
57
|
+
this.exportDeployments(deployments, docExports, document)
|
|
39
58
|
} catch (e) {
|
|
40
59
|
logError(e)
|
|
41
60
|
}
|
|
@@ -43,14 +62,15 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
private exportViews(
|
|
46
|
-
|
|
65
|
+
modelViews: ast.ModelViews[] | undefined,
|
|
47
66
|
docExports: AstNodeDescription[],
|
|
48
67
|
document: LikeC4LangiumDocument
|
|
49
68
|
) {
|
|
69
|
+
const views = modelViews?.flatMap(m => m.views)
|
|
50
70
|
if (isNullish(views) || views.length === 0) {
|
|
51
71
|
return
|
|
52
72
|
}
|
|
53
|
-
for (const viewAst of views
|
|
73
|
+
for (const viewAst of views) {
|
|
54
74
|
try {
|
|
55
75
|
if (isTruthy(viewAst.name)) {
|
|
56
76
|
docExports.push(this.descriptions.createDescription(viewAst, viewAst.name, document))
|
|
@@ -139,12 +159,14 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
139
159
|
const spec of specifications.flatMap(s => [
|
|
140
160
|
...s.elements,
|
|
141
161
|
...s.relationships,
|
|
162
|
+
...s.deploymentNodes,
|
|
142
163
|
...s.tags,
|
|
143
164
|
...s.colors
|
|
144
165
|
])
|
|
145
166
|
) {
|
|
146
167
|
try {
|
|
147
168
|
switch (true) {
|
|
169
|
+
case ast.isSpecificationDeploymentNodeKind(spec):
|
|
148
170
|
case ast.isSpecificationElementKind(spec): {
|
|
149
171
|
if (isTruthy(spec.kind.name)) {
|
|
150
172
|
docExports.push(
|
|
@@ -188,21 +210,58 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
188
210
|
}
|
|
189
211
|
}
|
|
190
212
|
|
|
213
|
+
private exportDeployments(
|
|
214
|
+
modelDeployments: ast.ModelDeployments[] | undefined,
|
|
215
|
+
docExports: AstNodeDescription[],
|
|
216
|
+
document: LikeC4LangiumDocument
|
|
217
|
+
) {
|
|
218
|
+
const nodes = modelDeployments?.flatMap(m => m.elements)
|
|
219
|
+
if (isNullish(nodes) || nodes.length === 0) {
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
for (const node of nodes) {
|
|
223
|
+
try {
|
|
224
|
+
if (ast.isDeploymentNode(node) && isTruthy(node.name)) {
|
|
225
|
+
docExports.push(this.descriptions.createDescription(node, node.name, document))
|
|
226
|
+
}
|
|
227
|
+
} catch (e) {
|
|
228
|
+
logWarnError(e)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
191
233
|
override computeLocalScopes(
|
|
192
234
|
document: LikeC4LangiumDocument,
|
|
193
235
|
_cancelToken?: CancellationToken
|
|
194
236
|
): Promise<PrecomputedScopes> {
|
|
195
237
|
return new Promise(resolve => {
|
|
196
238
|
const root = document.parseResult.value
|
|
239
|
+
const descendants = [] as AstNodeDescription[]
|
|
197
240
|
const scopes = new MultiMap<AstNode, AstNodeDescription>()
|
|
241
|
+
|
|
198
242
|
for (const model of root.models) {
|
|
199
243
|
try {
|
|
200
|
-
|
|
201
|
-
|
|
244
|
+
descendants.push(
|
|
245
|
+
...this.processContainer(model, scopes, document)
|
|
246
|
+
)
|
|
202
247
|
} catch (e) {
|
|
203
248
|
logError(e)
|
|
204
249
|
}
|
|
205
250
|
}
|
|
251
|
+
for (const deployment of root.deployments) {
|
|
252
|
+
try {
|
|
253
|
+
descendants.push(
|
|
254
|
+
...this.processDeployments(deployment, scopes, document)
|
|
255
|
+
)
|
|
256
|
+
} catch (e) {
|
|
257
|
+
logWarnError(e)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
uniqueDescriptions(descendants).forEach(desc => {
|
|
262
|
+
scopes.add(root, desc)
|
|
263
|
+
})
|
|
264
|
+
|
|
206
265
|
resolve(scopes)
|
|
207
266
|
})
|
|
208
267
|
}
|
|
@@ -211,9 +270,10 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
211
270
|
container: ElementsContainer,
|
|
212
271
|
scopes: PrecomputedScopes,
|
|
213
272
|
document: LikeC4LangiumDocument
|
|
214
|
-
) {
|
|
273
|
+
): AstNodeDescription[] {
|
|
215
274
|
const localScope = new MultiMap<string, AstNodeDescription>()
|
|
216
|
-
const
|
|
275
|
+
const descedants = [] as AstNodeDescription[]
|
|
276
|
+
|
|
217
277
|
for (const el of container.elements) {
|
|
218
278
|
if (ast.isRelation(el)) {
|
|
219
279
|
continue
|
|
@@ -231,25 +291,74 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
231
291
|
|
|
232
292
|
if (subcontainer && subcontainer.elements.length > 0) {
|
|
233
293
|
try {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
294
|
+
descedants.push(
|
|
295
|
+
...this.processContainer(subcontainer, scopes, document)
|
|
296
|
+
)
|
|
238
297
|
} catch (e) {
|
|
239
|
-
|
|
298
|
+
logWarnError(e)
|
|
240
299
|
}
|
|
241
300
|
}
|
|
242
301
|
}
|
|
243
302
|
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
303
|
+
if (descedants.length) {
|
|
304
|
+
pipe(
|
|
305
|
+
descedants,
|
|
306
|
+
filter(desc => !localScope.has(desc.name)),
|
|
307
|
+
groupBy(desc => desc.name),
|
|
308
|
+
forEachObj((descs, name) => {
|
|
309
|
+
if (descs.length === 1) {
|
|
310
|
+
localScope.add(name, descs[0])
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
const local = [...localScope.values()]
|
|
316
|
+
scopes.addAll(container, local)
|
|
317
|
+
return local
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
protected processDeployments(
|
|
321
|
+
container: DeploymentsContainer,
|
|
322
|
+
scopes: PrecomputedScopes,
|
|
323
|
+
document: LikeC4LangiumDocument
|
|
324
|
+
): AstNodeDescription[] {
|
|
325
|
+
const localnames = new Set<string>()
|
|
326
|
+
const descedants = [] as AstNodeDescription[]
|
|
327
|
+
|
|
328
|
+
for (const el of container.elements) {
|
|
329
|
+
if (ast.isDeploymentRelation(el)) {
|
|
330
|
+
continue
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
let name = this.nameProvider.getName(el)
|
|
334
|
+
if (isTruthy(name)) {
|
|
335
|
+
const desc = this.descriptions.createDescription(el, name, document)
|
|
336
|
+
scopes.add(container, desc)
|
|
337
|
+
localnames.add(desc.name)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (ast.isDeploymentNode(el) && el.body) {
|
|
341
|
+
try {
|
|
342
|
+
descedants.push(
|
|
343
|
+
...this.processDeployments(el.body, scopes, document)
|
|
344
|
+
)
|
|
345
|
+
} catch (e) {
|
|
346
|
+
logWarnError(e)
|
|
249
347
|
}
|
|
250
348
|
}
|
|
251
349
|
}
|
|
252
|
-
|
|
253
|
-
|
|
350
|
+
if (descedants.length > 0) {
|
|
351
|
+
pipe(
|
|
352
|
+
descedants,
|
|
353
|
+
filter(desc => !localnames.has(desc.name)),
|
|
354
|
+
groupBy(desc => desc.name),
|
|
355
|
+
forEachObj((descs, name) => {
|
|
356
|
+
if (descs.length === 1) {
|
|
357
|
+
scopes.add(container, descs[0])
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
return [...scopes.get(container).values()]
|
|
254
363
|
}
|
|
255
364
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { invariant } from '@likec4/core'
|
|
2
1
|
import type * as c4 from '@likec4/core'
|
|
2
|
+
import { nonexhaustive } from '@likec4/core'
|
|
3
3
|
import type { AstNode } from 'langium'
|
|
4
4
|
import {
|
|
5
5
|
type AstNodeDescription,
|
|
@@ -16,20 +16,22 @@ import {
|
|
|
16
16
|
StreamImpl,
|
|
17
17
|
StreamScope
|
|
18
18
|
} from 'langium'
|
|
19
|
-
import { ast } from '../ast'
|
|
20
|
-
import { elementRef, getFqnElementRef } from '../elementRef'
|
|
19
|
+
import { ast, isLikeC4LangiumDocument } from '../ast'
|
|
21
20
|
import { logger } from '../logger'
|
|
22
|
-
import type { FqnIndex } from '../model
|
|
21
|
+
import type { DeploymentsIndex, FqnIndex } from '../model'
|
|
23
22
|
import type { LikeC4Services } from '../module'
|
|
23
|
+
import { elementRef, getFqnElementRef } from '../utils/elementRef'
|
|
24
24
|
|
|
25
25
|
const { getDocument } = AstUtils
|
|
26
26
|
|
|
27
27
|
export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
28
|
+
private deploymentsIndex: DeploymentsIndex
|
|
28
29
|
private fqnIndex: FqnIndex
|
|
29
30
|
|
|
30
31
|
constructor(services: LikeC4Services) {
|
|
31
32
|
super(services)
|
|
32
33
|
this.fqnIndex = services.likec4.FqnIndex
|
|
34
|
+
this.deploymentsIndex = services.likec4.DeploymentsIndex
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
private directChildrenOf(parent: c4.Fqn): Stream<AstNodeDescription> {
|
|
@@ -87,15 +89,20 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
87
89
|
override getScope(context: ReferenceInfo): Scope {
|
|
88
90
|
try {
|
|
89
91
|
const referenceType = this.reflection.getReferenceType(context)
|
|
90
|
-
if (referenceType !== ast.Element) {
|
|
91
|
-
return this.getGlobalScope(referenceType)
|
|
92
|
-
}
|
|
93
92
|
try {
|
|
94
93
|
const container = context.container
|
|
94
|
+
if (ast.isDeploymentRef(container)) {
|
|
95
|
+
return this.getScopeForDeploymentRef(container, context)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (referenceType !== ast.Element) {
|
|
99
|
+
return this.getGlobalScope(referenceType, context)
|
|
100
|
+
}
|
|
101
|
+
|
|
95
102
|
if (ast.isFqnElementRef(container) && context.property === 'el') {
|
|
96
103
|
const parent = container.parent
|
|
97
104
|
if (!parent) {
|
|
98
|
-
return this.getGlobalScope(referenceType)
|
|
105
|
+
return this.getGlobalScope(referenceType, context)
|
|
99
106
|
}
|
|
100
107
|
return new StreamScope(this.directChildrenOf(getFqnElementRef(parent)))
|
|
101
108
|
}
|
|
@@ -119,7 +126,7 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
119
126
|
return this.computeScope(context)
|
|
120
127
|
} catch (e) {
|
|
121
128
|
logger.warn(e)
|
|
122
|
-
return this.getGlobalScope(referenceType)
|
|
129
|
+
return this.getGlobalScope(referenceType, context)
|
|
123
130
|
}
|
|
124
131
|
} catch (e) {
|
|
125
132
|
logger.warn(e)
|
|
@@ -127,42 +134,62 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
127
134
|
}
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
protected
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
protected getScopeForDeploymentRef(container: ast.DeploymentRef, context: ReferenceInfo) {
|
|
138
|
+
const parent = container.parent
|
|
139
|
+
if (!parent) {
|
|
140
|
+
return new MapScope(
|
|
141
|
+
// First preference for deployment nodes
|
|
142
|
+
this.computeScope(context, ast.DeploymentNode).getAllElements(),
|
|
143
|
+
// Second preference for deployed instances
|
|
144
|
+
this.computeScope(context, ast.DeployedInstance)
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
const parentRef = parent.value.ref
|
|
148
|
+
if (!parentRef) {
|
|
149
|
+
return EMPTY_SCOPE
|
|
150
|
+
}
|
|
151
|
+
if (ast.isDeploymentNode(parentRef)) {
|
|
152
|
+
return new StreamScope(this.deploymentsIndex.nested(parentRef))
|
|
153
|
+
}
|
|
154
|
+
if (ast.isDeployedInstance(parentRef)) {
|
|
155
|
+
return new StreamScope(this.scopeElementRef(parentRef.element))
|
|
156
|
+
}
|
|
157
|
+
if (ast.isElement(parentRef)) {
|
|
158
|
+
return new StreamScope(this.uniqueDescedants(() => parentRef))
|
|
159
|
+
}
|
|
160
|
+
return nonexhaustive(parentRef)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
protected computeScope(context: ReferenceInfo, referenceType = this.reflection.getReferenceType(context)) {
|
|
164
|
+
const isElementReference = this.reflection.isSubtype(referenceType, ast.Element)
|
|
165
|
+
|
|
134
166
|
const scopes: Stream<AstNodeDescription>[] = []
|
|
135
167
|
const doc = getDocument(context.container)
|
|
136
168
|
const precomputed = doc.precomputedScopes
|
|
137
169
|
|
|
138
|
-
if (precomputed) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
while (container) {
|
|
142
|
-
const elements = precomputed.get(container).filter(byReferenceType)
|
|
143
|
-
if (elements.length > 0) {
|
|
144
|
-
scopes.push(stream(elements))
|
|
145
|
-
}
|
|
170
|
+
if (!precomputed) {
|
|
171
|
+
return this.getGlobalScope(referenceType, context)
|
|
172
|
+
}
|
|
146
173
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
container = container.$container
|
|
174
|
+
const byReferenceType = (desc: AstNodeDescription) => this.reflection.isSubtype(desc.type, referenceType)
|
|
175
|
+
let container: AstNode | undefined = context.container
|
|
176
|
+
while (container) {
|
|
177
|
+
const elements = precomputed.get(container).filter(byReferenceType)
|
|
178
|
+
if (elements.length > 0) {
|
|
179
|
+
scopes.push(stream(elements))
|
|
154
180
|
}
|
|
181
|
+
|
|
182
|
+
if (isElementReference && ast.isExtendElementBody(container)) {
|
|
183
|
+
scopes.push(this.scopeExtendElement(container.$container))
|
|
184
|
+
}
|
|
185
|
+
if (isElementReference && ast.isElementViewBody(container)) {
|
|
186
|
+
scopes.push(this.scopeElementView(container.$container))
|
|
187
|
+
}
|
|
188
|
+
container = container.$container
|
|
155
189
|
}
|
|
156
190
|
|
|
157
191
|
return scopes.reduceRight((outerScope, elements) => {
|
|
158
192
|
return this.createScope(elements, outerScope)
|
|
159
|
-
}, this.getGlobalScope(referenceType))
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Create a global scope filtered for the given reference type.
|
|
164
|
-
*/
|
|
165
|
-
protected override getGlobalScope(referenceType: string): Scope {
|
|
166
|
-
return new StreamScope(this.indexManager.allElements(referenceType))
|
|
193
|
+
}, this.getGlobalScope(referenceType, context))
|
|
167
194
|
}
|
|
168
195
|
}
|
|
@@ -16,13 +16,17 @@ export class NodeKindProvider implements LspNodeKindProvider {
|
|
|
16
16
|
switch (true) {
|
|
17
17
|
case hasType(
|
|
18
18
|
ast.Element,
|
|
19
|
-
ast.ExtendElement
|
|
19
|
+
ast.ExtendElement,
|
|
20
|
+
ast.DeploymentNode,
|
|
21
|
+
ast.DeployedInstance
|
|
20
22
|
):
|
|
21
23
|
return SymbolKind.Constructor
|
|
22
24
|
|
|
23
25
|
case hasType(
|
|
24
26
|
ast.Model,
|
|
25
27
|
ast.ModelViews,
|
|
28
|
+
ast.ModelDeployments,
|
|
29
|
+
ast.Globals,
|
|
26
30
|
ast.SpecificationRule
|
|
27
31
|
):
|
|
28
32
|
return SymbolKind.Namespace
|
|
@@ -46,7 +50,9 @@ export class NodeKindProvider implements LspNodeKindProvider {
|
|
|
46
50
|
|
|
47
51
|
case hasType(
|
|
48
52
|
ast.ElementKind,
|
|
49
|
-
ast.
|
|
53
|
+
ast.DeploymentNodeKind,
|
|
54
|
+
ast.SpecificationElementKind,
|
|
55
|
+
ast.SpecificationDeploymentNodeKind
|
|
50
56
|
):
|
|
51
57
|
return SymbolKind.TypeParameter
|
|
52
58
|
}
|
|
@@ -66,6 +72,8 @@ export class NodeKindProvider implements LspNodeKindProvider {
|
|
|
66
72
|
|
|
67
73
|
case hasType(
|
|
68
74
|
ast.Element,
|
|
75
|
+
ast.DeploymentNode,
|
|
76
|
+
ast.DeployedInstance,
|
|
69
77
|
ast.ExtendElement
|
|
70
78
|
):
|
|
71
79
|
return CompletionItemKind.Constructor
|
|
@@ -73,6 +81,8 @@ export class NodeKindProvider implements LspNodeKindProvider {
|
|
|
73
81
|
case hasType(
|
|
74
82
|
ast.Model,
|
|
75
83
|
ast.ModelViews,
|
|
84
|
+
ast.ModelDeployments,
|
|
85
|
+
ast.Globals,
|
|
76
86
|
ast.SpecificationRule
|
|
77
87
|
):
|
|
78
88
|
return CompletionItemKind.Module
|
|
@@ -98,7 +108,9 @@ export class NodeKindProvider implements LspNodeKindProvider {
|
|
|
98
108
|
|
|
99
109
|
case hasType(
|
|
100
110
|
ast.ElementKind,
|
|
101
|
-
ast.SpecificationElementKind
|
|
111
|
+
ast.SpecificationElementKind,
|
|
112
|
+
ast.DeploymentNodeKind,
|
|
113
|
+
ast.SpecificationDeploymentNodeKind
|
|
102
114
|
):
|
|
103
115
|
return CompletionItemKind.TypeParameter
|
|
104
116
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AstUtils } from 'langium'
|
|
2
|
+
import { isNullish } from 'remeda'
|
|
3
|
+
import { ast } from '../ast'
|
|
4
|
+
|
|
5
|
+
export function instanceRef(deploymentRef: ast.DeploymentRef): ast.DeployedInstance | null {
|
|
6
|
+
let referenceable
|
|
7
|
+
while ((referenceable = deploymentRef.value?.ref)) {
|
|
8
|
+
if (ast.isDeploymentNode(referenceable)) {
|
|
9
|
+
return null
|
|
10
|
+
}
|
|
11
|
+
if (ast.isDeployedInstance(referenceable)) {
|
|
12
|
+
return referenceable
|
|
13
|
+
}
|
|
14
|
+
if (isNullish(deploymentRef.parent)) {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
deploymentRef = deploymentRef.parent
|
|
18
|
+
}
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function deploymentNodeRef(deploymentRef: ast.DeploymentRef): ast.DeploymentNode | null {
|
|
23
|
+
let referenceable = deploymentRef.value.ref ?? null
|
|
24
|
+
if (!referenceable || ast.isDeploymentNode(referenceable)) {
|
|
25
|
+
return referenceable
|
|
26
|
+
}
|
|
27
|
+
const artifact = instanceRef(deploymentRef)
|
|
28
|
+
// Because path in deploymentRef may be omitted,
|
|
29
|
+
// we find artifact first and then its container
|
|
30
|
+
return artifact ? AstUtils.getContainerOfType(artifact, ast.isDeploymentNode) ?? null : null
|
|
31
|
+
}
|
package/src/utils/stringHash.ts
CHANGED