@likec4/language-server 1.18.0 → 1.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4FileSystem.d.ts +13 -0
- package/dist/LikeC4FileSystem.js +27 -0
- package/dist/Rpc.d.ts +9 -0
- package/dist/Rpc.js +132 -0
- package/dist/ast.d.ts +200 -0
- package/dist/ast.js +276 -0
- package/dist/browser.d.ts +7 -20
- package/dist/browser.js +13 -0
- package/dist/documentation/documentation-provider.d.ts +8 -0
- package/dist/documentation/documentation-provider.js +46 -0
- package/dist/documentation/index.d.ts +1 -0
- package/dist/documentation/index.js +1 -0
- package/dist/formatting/LikeC4Formatter.d.ts +27 -0
- package/dist/formatting/LikeC4Formatter.js +261 -0
- package/dist/formatting/utils.d.ts +6 -0
- package/dist/formatting/utils.js +15 -0
- package/dist/generated/ast.d.ts +1242 -0
- package/dist/generated/ast.js +1945 -0
- package/dist/generated/grammar.d.ts +6 -0
- package/dist/generated/grammar.js +3 -0
- package/dist/generated/module.d.ts +9 -0
- package/dist/generated/module.js +23 -0
- package/dist/generated-lib/icons.d.ts +1 -0
- package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
- package/dist/index.d.ts +9 -31
- package/dist/index.js +14 -0
- package/dist/like-c4.langium +845 -0
- package/dist/likec4lib.d.ts +4 -6
- package/dist/likec4lib.js +4 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +73 -0
- package/dist/lsp/CodeLensProvider.d.ts +9 -0
- package/dist/lsp/CodeLensProvider.js +40 -0
- package/dist/lsp/CompletionProvider.d.ts +6 -0
- package/dist/lsp/CompletionProvider.js +135 -0
- package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
- package/dist/lsp/DocumentHighlightProvider.js +10 -0
- package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
- package/dist/lsp/DocumentLinkProvider.js +49 -0
- package/dist/lsp/DocumentSymbolProvider.d.ts +32 -0
- package/dist/lsp/DocumentSymbolProvider.js +274 -0
- package/dist/lsp/HoverProvider.d.ts +10 -0
- package/dist/lsp/HoverProvider.js +69 -0
- package/dist/lsp/RenameProvider.d.ts +5 -0
- package/dist/lsp/RenameProvider.js +6 -0
- package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
- package/dist/lsp/SemanticTokenProvider.js +297 -0
- package/dist/lsp/index.d.ts +7 -0
- package/dist/lsp/index.js +7 -0
- package/dist/model/deployments-index.d.ts +60 -0
- package/dist/model/deployments-index.js +181 -0
- package/dist/model/fqn-computation.d.ts +3 -0
- package/dist/model/fqn-computation.js +72 -0
- package/dist/model/fqn-index.d.ts +25 -0
- package/dist/model/fqn-index.js +96 -0
- package/dist/model/index.d.ts +6 -0
- package/dist/model/index.js +6 -0
- package/dist/model/model-builder.d.ts +32 -0
- package/dist/model/model-builder.js +598 -0
- package/dist/model/model-locator.d.ts +23 -0
- package/dist/model/model-locator.js +126 -0
- package/dist/model/model-parser-where.d.ts +3 -0
- package/dist/model/model-parser-where.js +70 -0
- package/dist/model/model-parser.d.ts +292 -0
- package/dist/model/model-parser.js +72 -0
- package/dist/model/parser/Base.d.ts +28 -0
- package/dist/model/parser/Base.js +87 -0
- package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
- package/dist/model/parser/DeploymentModelParser.js +162 -0
- package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
- package/dist/model/parser/DeploymentViewParser.js +98 -0
- package/dist/model/parser/FqnRefParser.d.ts +29 -0
- package/dist/model/parser/FqnRefParser.js +108 -0
- package/dist/model/parser/GlobalsParser.d.ts +66 -0
- package/dist/model/parser/GlobalsParser.js +80 -0
- package/dist/model/parser/ModelParser.d.ts +27 -0
- package/dist/model/parser/ModelParser.js +122 -0
- package/dist/model/parser/PredicatesParser.d.ts +34 -0
- package/dist/model/parser/PredicatesParser.js +272 -0
- package/dist/model/parser/SpecificationParser.d.ts +27 -0
- package/dist/model/parser/SpecificationParser.js +120 -0
- package/dist/model/parser/ViewsParser.d.ts +64 -0
- package/dist/model/parser/ViewsParser.js +377 -0
- package/dist/model-change/ModelChanges.d.ts +15 -0
- package/dist/model-change/ModelChanges.js +89 -0
- package/dist/model-change/changeElementStyle.d.ts +16 -0
- package/dist/model-change/changeElementStyle.js +136 -0
- package/dist/model-change/changeViewLayout.d.ts +12 -0
- package/dist/model-change/changeViewLayout.js +32 -0
- package/dist/model-change/saveManualLayout.d.ts +11 -0
- package/dist/model-change/saveManualLayout.js +27 -0
- package/dist/module.d.ts +70 -0
- package/dist/module.js +162 -0
- package/dist/protocol.d.ts +38 -23
- package/dist/protocol.js +15 -0
- package/dist/references/index.d.ts +3 -0
- package/dist/references/index.js +3 -0
- package/dist/references/name-provider.d.ts +9 -0
- package/dist/references/name-provider.js +33 -0
- package/dist/references/scope-computation.d.ts +20 -0
- package/dist/references/scope-computation.js +281 -0
- package/dist/references/scope-provider.d.ts +16 -0
- package/dist/references/scope-provider.js +165 -0
- package/dist/shared/NodeKindProvider.d.ts +15 -0
- package/dist/shared/NodeKindProvider.js +108 -0
- package/dist/shared/WorkspaceManager.d.ts +18 -0
- package/dist/shared/WorkspaceManager.js +36 -0
- package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
- package/dist/shared/WorkspaceSymbolProvider.js +3 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/test/index.d.ts +1 -0
- package/dist/test/index.js +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +7 -0
- package/dist/test/testServices.d.ts +22 -0
- package/dist/test/testServices.js +119 -0
- package/dist/utils/elementRef.d.ts +11 -0
- package/dist/utils/elementRef.js +15 -0
- package/dist/utils/fqnRef.d.ts +8 -0
- package/dist/utils/fqnRef.js +46 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/printDocs.d.ts +2 -0
- package/dist/utils/printDocs.js +1 -0
- package/dist/utils/stringHash.d.ts +1 -0
- package/dist/utils/stringHash.js +5 -0
- package/dist/validation/_shared.d.ts +3 -0
- package/dist/validation/_shared.js +22 -0
- package/dist/validation/deployment-checks.d.ts +6 -0
- package/dist/validation/deployment-checks.js +114 -0
- package/dist/validation/dynamic-view-rule.d.ts +4 -0
- package/dist/validation/dynamic-view-rule.js +17 -0
- package/dist/validation/dynamic-view-step.d.ts +4 -0
- package/dist/validation/dynamic-view-step.js +29 -0
- package/dist/validation/element.d.ts +4 -0
- package/dist/validation/element.js +49 -0
- package/dist/validation/index.d.ts +15 -0
- package/dist/validation/index.js +152 -0
- package/dist/validation/property-checks.d.ts +6 -0
- package/dist/validation/property-checks.js +39 -0
- package/dist/validation/relation.d.ts +5 -0
- package/dist/validation/relation.js +56 -0
- package/dist/validation/specification.d.ts +11 -0
- package/dist/validation/specification.js +136 -0
- package/dist/validation/view-predicates/element-with.d.ts +4 -0
- package/dist/validation/view-predicates/element-with.js +31 -0
- package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
- package/dist/validation/view-predicates/expanded-element.js +12 -0
- package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
- package/dist/validation/view-predicates/expression-v2.js +83 -0
- package/dist/validation/view-predicates/incoming.d.ts +4 -0
- package/dist/validation/view-predicates/incoming.js +16 -0
- package/dist/validation/view-predicates/index.d.ts +6 -0
- package/dist/validation/view-predicates/index.js +6 -0
- package/dist/validation/view-predicates/outgoing.d.ts +4 -0
- package/dist/validation/view-predicates/outgoing.js +16 -0
- package/dist/validation/view-predicates/relation-with.d.ts +4 -0
- package/dist/validation/view-predicates/relation-with.js +13 -0
- package/dist/validation/view.d.ts +4 -0
- package/dist/validation/view.js +23 -0
- package/dist/view-utils/assignNavigateTo.d.ts +2 -0
- package/dist/view-utils/assignNavigateTo.js +25 -0
- package/dist/view-utils/index.d.ts +2 -0
- package/dist/view-utils/index.js +2 -0
- package/dist/view-utils/manual-layout.d.ts +7 -0
- package/dist/view-utils/manual-layout.js +99 -0
- package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
- package/dist/view-utils/resolve-relative-paths.js +78 -0
- package/dist/views/configurable-layouter.d.ts +7 -0
- package/dist/views/configurable-layouter.js +55 -0
- package/dist/views/index.d.ts +1 -0
- package/dist/views/index.js +1 -0
- package/dist/views/likec4-views.d.ts +26 -0
- package/dist/views/likec4-views.js +113 -0
- package/package.json +40 -54
- package/src/LikeC4FileSystem.ts +22 -21
- package/src/Rpc.ts +13 -7
- package/src/ast.ts +44 -133
- package/src/browser.ts +11 -11
- package/src/documentation/documentation-provider.ts +52 -0
- package/src/documentation/index.ts +1 -0
- package/src/generated/ast.ts +177 -177
- package/src/generated/grammar.ts +1 -1
- package/src/index.ts +13 -9
- package/src/like-c4.langium +37 -34
- package/src/logger.ts +34 -55
- package/src/lsp/CompletionProvider.ts +4 -4
- package/src/lsp/DocumentSymbolProvider.ts +110 -28
- package/src/lsp/HoverProvider.ts +5 -3
- package/src/lsp/SemanticTokenProvider.ts +2 -2
- package/src/model/deployments-index.ts +18 -14
- package/src/model/fqn-computation.ts +8 -8
- package/src/model/model-builder.ts +62 -60
- package/src/model/model-parser.ts +62 -1574
- package/src/model/parser/Base.ts +107 -0
- package/src/model/parser/DeploymentModelParser.ts +192 -0
- package/src/model/parser/DeploymentViewParser.ts +116 -0
- package/src/model/parser/FqnRefParser.ts +118 -0
- package/src/model/parser/GlobalsParser.ts +96 -0
- package/src/model/parser/ModelParser.ts +141 -0
- package/src/model/parser/PredicatesParser.ts +291 -0
- package/src/model/parser/SpecificationParser.ts +133 -0
- package/src/model/parser/ViewsParser.ts +428 -0
- package/src/module.ts +71 -25
- package/src/protocol.ts +29 -4
- package/src/references/scope-computation.ts +35 -35
- package/src/references/scope-provider.ts +13 -7
- package/src/utils/{deploymentRef.ts → fqnRef.ts} +27 -2
- package/src/validation/_shared.ts +0 -1
- package/src/validation/deployment-checks.ts +49 -62
- package/src/validation/dynamic-view-rule.ts +5 -4
- package/src/validation/dynamic-view-step.ts +23 -26
- package/src/validation/index.ts +100 -9
- package/src/validation/property-checks.ts +11 -10
- package/src/validation/specification.ts +38 -38
- package/src/validation/view-predicates/element-with.ts +6 -5
- package/src/validation/view-predicates/expanded-element.ts +6 -5
- package/src/validation/view-predicates/expression-v2.ts +101 -0
- package/src/validation/view-predicates/incoming.ts +6 -5
- package/src/validation/view-predicates/index.ts +1 -1
- package/src/validation/view-predicates/outgoing.ts +6 -5
- package/src/validation/view-predicates/relation-with.ts +6 -5
- package/src/validation/view.ts +5 -5
- package/src/view-utils/assignNavigateTo.ts +1 -1
- package/src/view-utils/manual-layout.ts +25 -0
- package/src/views/configurable-layouter.ts +65 -0
- package/src/views/index.ts +1 -0
- package/src/views/likec4-views.ts +139 -0
- package/dist/browser.cjs +0 -25
- package/dist/browser.d.cts +0 -23
- package/dist/browser.d.mts +0 -23
- package/dist/browser.mjs +0 -20
- package/dist/index.cjs +0 -53
- package/dist/index.d.cts +0 -34
- package/dist/index.d.mts +0 -34
- package/dist/index.mjs +0 -46
- package/dist/likec4lib.cjs +0 -1546
- package/dist/likec4lib.d.cts +0 -6
- package/dist/likec4lib.d.mts +0 -6
- package/dist/protocol.cjs +0 -25
- package/dist/protocol.d.cts +0 -48
- package/dist/protocol.d.mts +0 -48
- package/dist/protocol.mjs +0 -17
- package/dist/shared/language-server.CO_nmHiL.cjs +0 -7689
- package/dist/shared/language-server.Da6ey08o.d.cts +0 -1619
- package/dist/shared/language-server.De7S3e5Z.d.ts +0 -1619
- package/dist/shared/language-server.Dj4iDjtB.d.mts +0 -1619
- package/dist/shared/language-server.oO_9JoAG.mjs +0 -7666
- package/src/validation/view-predicates/deployments.ts +0 -56
|
@@ -1,1594 +1,82 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import type { Writable } from 'type-fest'
|
|
8
|
-
import type {
|
|
9
|
-
ChecksFromDiagnostics,
|
|
10
|
-
FqnIndexedDocument,
|
|
11
|
-
ParsedAstDeployment,
|
|
12
|
-
ParsedAstDeploymentRelation,
|
|
13
|
-
ParsedAstDeploymentView,
|
|
14
|
-
ParsedAstDynamicView,
|
|
15
|
-
ParsedAstElement,
|
|
16
|
-
ParsedAstElementView,
|
|
17
|
-
ParsedAstGlobals,
|
|
18
|
-
ParsedAstRelation,
|
|
19
|
-
ParsedLikeC4LangiumDocument,
|
|
20
|
-
ParsedLink
|
|
21
|
-
} from '../ast'
|
|
22
|
-
import {
|
|
23
|
-
ast,
|
|
24
|
-
checksFromDiagnostics,
|
|
25
|
-
cleanParsedModel,
|
|
26
|
-
isFqnIndexedDocument,
|
|
27
|
-
parseAstOpacityProperty,
|
|
28
|
-
resolveRelationPoints,
|
|
29
|
-
streamModel,
|
|
30
|
-
toAutoLayout,
|
|
31
|
-
toColor,
|
|
32
|
-
toElementStyle,
|
|
33
|
-
toRelationshipStyleExcludeDefaults,
|
|
34
|
-
ViewOps
|
|
35
|
-
} from '../ast'
|
|
36
|
-
import { type NotationProperty } from '../generated/ast'
|
|
37
|
-
import { logger, logWarnError } from '../logger'
|
|
1
|
+
import { invariant } from '@likec4/core'
|
|
2
|
+
import type { LangiumDocument } from 'langium'
|
|
3
|
+
import DefaultWeakMap from 'mnemonist/default-weak-map'
|
|
4
|
+
import { pipe } from 'remeda'
|
|
5
|
+
import type { LikeC4DocumentProps, ParsedLikeC4LangiumDocument } from '../ast'
|
|
6
|
+
import { isFqnIndexedDocument } from '../ast'
|
|
38
7
|
import type { LikeC4Services } from '../module'
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
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'
|
|
47
17
|
|
|
48
18
|
export type ModelParsedListener = () => void
|
|
49
19
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 {
|
|
56
33
|
}
|
|
57
34
|
|
|
58
|
-
export type IsValidFn = ChecksFromDiagnostics['isValid']
|
|
59
|
-
|
|
60
35
|
export class LikeC4ModelParser {
|
|
61
|
-
private
|
|
36
|
+
private cachedParsers = new DefaultWeakMap<LangiumDocument, DocumentParser>((doc: LangiumDocument) =>
|
|
37
|
+
new DocumentParser(this.services, doc as ParsedLikeC4LangiumDocument)
|
|
38
|
+
)
|
|
39
|
+
|
|
62
40
|
constructor(private services: LikeC4Services) {
|
|
63
|
-
this.fqnIndex = services.likec4.FqnIndex
|
|
64
|
-
logger.debug(`[ModelParser] Created`)
|
|
65
41
|
}
|
|
66
42
|
|
|
67
43
|
parse(doc: LangiumDocument): ParsedLikeC4LangiumDocument {
|
|
68
44
|
invariant(isFqnIndexedDocument(doc), `Not a FqnIndexedDocument: ${doc.uri.toString(true)}`)
|
|
69
45
|
try {
|
|
70
|
-
|
|
46
|
+
const props: Required<Omit<LikeC4DocumentProps, 'c4fqnIndex' | 'diagnostics'>> = {
|
|
47
|
+
c4Specification: {
|
|
48
|
+
tags: new Set(),
|
|
49
|
+
elements: {},
|
|
50
|
+
relationships: {},
|
|
51
|
+
colors: {},
|
|
52
|
+
deployments: {}
|
|
53
|
+
},
|
|
54
|
+
c4Elements: [],
|
|
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.cachedParsers.get(doc)
|
|
67
|
+
parser.parseSpecification()
|
|
68
|
+
parser.parseModel()
|
|
69
|
+
parser.parseGlobals()
|
|
70
|
+
parser.parseDeployment()
|
|
71
|
+
parser.parseViews()
|
|
72
|
+
return parser.doc
|
|
71
73
|
} catch (cause) {
|
|
72
74
|
throw new Error(`Error parsing document ${doc.uri.toString()}`, { cause })
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.parseSpecification(doc, isValid)
|
|
80
|
-
this.parseModel(doc, isValid)
|
|
81
|
-
this.parseGlobal(doc, isValid)
|
|
82
|
-
this.parseDeployment(doc, isValid)
|
|
83
|
-
this.parseViews(doc, isValid)
|
|
84
|
-
return doc
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
private parseSpecification(doc: ParsedLikeC4LangiumDocument, isValid: IsValidFn) {
|
|
88
|
-
const {
|
|
89
|
-
parseResult: {
|
|
90
|
-
value: {
|
|
91
|
-
specifications
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
c4Specification
|
|
95
|
-
} = doc
|
|
96
|
-
|
|
97
|
-
const element_specs = specifications.flatMap(s => s.elements.filter(isValid))
|
|
98
|
-
for (const { kind, props } of element_specs) {
|
|
99
|
-
try {
|
|
100
|
-
const kindName = kind.name as c4.ElementKind
|
|
101
|
-
if (!isTruthy(kindName)) {
|
|
102
|
-
continue
|
|
103
|
-
}
|
|
104
|
-
if (kindName in c4Specification.elements) {
|
|
105
|
-
logger.warn(`Element kind "${kindName}" is already defined`)
|
|
106
|
-
continue
|
|
107
|
-
}
|
|
108
|
-
const style = props.find(ast.isElementStyleProperty)
|
|
109
|
-
const bodyProps = pipe(
|
|
110
|
-
props.filter(ast.isSpecificationElementStringProperty) ?? [],
|
|
111
|
-
filter(p => isValid(p) && isNonNullish(p.value)),
|
|
112
|
-
mapToObj(p => [p.key, removeIndent(p.value)] satisfies [string, string])
|
|
113
|
-
)
|
|
114
|
-
c4Specification.elements[kindName] = {
|
|
115
|
-
...bodyProps,
|
|
116
|
-
style: {
|
|
117
|
-
...toElementStyle(style?.props, isValid)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} catch (e) {
|
|
121
|
-
logWarnError(e)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const relations_specs = specifications.flatMap(s => s.relationships.filter(isValid))
|
|
126
|
-
for (const { kind, props } of relations_specs) {
|
|
127
|
-
try {
|
|
128
|
-
const kindName = kind.name as c4.RelationshipKind
|
|
129
|
-
if (!isTruthy(kindName)) {
|
|
130
|
-
continue
|
|
131
|
-
}
|
|
132
|
-
if (kindName in c4Specification.relationships) {
|
|
133
|
-
logger.warn(`Relationship kind "${kindName}" is already defined`)
|
|
134
|
-
continue
|
|
135
|
-
}
|
|
136
|
-
const bodyProps = pipe(
|
|
137
|
-
props.filter(ast.isSpecificationRelationshipStringProperty) ?? [],
|
|
138
|
-
filter(p => isValid(p) && isNonNullish(p.value)),
|
|
139
|
-
mapToObj(p => [p.key, removeIndent(p.value)] satisfies [string, string])
|
|
140
|
-
)
|
|
141
|
-
c4Specification.relationships[kindName] = {
|
|
142
|
-
...bodyProps,
|
|
143
|
-
...toRelationshipStyleExcludeDefaults(props, isValid)
|
|
144
|
-
}
|
|
145
|
-
} catch (e) {
|
|
146
|
-
logWarnError(e)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const tags_specs = specifications.flatMap(s => s.tags.filter(isValid))
|
|
151
|
-
for (const tagSpec of tags_specs) {
|
|
152
|
-
const tag = tagSpec.tag.name as c4.Tag
|
|
153
|
-
if (isTruthy(tag)) {
|
|
154
|
-
c4Specification.tags.add(tag)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const deploymentNodes_specs = specifications.flatMap(s => s.deploymentNodes.filter(isValid))
|
|
159
|
-
for (const deploymentNode of deploymentNodes_specs) {
|
|
160
|
-
try {
|
|
161
|
-
Object.assign(c4Specification.deployments, this.parseSpecificationDeploymentNodeKind(deploymentNode, isValid))
|
|
162
|
-
} catch (e) {
|
|
163
|
-
logWarnError(e)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const colors_specs = specifications.flatMap(s => s.colors.filter(isValid))
|
|
168
|
-
for (const { name, color } of colors_specs) {
|
|
169
|
-
try {
|
|
170
|
-
const colorName = name.name as c4.CustomColor
|
|
171
|
-
if (colorName in c4Specification.colors) {
|
|
172
|
-
logger.warn(`Custom color "${colorName}" is already defined`)
|
|
173
|
-
continue
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
c4Specification.colors[colorName] = {
|
|
177
|
-
color: color as HexColorLiteral
|
|
178
|
-
}
|
|
179
|
-
} catch (e) {
|
|
180
|
-
logWarnError(e)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
private parseSpecificationDeploymentNodeKind(
|
|
186
|
-
{ kind, props }: ast.SpecificationDeploymentNodeKind,
|
|
187
|
-
isValid: IsValidFn
|
|
188
|
-
): { [key: c4.DeploymentNodeKind]: c4.DeploymentNodeKindSpecification } {
|
|
189
|
-
const kindName = kind.name as c4.DeploymentNodeKind
|
|
190
|
-
if (!isTruthy(kindName)) {
|
|
191
|
-
throw new Error('DeploymentNodeKind name is not resolved')
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const style = props.find(ast.isElementStyleProperty)
|
|
195
|
-
const bodyProps = pipe(
|
|
196
|
-
props.filter(ast.isSpecificationElementStringProperty) ?? [],
|
|
197
|
-
filter(p => isValid(p) && isNonNullish(p.value)),
|
|
198
|
-
mapToObj(p => [p.key, removeIndent(p.value)] satisfies [string, string])
|
|
199
|
-
)
|
|
200
|
-
return {
|
|
201
|
-
[kindName]: {
|
|
202
|
-
...bodyProps,
|
|
203
|
-
style: {
|
|
204
|
-
...toElementStyle(style?.props, isValid)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private parseModel(doc: ParsedLikeC4LangiumDocument, isValid: IsValidFn) {
|
|
211
|
-
for (const el of streamModel(doc, isValid)) {
|
|
212
|
-
if (ast.isElement(el)) {
|
|
213
|
-
try {
|
|
214
|
-
doc.c4Elements.push(this.parseElement(el, isValid))
|
|
215
|
-
} catch (e) {
|
|
216
|
-
logWarnError(e)
|
|
217
|
-
}
|
|
218
|
-
continue
|
|
219
|
-
}
|
|
220
|
-
if (ast.isRelation(el)) {
|
|
221
|
-
try {
|
|
222
|
-
doc.c4Relations.push(this.parseRelation(el, isValid))
|
|
223
|
-
} catch (e) {
|
|
224
|
-
logWarnError(e)
|
|
225
|
-
}
|
|
226
|
-
continue
|
|
227
|
-
}
|
|
228
|
-
nonexhaustive(el)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private parseElement(astNode: ast.Element, isValid: IsValidFn): ParsedAstElement {
|
|
233
|
-
const id = this.resolveFqn(astNode)
|
|
234
|
-
const kind = nonNullable(astNode.kind.ref, 'Element kind is not resolved').name as c4.ElementKind
|
|
235
|
-
const tags = this.convertTags(astNode.body)
|
|
236
|
-
const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
|
|
237
|
-
const style = toElementStyle(stylePropsAst, isValid)
|
|
238
|
-
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
|
|
239
|
-
const astPath = this.getAstNodePath(astNode)
|
|
240
|
-
|
|
241
|
-
let [title, description, technology] = astNode.props ?? []
|
|
242
|
-
|
|
243
|
-
const bodyProps = pipe(
|
|
244
|
-
astNode.body?.props ?? [],
|
|
245
|
-
filter(isValid),
|
|
246
|
-
filter(ast.isElementStringProperty),
|
|
247
|
-
mapToObj(p => [p.key, p.value || undefined])
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
title = removeIndent(title ?? bodyProps.title)
|
|
251
|
-
description = removeIndent(bodyProps.description ?? description)
|
|
252
|
-
technology = toSingleLine(bodyProps.technology ?? technology)
|
|
253
|
-
|
|
254
|
-
const links = this.convertLinks(astNode.body)
|
|
255
|
-
|
|
256
|
-
// Property has higher priority than from style
|
|
257
|
-
const iconProp = astNode.body?.props.find(ast.isIconProperty)
|
|
258
|
-
if (iconProp && isValid(iconProp)) {
|
|
259
|
-
const value = iconProp.libicon?.ref?.name ?? iconProp.value
|
|
260
|
-
if (isTruthy(value)) {
|
|
261
|
-
style.icon = value as c4.IconUrl
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
id,
|
|
267
|
-
kind,
|
|
268
|
-
astPath,
|
|
269
|
-
title: title ?? astNode.name,
|
|
270
|
-
...(metadata && { metadata }),
|
|
271
|
-
...(tags && { tags }),
|
|
272
|
-
...(links && isNonEmptyArray(links) && { links }),
|
|
273
|
-
...(isTruthy(technology) && { technology }),
|
|
274
|
-
...(isTruthy(description) && { description }),
|
|
275
|
-
style
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
private parseRelation(astNode: ast.Relation, isValid: IsValidFn): ParsedAstRelation {
|
|
280
|
-
const coupling = resolveRelationPoints(astNode)
|
|
281
|
-
const target = this.resolveFqn(coupling.target)
|
|
282
|
-
const source = this.resolveFqn(coupling.source)
|
|
283
|
-
const tags = this.convertTags(astNode) ?? this.convertTags(astNode.body)
|
|
284
|
-
const links = this.convertLinks(astNode.body)
|
|
285
|
-
const kind = astNode.kind?.ref?.name as (c4.RelationshipKind | undefined)
|
|
286
|
-
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
|
|
287
|
-
const astPath = this.getAstNodePath(astNode)
|
|
288
|
-
|
|
289
|
-
const bodyProps = mapToObj(
|
|
290
|
-
astNode.body?.props.filter(ast.isRelationStringProperty).filter(p => isNonNullish(p.value)) ?? [],
|
|
291
|
-
p => [p.key, p.value]
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
const navigateTo = pipe(
|
|
295
|
-
astNode.body?.props ?? [],
|
|
296
|
-
filter(ast.isRelationNavigateToProperty),
|
|
297
|
-
map(p => p.value.view.ref?.name),
|
|
298
|
-
filter(isTruthy),
|
|
299
|
-
first()
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
const title = removeIndent(astNode.title ?? bodyProps.title) ?? ''
|
|
303
|
-
const description = removeIndent(bodyProps.description)
|
|
304
|
-
const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology)
|
|
305
|
-
|
|
306
|
-
const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty)
|
|
307
|
-
const id = stringHash(
|
|
308
|
-
astPath,
|
|
309
|
-
source,
|
|
310
|
-
target
|
|
311
|
-
) as c4.RelationId
|
|
312
|
-
return {
|
|
313
|
-
id,
|
|
314
|
-
astPath,
|
|
315
|
-
source,
|
|
316
|
-
target,
|
|
317
|
-
title,
|
|
318
|
-
...(metadata && { metadata }),
|
|
319
|
-
...(isTruthy(technology) && { technology }),
|
|
320
|
-
...(isTruthy(description) && { description }),
|
|
321
|
-
...(kind && { kind }),
|
|
322
|
-
...(tags && { tags }),
|
|
323
|
-
...(isNonEmptyArray(links) && { links }),
|
|
324
|
-
...toRelationshipStyleExcludeDefaults(styleProp?.props, isValid),
|
|
325
|
-
...(navigateTo && { navigateTo: navigateTo as c4.ViewId })
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
private parseGlobal(doc: ParsedLikeC4LangiumDocument, isValid: IsValidFn) {
|
|
330
|
-
const { parseResult, c4Globals } = doc
|
|
331
|
-
|
|
332
|
-
const globals = parseResult.value.globals.filter(isValid)
|
|
333
|
-
|
|
334
|
-
const elRelPredicates = globals.flatMap(r => r.predicates.filter(isValid))
|
|
335
|
-
for (const predicate of elRelPredicates) {
|
|
336
|
-
try {
|
|
337
|
-
const globalPredicateId = predicate.name as c4.GlobalPredicateId
|
|
338
|
-
if (!isTruthy(globalPredicateId)) {
|
|
339
|
-
continue
|
|
340
|
-
}
|
|
341
|
-
if (globalPredicateId in c4Globals.predicates) {
|
|
342
|
-
logger.warn(`Global predicate named "${globalPredicateId}" is already defined`)
|
|
343
|
-
continue
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
this.parseAndStoreGlobalPredicateGroupOrDynamic(predicate, globalPredicateId, c4Globals, isValid)
|
|
347
|
-
} catch (e) {
|
|
348
|
-
logWarnError(e)
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const styles = globals.flatMap(r => r.styles.filter(isValid))
|
|
353
|
-
for (const style of styles) {
|
|
354
|
-
try {
|
|
355
|
-
const globalStyleId = style.id.name as c4.GlobalStyleID
|
|
356
|
-
if (!isTruthy(globalStyleId)) {
|
|
357
|
-
continue
|
|
358
|
-
}
|
|
359
|
-
if (globalStyleId in c4Globals.styles) {
|
|
360
|
-
logger.warn(`Global style named "${globalStyleId}" is already defined`)
|
|
361
|
-
continue
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const styles = this.parseGlobalStyleOrGroup(style, isValid)
|
|
365
|
-
if (styles.length > 0) {
|
|
366
|
-
c4Globals.styles[globalStyleId] = styles as c4.NonEmptyArray<c4.ViewRuleStyle>
|
|
367
|
-
}
|
|
368
|
-
} catch (e) {
|
|
369
|
-
logWarnError(e)
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
private parseAndStoreGlobalPredicateGroupOrDynamic(
|
|
375
|
-
astRule: ast.GlobalPredicateGroup | ast.GlobalDynamicPredicateGroup,
|
|
376
|
-
id: c4.GlobalPredicateId,
|
|
377
|
-
c4Globals: ParsedAstGlobals,
|
|
378
|
-
isValid: IsValidFn
|
|
379
|
-
) {
|
|
380
|
-
if (ast.isGlobalPredicateGroup(astRule)) {
|
|
381
|
-
const predicates = this.parseGlobalPredicateGroup(astRule, isValid)
|
|
382
|
-
if (predicates.length > 0) {
|
|
383
|
-
c4Globals.predicates[id] = predicates as c4.NonEmptyArray<c4.ViewRulePredicate>
|
|
384
|
-
}
|
|
385
|
-
return
|
|
386
|
-
}
|
|
387
|
-
if (ast.isGlobalDynamicPredicateGroup(astRule)) {
|
|
388
|
-
const predicates = this.parseGlobalDynamicPredicateGroup(astRule, isValid)
|
|
389
|
-
if (predicates.length > 0) {
|
|
390
|
-
c4Globals.dynamicPredicates[id] = predicates as c4.NonEmptyArray<c4.DynamicViewIncludeRule>
|
|
391
|
-
}
|
|
392
|
-
return
|
|
393
|
-
}
|
|
394
|
-
nonexhaustive(astRule)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
private parseGlobalPredicateGroup(
|
|
398
|
-
astRule: ast.GlobalPredicateGroup,
|
|
399
|
-
isValid: IsValidFn
|
|
400
|
-
): c4.ViewRulePredicate[] {
|
|
401
|
-
return astRule.predicates.map(p => this.parseViewRulePredicate(p, isValid))
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private parseGlobalDynamicPredicateGroup(
|
|
405
|
-
astRule: ast.GlobalDynamicPredicateGroup,
|
|
406
|
-
isValid: IsValidFn
|
|
407
|
-
): c4.DynamicViewIncludeRule[] {
|
|
408
|
-
return astRule.predicates.map(p => this.parseDynamicViewIncludePredicate(p, isValid))
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
private parseGlobalStyleOrGroup(
|
|
412
|
-
astRule: ast.GlobalStyle | ast.GlobalStyleGroup,
|
|
413
|
-
isValid: IsValidFn
|
|
414
|
-
): c4.ViewRuleStyle[] {
|
|
415
|
-
if (ast.isGlobalStyle(astRule)) {
|
|
416
|
-
return [this.parseViewRuleStyle(astRule, isValid)]
|
|
417
|
-
}
|
|
418
|
-
if (ast.isGlobalStyleGroup(astRule)) {
|
|
419
|
-
return astRule.styles.map(s => this.parseViewRuleStyle(s, isValid))
|
|
420
|
-
}
|
|
421
|
-
nonexhaustive(astRule)
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
private parseViews(doc: ParsedLikeC4LangiumDocument, isValid: IsValidFn) {
|
|
425
|
-
for (const viewBlock of doc.parseResult.value.views) {
|
|
426
|
-
const localStyles = viewBlock.styles.flatMap(s => {
|
|
427
|
-
try {
|
|
428
|
-
return isValid(s) ? this.parseViewRuleStyleOrGlobalRef(s, isValid) : []
|
|
429
|
-
} catch (e) {
|
|
430
|
-
logWarnError(e)
|
|
431
|
-
return []
|
|
432
|
-
}
|
|
433
|
-
})
|
|
434
|
-
|
|
435
|
-
for (const view of viewBlock.views) {
|
|
436
|
-
try {
|
|
437
|
-
if (!isValid(view)) {
|
|
438
|
-
continue
|
|
439
|
-
}
|
|
440
|
-
switch (true) {
|
|
441
|
-
case ast.isElementView(view):
|
|
442
|
-
doc.c4Views.push(this.parseElementView(view, localStyles, isValid))
|
|
443
|
-
break
|
|
444
|
-
case ast.isDynamicView(view):
|
|
445
|
-
doc.c4Views.push(this.parseDynamicElementView(view, localStyles, isValid))
|
|
446
|
-
break
|
|
447
|
-
case ast.isDeploymentView(view):
|
|
448
|
-
doc.c4Views.push(this.parseDeploymentView(view, isValid))
|
|
449
|
-
break
|
|
450
|
-
default:
|
|
451
|
-
nonexhaustive(view)
|
|
452
|
-
}
|
|
453
|
-
} catch (e) {
|
|
454
|
-
logWarnError(e)
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// TODO validate view rules
|
|
461
|
-
private parseViewRulePredicate(astNode: ast.ViewRulePredicate, _isValid: IsValidFn): c4.ViewRulePredicate {
|
|
462
|
-
const exprs = [] as c4.Expression[]
|
|
463
|
-
let predicate = astNode.predicates
|
|
464
|
-
while (predicate) {
|
|
465
|
-
const { value, prev } = predicate
|
|
466
|
-
try {
|
|
467
|
-
if (isTruthy(value) && _isValid(value as any)) {
|
|
468
|
-
exprs.unshift(this.parsePredicate(value, _isValid))
|
|
469
|
-
}
|
|
470
|
-
} catch (e) {
|
|
471
|
-
logWarnError(e)
|
|
472
|
-
}
|
|
473
|
-
if (!prev) {
|
|
474
|
-
break
|
|
475
|
-
}
|
|
476
|
-
predicate = prev
|
|
477
|
-
}
|
|
478
|
-
return ast.isIncludePredicate(astNode) ? { include: exprs } : { exclude: exprs }
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
private parsePredicate(astNode: ast.Predicate, _isValid: IsValidFn): c4.Expression {
|
|
482
|
-
if (ast.isElementPredicate(astNode)) {
|
|
483
|
-
return this.parseElementPredicate(astNode, _isValid)
|
|
484
|
-
}
|
|
485
|
-
if (ast.isRelationPredicate(astNode)) {
|
|
486
|
-
return this.parseRelationPredicate(astNode, _isValid)
|
|
487
|
-
}
|
|
488
|
-
nonexhaustive(astNode)
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
private parseElementExpressionsIterator(astNode: ast.ElementExpressionsIterator): c4.ElementExpression[] {
|
|
492
|
-
const exprs = [] as c4.ElementExpression[]
|
|
493
|
-
let iter: ast.ElementExpressionsIterator['prev'] = astNode
|
|
494
|
-
while (iter) {
|
|
495
|
-
try {
|
|
496
|
-
if (iter.value) {
|
|
497
|
-
exprs.unshift(this.parseElementExpr(iter.value))
|
|
498
|
-
}
|
|
499
|
-
} catch (e) {
|
|
500
|
-
logWarnError(e)
|
|
501
|
-
}
|
|
502
|
-
iter = iter.prev
|
|
503
|
-
}
|
|
504
|
-
return exprs
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
private parseElementPredicate(astNode: ast.ElementPredicate, _isValid: IsValidFn): c4.ElementPredicateExpression {
|
|
508
|
-
if (ast.isElementPredicateWith(astNode)) {
|
|
509
|
-
return this.parseElementPredicateWith(astNode, _isValid)
|
|
510
|
-
}
|
|
511
|
-
if (ast.isElementPredicateWhere(astNode)) {
|
|
512
|
-
return this.parseElementPredicateWhere(astNode)
|
|
513
|
-
}
|
|
514
|
-
if (ast.isElementExpression(astNode)) {
|
|
515
|
-
return this.parseElementExpr(astNode)
|
|
516
|
-
}
|
|
517
|
-
nonexhaustive(astNode)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
private parseElementExpr(astNode: ast.ElementExpression): c4.ElementExpression {
|
|
521
|
-
if (ast.isWildcardExpression(astNode)) {
|
|
522
|
-
return {
|
|
523
|
-
wildcard: true
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
if (ast.isElementKindExpression(astNode)) {
|
|
527
|
-
invariant(astNode.kind?.ref, 'ElementKindExpr kind is not resolved: ' + astNode.$cstNode?.text)
|
|
528
|
-
return {
|
|
529
|
-
elementKind: astNode.kind.ref.name as c4.ElementKind,
|
|
530
|
-
isEqual: astNode.isEqual
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
if (ast.isElementTagExpression(astNode)) {
|
|
534
|
-
invariant(astNode.tag?.ref, 'ElementTagExpr tag is not resolved: ' + astNode.$cstNode?.text)
|
|
535
|
-
let elementTag = astNode.tag.$refText
|
|
536
|
-
if (elementTag.startsWith('#')) {
|
|
537
|
-
elementTag = elementTag.slice(1)
|
|
538
|
-
}
|
|
539
|
-
return {
|
|
540
|
-
elementTag: elementTag as c4.Tag,
|
|
541
|
-
isEqual: astNode.isEqual
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
if (ast.isExpandElementExpression(astNode)) {
|
|
545
|
-
const elementNode = elementRef(astNode.expand)
|
|
546
|
-
invariant(elementNode, 'Element not found ' + astNode.expand.$cstNode?.text)
|
|
547
|
-
const expanded = this.resolveFqn(elementNode)
|
|
548
|
-
return {
|
|
549
|
-
expanded
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
if (ast.isElementDescedantsExpression(astNode)) {
|
|
553
|
-
const elementNode = elementRef(astNode.parent)
|
|
554
|
-
invariant(elementNode, 'Element not found ' + astNode.parent.$cstNode?.text)
|
|
555
|
-
const element = this.resolveFqn(elementNode)
|
|
556
|
-
return {
|
|
557
|
-
element,
|
|
558
|
-
isChildren: astNode.suffix === '.*',
|
|
559
|
-
isDescendants: astNode.suffix === '.**'
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
if (ast.isElementRef(astNode)) {
|
|
563
|
-
const elementNode = elementRef(astNode)
|
|
564
|
-
invariant(elementNode, 'Element not found ' + astNode.$cstNode?.text)
|
|
565
|
-
const element = this.resolveFqn(elementNode)
|
|
566
|
-
return {
|
|
567
|
-
element
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
nonexhaustive(astNode)
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
private parseElementPredicateWith(
|
|
574
|
-
astNode: ast.ElementPredicateWith,
|
|
575
|
-
_isValid: IsValidFn
|
|
576
|
-
): c4.CustomElementExpr {
|
|
577
|
-
const expr = this.parseElementPredicate(astNode.subject, _isValid)
|
|
578
|
-
const props = astNode.custom?.props ?? []
|
|
579
|
-
return props.reduce(
|
|
580
|
-
(acc, prop) => {
|
|
581
|
-
if (!_isValid(prop)) {
|
|
582
|
-
return acc
|
|
583
|
-
}
|
|
584
|
-
if (ast.isNavigateToProperty(prop)) {
|
|
585
|
-
const viewId = prop.value.view.$refText
|
|
586
|
-
if (isTruthy(viewId)) {
|
|
587
|
-
acc.custom.navigateTo = viewId as c4.ViewId
|
|
588
|
-
}
|
|
589
|
-
return acc
|
|
590
|
-
}
|
|
591
|
-
if (ast.isElementStringProperty(prop)) {
|
|
592
|
-
if (isDefined(prop.value)) {
|
|
593
|
-
acc.custom[prop.key] = removeIndent(prop.value) || ''
|
|
594
|
-
}
|
|
595
|
-
return acc
|
|
596
|
-
}
|
|
597
|
-
if (ast.isIconProperty(prop)) {
|
|
598
|
-
const value = prop.libicon?.ref?.name ?? prop.value
|
|
599
|
-
if (isDefined(value)) {
|
|
600
|
-
acc.custom[prop.key] = value as c4.IconUrl
|
|
601
|
-
}
|
|
602
|
-
return acc
|
|
603
|
-
}
|
|
604
|
-
if (ast.isColorProperty(prop)) {
|
|
605
|
-
const value = toColor(prop)
|
|
606
|
-
if (isDefined(value)) {
|
|
607
|
-
acc.custom[prop.key] = value
|
|
608
|
-
}
|
|
609
|
-
return acc
|
|
610
|
-
}
|
|
611
|
-
if (ast.isShapeProperty(prop)) {
|
|
612
|
-
if (isDefined(prop.value)) {
|
|
613
|
-
acc.custom[prop.key] = prop.value
|
|
614
|
-
}
|
|
615
|
-
return acc
|
|
616
|
-
}
|
|
617
|
-
if (ast.isBorderProperty(prop)) {
|
|
618
|
-
if (isDefined(prop.value)) {
|
|
619
|
-
acc.custom[prop.key] = prop.value
|
|
620
|
-
}
|
|
621
|
-
return acc
|
|
622
|
-
}
|
|
623
|
-
if (ast.isOpacityProperty(prop)) {
|
|
624
|
-
if (isDefined(prop.value)) {
|
|
625
|
-
acc.custom[prop.key] = parseAstOpacityProperty(prop)
|
|
626
|
-
}
|
|
627
|
-
return acc
|
|
628
|
-
}
|
|
629
|
-
if (ast.isNotationProperty(prop)) {
|
|
630
|
-
if (isTruthy(prop.value)) {
|
|
631
|
-
acc.custom[prop.key] = removeIndent(prop.value)
|
|
632
|
-
}
|
|
633
|
-
return acc
|
|
634
|
-
}
|
|
635
|
-
nonexhaustive(prop)
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
custom: {
|
|
639
|
-
expr
|
|
640
|
-
}
|
|
641
|
-
} as c4.CustomElementExpr
|
|
642
|
-
)
|
|
643
|
-
}
|
|
644
|
-
private parseElementPredicateWhere(
|
|
645
|
-
astNode: ast.ElementPredicateWhere
|
|
646
|
-
): c4.ElementWhereExpr {
|
|
647
|
-
const expr = this.parseElementExpr(astNode.subject)
|
|
648
|
-
return {
|
|
649
|
-
where: {
|
|
650
|
-
expr,
|
|
651
|
-
condition: astNode.where ? parseWhereClause(astNode.where) : {
|
|
652
|
-
kind: { neq: '--always-true--' }
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
private parseRelationPredicate(astNode: ast.RelationPredicate, _isValid: IsValidFn): c4.RelationPredicateExpression {
|
|
659
|
-
if (ast.isRelationPredicateWith(astNode)) {
|
|
660
|
-
let relation = ast.isRelationPredicateWhere(astNode.subject)
|
|
661
|
-
? this.parseRelationPredicateWhere(astNode.subject)
|
|
662
|
-
: this.parseRelationExpr(astNode.subject)
|
|
663
|
-
|
|
664
|
-
return this.parseRelationPredicateWith(astNode, relation)
|
|
665
|
-
}
|
|
666
|
-
if (ast.isRelationPredicateWhere(astNode)) {
|
|
667
|
-
return this.parseRelationPredicateWhere(astNode)
|
|
668
|
-
}
|
|
669
|
-
if (ast.isRelationExpression(astNode)) {
|
|
670
|
-
return this.parseRelationExpr(astNode)
|
|
671
|
-
}
|
|
672
|
-
nonexhaustive(astNode)
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
private parseRelationPredicateWhere(
|
|
676
|
-
astNode: ast.RelationPredicateWhere
|
|
677
|
-
): c4.RelationWhereExpr {
|
|
678
|
-
const expr = this.parseRelationExpr(astNode.subject)
|
|
679
|
-
return {
|
|
680
|
-
where: {
|
|
681
|
-
expr,
|
|
682
|
-
condition: astNode.where ? parseWhereClause(astNode.where) : {
|
|
683
|
-
kind: { neq: '--always-true--' }
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
private parseRelationPredicateWith(
|
|
690
|
-
astNode: ast.RelationPredicateWith,
|
|
691
|
-
relation: c4.RelationExpression | c4.RelationWhereExpr
|
|
692
|
-
): c4.CustomRelationExpr {
|
|
693
|
-
const props = astNode.custom?.props ?? []
|
|
694
|
-
return props.reduce(
|
|
695
|
-
(acc, prop) => {
|
|
696
|
-
if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
|
|
697
|
-
if (isDefined(prop.value)) {
|
|
698
|
-
acc.customRelation[prop.key] = removeIndent(prop.value) ?? ''
|
|
699
|
-
}
|
|
700
|
-
return acc
|
|
701
|
-
}
|
|
702
|
-
if (ast.isArrowProperty(prop)) {
|
|
703
|
-
if (isTruthy(prop.value)) {
|
|
704
|
-
acc.customRelation[prop.key] = prop.value
|
|
705
|
-
}
|
|
706
|
-
return acc
|
|
707
|
-
}
|
|
708
|
-
if (ast.isColorProperty(prop)) {
|
|
709
|
-
const value = toColor(prop)
|
|
710
|
-
if (isTruthy(value)) {
|
|
711
|
-
acc.customRelation[prop.key] = value
|
|
712
|
-
}
|
|
713
|
-
return acc
|
|
714
|
-
}
|
|
715
|
-
if (ast.isLineProperty(prop)) {
|
|
716
|
-
if (isTruthy(prop.value)) {
|
|
717
|
-
acc.customRelation[prop.key] = prop.value
|
|
718
|
-
}
|
|
719
|
-
return acc
|
|
720
|
-
}
|
|
721
|
-
if (ast.isRelationNavigateToProperty(prop)) {
|
|
722
|
-
const viewId = prop.value.view.ref?.name
|
|
723
|
-
if (isTruthy(viewId)) {
|
|
724
|
-
acc.customRelation.navigateTo = viewId as c4.ViewId
|
|
725
|
-
}
|
|
726
|
-
return acc
|
|
727
|
-
}
|
|
728
|
-
nonexhaustive(prop)
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
customRelation: {
|
|
732
|
-
relation
|
|
733
|
-
}
|
|
734
|
-
} as c4.CustomRelationExpr
|
|
735
|
-
)
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
private parseRelationExpr(astNode: ast.RelationExpression): c4.RelationExpression {
|
|
739
|
-
if (ast.isDirectedRelationExpression(astNode)) {
|
|
740
|
-
return {
|
|
741
|
-
source: this.parseElementExpr(astNode.source.from),
|
|
742
|
-
target: this.parseElementExpr(astNode.target),
|
|
743
|
-
isBidirectional: astNode.source.isBidirectional
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
if (ast.isInOutRelationExpression(astNode)) {
|
|
747
|
-
return {
|
|
748
|
-
inout: this.parseElementExpr(astNode.inout.to)
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
if (ast.isOutgoingRelationExpression(astNode)) {
|
|
752
|
-
return {
|
|
753
|
-
outgoing: this.parseElementExpr(astNode.from)
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
if (ast.isIncomingRelationExpression(astNode)) {
|
|
757
|
-
return {
|
|
758
|
-
incoming: this.parseElementExpr(astNode.to)
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
nonexhaustive(astNode)
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
private parseViewRule(astRule: ast.ViewRule, isValid: IsValidFn): c4.ViewRule {
|
|
765
|
-
if (ast.isViewRulePredicate(astRule)) {
|
|
766
|
-
return this.parseViewRulePredicate(astRule, isValid)
|
|
767
|
-
}
|
|
768
|
-
if (ast.isViewRuleGlobalPredicateRef(astRule)) {
|
|
769
|
-
return this.parseViewRuleGlobalPredicateRef(astRule, isValid)
|
|
770
|
-
}
|
|
771
|
-
if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
|
|
772
|
-
return this.parseViewRuleStyleOrGlobalRef(astRule, isValid)
|
|
773
|
-
}
|
|
774
|
-
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
775
|
-
return toAutoLayout(astRule)
|
|
776
|
-
}
|
|
777
|
-
if (ast.isViewRuleGroup(astRule)) {
|
|
778
|
-
return this.parseViewRuleGroup(astRule, isValid)
|
|
779
|
-
}
|
|
780
|
-
nonexhaustive(astRule)
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
private parseViewRuleGlobalPredicateRef(
|
|
784
|
-
astRule: ast.ViewRuleGlobalPredicateRef | ast.DynamicViewGlobalPredicateRef,
|
|
785
|
-
_isValid: IsValidFn
|
|
786
|
-
): c4.ViewRuleGlobalPredicateRef {
|
|
787
|
-
return {
|
|
788
|
-
predicateId: astRule.predicate.$refText as c4.GlobalPredicateId
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
private parseViewRuleStyleOrGlobalRef(
|
|
793
|
-
astRule: ast.ViewRuleStyleOrGlobalRef,
|
|
794
|
-
isValid: IsValidFn
|
|
795
|
-
): c4.ViewRuleStyleOrGlobalRef {
|
|
796
|
-
if (ast.isViewRuleStyle(astRule)) {
|
|
797
|
-
return this.parseViewRuleStyle(astRule, isValid)
|
|
798
|
-
}
|
|
799
|
-
if (ast.isViewRuleGlobalStyle(astRule)) {
|
|
800
|
-
return this.parseViewRuleGlobalStyle(astRule, isValid)
|
|
801
|
-
}
|
|
802
|
-
nonexhaustive(astRule)
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
private parseViewRuleStyle(astRule: ast.ViewRuleStyle | ast.GlobalStyle, isValid: IsValidFn): c4.ViewRuleStyle {
|
|
806
|
-
const styleProps = astRule.props.filter(ast.isStyleProperty)
|
|
807
|
-
const targets = astRule.target
|
|
808
|
-
const notation = astRule.props.find(ast.isNotationProperty)
|
|
809
|
-
return this.parseRuleStyle(styleProps, targets, isValid, notation)
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
private parseViewRuleGroup(astNode: ast.ViewRuleGroup, _isValid: IsValidFn): c4.ViewRuleGroup {
|
|
813
|
-
const groupRules = [] as c4.ViewRuleGroup['groupRules']
|
|
814
|
-
for (const rule of astNode.groupRules) {
|
|
815
|
-
try {
|
|
816
|
-
if (!_isValid(rule)) {
|
|
817
|
-
continue
|
|
818
|
-
}
|
|
819
|
-
if (ast.isViewRulePredicate(rule)) {
|
|
820
|
-
groupRules.push(this.parseViewRulePredicate(rule, _isValid))
|
|
821
|
-
continue
|
|
822
|
-
}
|
|
823
|
-
if (ast.isViewRuleGroup(rule)) {
|
|
824
|
-
groupRules.push(this.parseViewRuleGroup(rule, _isValid))
|
|
825
|
-
continue
|
|
826
|
-
}
|
|
827
|
-
nonexhaustive(rule)
|
|
828
|
-
} catch (e) {
|
|
829
|
-
logWarnError(e)
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
return {
|
|
833
|
-
title: toSingleLine(astNode.title) ?? null,
|
|
834
|
-
groupRules,
|
|
835
|
-
...toElementStyle(astNode.props, _isValid)
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
private parseRuleStyle(
|
|
840
|
-
styleProperties: ast.StyleProperty[],
|
|
841
|
-
elementExpressionsIterator: ast.ElementExpressionsIterator,
|
|
842
|
-
isValid: IsValidFn,
|
|
843
|
-
notationProperty?: NotationProperty
|
|
844
|
-
): c4.ViewRuleStyle {
|
|
845
|
-
const styleProps = toElementStyle(styleProperties, isValid)
|
|
846
|
-
const notation = removeIndent(notationProperty?.value)
|
|
847
|
-
const targets = this.parseElementExpressionsIterator(elementExpressionsIterator)
|
|
848
|
-
return {
|
|
849
|
-
targets,
|
|
850
|
-
...(notation && { notation }),
|
|
851
|
-
style: {
|
|
852
|
-
...styleProps
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
private parseViewRuleGlobalStyle(astRule: ast.ViewRuleGlobalStyle, _isValid: IsValidFn): c4.ViewRuleGlobalStyle {
|
|
858
|
-
return {
|
|
859
|
-
styleId: astRule.style.$refText as c4.GlobalStyleID
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
private parseViewManualLayout(node: ast.LikeC4View): c4.ViewManualLayout | undefined {
|
|
864
|
-
const commentNode = CstUtils.findCommentNode(node.$cstNode, ['BLOCK_COMMENT'])
|
|
865
|
-
if (!commentNode || !hasManualLayout(commentNode.text)) {
|
|
866
|
-
return undefined
|
|
867
|
-
}
|
|
868
|
-
try {
|
|
869
|
-
return deserializeFromComment(commentNode.text)
|
|
870
|
-
} catch (e) {
|
|
871
|
-
const doc = getDocument(node)
|
|
872
|
-
logger.warn(e)
|
|
873
|
-
logger.warn(
|
|
874
|
-
`Ignoring manual layout of "${node.name ?? 'unnamed'}" at ${doc.uri.fsPath}:${
|
|
875
|
-
1 + (commentNode.range.start.line || 0)
|
|
876
|
-
}`
|
|
877
|
-
)
|
|
878
|
-
return undefined
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
private parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps {
|
|
883
|
-
return {
|
|
884
|
-
__parallel: node.steps.map(step => this.parseDynamicStep(step))
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
private parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep {
|
|
889
|
-
const sourceEl = elementRef(node.source)
|
|
890
|
-
if (!sourceEl) {
|
|
891
|
-
throw new Error('Invalid reference to source')
|
|
892
|
-
}
|
|
893
|
-
const targetEl = elementRef(node.target)
|
|
894
|
-
if (!targetEl) {
|
|
895
|
-
throw new Error('Invalid reference to target')
|
|
896
|
-
}
|
|
897
|
-
let source = this.resolveFqn(sourceEl)
|
|
898
|
-
let target = this.resolveFqn(targetEl)
|
|
899
|
-
const title = removeIndent(node.title) ?? null
|
|
900
|
-
|
|
901
|
-
let step: Writable<c4.DynamicViewStep> = {
|
|
902
|
-
source,
|
|
903
|
-
target,
|
|
904
|
-
title
|
|
905
|
-
}
|
|
906
|
-
if (node.isBackward) {
|
|
907
|
-
step = {
|
|
908
|
-
source: target,
|
|
909
|
-
target: source,
|
|
910
|
-
title,
|
|
911
|
-
isBackward: true
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
if (!isArray(node.custom?.props)) {
|
|
915
|
-
return step
|
|
916
|
-
}
|
|
917
|
-
for (const prop of node.custom.props) {
|
|
918
|
-
try {
|
|
919
|
-
switch (true) {
|
|
920
|
-
case ast.isRelationNavigateToProperty(prop): {
|
|
921
|
-
const viewId = prop.value.view.ref?.name
|
|
922
|
-
if (isTruthy(viewId)) {
|
|
923
|
-
step.navigateTo = viewId as c4.ViewId
|
|
924
|
-
}
|
|
925
|
-
break
|
|
926
|
-
}
|
|
927
|
-
case ast.isRelationStringProperty(prop):
|
|
928
|
-
case ast.isNotationProperty(prop):
|
|
929
|
-
case ast.isNotesProperty(prop): {
|
|
930
|
-
if (isDefined(prop.value)) {
|
|
931
|
-
step[prop.key] = removeIndent(prop.value) ?? ''
|
|
932
|
-
}
|
|
933
|
-
break
|
|
934
|
-
}
|
|
935
|
-
case ast.isArrowProperty(prop): {
|
|
936
|
-
if (isDefined(prop.value)) {
|
|
937
|
-
step[prop.key] = prop.value
|
|
938
|
-
}
|
|
939
|
-
break
|
|
940
|
-
}
|
|
941
|
-
case ast.isColorProperty(prop): {
|
|
942
|
-
const value = toColor(prop)
|
|
943
|
-
if (isDefined(value)) {
|
|
944
|
-
step[prop.key] = value
|
|
945
|
-
}
|
|
946
|
-
break
|
|
947
|
-
}
|
|
948
|
-
case ast.isLineProperty(prop): {
|
|
949
|
-
if (isDefined(prop.value)) {
|
|
950
|
-
step[prop.key] = prop.value
|
|
951
|
-
}
|
|
952
|
-
break
|
|
953
|
-
}
|
|
954
|
-
default:
|
|
955
|
-
nonexhaustive(prop)
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
catch (e) {
|
|
959
|
-
logWarnError(e)
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
return step
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
private parseElementView(
|
|
966
|
-
astNode: ast.ElementView,
|
|
967
|
-
additionalStyles: c4.ViewRuleStyleOrGlobalRef[],
|
|
968
|
-
isValid: IsValidFn
|
|
969
|
-
): ParsedAstElementView {
|
|
970
|
-
const body = astNode.body
|
|
971
|
-
invariant(body, 'ElementView body is not defined')
|
|
972
|
-
const astPath = this.getAstNodePath(astNode)
|
|
973
|
-
|
|
974
|
-
let viewOf = null as c4.Fqn | null
|
|
975
|
-
if ('viewOf' in astNode) {
|
|
976
|
-
const viewOfEl = elementRef(astNode.viewOf)
|
|
977
|
-
const _viewOf = viewOfEl && this.resolveFqn(viewOfEl)
|
|
978
|
-
if (!_viewOf) {
|
|
979
|
-
logger.warn('viewOf is not resolved: ' + astNode.$cstNode?.text)
|
|
980
|
-
} else {
|
|
981
|
-
viewOf = _viewOf
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
let id = astNode.name
|
|
986
|
-
if (!id) {
|
|
987
|
-
id = 'view_' + stringHash(
|
|
988
|
-
getDocument(astNode).uri.toString(),
|
|
989
|
-
astPath,
|
|
990
|
-
viewOf ?? ''
|
|
991
|
-
) as c4.ViewId
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
const title = toSingleLine(body.props.find(p => p.key === 'title')?.value) ?? null
|
|
995
|
-
const description = removeIndent(body.props.find(p => p.key === 'description')?.value) ?? null
|
|
996
|
-
|
|
997
|
-
const tags = this.convertTags(body)
|
|
998
|
-
const links = this.convertLinks(body)
|
|
999
|
-
|
|
1000
|
-
const manualLayout = this.parseViewManualLayout(astNode)
|
|
1001
|
-
|
|
1002
|
-
const view: ParsedAstElementView = {
|
|
1003
|
-
__: 'element',
|
|
1004
|
-
id: id as c4.ViewId,
|
|
1005
|
-
astPath,
|
|
1006
|
-
title,
|
|
1007
|
-
description,
|
|
1008
|
-
tags,
|
|
1009
|
-
links: isNonEmptyArray(links) ? links : null,
|
|
1010
|
-
rules: [
|
|
1011
|
-
...additionalStyles,
|
|
1012
|
-
...body.rules.flatMap(n => {
|
|
1013
|
-
try {
|
|
1014
|
-
return isValid(n) ? this.parseViewRule(n, isValid) : []
|
|
1015
|
-
} catch (e) {
|
|
1016
|
-
logWarnError(e)
|
|
1017
|
-
return []
|
|
1018
|
-
}
|
|
1019
|
-
})
|
|
1020
|
-
],
|
|
1021
|
-
...(viewOf && { viewOf }),
|
|
1022
|
-
...(manualLayout && { manualLayout })
|
|
1023
|
-
}
|
|
1024
|
-
ViewOps.writeId(astNode, view.id)
|
|
1025
|
-
|
|
1026
|
-
if ('extends' in astNode) {
|
|
1027
|
-
const extendsView = astNode.extends.view.ref
|
|
1028
|
-
invariant(extendsView?.name, 'view extends is not resolved: ' + astNode.$cstNode?.text)
|
|
1029
|
-
return Object.assign(view, {
|
|
1030
|
-
extends: extendsView.name as c4.ViewId
|
|
1031
|
-
})
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
return view
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
private parseDynamicElementView(
|
|
1038
|
-
astNode: ast.DynamicView,
|
|
1039
|
-
additionalStyles: c4.ViewRuleStyleOrGlobalRef[],
|
|
1040
|
-
isValid: IsValidFn
|
|
1041
|
-
): ParsedAstDynamicView {
|
|
1042
|
-
const body = astNode.body
|
|
1043
|
-
invariant(body, 'DynamicElementView body is not defined')
|
|
1044
|
-
// only valid props
|
|
1045
|
-
const props = body.props.filter(isValid)
|
|
1046
|
-
const astPath = this.getAstNodePath(astNode)
|
|
1047
|
-
|
|
1048
|
-
let id = astNode.name
|
|
1049
|
-
if (!id) {
|
|
1050
|
-
id = 'dynamic_' + stringHash(
|
|
1051
|
-
getDocument(astNode).uri.toString(),
|
|
1052
|
-
astPath
|
|
1053
|
-
) as c4.ViewId
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
const title = toSingleLine(props.find(p => p.key === 'title')?.value) ?? null
|
|
1057
|
-
const description = removeIndent(props.find(p => p.key === 'description')?.value) ?? null
|
|
1058
|
-
|
|
1059
|
-
const tags = this.convertTags(body)
|
|
1060
|
-
const links = this.convertLinks(body)
|
|
1061
|
-
|
|
1062
|
-
ViewOps.writeId(astNode, id as c4.ViewId)
|
|
1063
|
-
|
|
1064
|
-
const manualLayout = this.parseViewManualLayout(astNode)
|
|
1065
|
-
|
|
1066
|
-
return {
|
|
1067
|
-
__: 'dynamic',
|
|
1068
|
-
id: id as c4.ViewId,
|
|
1069
|
-
astPath,
|
|
1070
|
-
title,
|
|
1071
|
-
description,
|
|
1072
|
-
tags,
|
|
1073
|
-
links: isNonEmptyArray(links) ? links : null,
|
|
1074
|
-
rules: [
|
|
1075
|
-
...additionalStyles,
|
|
1076
|
-
...body.rules.flatMap(n => {
|
|
1077
|
-
try {
|
|
1078
|
-
return isValid(n) ? this.parseDynamicViewRule(n, isValid) : []
|
|
1079
|
-
} catch (e) {
|
|
1080
|
-
logWarnError(e)
|
|
1081
|
-
return []
|
|
1082
|
-
}
|
|
1083
|
-
}, [] as Array<c4.DynamicViewRule>)
|
|
1084
|
-
],
|
|
1085
|
-
steps: body.steps.reduce((acc, n) => {
|
|
1086
|
-
try {
|
|
1087
|
-
if (isValid(n)) {
|
|
1088
|
-
if (ast.isDynamicViewParallelSteps(n)) {
|
|
1089
|
-
acc.push(this.parseDynamicParallelSteps(n))
|
|
1090
|
-
} else {
|
|
1091
|
-
acc.push(this.parseDynamicStep(n))
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
} catch (e) {
|
|
1095
|
-
logWarnError(e)
|
|
1096
|
-
}
|
|
1097
|
-
return acc
|
|
1098
|
-
}, [] as c4.DynamicViewStepOrParallel[]),
|
|
1099
|
-
...(manualLayout && { manualLayout })
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
private parseDynamicViewRule(astRule: ast.DynamicViewRule, isValid: IsValidFn): c4.DynamicViewRule {
|
|
1104
|
-
if (ast.isDynamicViewIncludePredicate(astRule)) {
|
|
1105
|
-
return this.parseDynamicViewIncludePredicate(astRule, isValid)
|
|
1106
|
-
}
|
|
1107
|
-
if (ast.isDynamicViewGlobalPredicateRef(astRule)) {
|
|
1108
|
-
return this.parseViewRuleGlobalPredicateRef(astRule, isValid)
|
|
1109
|
-
}
|
|
1110
|
-
if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
|
|
1111
|
-
return this.parseViewRuleStyleOrGlobalRef(astRule, isValid)
|
|
1112
|
-
}
|
|
1113
|
-
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
1114
|
-
return toAutoLayout(astRule)
|
|
1115
|
-
}
|
|
1116
|
-
nonexhaustive(astRule)
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
private parseDynamicViewIncludePredicate(
|
|
1120
|
-
astRule: ast.DynamicViewIncludePredicate,
|
|
1121
|
-
isValid: IsValidFn
|
|
1122
|
-
): c4.DynamicViewIncludeRule {
|
|
1123
|
-
const include = [] as c4.ElementPredicateExpression[]
|
|
1124
|
-
let iter: ast.DynamicViewPredicateIterator | undefined = astRule.predicates
|
|
1125
|
-
while (iter) {
|
|
1126
|
-
try {
|
|
1127
|
-
if (isNonNullish(iter.value) && isValid(iter.value as any)) {
|
|
1128
|
-
const c4expr = this.parseElementPredicate(iter.value, isValid)
|
|
1129
|
-
include.unshift(c4expr)
|
|
1130
|
-
}
|
|
1131
|
-
} catch (e) {
|
|
1132
|
-
logWarnError(e)
|
|
1133
|
-
}
|
|
1134
|
-
iter = iter.prev
|
|
1135
|
-
}
|
|
1136
|
-
return { include }
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
private parseDeployment(doc: ParsedLikeC4LangiumDocument, isValid: IsValidFn) {
|
|
1140
|
-
type TraversePair = ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentRelation
|
|
1141
|
-
const traverseStack: TraversePair[] = doc.parseResult.value.deployments.flatMap(d => d.elements)
|
|
1142
|
-
|
|
1143
|
-
let next: TraversePair | undefined
|
|
1144
|
-
while ((next = traverseStack.shift())) {
|
|
1145
|
-
if (ast.isDeploymentRelation(next)) {
|
|
1146
|
-
doc.c4DeploymentRelations.push(this.parseDeploymentRelation(next, isValid))
|
|
1147
|
-
continue
|
|
1148
|
-
}
|
|
1149
|
-
if (!isValid(next)) {
|
|
1150
|
-
continue
|
|
1151
|
-
}
|
|
1152
|
-
try {
|
|
1153
|
-
switch (true) {
|
|
1154
|
-
case ast.isDeployedInstance(next):
|
|
1155
|
-
doc.c4Deployments.push(this.parseDeployedInstance(next, isValid))
|
|
1156
|
-
break
|
|
1157
|
-
case ast.isDeploymentNode(next): {
|
|
1158
|
-
doc.c4Deployments.push(this.parseDeploymentNode(next, isValid))
|
|
1159
|
-
if (next.body && next.body.elements.length > 0) {
|
|
1160
|
-
traverseStack.push(...next.body.elements)
|
|
1161
|
-
}
|
|
1162
|
-
break
|
|
1163
|
-
}
|
|
1164
|
-
default:
|
|
1165
|
-
nonexhaustive(next)
|
|
1166
|
-
}
|
|
1167
|
-
} catch (e) {
|
|
1168
|
-
logWarnError(e)
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
public parseDeploymentNode(
|
|
1174
|
-
astNode: ast.DeploymentNode,
|
|
1175
|
-
isValid: IsValidFn
|
|
1176
|
-
): ParsedAstDeployment.Node {
|
|
1177
|
-
const id = this.resolveFqn(astNode)
|
|
1178
|
-
const kind = nonNullable(astNode.kind.ref, 'DeploymentKind not resolved').name as c4.DeploymentNodeKind
|
|
1179
|
-
const tags = this.convertTags(astNode.body)
|
|
1180
|
-
const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
|
|
1181
|
-
const style = toElementStyle(stylePropsAst, isValid)
|
|
1182
|
-
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
|
|
1183
|
-
|
|
1184
|
-
const bodyProps = pipe(
|
|
1185
|
-
astNode.body?.props ?? [],
|
|
1186
|
-
filter(isValid),
|
|
1187
|
-
filter(ast.isElementStringProperty),
|
|
1188
|
-
mapToObj(p => [p.key, p.value || undefined])
|
|
1189
|
-
)
|
|
1190
|
-
|
|
1191
|
-
const title = removeIndent(astNode.title ?? bodyProps.title)
|
|
1192
|
-
const description = removeIndent(bodyProps.description)
|
|
1193
|
-
const technology = toSingleLine(bodyProps.technology)
|
|
1194
|
-
|
|
1195
|
-
const links = this.convertLinks(astNode.body)
|
|
1196
|
-
|
|
1197
|
-
// Property has higher priority than from style
|
|
1198
|
-
const iconProp = astNode.body?.props.find(ast.isIconProperty)
|
|
1199
|
-
if (iconProp && isValid(iconProp)) {
|
|
1200
|
-
const value = iconProp.libicon?.ref?.name ?? iconProp.value
|
|
1201
|
-
if (isTruthy(value)) {
|
|
1202
|
-
style.icon = value as c4.IconUrl
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
return {
|
|
1207
|
-
id,
|
|
1208
|
-
kind,
|
|
1209
|
-
title: title ?? nameFromFqn(id),
|
|
1210
|
-
...(metadata && { metadata }),
|
|
1211
|
-
...(tags && { tags }),
|
|
1212
|
-
...(links && isNonEmptyArray(links) && { links }),
|
|
1213
|
-
...(isTruthy(technology) && { technology }),
|
|
1214
|
-
...(isTruthy(description) && { description }),
|
|
1215
|
-
style
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
public parseDeployedInstance(
|
|
1220
|
-
astNode: ast.DeployedInstance,
|
|
1221
|
-
isValid: IsValidFn
|
|
1222
|
-
): ParsedAstDeployment.Instance {
|
|
1223
|
-
const id = this.resolveFqn(astNode)
|
|
1224
|
-
const element = this.resolveFqn(nonNullable(elementRef(astNode.element), 'DeployedInstance element not found'))
|
|
1225
|
-
|
|
1226
|
-
const tags = this.convertTags(astNode.body)
|
|
1227
|
-
const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props
|
|
1228
|
-
const style = toElementStyle(stylePropsAst, isValid)
|
|
1229
|
-
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
|
|
1230
|
-
|
|
1231
|
-
const bodyProps = pipe(
|
|
1232
|
-
astNode.body?.props ?? [],
|
|
1233
|
-
filter(isValid),
|
|
1234
|
-
filter(ast.isElementStringProperty),
|
|
1235
|
-
mapToObj(p => [p.key, p.value || undefined])
|
|
1236
|
-
)
|
|
1237
|
-
|
|
1238
|
-
const title = removeIndent(astNode.title ?? bodyProps.title)
|
|
1239
|
-
const description = removeIndent(bodyProps.description)
|
|
1240
|
-
const technology = toSingleLine(bodyProps.technology)
|
|
1241
|
-
|
|
1242
|
-
const links = this.convertLinks(astNode.body)
|
|
1243
|
-
|
|
1244
|
-
// Property has higher priority than from style
|
|
1245
|
-
const iconProp = astNode.body?.props.find(ast.isIconProperty)
|
|
1246
|
-
if (iconProp && isValid(iconProp)) {
|
|
1247
|
-
const value = iconProp.libicon?.ref?.name ?? iconProp.value
|
|
1248
|
-
if (isTruthy(value)) {
|
|
1249
|
-
style.icon = value as c4.IconUrl
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
return {
|
|
1254
|
-
id,
|
|
1255
|
-
element,
|
|
1256
|
-
...(metadata && { metadata }),
|
|
1257
|
-
...(title && { title }),
|
|
1258
|
-
...(tags && { tags }),
|
|
1259
|
-
...(links && isNonEmptyArray(links) && { links }),
|
|
1260
|
-
...(isTruthy(technology) && { technology }),
|
|
1261
|
-
...(isTruthy(description) && { description }),
|
|
1262
|
-
style
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
public parseDeploymentRelation(
|
|
1267
|
-
astNode: ast.DeploymentRelation,
|
|
1268
|
-
isValid: IsValidFn
|
|
1269
|
-
): ParsedAstDeploymentRelation {
|
|
1270
|
-
const astPath = this.getAstNodePath(astNode)
|
|
1271
|
-
const source = this.parseDeploymentDef(astNode.source)
|
|
1272
|
-
const target = this.parseDeploymentDef(astNode.target)
|
|
1273
|
-
|
|
1274
|
-
const tags = this.convertTags(astNode) ?? this.convertTags(astNode.body)
|
|
1275
|
-
const links = this.convertLinks(astNode.body)
|
|
1276
|
-
const kind = astNode.kind?.ref?.name as (c4.RelationshipKind | undefined)
|
|
1277
|
-
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty))
|
|
1278
|
-
|
|
1279
|
-
const bodyProps = mapToObj(
|
|
1280
|
-
astNode.body?.props.filter(ast.isRelationStringProperty) ?? [],
|
|
1281
|
-
p => [p.key, p.value as string | undefined]
|
|
1282
|
-
)
|
|
1283
|
-
|
|
1284
|
-
const navigateTo = pipe(
|
|
1285
|
-
astNode.body?.props ?? [],
|
|
1286
|
-
filter(ast.isRelationNavigateToProperty),
|
|
1287
|
-
map(p => p.value.view.ref?.name),
|
|
1288
|
-
filter(isTruthy),
|
|
1289
|
-
first()
|
|
1290
|
-
)
|
|
1291
|
-
|
|
1292
|
-
const title = removeIndent(astNode.title ?? bodyProps.title)
|
|
1293
|
-
const description = removeIndent(bodyProps.description)
|
|
1294
|
-
const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology)
|
|
1295
|
-
|
|
1296
|
-
const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty)
|
|
1297
|
-
|
|
1298
|
-
const id = stringHash(
|
|
1299
|
-
'deployment',
|
|
1300
|
-
astPath,
|
|
1301
|
-
source.id,
|
|
1302
|
-
target.id
|
|
1303
|
-
) as c4.RelationId
|
|
1304
|
-
|
|
1305
|
-
return {
|
|
1306
|
-
id,
|
|
1307
|
-
source,
|
|
1308
|
-
target,
|
|
1309
|
-
...title && { title },
|
|
1310
|
-
...(metadata && { metadata }),
|
|
1311
|
-
...(isTruthy(technology) && { technology }),
|
|
1312
|
-
...(isTruthy(description) && { description }),
|
|
1313
|
-
...(kind && { kind }),
|
|
1314
|
-
...(tags && { tags }),
|
|
1315
|
-
...(isNonEmptyArray(links) && { links }),
|
|
1316
|
-
...toRelationshipStyleExcludeDefaults(styleProp?.props, isValid),
|
|
1317
|
-
...(navigateTo && { navigateTo: navigateTo as c4.ViewId }),
|
|
1318
|
-
astPath
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
private parseDeploymentView(
|
|
1323
|
-
astNode: ast.DeploymentView,
|
|
1324
|
-
isValid: IsValidFn
|
|
1325
|
-
): ParsedAstDeploymentView {
|
|
1326
|
-
const body = astNode.body
|
|
1327
|
-
invariant(body, 'DynamicElementView body is not defined')
|
|
1328
|
-
// only valid props
|
|
1329
|
-
const props = body.props.filter(isValid)
|
|
1330
|
-
const astPath = this.getAstNodePath(astNode)
|
|
1331
|
-
|
|
1332
|
-
let id = astNode.name
|
|
1333
|
-
if (!id) {
|
|
1334
|
-
id = 'deployment_' + stringHash(
|
|
1335
|
-
getDocument(astNode).uri.toString(),
|
|
1336
|
-
astPath
|
|
1337
|
-
) as c4.ViewId
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
const title = toSingleLine(props.find(p => p.key === 'title')?.value) ?? null
|
|
1341
|
-
const description = removeIndent(props.find(p => p.key === 'description')?.value) ?? null
|
|
1342
|
-
|
|
1343
|
-
const tags = this.convertTags(body)
|
|
1344
|
-
const links = this.convertLinks(body)
|
|
1345
|
-
|
|
1346
|
-
ViewOps.writeId(astNode, id as c4.ViewId)
|
|
1347
|
-
|
|
1348
|
-
const manualLayout = this.parseViewManualLayout(astNode)
|
|
1349
|
-
|
|
1350
|
-
return {
|
|
1351
|
-
__: 'deployment',
|
|
1352
|
-
id: id as c4.ViewId,
|
|
1353
|
-
astPath,
|
|
1354
|
-
title,
|
|
1355
|
-
description,
|
|
1356
|
-
tags,
|
|
1357
|
-
links: isNonEmptyArray(links) ? links : null,
|
|
1358
|
-
rules: body.rules.flatMap(n => {
|
|
1359
|
-
try {
|
|
1360
|
-
return isValid(n) ? this.parseDeploymentViewRule(n, isValid) : []
|
|
1361
|
-
} catch (e) {
|
|
1362
|
-
logWarnError(e)
|
|
1363
|
-
return []
|
|
1364
|
-
}
|
|
1365
|
-
}),
|
|
1366
|
-
...(manualLayout && { manualLayout })
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
private parseDeploymentViewRule(astRule: ast.DeploymentViewRule, isValid: IsValidFn): c4.DeploymentViewRule {
|
|
1371
|
-
if (ast.isDeploymentViewRulePredicate(astRule)) {
|
|
1372
|
-
return this.parseDeploymentViewRulePredicate(astRule, isValid)
|
|
1373
|
-
}
|
|
1374
|
-
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
1375
|
-
return toAutoLayout(astRule)
|
|
1376
|
-
}
|
|
1377
|
-
if (ast.isDeploymentViewRuleStyle(astRule)) {
|
|
1378
|
-
return this.parseDeploymentViewRuleStyle(astRule, isValid)
|
|
1379
|
-
}
|
|
1380
|
-
nonexhaustive(astRule)
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
private parseDeploymentViewRulePredicate(
|
|
1384
|
-
astRule: ast.DeploymentViewRulePredicate,
|
|
1385
|
-
isValid: IsValidFn
|
|
1386
|
-
): c4.DeploymentViewRulePredicate {
|
|
1387
|
-
const exprs = [] as c4.DeploymentExpression[]
|
|
1388
|
-
let iterator: ast.DeploymentViewRulePredicateExpression | undefined = astRule.expr
|
|
1389
|
-
while (iterator) {
|
|
1390
|
-
try {
|
|
1391
|
-
const expr = iterator.value
|
|
1392
|
-
if (isNonNullish(expr) && isValid(expr)) {
|
|
1393
|
-
switch (true) {
|
|
1394
|
-
case ast.isDeploymentElementExpression(expr):
|
|
1395
|
-
exprs.unshift(this.parseDeploymentElementExpression(expr))
|
|
1396
|
-
break
|
|
1397
|
-
case ast.isDeploymentRelationExpression(expr):
|
|
1398
|
-
exprs.unshift(this.parseDeploymentRelationExpression(expr))
|
|
1399
|
-
break
|
|
1400
|
-
default:
|
|
1401
|
-
nonexhaustive(expr)
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
} catch (e) {
|
|
1405
|
-
logWarnError(e)
|
|
1406
|
-
}
|
|
1407
|
-
iterator = iterator.prev
|
|
1408
|
-
}
|
|
1409
|
-
return astRule.isInclude ? { include: exprs } : { exclude: exprs }
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
private parseDeploymentElementExpression(astNode: ast.DeploymentElementExpression): c4.DeploymentExpression {
|
|
1413
|
-
if (ast.isWildcardExpression(astNode)) {
|
|
1414
|
-
return {
|
|
1415
|
-
wildcard: true
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
if (ast.isDeploymentRefExpression(astNode)) {
|
|
1419
|
-
const ref = this.parseDeploymentDef(astNode.ref)
|
|
1420
|
-
switch (true) {
|
|
1421
|
-
case astNode.selector === '._':
|
|
1422
|
-
return {
|
|
1423
|
-
ref,
|
|
1424
|
-
selector: 'expanded'
|
|
1425
|
-
}
|
|
1426
|
-
case astNode.selector === '.**':
|
|
1427
|
-
return {
|
|
1428
|
-
ref,
|
|
1429
|
-
selector: 'descendants'
|
|
1430
|
-
}
|
|
1431
|
-
case astNode.selector === '.*':
|
|
1432
|
-
return {
|
|
1433
|
-
ref,
|
|
1434
|
-
selector: 'children'
|
|
1435
|
-
}
|
|
1436
|
-
default:
|
|
1437
|
-
return { ref }
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
nonexhaustive(astNode)
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
private parseDeploymentRelationExpression(
|
|
1444
|
-
astNode: ast.DeploymentRelationExpression
|
|
1445
|
-
): c4.DeploymentRelationExpression {
|
|
1446
|
-
if (ast.isDirectedDeploymentRelationExpression(astNode)) {
|
|
1447
|
-
return {
|
|
1448
|
-
source: this.parseDeploymentElementExpression(astNode.source.from),
|
|
1449
|
-
target: this.parseDeploymentElementExpression(astNode.target),
|
|
1450
|
-
isBidirectional: astNode.source.isBidirectional
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
if (ast.isInOutDeploymentRelationExpression(astNode)) {
|
|
1454
|
-
return {
|
|
1455
|
-
inout: this.parseDeploymentElementExpression(astNode.inout.to)
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
if (ast.isOutgoingDeploymentRelationExpression(astNode)) {
|
|
1459
|
-
return {
|
|
1460
|
-
outgoing: this.parseDeploymentElementExpression(astNode.from)
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
if (ast.isIncomingDeploymentRelationExpression(astNode)) {
|
|
1464
|
-
return {
|
|
1465
|
-
incoming: this.parseDeploymentElementExpression(astNode.to)
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
nonexhaustive(astNode)
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
private parseDeploymentExpressionIterator(
|
|
1472
|
-
astNode: ast.DeploymentExpressionIterator,
|
|
1473
|
-
isValid: IsValidFn
|
|
1474
|
-
): c4.DeploymentExpression[] {
|
|
1475
|
-
const exprs = [] as c4.DeploymentExpression[]
|
|
1476
|
-
let iter: ast.DeploymentExpressionIterator['prev'] = astNode
|
|
1477
|
-
while (iter) {
|
|
1478
|
-
try {
|
|
1479
|
-
if (isNonNullish(iter.value) && isValid(iter.value)) {
|
|
1480
|
-
exprs.unshift(this.parseDeploymentElementExpression(iter.value))
|
|
1481
|
-
}
|
|
1482
|
-
} catch (e) {
|
|
1483
|
-
logWarnError(e)
|
|
1484
|
-
}
|
|
1485
|
-
iter = iter.prev
|
|
1486
|
-
}
|
|
1487
|
-
return exprs
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
private parseDeploymentDef(astNode: ast.DeploymentRef): c4.DeploymentRef {
|
|
1491
|
-
const refValue = nonNullable(
|
|
1492
|
-
astNode.value.ref,
|
|
1493
|
-
`Deployment ref is empty ${astNode.$cstNode?.range.start.line}:${astNode.$cstNode?.range.start.character}`
|
|
1494
|
-
)
|
|
1495
|
-
if (ast.isDeploymentNode(refValue)) {
|
|
1496
|
-
return {
|
|
1497
|
-
id: this.resolveFqn(refValue)
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
const deployedInstanceAst = nonNullable(instanceRef(astNode), 'Instance ref not found')
|
|
1501
|
-
const id = this.resolveFqn(deployedInstanceAst)
|
|
1502
|
-
|
|
1503
|
-
if (ast.isElement(refValue)) {
|
|
1504
|
-
const element = this.resolveFqn(refValue)
|
|
1505
|
-
return {
|
|
1506
|
-
id,
|
|
1507
|
-
element
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
// To ensure with compiler we processed all types
|
|
1512
|
-
invariant(ast.isDeployedInstance(refValue), 'Invalid deployment ref: ' + this.getAstNodePath(astNode))
|
|
1513
|
-
return {
|
|
1514
|
-
id
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
protected parseDeploymentViewRuleStyle(
|
|
1519
|
-
astRule: ast.DeploymentViewRuleStyle,
|
|
1520
|
-
isValid: IsValidFn
|
|
1521
|
-
): c4.DeploymentViewRuleStyle {
|
|
1522
|
-
const styleProps = astRule.props.filter(ast.isStyleProperty)
|
|
1523
|
-
const notationProperty = astRule.props.find(ast.isNotationProperty)
|
|
1524
|
-
const notation = removeIndent(notationProperty?.value)
|
|
1525
|
-
const targets = this.parseDeploymentExpressionIterator(astRule.target, isValid)
|
|
1526
|
-
return {
|
|
1527
|
-
targets,
|
|
1528
|
-
...(notation && { notation }),
|
|
1529
|
-
style: {
|
|
1530
|
-
...toElementStyle(styleProps, isValid)
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
protected resolveFqn(node: ast.FqnReferenceable): c4.Fqn {
|
|
1536
|
-
if (ast.isDeploymentElement(node)) {
|
|
1537
|
-
return this.services.likec4.DeploymentsIndex.getFqnName(node)
|
|
1538
|
-
}
|
|
1539
|
-
if (ast.isExtendElement(node)) {
|
|
1540
|
-
return getFqnElementRef(node.element)
|
|
1541
|
-
}
|
|
1542
|
-
const fqn = this.fqnIndex.getFqn(node)
|
|
1543
|
-
invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`)
|
|
1544
|
-
return fqn
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
private getAstNodePath(node: AstNode) {
|
|
1548
|
-
return this.services.workspace.AstNodeLocator.getAstNodePath(node)
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
private getMetadata(metadataAstNode: ast.MetadataProperty | undefined): { [key: string]: string } | undefined {
|
|
1552
|
-
return metadataAstNode?.props != null
|
|
1553
|
-
? mapToObj(metadataAstNode.props, (p) => [p.key, removeIndent(p.value)] as [string, string])
|
|
1554
|
-
: undefined
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
private convertTags<E extends { tags?: ast.Tags }>(withTags?: E) {
|
|
1558
|
-
let iter = withTags?.tags
|
|
1559
|
-
if (!iter) {
|
|
1560
|
-
return null
|
|
1561
|
-
}
|
|
1562
|
-
const tags = [] as c4.Tag[]
|
|
1563
|
-
while (iter) {
|
|
1564
|
-
try {
|
|
1565
|
-
const values = iter.values.map(t => t.ref?.name).filter(isTruthy) as c4.Tag[]
|
|
1566
|
-
if (values.length > 0) {
|
|
1567
|
-
tags.unshift(...values)
|
|
1568
|
-
}
|
|
1569
|
-
} catch (e) {
|
|
1570
|
-
// ignore
|
|
1571
|
-
}
|
|
1572
|
-
iter = iter.prev
|
|
1573
|
-
}
|
|
1574
|
-
return isNonEmptyArray(tags) ? tags : null
|
|
1575
|
-
}
|
|
1576
|
-
|
|
1577
|
-
private convertLinks(source?: ast.LinkProperty['$container']): ParsedLink[] | undefined {
|
|
1578
|
-
if (!source?.props || source.props.length === 0) {
|
|
1579
|
-
return undefined
|
|
1580
|
-
}
|
|
1581
|
-
return pipe(
|
|
1582
|
-
source.props,
|
|
1583
|
-
filter(ast.isLinkProperty),
|
|
1584
|
-
flatMap(p => {
|
|
1585
|
-
const url = p.value
|
|
1586
|
-
if (isTruthy(url)) {
|
|
1587
|
-
const title = isTruthy(p.title) ? toSingleLine(p.title) : undefined
|
|
1588
|
-
return title ? { url, title } : { url }
|
|
1589
|
-
}
|
|
1590
|
-
return []
|
|
1591
|
-
})
|
|
1592
|
-
)
|
|
78
|
+
forDocument(doc: LangiumDocument): DocumentParser {
|
|
79
|
+
invariant(isFqnIndexedDocument(doc), `Not a FqnIndexedDocument: ${doc.uri.toString(true)}`)
|
|
80
|
+
return this.cachedParsers.get(doc)
|
|
1593
81
|
}
|
|
1594
82
|
}
|