@likec4/language-server 1.21.1 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +4 -1
  2. package/bin/likec4-language-server.mjs +5 -2
  3. package/dist/LikeC4FileSystem.js +2 -2
  4. package/dist/browser.d.ts +3 -3
  5. package/dist/browser.js +17 -2
  6. package/dist/bundled.d.ts +8 -0
  7. package/dist/bundled.js +25 -0
  8. package/dist/bundled.mjs +2555 -4022
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js +23 -2
  11. package/dist/logger.d.ts +9 -3
  12. package/dist/logger.js +35 -55
  13. package/dist/model/fqn-computation.js +2 -2
  14. package/dist/model/model-builder.js +13 -14
  15. package/dist/model-change/ModelChanges.js +2 -2
  16. package/dist/module.js +1 -4
  17. package/dist/references/scope-provider.js +3 -3
  18. package/dist/view-utils/manual-layout.js +2 -2
  19. package/dist/views/configurable-layouter.js +4 -4
  20. package/dist/views/likec4-views.d.ts +2 -1
  21. package/dist/views/likec4-views.js +2 -2
  22. package/package.json +14 -12
  23. package/dist/test/setup.d.ts +0 -1
  24. package/dist/test/setup.js +0 -7
  25. package/src/LikeC4FileSystem.ts +0 -38
  26. package/src/Rpc.ts +0 -134
  27. package/src/ast.ts +0 -556
  28. package/src/browser.ts +0 -35
  29. package/src/documentation/documentation-provider.ts +0 -52
  30. package/src/documentation/index.ts +0 -1
  31. package/src/formatting/LikeC4Formatter.ts +0 -639
  32. package/src/formatting/utils.ts +0 -26
  33. package/src/generated/ast.ts +0 -3735
  34. package/src/generated/grammar.ts +0 -10
  35. package/src/generated/module.ts +0 -33
  36. package/src/generated-lib/icons.ts +0 -1538
  37. package/src/index.ts +0 -30
  38. package/src/like-c4.langium +0 -901
  39. package/src/likec4lib.ts +0 -6
  40. package/src/logger.ts +0 -80
  41. package/src/lsp/CodeLensProvider.ts +0 -50
  42. package/src/lsp/CompletionProvider.ts +0 -147
  43. package/src/lsp/DocumentHighlightProvider.ts +0 -12
  44. package/src/lsp/DocumentLinkProvider.ts +0 -65
  45. package/src/lsp/DocumentSymbolProvider.ts +0 -313
  46. package/src/lsp/HoverProvider.ts +0 -92
  47. package/src/lsp/RenameProvider.ts +0 -8
  48. package/src/lsp/SemanticTokenProvider.ts +0 -383
  49. package/src/lsp/index.ts +0 -8
  50. package/src/model/deployments-index.ts +0 -209
  51. package/src/model/fqn-computation.ts +0 -83
  52. package/src/model/fqn-index.ts +0 -138
  53. package/src/model/index.ts +0 -6
  54. package/src/model/model-builder.ts +0 -724
  55. package/src/model/model-locator.ts +0 -146
  56. package/src/model/model-parser-where.ts +0 -84
  57. package/src/model/model-parser.ts +0 -86
  58. package/src/model/parser/Base.ts +0 -113
  59. package/src/model/parser/DeploymentModelParser.ts +0 -192
  60. package/src/model/parser/DeploymentViewParser.ts +0 -122
  61. package/src/model/parser/FqnRefParser.ts +0 -143
  62. package/src/model/parser/GlobalsParser.ts +0 -96
  63. package/src/model/parser/ModelParser.ts +0 -170
  64. package/src/model/parser/PredicatesParser.ts +0 -315
  65. package/src/model/parser/SpecificationParser.ts +0 -133
  66. package/src/model/parser/ViewsParser.ts +0 -428
  67. package/src/model-change/ModelChanges.ts +0 -101
  68. package/src/model-change/changeElementStyle.ts +0 -172
  69. package/src/model-change/changeViewLayout.ts +0 -47
  70. package/src/model-change/saveManualLayout.ts +0 -41
  71. package/src/module.ts +0 -255
  72. package/src/protocol.ts +0 -93
  73. package/src/references/index.ts +0 -3
  74. package/src/references/name-provider.ts +0 -37
  75. package/src/references/scope-computation.ts +0 -364
  76. package/src/references/scope-provider.ts +0 -201
  77. package/src/shared/NodeKindProvider.ts +0 -121
  78. package/src/shared/WorkspaceManager.ts +0 -48
  79. package/src/shared/WorkspaceSymbolProvider.ts +0 -3
  80. package/src/shared/index.ts +0 -3
  81. package/src/test/index.ts +0 -1
  82. package/src/test/setup.ts +0 -8
  83. package/src/test/testServices.ts +0 -152
  84. package/src/utils/disposable.ts +0 -30
  85. package/src/utils/elementRef.ts +0 -26
  86. package/src/utils/fqnRef.ts +0 -56
  87. package/src/utils/index.ts +0 -2
  88. package/src/utils/printDocs.ts +0 -3
  89. package/src/utils/stringHash.ts +0 -6
  90. package/src/validation/_shared.ts +0 -29
  91. package/src/validation/deployment-checks.ts +0 -131
  92. package/src/validation/dynamic-view-rule.ts +0 -23
  93. package/src/validation/dynamic-view-step.ts +0 -36
  94. package/src/validation/element.ts +0 -56
  95. package/src/validation/index.ts +0 -171
  96. package/src/validation/property-checks.ts +0 -52
  97. package/src/validation/relation.ts +0 -63
  98. package/src/validation/specification.ts +0 -205
  99. package/src/validation/view-predicates/element-with.ts +0 -36
  100. package/src/validation/view-predicates/expanded-element.ts +0 -16
  101. package/src/validation/view-predicates/expression-v2.ts +0 -101
  102. package/src/validation/view-predicates/incoming.ts +0 -20
  103. package/src/validation/view-predicates/index.ts +0 -6
  104. package/src/validation/view-predicates/outgoing.ts +0 -20
  105. package/src/validation/view-predicates/relation-with.ts +0 -17
  106. package/src/validation/view.ts +0 -37
  107. package/src/view-utils/assignNavigateTo.ts +0 -31
  108. package/src/view-utils/index.ts +0 -2
  109. package/src/view-utils/manual-layout.ts +0 -116
  110. package/src/view-utils/resolve-relative-paths.ts +0 -90
  111. package/src/views/configurable-layouter.ts +0 -65
  112. package/src/views/index.ts +0 -1
  113. package/src/views/likec4-views.ts +0 -139
package/src/likec4lib.ts DELETED
@@ -1,6 +0,0 @@
1
- import { LibIcons } from './generated-lib/icons'
2
-
3
- export const Scheme = 'likec4builtin'
4
- export const Uri = `${Scheme}:///likec4/lib/icons.c4` as const
5
-
6
- export { LibIcons as Content }
package/src/logger.ts DELETED
@@ -1,80 +0,0 @@
1
- import { nonexhaustive } from '@likec4/core'
2
- import { type ConsolaReporter, formatLogObj, LogLevels, rootLogger as root } from '@likec4/log'
3
- import { BROWSER } from 'esm-env'
4
- import type { Connection } from 'vscode-languageserver'
5
-
6
- export const logger = root.withTag('lsp')
7
- // export const logger = root
8
-
9
- export function logError(err: unknown): void {
10
- logger.error(err)
11
- }
12
-
13
- /**
14
- * Logs an error as warning (not critical)
15
- */
16
- export function logWarnError(err: unknown): void {
17
- logger.warn(err)
18
- }
19
-
20
- export function setLogLevel(level: keyof typeof LogLevels): void {
21
- logger.level = LogLevels[level]
22
- }
23
-
24
- export function logToLspConnection(connection: Connection): void {
25
- const reporter: ConsolaReporter = {
26
- log: (logObj, _ctx) => {
27
- const { message, error } = formatLogObj(logObj)
28
- switch (logObj.type) {
29
- case 'silent': {
30
- // ignore
31
- break
32
- }
33
- case 'verbose':
34
- case 'trace': {
35
- connection.tracer.log(message)
36
- break
37
- }
38
- case 'debug': {
39
- connection.console.debug(message)
40
- break
41
- }
42
- case 'log': {
43
- connection.console.log(message)
44
- break
45
- }
46
- case 'info':
47
- case 'box':
48
- case 'ready':
49
- case 'start':
50
- case 'success': {
51
- connection.console.info(message)
52
- break
53
- }
54
- case 'warn': {
55
- connection.console.warn(message)
56
- break
57
- }
58
- case 'fail':
59
- case 'error':
60
- case 'fatal': {
61
- connection.console.error(message)
62
- if (error) {
63
- connection.telemetry.logEvent({ eventName: 'error', ...error })
64
- } else {
65
- connection.telemetry.logEvent({ eventName: 'error', message })
66
- }
67
- break
68
- }
69
- default:
70
- nonexhaustive(logObj.type)
71
- }
72
- },
73
- }
74
- if (BROWSER) {
75
- root.addReporter(reporter)
76
- } else {
77
- root.setReporters([reporter])
78
- }
79
- logger.setReporters(root.options.reporters)
80
- }
@@ -1,50 +0,0 @@
1
- import { DocumentState, type LangiumDocument, type MaybePromise } from 'langium'
2
- import type { CodeLensProvider } from 'langium/lsp'
3
- import type { CancellationToken, CodeLens, CodeLensParams } from 'vscode-languageserver'
4
- import { isParsedLikeC4LangiumDocument, ViewOps } from '../ast'
5
- import { logger } from '../logger'
6
- import type { LikeC4Services } from '../module'
7
-
8
- export class LikeC4CodeLensProvider implements CodeLensProvider {
9
- constructor(private services: LikeC4Services) {
10
- }
11
-
12
- async provideCodeLens(
13
- doc: LangiumDocument,
14
- _params: CodeLensParams,
15
- cancelToken?: CancellationToken
16
- ): Promise<CodeLens[] | undefined> {
17
- if (doc.state !== DocumentState.Validated) {
18
- logger.debug(`Waiting for document ${doc.uri.path} to be validated`)
19
- await this.services.shared.workspace.DocumentBuilder.waitUntil(DocumentState.Validated, doc.uri, cancelToken)
20
- logger.debug(`Document ${doc.uri.path} is validated`)
21
- }
22
- if (!isParsedLikeC4LangiumDocument(doc)) {
23
- return
24
- }
25
- const views = doc.parseResult.value.views.flatMap(v => v.views)
26
- return views.flatMap<CodeLens>(ast => {
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
- const viewId = ViewOps.readId(ast)
29
- const range = ast.$cstNode?.range
30
- if (!range || !viewId) {
31
- return []
32
- }
33
-
34
- return {
35
- range: {
36
- start: range.start,
37
- end: {
38
- line: range.start.line,
39
- character: range.start.character + 4
40
- }
41
- },
42
- command: {
43
- command: 'likec4.open-preview',
44
- arguments: [viewId],
45
- title: 'open preview'
46
- }
47
- }
48
- })
49
- }
50
- }
@@ -1,147 +0,0 @@
1
- import { type GrammarAST, type MaybePromise, AstUtils } from 'langium'
2
- import {
3
- type CompletionAcceptor,
4
- type CompletionContext,
5
- type CompletionProviderOptions,
6
- DefaultCompletionProvider,
7
- } from 'langium/lsp'
8
- import { anyPass } from 'remeda'
9
- import { CompletionItemKind, InsertTextFormat } from 'vscode-languageserver-types'
10
- import { ast } from '../ast'
11
-
12
- const STYLE_FIELDS = [
13
- 'color',
14
- 'shape',
15
- 'icon',
16
- 'border',
17
- 'opacity',
18
- 'multiple',
19
- 'size',
20
- ].join(',')
21
-
22
- export class LikeC4CompletionProvider extends DefaultCompletionProvider {
23
- override readonly completionOptions = {
24
- triggerCharacters: ['.'],
25
- } satisfies CompletionProviderOptions
26
-
27
- protected override completionForKeyword(
28
- context: CompletionContext,
29
- keyword: GrammarAST.Keyword,
30
- acceptor: CompletionAcceptor,
31
- ): MaybePromise<void> {
32
- if (!this.filterKeyword(context, keyword)) {
33
- return
34
- }
35
- if (keyword.value === 'deployment' && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
36
- return acceptor(context, {
37
- label: keyword.value,
38
- detail: `Insert deployment view`,
39
- kind: CompletionItemKind.Class,
40
- insertTextFormat: InsertTextFormat.Snippet,
41
- insertText: [
42
- 'deployment view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {',
43
- '\ttitle \'${2:Untitled}\'',
44
- '\t',
45
- '\tinclude $0',
46
- '}',
47
- ].join('\n'),
48
- })
49
- }
50
- if (['title', 'description', 'technology'].includes(keyword.value)) {
51
- return acceptor(context, {
52
- label: keyword.value,
53
- kind: CompletionItemKind.Property,
54
- insertTextFormat: InsertTextFormat.Snippet,
55
- insertText: `${keyword.value} '\${0}'`,
56
- })
57
- }
58
- if (['views', 'specification', 'model', 'deployment', 'with'].includes(keyword.value)) {
59
- return acceptor(context, {
60
- label: keyword.value,
61
- detail: `Insert ${keyword.value} block`,
62
- kind: CompletionItemKind.Module,
63
- insertTextFormat: InsertTextFormat.Snippet,
64
- insertText: `${keyword.value} {\n\t$0\n}`,
65
- })
66
- }
67
- if (keyword.value === 'group') {
68
- return acceptor(context, {
69
- label: keyword.value,
70
- detail: `Insert group block`,
71
- kind: CompletionItemKind.Class,
72
- insertTextFormat: InsertTextFormat.Snippet,
73
- insertText: [
74
- 'group \'${1:Title}\' {',
75
- '\t$0',
76
- '}',
77
- ].join('\n'),
78
- })
79
- }
80
- if (keyword.value === 'dynamic' && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
81
- return acceptor(context, {
82
- label: keyword.value,
83
- detail: `Insert dynamic view`,
84
- kind: CompletionItemKind.Class,
85
- insertTextFormat: InsertTextFormat.Snippet,
86
- insertText: [
87
- 'dynamic view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {',
88
- '\ttitle \'${2:Untitled}\'',
89
- '\t',
90
- '\t$0',
91
- '}',
92
- ].join('\n'),
93
- })
94
- }
95
- if (keyword.value === 'style' && context.node) {
96
- if (AstUtils.hasContainerOfType(context.node, ast.isGlobalStyle)) {
97
- return acceptor(context, {
98
- label: keyword.value,
99
- detail: `Insert ${keyword.value} block`,
100
- kind: CompletionItemKind.Module,
101
- insertTextFormat: InsertTextFormat.Snippet,
102
- insertText: `${keyword.value} \${1:name} \${2:*} {\n\t\${3|${STYLE_FIELDS}|} $0\n}`,
103
- })
104
- }
105
- if (AstUtils.hasContainerOfType(context.node, anyPass([ast.isModelViews, ast.isGlobalStyleGroup]))) {
106
- return acceptor(context, {
107
- label: keyword.value,
108
- detail: `Insert ${keyword.value} block`,
109
- kind: CompletionItemKind.Module,
110
- insertTextFormat: InsertTextFormat.Snippet,
111
- insertText: `${keyword.value} \${1:*} {\n\t\${2|${STYLE_FIELDS}|} $0\n}`,
112
- })
113
- }
114
- return acceptor(context, {
115
- label: keyword.value,
116
- detail: `Insert ${keyword.value} block`,
117
- kind: CompletionItemKind.Module,
118
- insertTextFormat: InsertTextFormat.Snippet,
119
- insertText: `${keyword.value} {\n\t\${1|${STYLE_FIELDS}|} $0\n}`,
120
- })
121
- }
122
- if (keyword.value === 'extend') {
123
- return acceptor(context, {
124
- label: keyword.value,
125
- detail: `Extend another view`,
126
- kind: CompletionItemKind.Class,
127
- insertTextFormat: InsertTextFormat.Snippet,
128
- insertText: 'extend ${1:element} {\n\t$0\n}',
129
- })
130
- }
131
-
132
- if (keyword.value === 'autoLayout') {
133
- return acceptor(context, {
134
- label: keyword.value,
135
- kind: CompletionItemKind.Class,
136
- insertTextFormat: InsertTextFormat.Snippet,
137
- insertText: 'autoLayout ${1|TopBottom,BottomTop,LeftRight,RightLeft|}$0',
138
- })
139
- }
140
- acceptor(context, {
141
- label: keyword.value,
142
- kind: this.getKeywordCompletionItemKind(keyword),
143
- detail: 'Keyword',
144
- sortText: '1',
145
- })
146
- }
147
- }
@@ -1,12 +0,0 @@
1
- import type { ReferenceDescription } from 'langium'
2
- import { DefaultDocumentHighlightProvider } from 'langium/lsp'
3
- import { DocumentHighlight, DocumentHighlightKind } from 'vscode-languageserver'
4
-
5
- export class LikeC4DocumentHighlightProvider extends DefaultDocumentHighlightProvider {
6
- /**
7
- * Override this method to determine the highlight kind of the given reference.
8
- */
9
- protected override createDocumentHighlight(reference: ReferenceDescription): DocumentHighlight {
10
- return DocumentHighlight.create(reference.segment.range, DocumentHighlightKind.Read)
11
- }
12
- }
@@ -1,65 +0,0 @@
1
- import type { LangiumDocument, MaybePromise } from 'langium'
2
- import { AstUtils, GrammarUtils } from 'langium'
3
- import type { DocumentLinkProvider } from 'langium/lsp'
4
- import { hasLeadingSlash, hasProtocol, isRelative, withoutBase, withoutLeadingSlash } from 'ufo'
5
- import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver'
6
- import { ast, isParsedLikeC4LangiumDocument } from '../ast'
7
- import { logWarnError } from '../logger'
8
- import type { LikeC4Services } from '../module'
9
-
10
- export class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
11
- constructor(private services: LikeC4Services) {
12
- //
13
- }
14
- getDocumentLinks(
15
- doc: LangiumDocument,
16
- _params: DocumentLinkParams
17
- ): MaybePromise<DocumentLink[]> {
18
- if (!isParsedLikeC4LangiumDocument(doc)) {
19
- return []
20
- }
21
- return AstUtils.streamAllContents(doc.parseResult.value)
22
- .filter(ast.isLinkProperty)
23
- .map((n): DocumentLink | null => {
24
- try {
25
- const range = GrammarUtils.findNodeForProperty(n.$cstNode, 'value')?.range
26
- const target = this.resolveLink(doc, n.value)
27
- if (range && hasProtocol(target)) {
28
- return {
29
- range,
30
- target
31
- }
32
- }
33
- } catch (e) {
34
- logWarnError(e)
35
- }
36
- return null
37
- })
38
- .nonNullable()
39
- .toArray()
40
- }
41
-
42
- resolveLink(doc: LangiumDocument, link: string): string {
43
- if (hasProtocol(link) || hasLeadingSlash(link)) {
44
- return link
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
- }
56
- if (isRelative(link)) {
57
- const base = new URL(doc.uri.toString(true))
58
- const linkURL = new URL(link, base).toString()
59
- return withoutLeadingSlash(
60
- withoutBase(linkURL, this.services.shared.workspace.WorkspaceManager.workspaceURL.toString())
61
- )
62
- }
63
- return null
64
- }
65
- }
@@ -1,313 +0,0 @@
1
- import { nonexhaustive } from '@likec4/core'
2
- import { type AstNode, type MaybePromise, AstUtils, GrammarUtils } from 'langium'
3
- import type { DocumentSymbolProvider, NodeKindProvider } from 'langium/lsp'
4
- import { filter, isEmpty, isTruthy, map, pipe } from 'remeda'
5
- import { type DocumentSymbol, SymbolKind } from 'vscode-languageserver-types'
6
- import { type LikeC4LangiumDocument, ast } from '../ast'
7
- import { logError, logWarnError } from '../logger'
8
- import type { LikeC4ModelLocator, LikeC4ModelParser } from '../model'
9
- import type { LikeC4Services } from '../module'
10
- import type { LikeC4NameProvider } from '../references'
11
- import { getFqnElementRef } from '../utils/elementRef'
12
-
13
- export class LikeC4DocumentSymbolProvider implements DocumentSymbolProvider {
14
- protected readonly nodeKindProvider: NodeKindProvider
15
- protected readonly nameProvider: LikeC4NameProvider
16
- protected readonly parser: LikeC4ModelParser
17
- protected readonly locator: LikeC4ModelLocator
18
-
19
- constructor(private services: LikeC4Services) {
20
- this.nodeKindProvider = services.shared.lsp.NodeKindProvider
21
- this.parser = services.likec4.ModelParser
22
- this.locator = services.likec4.ModelLocator
23
- this.nameProvider = services.references.NameProvider
24
- }
25
-
26
- getSymbols({
27
- parseResult: {
28
- value: { specifications, models, deployments, views, likec4lib },
29
- },
30
- }: LikeC4LangiumDocument): MaybePromise<DocumentSymbol[]> {
31
- return [
32
- ...likec4lib.map(l => () => this.getLikec4LibSymbol(l)),
33
- ...specifications.map(s => () => this.getSpecSymbol(s)),
34
- ...models.map(s => () => this.getModelSymbol(s)),
35
- ...deployments.map(s => () => this.getDeploymentModelSymbol(s)),
36
- ...views.map(s => () => this.getModelViewsSymbol(s)),
37
- ].flatMap(fn => {
38
- try {
39
- return fn() ?? []
40
- } catch (e) {
41
- logWarnError(e)
42
- return []
43
- }
44
- })
45
- }
46
-
47
- protected getLikec4LibSymbol(astLib: ast.LikeC4Lib): DocumentSymbol[] {
48
- const cstModel = astLib?.$cstNode
49
- if (!cstModel) return []
50
- const children = astLib.icons.map(i => this.getLibIconSymbol(i)).filter(isTruthy)
51
- if (children.length === 0) return []
52
- return [
53
- {
54
- kind: SymbolKind.Namespace,
55
- name: 'icons',
56
- range: cstModel.range,
57
- selectionRange: GrammarUtils.findNodeForKeyword(cstModel, 'icons')?.range ?? cstModel.range,
58
- children,
59
- },
60
- ]
61
- }
62
-
63
- protected getSpecSymbol(astSpec: ast.SpecificationRule): DocumentSymbol[] {
64
- const cstModel = astSpec?.$cstNode
65
- if (!cstModel) return []
66
- const specKeywordNode = GrammarUtils.findNodeForProperty(cstModel, 'name')
67
- if (!specKeywordNode) return []
68
-
69
- const specSymbols = pipe(
70
- [...astSpec.elements, ...astSpec.tags, ...astSpec.relationships],
71
- map(nd => {
72
- try {
73
- if (
74
- ast.isSpecificationElementKind(nd) || ast.isSpecificationRelationshipKind(nd)
75
- || ast.isSpecificationDeploymentNodeKind(nd)
76
- ) {
77
- return this.getKindSymbol(nd)
78
- }
79
- if (ast.isSpecificationTag(nd)) {
80
- return this.getTagSymbol(nd)
81
- }
82
- } catch (e) {
83
- logWarnError(e)
84
- return null
85
- }
86
- nonexhaustive(nd)
87
- }),
88
- filter(isTruthy),
89
- )
90
-
91
- if (specSymbols.length === 0) return []
92
-
93
- return [
94
- {
95
- kind: SymbolKind.Namespace,
96
- name: astSpec.name,
97
- range: cstModel.range,
98
- selectionRange: specKeywordNode.range,
99
- children: specSymbols,
100
- },
101
- ]
102
- }
103
-
104
- protected getModelSymbol(astModel: ast.Model): DocumentSymbol[] {
105
- const cstModel = astModel.$cstNode
106
- if (!cstModel) return []
107
- const nameNode = GrammarUtils.findNodeForProperty(cstModel, 'name')
108
- if (!nameNode) return []
109
- return [
110
- {
111
- kind: this.symbolKind(astModel),
112
- name: astModel.name,
113
- range: cstModel.range,
114
- selectionRange: nameNode.range,
115
- children: astModel.elements.flatMap(e => this.getElementsSymbol(e)),
116
- },
117
- ]
118
- }
119
-
120
- protected getDeploymentModelSymbol(astModel: ast.ModelDeployments): DocumentSymbol[] {
121
- const cstModel = astModel.$cstNode
122
- if (!cstModel) return []
123
- const nameNode = GrammarUtils.findNodeForProperty(cstModel, 'name')
124
- if (!nameNode) return []
125
- return [
126
- {
127
- kind: this.symbolKind(astModel),
128
- name: astModel.name,
129
- range: cstModel.range,
130
- selectionRange: nameNode.range,
131
- children: astModel.elements.flatMap(e => this.getDeploymentElementSymbol(e)),
132
- },
133
- ]
134
- }
135
-
136
- protected getElementsSymbol(
137
- el: ast.Element | ast.Relation | ast.ExtendElement,
138
- ): DocumentSymbol[] {
139
- try {
140
- if (ast.isExtendElement(el)) {
141
- return this.getExtendElementSymbol(el)
142
- }
143
- if (ast.isElement(el)) {
144
- return this.getElementSymbol(el)
145
- }
146
- } catch (e) {
147
- logWarnError(e)
148
- }
149
- return []
150
- }
151
-
152
- protected getExtendElementSymbol(astElement: ast.ExtendElement): DocumentSymbol[] {
153
- const cst = astElement.$cstNode
154
- const nameNode = astElement.element.$cstNode
155
- const body = astElement.body
156
- if (!cst || !nameNode) return []
157
-
158
- return [
159
- {
160
- kind: this.symbolKind(astElement),
161
- name: getFqnElementRef(astElement.element),
162
- range: cst.range,
163
- selectionRange: nameNode.range,
164
- children: body.elements.flatMap(e => this.getElementsSymbol(e)),
165
- },
166
- ]
167
- }
168
-
169
- protected getElementSymbol(astElement: ast.Element): DocumentSymbol[] {
170
- const cst = astElement.$cstNode
171
- const nameNode = GrammarUtils.findNodeForProperty(cst, 'name')
172
- if (!nameNode || !cst) return []
173
-
174
- const name = astElement.name
175
- const kind = astElement.kind.$refText
176
- // TODO: return the title as well
177
- const detail = kind // + (astElement.title ? ': ' + astElement.title : '').replaceAll('\n', ' ').trim()
178
- return [
179
- {
180
- kind: this.symbolKind(astElement),
181
- name: name,
182
- range: cst.range,
183
- selectionRange: nameNode.range,
184
- detail,
185
- children: astElement.body?.elements.flatMap(e => this.getElementsSymbol(e)) ?? [],
186
- },
187
- ]
188
- }
189
- protected getModelViewsSymbol(astViews: ast.ModelViews): DocumentSymbol[] {
190
- const cst = astViews.$cstNode
191
- const nameNode = GrammarUtils.findNodeForProperty(cst, 'name')
192
- if (!nameNode || !cst) return []
193
- return [
194
- {
195
- kind: this.symbolKind(astViews),
196
- name: astViews.name,
197
- range: cst.range,
198
- selectionRange: nameNode.range,
199
- children: astViews.views.flatMap(e => this.getViewSymbol(e)),
200
- },
201
- ]
202
- }
203
-
204
- protected getKindSymbol(
205
- astKind: ast.SpecificationElementKind | ast.SpecificationRelationshipKind,
206
- ): DocumentSymbol | null {
207
- if (!astKind.$cstNode || !astKind.kind.$cstNode || isEmpty(astKind.kind.name)) return null
208
-
209
- return {
210
- kind: this.symbolKind(astKind),
211
- name: astKind.kind.name,
212
- range: astKind.$cstNode.range,
213
- selectionRange: astKind.kind.$cstNode.range,
214
- }
215
- }
216
-
217
- protected getTagSymbol(astTag: ast.SpecificationTag): DocumentSymbol | null {
218
- if (!astTag.$cstNode || !astTag.tag.$cstNode || isEmpty(astTag.tag.name)) return null
219
- return {
220
- kind: this.symbolKind(astTag),
221
- name: '#' + astTag.tag.name,
222
- range: astTag.$cstNode.range,
223
- selectionRange: astTag.tag.$cstNode.range,
224
- }
225
- }
226
-
227
- protected getLibIconSymbol(astTag: ast.LibIcon): DocumentSymbol | null {
228
- if (!astTag.$cstNode || isEmpty(astTag.name)) return null
229
- return {
230
- kind: this.symbolKind(astTag),
231
- name: astTag.name,
232
- range: astTag.$cstNode.range,
233
- selectionRange: astTag.$cstNode.range,
234
- }
235
- }
236
-
237
- protected getViewSymbol(astView: ast.LikeC4View): DocumentSymbol[] {
238
- const cst = astView?.$cstNode
239
- if (!cst) return []
240
- const nameNode = astView.name ? GrammarUtils.findNodeForProperty(cst, 'name') : null
241
- if (!nameNode) return []
242
- return [
243
- {
244
- kind: this.symbolKind(astView),
245
- name: nameNode.text,
246
- range: cst.range,
247
- selectionRange: nameNode.range,
248
- children: [],
249
- },
250
- ]
251
- }
252
-
253
- protected getDeploymentElementSymbol(el: ast.DeploymentElement | ast.DeploymentRelation): DocumentSymbol[] {
254
- try {
255
- if (ast.isDeploymentNode(el)) {
256
- return this.getDeploymentNodeSymbol(el)
257
- }
258
- if (ast.isDeployedInstance(el)) {
259
- return this.getDeployedInstanceSymbol(el)
260
- }
261
- } catch (e) {
262
- logWarnError(e)
263
- }
264
- return []
265
- }
266
-
267
- protected getDeploymentNodeSymbol(astElement: ast.DeploymentNode): DocumentSymbol[] {
268
- const cst = astElement.$cstNode
269
- const nameNode = this.nameProvider.getNameNode(astElement)
270
- if (!nameNode || !cst) return []
271
-
272
- const name = this.nameProvider.getNameStrict(astElement)
273
- const kind = astElement.kind.$refText
274
- // TODO: return the title as well
275
- const detail = kind // + (astElement.title ? ': ' + astElement.title : '').replaceAll('\n', ' ').trim()
276
- return [
277
- {
278
- kind: this.symbolKind(astElement),
279
- name: name,
280
- range: cst.range,
281
- selectionRange: nameNode.range,
282
- detail,
283
- children: astElement.body?.elements.flatMap(e => this.getDeploymentElementSymbol(e)) ?? [],
284
- },
285
- ]
286
- }
287
-
288
- protected getDeployedInstanceSymbol(astElement: ast.DeployedInstance): DocumentSymbol[] {
289
- const cst = astElement.$cstNode
290
- const nameNode = this.nameProvider.getNameNode(astElement)
291
- if (!nameNode || !cst) return []
292
-
293
- const doc = AstUtils.getDocument(astElement)
294
- const instance = this.parser.forDocument(doc).parseDeployedInstance(astElement)
295
-
296
- const name = this.nameProvider.getNameStrict(astElement)
297
- const detail = 'instance of ' + instance.element
298
- return [
299
- {
300
- kind: this.symbolKind(astElement),
301
- name: name,
302
- range: cst.range,
303
- selectionRange: nameNode.range,
304
- detail,
305
- children: [],
306
- },
307
- ]
308
- }
309
-
310
- protected symbolKind(node: AstNode): SymbolKind {
311
- return this.nodeKindProvider.getSymbolKind(node)
312
- }
313
- }