@likec4/language-server 1.21.0 → 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 (114) 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 +2587 -4306
  9. package/dist/generated-lib/icons.js +1 -0
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +23 -2
  12. package/dist/logger.d.ts +9 -3
  13. package/dist/logger.js +35 -55
  14. package/dist/model/fqn-computation.js +2 -2
  15. package/dist/model/model-builder.js +13 -14
  16. package/dist/model-change/ModelChanges.js +2 -2
  17. package/dist/module.js +1 -4
  18. package/dist/references/scope-provider.js +3 -3
  19. package/dist/view-utils/manual-layout.js +2 -2
  20. package/dist/views/configurable-layouter.js +4 -4
  21. package/dist/views/likec4-views.d.ts +2 -1
  22. package/dist/views/likec4-views.js +2 -2
  23. package/package.json +14 -14
  24. package/dist/test/setup.d.ts +0 -1
  25. package/dist/test/setup.js +0 -7
  26. package/src/LikeC4FileSystem.ts +0 -38
  27. package/src/Rpc.ts +0 -134
  28. package/src/ast.ts +0 -556
  29. package/src/browser.ts +0 -35
  30. package/src/documentation/documentation-provider.ts +0 -52
  31. package/src/documentation/index.ts +0 -1
  32. package/src/formatting/LikeC4Formatter.ts +0 -639
  33. package/src/formatting/utils.ts +0 -26
  34. package/src/generated/ast.ts +0 -3735
  35. package/src/generated/grammar.ts +0 -10
  36. package/src/generated/module.ts +0 -33
  37. package/src/generated-lib/icons.ts +0 -1537
  38. package/src/index.ts +0 -30
  39. package/src/like-c4.langium +0 -901
  40. package/src/likec4lib.ts +0 -6
  41. package/src/logger.ts +0 -80
  42. package/src/lsp/CodeLensProvider.ts +0 -50
  43. package/src/lsp/CompletionProvider.ts +0 -147
  44. package/src/lsp/DocumentHighlightProvider.ts +0 -12
  45. package/src/lsp/DocumentLinkProvider.ts +0 -65
  46. package/src/lsp/DocumentSymbolProvider.ts +0 -313
  47. package/src/lsp/HoverProvider.ts +0 -92
  48. package/src/lsp/RenameProvider.ts +0 -8
  49. package/src/lsp/SemanticTokenProvider.ts +0 -383
  50. package/src/lsp/index.ts +0 -8
  51. package/src/model/deployments-index.ts +0 -209
  52. package/src/model/fqn-computation.ts +0 -83
  53. package/src/model/fqn-index.ts +0 -138
  54. package/src/model/index.ts +0 -6
  55. package/src/model/model-builder.ts +0 -724
  56. package/src/model/model-locator.ts +0 -146
  57. package/src/model/model-parser-where.ts +0 -84
  58. package/src/model/model-parser.ts +0 -86
  59. package/src/model/parser/Base.ts +0 -113
  60. package/src/model/parser/DeploymentModelParser.ts +0 -192
  61. package/src/model/parser/DeploymentViewParser.ts +0 -122
  62. package/src/model/parser/FqnRefParser.ts +0 -143
  63. package/src/model/parser/GlobalsParser.ts +0 -96
  64. package/src/model/parser/ModelParser.ts +0 -170
  65. package/src/model/parser/PredicatesParser.ts +0 -315
  66. package/src/model/parser/SpecificationParser.ts +0 -133
  67. package/src/model/parser/ViewsParser.ts +0 -428
  68. package/src/model-change/ModelChanges.ts +0 -101
  69. package/src/model-change/changeElementStyle.ts +0 -172
  70. package/src/model-change/changeViewLayout.ts +0 -47
  71. package/src/model-change/saveManualLayout.ts +0 -41
  72. package/src/module.ts +0 -255
  73. package/src/protocol.ts +0 -93
  74. package/src/references/index.ts +0 -3
  75. package/src/references/name-provider.ts +0 -37
  76. package/src/references/scope-computation.ts +0 -364
  77. package/src/references/scope-provider.ts +0 -201
  78. package/src/shared/NodeKindProvider.ts +0 -121
  79. package/src/shared/WorkspaceManager.ts +0 -48
  80. package/src/shared/WorkspaceSymbolProvider.ts +0 -3
  81. package/src/shared/index.ts +0 -3
  82. package/src/test/index.ts +0 -1
  83. package/src/test/setup.ts +0 -8
  84. package/src/test/testServices.ts +0 -152
  85. package/src/utils/disposable.ts +0 -30
  86. package/src/utils/elementRef.ts +0 -26
  87. package/src/utils/fqnRef.ts +0 -56
  88. package/src/utils/index.ts +0 -2
  89. package/src/utils/printDocs.ts +0 -3
  90. package/src/utils/stringHash.ts +0 -6
  91. package/src/validation/_shared.ts +0 -29
  92. package/src/validation/deployment-checks.ts +0 -131
  93. package/src/validation/dynamic-view-rule.ts +0 -23
  94. package/src/validation/dynamic-view-step.ts +0 -36
  95. package/src/validation/element.ts +0 -56
  96. package/src/validation/index.ts +0 -171
  97. package/src/validation/property-checks.ts +0 -52
  98. package/src/validation/relation.ts +0 -63
  99. package/src/validation/specification.ts +0 -205
  100. package/src/validation/view-predicates/element-with.ts +0 -36
  101. package/src/validation/view-predicates/expanded-element.ts +0 -16
  102. package/src/validation/view-predicates/expression-v2.ts +0 -101
  103. package/src/validation/view-predicates/incoming.ts +0 -20
  104. package/src/validation/view-predicates/index.ts +0 -6
  105. package/src/validation/view-predicates/outgoing.ts +0 -20
  106. package/src/validation/view-predicates/relation-with.ts +0 -17
  107. package/src/validation/view.ts +0 -37
  108. package/src/view-utils/assignNavigateTo.ts +0 -31
  109. package/src/view-utils/index.ts +0 -2
  110. package/src/view-utils/manual-layout.ts +0 -116
  111. package/src/view-utils/resolve-relative-paths.ts +0 -90
  112. package/src/views/configurable-layouter.ts +0 -65
  113. package/src/views/index.ts +0 -1
  114. package/src/views/likec4-views.ts +0 -139
@@ -1,146 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import type { LangiumDocuments } from 'langium'
3
- import { AstUtils, GrammarUtils } from 'langium'
4
- import { isString } from 'remeda'
5
- import type { Location } from 'vscode-languageserver-types'
6
- import type { ParsedAstElement } from '../ast'
7
- import { ast, isParsedLikeC4LangiumDocument } from '../ast'
8
- import type { LikeC4Services } from '../module'
9
- import type { DeploymentsIndex } from './deployments-index'
10
- import { type FqnIndex } from './fqn-index'
11
-
12
- const { findNodeForKeyword, findNodeForProperty } = GrammarUtils
13
- const { getDocument } = AstUtils
14
-
15
- export class LikeC4ModelLocator {
16
- private fqnIndex: FqnIndex
17
- private deploymentsIndex: DeploymentsIndex
18
- private langiumDocuments: LangiumDocuments
19
-
20
- constructor(private services: LikeC4Services) {
21
- this.fqnIndex = services.likec4.FqnIndex
22
- this.deploymentsIndex = services.likec4.DeploymentsIndex
23
- this.langiumDocuments = services.shared.workspace.LangiumDocuments
24
- }
25
-
26
- private documents() {
27
- return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument)
28
- }
29
-
30
- public getParsedElement(astNodeOrFqn: ast.Element | c4.Fqn): ParsedAstElement | null {
31
- if (isString(astNodeOrFqn)) {
32
- const fqn = astNodeOrFqn
33
- const entry = this.fqnIndex.byFqn(astNodeOrFqn).head()
34
- if (!entry) {
35
- return null
36
- }
37
- const doc = this.langiumDocuments.getDocument(entry.documentUri)
38
- if (!doc || !isParsedLikeC4LangiumDocument(doc)) {
39
- return null
40
- }
41
- return doc.c4Elements.find(e => e.id === fqn) ?? null
42
- }
43
-
44
- const fqn = this.fqnIndex.getFqn(astNodeOrFqn)
45
- if (!fqn) return null
46
- const doc = getDocument(astNodeOrFqn)
47
- if (!isParsedLikeC4LangiumDocument(doc)) {
48
- return null
49
- }
50
- return doc.c4Elements.find(e => e.id === fqn) ?? null
51
- }
52
-
53
- public locateElement(fqn: c4.Fqn, _prop?: string): Location | null {
54
- const entry = this.fqnIndex.byFqn(fqn).head()
55
- const docsegment = entry?.nameSegment ?? entry?.selectionSegment
56
- if (!entry || !docsegment) {
57
- return null
58
- }
59
- return {
60
- uri: entry.documentUri.toString(),
61
- range: docsegment.range
62
- }
63
- }
64
- public locateDeploymentElement(fqn: c4.Fqn, _prop?: string): Location | null {
65
- const entry = this.deploymentsIndex.byFqn(fqn).head()
66
- const docsegment = entry?.nameSegment ?? entry?.selectionSegment
67
- if (!entry || !docsegment) {
68
- return null
69
- }
70
- return {
71
- uri: entry.documentUri.toString(),
72
- range: docsegment.range
73
- }
74
- }
75
-
76
- public locateRelation(relationId: c4.RelationId): Location | null {
77
- for (const doc of this.documents()) {
78
- const relation = doc.c4Relations.find(r => r.id === relationId)
79
- ?? doc.c4DeploymentRelations.find(r => r.id === relationId)
80
- if (!relation) {
81
- continue
82
- }
83
- const node = this.services.workspace.AstNodeLocator.getAstNode(
84
- doc.parseResult.value,
85
- relation.astPath
86
- )
87
- if (!ast.isRelation(node) && !ast.isDeploymentRelation(node)) {
88
- continue
89
- }
90
-
91
- let targetNode = node.title ? findNodeForProperty(node.$cstNode, 'title') : undefined
92
- targetNode ??= node.kind ? findNodeForProperty(node.$cstNode, 'kind') : undefined
93
- targetNode ??= findNodeForProperty(node.$cstNode, 'target')
94
- targetNode ??= node.$cstNode
95
-
96
- if (!targetNode) {
97
- continue
98
- }
99
-
100
- return {
101
- uri: doc.uri.toString(),
102
- range: targetNode.range
103
- }
104
- }
105
- return null
106
- }
107
-
108
- public locateViewAst(viewId: c4.ViewId) {
109
- for (const doc of this.documents()) {
110
- const view = doc.c4Views.find(r => r.id === viewId)
111
- if (!view) {
112
- continue
113
- }
114
- const viewAst = this.services.workspace.AstNodeLocator.getAstNode(
115
- doc.parseResult.value,
116
- view.astPath
117
- )
118
- if (ast.isLikeC4View(viewAst)) {
119
- return {
120
- doc,
121
- view,
122
- viewAst
123
- }
124
- }
125
- }
126
- return null
127
- }
128
-
129
- public locateView(viewId: c4.ViewId): Location | null {
130
- const res = this.locateViewAst(viewId)
131
- if (!res) {
132
- return null
133
- }
134
- const node = res.viewAst
135
- let targetNode = node.name ? findNodeForProperty(node.$cstNode, 'name') : undefined
136
- targetNode ??= findNodeForKeyword(node.$cstNode, 'view')
137
- targetNode ??= node.$cstNode
138
- if (!targetNode) {
139
- return null
140
- }
141
- return {
142
- uri: res.doc.uri.toString(),
143
- range: targetNode.range
144
- }
145
- }
146
- }
@@ -1,84 +0,0 @@
1
- import { invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core'
2
- import { isAndOperator, isOrOperator } from '@likec4/core'
3
- import type * as c4 from '@likec4/core'
4
- import { ast } from '../ast'
5
-
6
- const parseEquals = (
7
- { operator, not }: ast.WhereKindEqual | ast.WhereTagEqual,
8
- value: string,
9
- ): c4.EqualOperator<string> => {
10
- if (operator.startsWith('!=')) {
11
- return {
12
- neq: value,
13
- }
14
- }
15
- if (operator.startsWith('=')) {
16
- return {
17
- eq: value,
18
- }
19
- }
20
- return not ? { neq: value } : { eq: value }
21
- }
22
-
23
- function parseParticipant(astNode: ast.WhereExpression): ast.Participant | null {
24
- if (!ast.isWhereRelationParticipantKind(astNode) && !ast.isWhereRelationParticipantTag(astNode)) {
25
- return null
26
- }
27
-
28
- return astNode.participant
29
- }
30
-
31
- export function parseWhereClause(astNode: ast.WhereExpression): c4.WhereOperator<string, string> {
32
- switch (true) {
33
- case ast.isWhereTagEqual(astNode): {
34
- const tag = astNode.value?.ref?.name
35
- const participant = parseParticipant(astNode)
36
- invariant(tag, 'Expected tag name')
37
- const tagOperator = { tag: parseEquals(astNode, tag) }
38
- return participant ? { participant, operator: tagOperator } : tagOperator
39
- }
40
- case ast.isWhereKindEqual(astNode): {
41
- const kind = astNode.value?.ref?.name
42
- const participant = parseParticipant(astNode)
43
- invariant(kind, 'Expected kind name')
44
- const kindOperator = { kind: parseEquals(astNode, kind) }
45
- return participant ? { participant, operator: kindOperator } : kindOperator
46
- }
47
- case ast.isWhereElementNegation(astNode) || ast.isWhereRelationNegation(astNode): {
48
- return {
49
- not: parseWhereClause(astNode.value),
50
- }
51
- }
52
- case ast.isWhereBinaryExpression(astNode): {
53
- const left = parseWhereClause(astNode.left)
54
- const right = parseWhereClause(astNode.right)
55
- const operator = astNode.operator.toLowerCase() as Lowercase<ast.WhereBinaryExpression['operator']>
56
- switch (operator) {
57
- case 'and': {
58
- const operands = [
59
- isAndOperator(left) ? left.and : left,
60
- isAndOperator(right) ? right.and : right,
61
- ].flat()
62
- invariant(isNonEmptyArray(operands), 'Expected non-empty array')
63
- return {
64
- and: operands,
65
- }
66
- }
67
- case 'or': {
68
- const operands = [
69
- isOrOperator(left) ? left.or : left,
70
- isOrOperator(right) ? right.or : right,
71
- ].flat()
72
- invariant(isNonEmptyArray(operands), 'Expected non-empty array')
73
- return {
74
- or: operands,
75
- }
76
- }
77
- default:
78
- nonexhaustive(operator)
79
- }
80
- }
81
- default:
82
- nonexhaustive(astNode)
83
- }
84
- }
@@ -1,86 +0,0 @@
1
- import { invariant } from '@likec4/core'
2
- import { type LangiumDocument, DocumentCache, DocumentState } from 'langium'
3
- import { DefaultWeakMap } from 'mnemonist'
4
- import { pipe } from 'remeda'
5
- import type { LikeC4DocumentProps, ParsedLikeC4LangiumDocument } from '../ast'
6
- import { isFqnIndexedDocument } from '../ast'
7
- import type { LikeC4Services } from '../module'
8
- import { BaseParser } from './parser/Base'
9
- import { DeploymentModelParser } from './parser/DeploymentModelParser'
10
- import { DeploymentViewParser } from './parser/DeploymentViewParser'
11
- import { ExpressionV2Parser } from './parser/FqnRefParser'
12
- import { GlobalsParser } from './parser/GlobalsParser'
13
- import { ModelParser } from './parser/ModelParser'
14
- import { PredicatesParser } from './parser/PredicatesParser'
15
- import { SpecificationParser } from './parser/SpecificationParser'
16
- import { ViewsParser } from './parser/ViewsParser'
17
-
18
- export type ModelParsedListener = () => void
19
-
20
- const DocumentParserFromMixins = pipe(
21
- BaseParser,
22
- ExpressionV2Parser,
23
- ModelParser,
24
- DeploymentModelParser,
25
- DeploymentViewParser,
26
- PredicatesParser,
27
- SpecificationParser,
28
- ViewsParser,
29
- GlobalsParser,
30
- )
31
-
32
- export class DocumentParser extends DocumentParserFromMixins {
33
- }
34
-
35
- export class LikeC4ModelParser {
36
- private cachedParsers: DocumentCache<string, DocumentParser>
37
-
38
- constructor(private services: LikeC4Services) {
39
- this.cachedParsers = new DocumentCache(services.shared, DocumentState.Validated)
40
- }
41
-
42
- parse(doc: LangiumDocument): ParsedLikeC4LangiumDocument {
43
- invariant(isFqnIndexedDocument(doc), `Not a FqnIndexedDocument: ${doc.uri.toString(true)}`)
44
- try {
45
- const props: Required<Omit<LikeC4DocumentProps, 'c4fqnIndex' | 'diagnostics'>> = {
46
- c4Specification: {
47
- tags: new Set(),
48
- elements: {},
49
- relationships: {},
50
- colors: {},
51
- deployments: {},
52
- },
53
- c4Elements: [],
54
- c4ExtendElements: [],
55
- c4Relations: [],
56
- c4Deployments: [],
57
- c4DeploymentRelations: [],
58
- c4Globals: {
59
- predicates: {},
60
- dynamicPredicates: {},
61
- styles: {},
62
- },
63
- c4Views: [],
64
- }
65
- doc = Object.assign(doc, props)
66
- const parser = this.forDocument(doc)
67
- parser.parseSpecification()
68
- parser.parseModel()
69
- parser.parseGlobals()
70
- parser.parseDeployment()
71
- parser.parseViews()
72
- return parser.doc
73
- } catch (cause) {
74
- throw new Error(`Error parsing document ${doc.uri.toString()}`, { cause })
75
- }
76
- }
77
-
78
- forDocument(doc: LangiumDocument): DocumentParser {
79
- invariant(isFqnIndexedDocument(doc), `Not a FqnIndexedDocument: ${doc.uri.toString(true)}`)
80
- return this.cachedParsers.get(
81
- doc.uri,
82
- 'DocumentParser',
83
- () => new DocumentParser(this.services, doc as ParsedLikeC4LangiumDocument),
84
- )
85
- }
86
- }
@@ -1,113 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { invariant, isNonEmptyArray } from '@likec4/core'
3
- import type { AstNode } from 'langium'
4
- import { filter, flatMap, fromEntries, isEmpty, isNonNullish, isTruthy, map, pipe, unique } from 'remeda'
5
- import stripIndent from 'strip-indent'
6
- import { type ParsedLikeC4LangiumDocument, type ParsedLink, ast } from '../../ast'
7
- import type { LikeC4Services } from '../../module'
8
- import { getFqnElementRef } from '../../utils/elementRef'
9
- import { type IsValidFn, checksFromDiagnostics } from '../../validation'
10
-
11
- // the class which this mixin is applied to
12
- export type GConstructor<T = {}> = new(...args: any[]) => T
13
-
14
- export function toSingleLine<T extends string | undefined | null>(str: T): T {
15
- return (isNonNullish(str) ? removeIndent(str).split('\n').join(' ') : undefined) as T
16
- }
17
-
18
- export function removeIndent<T extends string | undefined | null>(str: T): T {
19
- return (isNonNullish(str) ? stripIndent(str).trim() : undefined) as T
20
- }
21
-
22
- export type Base = GConstructor<BaseParser>
23
-
24
- export class BaseParser {
25
- isValid: IsValidFn
26
-
27
- constructor(
28
- public readonly services: LikeC4Services,
29
- public readonly doc: ParsedLikeC4LangiumDocument,
30
- ) {
31
- // do nothing
32
- this.isValid = checksFromDiagnostics(doc).isValid
33
- }
34
-
35
- resolveFqn(node: ast.FqnReferenceable): c4.Fqn {
36
- if (ast.isDeploymentElement(node)) {
37
- return this.services.likec4.DeploymentsIndex.getFqn(node)
38
- }
39
- if (ast.isExtendElement(node)) {
40
- return getFqnElementRef(node.element)
41
- }
42
- const fqn = this.services.likec4.FqnIndex.getFqn(node)
43
- invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`)
44
- return fqn
45
- }
46
-
47
- getAstNodePath(node: AstNode) {
48
- return this.services.workspace.AstNodeLocator.getAstNodePath(node)
49
- }
50
-
51
- getMetadata(metadataAstNode: ast.MetadataProperty | undefined): { [key: string]: string } | undefined {
52
- if (!metadataAstNode || !this.isValid(metadataAstNode) || isEmpty(metadataAstNode.props)) {
53
- return undefined
54
- }
55
- const data = pipe(
56
- metadataAstNode.props,
57
- map(p => [p.key, removeIndent(p.value)] as [string, string]),
58
- filter(([_, value]) => isTruthy(value)),
59
- fromEntries(),
60
- )
61
- return isEmpty(data) ? undefined : data
62
- }
63
-
64
- convertTags<E extends { tags?: ast.Tags }>(withTags?: E) {
65
- return this.parseTags(withTags)
66
- }
67
- parseTags<E extends { tags?: ast.Tags }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null {
68
- let iter = withTags?.tags
69
- if (!iter) {
70
- return null
71
- }
72
- let tags = [] as c4.Tag[]
73
- while (iter) {
74
- try {
75
- if (this.isValid(iter)) {
76
- const values = iter.values.map(t => t.ref?.name).filter(isTruthy) as c4.Tag[]
77
- if (values.length > 0) {
78
- tags.push(...values)
79
- }
80
- }
81
- } catch (e) {
82
- // ignore
83
- }
84
- iter = iter.prev
85
- }
86
- tags = unique(tags.reverse())
87
- return isNonEmptyArray(tags) ? tags : null
88
- }
89
-
90
- convertLinks(source?: ast.LinkProperty['$container']): ParsedLink[] | undefined {
91
- return this.parseLinks(source)
92
- }
93
- parseLinks(source?: ast.LinkProperty['$container']): ParsedLink[] | undefined {
94
- if (!source?.props || source.props.length === 0) {
95
- return undefined
96
- }
97
- return pipe(
98
- source.props,
99
- filter(ast.isLinkProperty),
100
- flatMap(p => {
101
- if (!this.isValid(p)) {
102
- return []
103
- }
104
- const url = p.value
105
- if (isTruthy(url)) {
106
- const title = isTruthy(p.title) ? toSingleLine(p.title) : undefined
107
- return title ? { url, title } : { url }
108
- }
109
- return []
110
- }),
111
- )
112
- }
113
- }
@@ -1,192 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { FqnRef, isNonEmptyArray, nameFromFqn, nonexhaustive, nonNullable } from '@likec4/core'
3
- import { filter, first, isTruthy, map, mapToObj, pipe } from 'remeda'
4
- import {
5
- type ParsedAstDeployment,
6
- type ParsedAstDeploymentRelation,
7
- ast,
8
- streamDeploymentModel,
9
- toElementStyle,
10
- toRelationshipStyleExcludeDefaults,
11
- } from '../../ast'
12
- import { logWarnError } from '../../logger'
13
- import { elementRef } from '../../utils/elementRef'
14
- import { stringHash } from '../../utils/stringHash'
15
- import { removeIndent, toSingleLine } from './Base'
16
- import type { WithExpressionV2 } from './FqnRefParser'
17
-
18
- export type WithDeploymentModel = ReturnType<typeof DeploymentModelParser>
19
-
20
- export function DeploymentModelParser<TBase extends WithExpressionV2>(B: TBase) {
21
- return class DeploymentModelParser extends B {
22
- parseDeployment() {
23
- const doc = this.doc
24
- for (const el of streamDeploymentModel(doc)) {
25
- try {
26
- switch (true) {
27
- case ast.isDeploymentRelation(el): {
28
- if (this.isValid(el)) {
29
- doc.c4DeploymentRelations.push(this.parseDeploymentRelation(el))
30
- }
31
- break
32
- }
33
- case ast.isDeployedInstance(el):
34
- doc.c4Deployments.push(this.parseDeployedInstance(el))
35
- break
36
- case ast.isDeploymentNode(el): {
37
- doc.c4Deployments.push(this.parseDeploymentNode(el))
38
- break
39
- }
40
- default:
41
- nonexhaustive(el)
42
- }
43
- } catch (e) {
44
- logWarnError(e)
45
- }
46
- }
47
- }
48
-
49
- parseDeploymentNode(astNode: ast.DeploymentNode): ParsedAstDeployment.Node {
50
- const isValid = this.isValid
51
- const id = this.resolveFqn(astNode)
52
- const kind = nonNullable(astNode.kind.ref, 'DeploymentKind not resolved').name as c4.DeploymentNodeKind
53
- const tags = this.convertTags(astNode.body)
54
- const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
55
- const style = toElementStyle(stylePropsAst, isValid)
56
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
57
-
58
- const bodyProps = pipe(
59
- astNode.body?.props ?? [],
60
- filter(isValid),
61
- filter(ast.isElementStringProperty),
62
- mapToObj(p => [p.key, p.value || undefined]),
63
- )
64
-
65
- const title = removeIndent(astNode.title ?? bodyProps.title)
66
- const description = removeIndent(bodyProps.description)
67
- const technology = toSingleLine(bodyProps.technology)
68
-
69
- const links = this.convertLinks(astNode.body)
70
-
71
- // Property has higher priority than from style
72
- const iconProp = astNode.body?.props.find(ast.isIconProperty)
73
- if (iconProp && isValid(iconProp)) {
74
- const value = iconProp.libicon?.ref?.name ?? iconProp.value
75
- if (isTruthy(value)) {
76
- style.icon = value as c4.IconUrl
77
- }
78
- }
79
-
80
- return {
81
- id,
82
- kind,
83
- title: title ?? nameFromFqn(id),
84
- ...(metadata && { metadata }),
85
- ...(tags && { tags }),
86
- ...(links && isNonEmptyArray(links) && { links }),
87
- ...(isTruthy(technology) && { technology }),
88
- ...(isTruthy(description) && { description }),
89
- style,
90
- }
91
- }
92
-
93
- parseDeployedInstance(astNode: ast.DeployedInstance): ParsedAstDeployment.Instance {
94
- const isValid = this.isValid
95
- const id = this.resolveFqn(astNode)
96
- const element = this.resolveFqn(nonNullable(elementRef(astNode.element), 'DeployedInstance element not found'))
97
-
98
- const tags = this.convertTags(astNode.body)
99
- const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
100
- const style = toElementStyle(stylePropsAst, isValid)
101
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
102
-
103
- const bodyProps = pipe(
104
- astNode.body?.props ?? [],
105
- filter(isValid),
106
- filter(ast.isElementStringProperty),
107
- mapToObj(p => [p.key, p.value || undefined]),
108
- )
109
-
110
- const title = removeIndent(astNode.title ?? bodyProps.title)
111
- const description = removeIndent(bodyProps.description)
112
- const technology = toSingleLine(bodyProps.technology)
113
-
114
- const links = this.convertLinks(astNode.body)
115
-
116
- // Property has higher priority than from style
117
- const iconProp = astNode.body?.props.find(ast.isIconProperty)
118
- if (iconProp && isValid(iconProp)) {
119
- const value = iconProp.libicon?.ref?.name ?? iconProp.value
120
- if (isTruthy(value)) {
121
- style.icon = value as c4.IconUrl
122
- }
123
- }
124
-
125
- return {
126
- id,
127
- element,
128
- ...(metadata && { metadata }),
129
- ...(title && { title }),
130
- ...(tags && { tags }),
131
- ...(links && isNonEmptyArray(links) && { links }),
132
- ...(isTruthy(technology) && { technology }),
133
- ...(isTruthy(description) && { description }),
134
- style,
135
- }
136
- }
137
-
138
- parseDeploymentRelation(astNode: ast.DeploymentRelation): ParsedAstDeploymentRelation {
139
- const isValid = this.isValid
140
- const astPath = this.getAstNodePath(astNode)
141
- const source = FqnRef.toDeploymentRef(this.parseFqnRef(astNode.source))
142
- const target = FqnRef.toDeploymentRef(this.parseFqnRef(astNode.target))
143
-
144
- const tags = this.convertTags(astNode) ?? this.convertTags(astNode.body)
145
- const links = this.convertLinks(astNode.body)
146
- const kind = astNode.kind?.ref?.name as (c4.RelationshipKind | undefined)
147
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
148
-
149
- const bodyProps = mapToObj(
150
- astNode.body?.props.filter(ast.isRelationStringProperty) ?? [],
151
- p => [p.key, p.value as string | undefined],
152
- )
153
-
154
- const navigateTo = pipe(
155
- astNode.body?.props ?? [],
156
- filter(ast.isRelationNavigateToProperty),
157
- map(p => p.value.view.ref?.name),
158
- filter(isTruthy),
159
- first(),
160
- )
161
-
162
- const title = removeIndent(astNode.title ?? bodyProps.title)
163
- const description = removeIndent(bodyProps.description)
164
- const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology)
165
-
166
- const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty)
167
-
168
- const id = stringHash(
169
- 'deployment',
170
- astPath,
171
- source.id,
172
- target.id,
173
- ) as c4.RelationId
174
-
175
- return {
176
- id,
177
- source,
178
- target,
179
- ...title && { title },
180
- ...(metadata && { metadata }),
181
- ...(isTruthy(technology) && { technology }),
182
- ...(isTruthy(description) && { description }),
183
- ...(kind && { kind }),
184
- ...(tags && { tags }),
185
- ...(isNonEmptyArray(links) && { links }),
186
- ...toRelationshipStyleExcludeDefaults(styleProp?.props, isValid),
187
- ...(navigateTo && { navigateTo: navigateTo as c4.ViewId }),
188
- astPath,
189
- }
190
- }
191
- }
192
- }