@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,122 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core'
3
- import { isNonNullish } from 'remeda'
4
- import { type ParsedAstDeploymentView, ast, toAutoLayout, toElementStyle, ViewOps } from '../../ast'
5
- import { logWarnError } from '../../logger'
6
- import { stringHash } from '../../utils'
7
- import { parseViewManualLayout } from '../../view-utils/manual-layout'
8
- import { removeIndent, toSingleLine } from './Base'
9
- import type { WithDeploymentModel } from './DeploymentModelParser'
10
- import type { WithExpressionV2 } from './FqnRefParser'
11
-
12
- export type WithDeploymentView = ReturnType<typeof DeploymentViewParser>
13
-
14
- export function DeploymentViewParser<TBase extends WithExpressionV2 & WithDeploymentModel>(B: TBase) {
15
- return class DeploymentViewParser extends B {
16
- parseDeploymentView(
17
- astNode: ast.DeploymentView,
18
- ): ParsedAstDeploymentView {
19
- const body = astNode.body
20
- invariant(body, 'DynamicElementView body is not defined')
21
- // only valid props
22
- const props = body.props.filter(this.isValid)
23
- const astPath = this.getAstNodePath(astNode)
24
-
25
- let id = astNode.name
26
- if (!id) {
27
- id = 'deployment_' + stringHash(
28
- this.doc.uri.toString(),
29
- astPath,
30
- ) as c4.ViewId
31
- }
32
-
33
- const title = toSingleLine(props.find(p => p.key === 'title')?.value) ?? null
34
- const description = removeIndent(props.find(p => p.key === 'description')?.value) ?? null
35
-
36
- const tags = this.convertTags(body)
37
- const links = this.convertLinks(body)
38
-
39
- ViewOps.writeId(astNode, id as c4.ViewId)
40
-
41
- const manualLayout = parseViewManualLayout(astNode)
42
-
43
- return {
44
- __: 'deployment',
45
- id: id as c4.ViewId,
46
- astPath,
47
- title,
48
- description,
49
- tags,
50
- links: isNonEmptyArray(links) ? links : null,
51
- rules: body.rules.flatMap(n => {
52
- try {
53
- return this.isValid(n) ? this.parseDeploymentViewRule(n) : []
54
- } catch (e) {
55
- logWarnError(e)
56
- return []
57
- }
58
- }),
59
- ...(manualLayout && { manualLayout }),
60
- }
61
- }
62
-
63
- parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule {
64
- if (ast.isDeploymentViewRulePredicate(astRule)) {
65
- return this.parseDeploymentViewRulePredicate(astRule)
66
- }
67
- if (ast.isViewRuleAutoLayout(astRule)) {
68
- return toAutoLayout(astRule)
69
- }
70
- if (ast.isDeploymentViewRuleStyle(astRule)) {
71
- return this.parseDeploymentViewRuleStyle(astRule)
72
- }
73
- nonexhaustive(astRule)
74
- }
75
-
76
- parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewRulePredicate {
77
- const exprs = [] as c4.ExpressionV2[]
78
- let iterator: ast.DeploymentViewRulePredicateExpression | undefined = astRule.expr
79
- while (iterator) {
80
- try {
81
- const expr = iterator.value
82
- if (isNonNullish(expr) && this.isValid(expr)) {
83
- switch (true) {
84
- case ast.isFqnExpr(expr):
85
- exprs.unshift(this.parseFqnExpr(expr))
86
- break
87
- case ast.isElementPredicateWhereV2(expr):
88
- exprs.unshift(this.parseElementWhereExpr(expr))
89
- break
90
- case ast.isRelationExpr(expr):
91
- exprs.unshift(this.parseRelationExpr(expr))
92
- break
93
- case ast.isRelationPredicateWhereV2(expr):
94
- exprs.unshift(this.parseRelationWhereExpr(expr))
95
- break
96
- default:
97
- nonexhaustive(expr)
98
- }
99
- }
100
- } catch (e) {
101
- logWarnError(e)
102
- }
103
- iterator = iterator.prev
104
- }
105
- return astRule.isInclude ? { include: exprs } : { exclude: exprs }
106
- }
107
-
108
- parseDeploymentViewRuleStyle(astRule: ast.DeploymentViewRuleStyle): c4.DeploymentViewRuleStyle {
109
- const styleProps = astRule.props.filter(ast.isStyleProperty)
110
- const notationProperty = astRule.props.find(ast.isNotationProperty)
111
- const notation = removeIndent(notationProperty?.value)
112
- const targets = this.parseFqnExpressions(astRule.targets)
113
- return {
114
- targets,
115
- ...(notation && { notation }),
116
- style: {
117
- ...toElementStyle(styleProps, this.isValid),
118
- },
119
- }
120
- }
121
- }
122
- }
@@ -1,143 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { nonexhaustive, nonNullable } from '@likec4/core'
3
- import { isNonNullish } from 'remeda'
4
- import { ast } from '../../ast'
5
- import { logWarnError } from '../../logger'
6
- import { instanceRef } from '../../utils/fqnRef'
7
- import { parseWhereClause } from '../model-parser-where'
8
- import type { Base } from './Base'
9
-
10
- export type WithExpressionV2 = ReturnType<typeof ExpressionV2Parser>
11
-
12
- export function ExpressionV2Parser<TBase extends Base>(B: TBase) {
13
- return class ExpressionV2Parser extends B {
14
- parseFqnRef(astNode: ast.FqnRef): c4.FqnRef {
15
- const refValue = nonNullable(
16
- astNode.value.ref,
17
- `FqnRef is empty ${astNode.$cstNode?.range.start.line}:${astNode.$cstNode?.range.start.character}`,
18
- )
19
- if (ast.isElement(refValue)) {
20
- const deployedInstanceAst = instanceRef(astNode)
21
- if (!deployedInstanceAst) {
22
- return {
23
- model: this.resolveFqn(refValue),
24
- }
25
- }
26
- const deployment = this.resolveFqn(deployedInstanceAst)
27
- const element = this.resolveFqn(refValue)
28
- return {
29
- deployment,
30
- element,
31
- }
32
- }
33
-
34
- if (ast.isDeploymentElement(refValue)) {
35
- return {
36
- deployment: this.resolveFqn(refValue),
37
- }
38
- }
39
- nonexhaustive(refValue)
40
- }
41
-
42
- parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr {
43
- if (ast.isWildcardExpression(astNode)) {
44
- return {
45
- wildcard: true,
46
- }
47
- }
48
- if (ast.isFqnRefExpr(astNode)) {
49
- return this.parseFqnRefExpr(astNode)
50
- }
51
- nonexhaustive(astNode)
52
- }
53
-
54
- parseFqnRefExpr(astNode: ast.FqnRefExpr): c4.FqnExpr.NonWildcard {
55
- const ref = this.parseFqnRef(astNode.ref)
56
- switch (true) {
57
- case astNode.selector === '._':
58
- return {
59
- ref,
60
- selector: 'expanded',
61
- } as c4.FqnExpr.NonWildcard
62
- case astNode.selector === '.**':
63
- return {
64
- ref,
65
- selector: 'descendants',
66
- } as c4.FqnExpr.NonWildcard
67
- case astNode.selector === '.*':
68
- return {
69
- ref,
70
- selector: 'children',
71
- } as c4.FqnExpr.NonWildcard
72
- default:
73
- return { ref } as c4.FqnExpr.NonWildcard
74
- }
75
- }
76
-
77
- parseElementWhereExpr(astNode: ast.ElementPredicateWhereV2): c4.RelationExpr {
78
- return {
79
- where: {
80
- expr: this.parseFqnExpr(astNode.subject as ast.FqnExpr),
81
- condition: astNode.where ? parseWhereClause(astNode.where) : {
82
- kind: { neq: '--always-true--' },
83
- },
84
- },
85
- }
86
- }
87
-
88
- parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[] {
89
- const exprs = [] as c4.FqnExpr[]
90
- let iter: ast.FqnExpressions['prev'] = astNode
91
- while (iter) {
92
- try {
93
- if (isNonNullish(iter.value) && this.isValid(iter.value)) {
94
- exprs.push(this.parseFqnExpr(iter.value))
95
- }
96
- } catch (e) {
97
- logWarnError(e)
98
- }
99
- iter = iter.prev
100
- }
101
- return exprs.reverse()
102
- }
103
-
104
- parseRelationWhereExpr(astNode: ast.RelationPredicateWhereV2): c4.RelationExpr {
105
- return {
106
- where: {
107
- expr: this.parseRelationExpr(astNode.subject as ast.RelationExpr),
108
- condition: astNode.where ? parseWhereClause(astNode.where) : {
109
- kind: { neq: '--always-true--' },
110
- },
111
- },
112
- }
113
- }
114
-
115
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr {
116
- if (ast.isRelationPredicateWhere(astNode)) {
117
- }
118
- if (ast.isDirectedRelationExpr(astNode)) {
119
- return {
120
- source: this.parseFqnExpr(astNode.source.from),
121
- target: this.parseFqnExpr(astNode.target),
122
- isBidirectional: astNode.source.isBidirectional,
123
- }
124
- }
125
- if (ast.isInOutRelationExpr(astNode)) {
126
- return {
127
- inout: this.parseFqnExpr(astNode.inout.to),
128
- }
129
- }
130
- if (ast.isOutgoingRelationExpr(astNode)) {
131
- return {
132
- outgoing: this.parseFqnExpr(astNode.from),
133
- }
134
- }
135
- if (ast.isIncomingRelationExpr(astNode)) {
136
- return {
137
- incoming: this.parseFqnExpr(astNode.to),
138
- }
139
- }
140
- nonexhaustive(astNode)
141
- }
142
- }
143
- }
@@ -1,96 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { nonexhaustive } from '@likec4/core'
3
- import { isTruthy } from 'remeda'
4
- import { ast, type ParsedAstGlobals } from '../../ast'
5
- import { logger, logWarnError } from '../../logger'
6
- import type { WithViewsParser } from './ViewsParser'
7
-
8
- export function GlobalsParser<TBase extends WithViewsParser>(B: TBase) {
9
- return class GlobalsParser extends B {
10
- parseGlobals() {
11
- const { parseResult, c4Globals } = this.doc
12
- const isValid = this.isValid
13
-
14
- const globals = parseResult.value.globals.filter(isValid)
15
-
16
- const elRelPredicates = globals.flatMap(r => r.predicates.filter(isValid))
17
- for (const predicate of elRelPredicates) {
18
- try {
19
- const globalPredicateId = predicate.name as c4.GlobalPredicateId
20
- if (!isTruthy(globalPredicateId)) {
21
- continue
22
- }
23
- if (globalPredicateId in c4Globals.predicates) {
24
- logger.warn(`Global predicate named "${globalPredicateId}" is already defined`)
25
- continue
26
- }
27
-
28
- this.parseAndStoreGlobalPredicateGroupOrDynamic(predicate, globalPredicateId, c4Globals)
29
- } catch (e) {
30
- logWarnError(e)
31
- }
32
- }
33
-
34
- const styles = globals.flatMap(r => r.styles.filter(isValid))
35
- for (const style of styles) {
36
- try {
37
- const globalStyleId = style.id.name as c4.GlobalStyleID
38
- if (!isTruthy(globalStyleId)) {
39
- continue
40
- }
41
- if (globalStyleId in c4Globals.styles) {
42
- logger.warn(`Global style named "${globalStyleId}" is already defined`)
43
- continue
44
- }
45
-
46
- const styles = this.parseGlobalStyleOrGroup(style)
47
- if (styles.length > 0) {
48
- c4Globals.styles[globalStyleId] = styles as c4.NonEmptyArray<c4.ViewRuleStyle>
49
- }
50
- } catch (e) {
51
- logWarnError(e)
52
- }
53
- }
54
- }
55
-
56
- parseAndStoreGlobalPredicateGroupOrDynamic(
57
- astRule: ast.GlobalPredicateGroup | ast.GlobalDynamicPredicateGroup,
58
- id: c4.GlobalPredicateId,
59
- c4Globals: ParsedAstGlobals
60
- ) {
61
- if (ast.isGlobalPredicateGroup(astRule)) {
62
- const predicates = this.parseGlobalPredicateGroup(astRule)
63
- if (predicates.length > 0) {
64
- c4Globals.predicates[id] = predicates as c4.NonEmptyArray<c4.ViewRulePredicate>
65
- }
66
- return
67
- }
68
- if (ast.isGlobalDynamicPredicateGroup(astRule)) {
69
- const predicates = this.parseGlobalDynamicPredicateGroup(astRule)
70
- if (predicates.length > 0) {
71
- c4Globals.dynamicPredicates[id] = predicates as c4.NonEmptyArray<c4.DynamicViewIncludeRule>
72
- }
73
- return
74
- }
75
- nonexhaustive(astRule)
76
- }
77
-
78
- parseGlobalPredicateGroup(astRule: ast.GlobalPredicateGroup): c4.ViewRulePredicate[] {
79
- return astRule.predicates.map(p => this.parseViewRulePredicate(p))
80
- }
81
-
82
- parseGlobalDynamicPredicateGroup(astRule: ast.GlobalDynamicPredicateGroup): c4.DynamicViewIncludeRule[] {
83
- return astRule.predicates.map(p => this.parseDynamicViewIncludePredicate(p))
84
- }
85
-
86
- parseGlobalStyleOrGroup(astRule: ast.GlobalStyle | ast.GlobalStyleGroup): c4.ViewRuleStyle[] {
87
- if (ast.isGlobalStyle(astRule)) {
88
- return [this.parseViewRuleStyle(astRule)]
89
- }
90
- if (ast.isGlobalStyleGroup(astRule)) {
91
- return astRule.styles.map(s => this.parseViewRuleStyle(s))
92
- }
93
- nonexhaustive(astRule)
94
- }
95
- }
96
- }
@@ -1,170 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { isNonEmptyArray, nonexhaustive, nonNullable } from '@likec4/core'
3
- import { filter, first, isEmpty, isNonNullish, isTruthy, map, mapToObj, pipe } from 'remeda'
4
- import {
5
- type ParsedAstElement,
6
- type ParsedAstExtendElement,
7
- type ParsedAstRelation,
8
- ast,
9
- resolveRelationPoints,
10
- streamModel,
11
- toElementStyle,
12
- toRelationshipStyleExcludeDefaults,
13
- } from '../../ast'
14
- import { logWarnError } from '../../logger'
15
- import { stringHash } from '../../utils/stringHash'
16
- import { type Base, removeIndent, toSingleLine } from './Base'
17
-
18
- export type WithModel = ReturnType<typeof ModelParser>
19
-
20
- export function ModelParser<TBase extends Base>(B: TBase) {
21
- return class ModelParser extends B {
22
- parseModel() {
23
- const doc = this.doc
24
- for (const el of streamModel(doc)) {
25
- try {
26
- if (ast.isElement(el)) {
27
- doc.c4Elements.push(this.parseElement(el))
28
- continue
29
- }
30
- if (ast.isRelation(el)) {
31
- if (this.isValid(el)) {
32
- doc.c4Relations.push(this.parseRelation(el))
33
- }
34
- continue
35
- }
36
- if (ast.isExtendElement(el)) {
37
- const parsed = this.parseExtendElement(el)
38
- if (parsed) {
39
- doc.c4ExtendElements.push(parsed)
40
- }
41
- continue
42
- }
43
- nonexhaustive(el)
44
- } catch (e) {
45
- logWarnError(e)
46
- }
47
- }
48
- }
49
-
50
- parseElement(astNode: ast.Element): ParsedAstElement {
51
- const isValid = this.isValid
52
- const id = this.resolveFqn(astNode)
53
- const kind = nonNullable(astNode.kind.ref, 'Element kind is not resolved').name as c4.ElementKind
54
- const tags = this.parseTags(astNode.body)
55
- const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
56
- const style = toElementStyle(stylePropsAst, isValid)
57
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
58
- const astPath = this.getAstNodePath(astNode)
59
-
60
- let [title, description, technology] = astNode.props ?? []
61
-
62
- const bodyProps = pipe(
63
- astNode.body?.props ?? [],
64
- filter(isValid),
65
- filter(ast.isElementStringProperty),
66
- mapToObj(p => [p.key, p.value || undefined]),
67
- )
68
-
69
- title = removeIndent(title ?? bodyProps.title)
70
- description = removeIndent(bodyProps.description ?? description)
71
- technology = toSingleLine(bodyProps.technology ?? technology)
72
-
73
- const links = this.parseLinks(astNode.body)
74
-
75
- // Property has higher priority than from style
76
- const iconProp = astNode.body?.props.find(ast.isIconProperty)
77
- if (iconProp && isValid(iconProp)) {
78
- const value = iconProp.libicon?.ref?.name ?? iconProp.value
79
- if (isTruthy(value)) {
80
- style.icon = value as c4.IconUrl
81
- }
82
- }
83
-
84
- return {
85
- id,
86
- kind,
87
- astPath,
88
- title: title ?? astNode.name,
89
- ...(metadata && { metadata }),
90
- ...(tags && { tags }),
91
- ...(links && isNonEmptyArray(links) && { links }),
92
- ...(isTruthy(technology) && { technology }),
93
- ...(isTruthy(description) && { description }),
94
- style,
95
- }
96
- }
97
-
98
- parseExtendElement(astNode: ast.ExtendElement): ParsedAstExtendElement | null {
99
- const isValid = this.isValid
100
- const id = this.resolveFqn(astNode)
101
- const tags = this.parseTags(astNode.body)
102
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
103
- const astPath = this.getAstNodePath(astNode)
104
- const links = this.parseLinks(astNode.body) ?? []
105
-
106
- if (!tags && isEmpty(metadata ?? {}) && isEmpty(links)) {
107
- return null
108
- }
109
-
110
- return {
111
- id,
112
- astPath,
113
- ...(metadata && { metadata }),
114
- ...(tags && { tags }),
115
- ...(links && isNonEmptyArray(links) && { links }),
116
- }
117
- }
118
-
119
- parseRelation(astNode: ast.Relation): ParsedAstRelation {
120
- const isValid = this.isValid
121
- const coupling = resolveRelationPoints(astNode)
122
- const target = this.resolveFqn(coupling.target)
123
- const source = this.resolveFqn(coupling.source)
124
- const tags = this.parseTags(astNode) ?? this.parseTags(astNode.body)
125
- const links = this.parseLinks(astNode.body)
126
- const kind = astNode.kind?.ref?.name as (c4.RelationshipKind | undefined)
127
- const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
128
- const astPath = this.getAstNodePath(astNode)
129
-
130
- const bodyProps = mapToObj(
131
- astNode.body?.props.filter(ast.isRelationStringProperty).filter(p => isNonNullish(p.value)) ?? [],
132
- p => [p.key, p.value],
133
- )
134
-
135
- const navigateTo = pipe(
136
- astNode.body?.props ?? [],
137
- filter(ast.isRelationNavigateToProperty),
138
- map(p => p.value.view.ref?.name),
139
- filter(isTruthy),
140
- first(),
141
- )
142
-
143
- const title = removeIndent(astNode.title ?? bodyProps.title) ?? ''
144
- const description = removeIndent(bodyProps.description)
145
- const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology)
146
-
147
- const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty)
148
- const id = stringHash(
149
- astPath,
150
- source,
151
- target,
152
- ) as c4.RelationId
153
- return {
154
- id,
155
- astPath,
156
- source,
157
- target,
158
- title,
159
- ...(metadata && { metadata }),
160
- ...(isTruthy(technology) && { technology }),
161
- ...(isTruthy(description) && { description }),
162
- ...(kind && { kind }),
163
- ...(tags && { tags }),
164
- ...(isNonEmptyArray(links) && { links }),
165
- ...toRelationshipStyleExcludeDefaults(styleProp?.props, isValid),
166
- ...(navigateTo && { navigateTo: navigateTo as c4.ViewId }),
167
- }
168
- }
169
- }
170
- }