@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
package/src/Rpc.ts DELETED
@@ -1,134 +0,0 @@
1
- import { debounce, funnel } from 'remeda'
2
- import { logError, logger } from './logger'
3
- import type { LikeC4Services } from './module'
4
-
5
- import { nonexhaustive } from '@likec4/core'
6
- import { Disposable, interruptAndCheck, URI, UriUtils } from 'langium'
7
- import { isLikeC4LangiumDocument } from './ast'
8
- import { Scheme } from './likec4lib'
9
- import {
10
- buildDocuments,
11
- changeView,
12
- computeView,
13
- fetchComputedModel,
14
- fetchModel,
15
- layoutView,
16
- locate,
17
- onDidChangeModel,
18
- } from './protocol'
19
- import { ADisposable } from './utils'
20
-
21
- export class Rpc extends ADisposable {
22
- constructor(private services: LikeC4Services) {
23
- super()
24
- }
25
-
26
- init() {
27
- const modelBuilder = this.services.likec4.ModelBuilder
28
- const modelLocator = this.services.likec4.ModelLocator
29
- const modelEditor = this.services.likec4.ModelChanges
30
- const views = this.services.likec4.Views
31
- const connection = this.services.shared.lsp.Connection
32
- if (!connection) {
33
- logger.info(`[ServerRpc] no connection, not initializing`)
34
- return
35
- }
36
- logger.info(`[ServerRpc] init`)
37
- const LangiumDocuments = this.services.shared.workspace.LangiumDocuments
38
- const DocumentBuilder = this.services.shared.workspace.DocumentBuilder
39
-
40
- const notifyModelParsed = funnel(
41
- () => {
42
- connection.sendNotification(onDidChangeModel, '').catch(e => {
43
- logger.warn(`[ServerRpc] error sending onDidChangeModel: ${e}`)
44
- return Promise.resolve()
45
- })
46
- },
47
- {
48
- minQuietPeriodMs: 250,
49
- maxBurstDurationMs: 1000,
50
- minGapMs: 200,
51
- },
52
- )
53
-
54
- let isFirstBuild = true
55
-
56
- this.onDispose(
57
- modelBuilder.onModelParsed(() => notifyModelParsed.call()),
58
- connection.onRequest(fetchComputedModel, async ({ cleanCaches }, cancelToken) => {
59
- if (cleanCaches) {
60
- this.services.WorkspaceCache.clear()
61
- this.services.DocumentCache.clear()
62
- }
63
- const model = await modelBuilder.buildComputedModel(cancelToken)
64
- return { model }
65
- }),
66
- connection.onRequest(fetchModel, async cancelToken => {
67
- const model = await modelBuilder.buildModel(cancelToken)
68
- return { model }
69
- }),
70
- connection.onRequest(computeView, async ({ viewId }, cancelToken) => {
71
- const view = await modelBuilder.computeView(viewId, cancelToken)
72
- return { view }
73
- }),
74
- connection.onRequest(layoutView, async ({ viewId }, cancelToken) => {
75
- const result = await views.layoutView(viewId, cancelToken)
76
- return { result }
77
- }),
78
- connection.onRequest(buildDocuments, async ({ docs }, cancelToken) => {
79
- const changed = docs.map(d => URI.parse(d))
80
- const notChanged = (uri: URI) => changed.every(c => !UriUtils.equals(c, uri))
81
- const deleted = LangiumDocuments.all
82
- .filter(d => isLikeC4LangiumDocument(d) && notChanged(d.uri) && d.uri.scheme !== Scheme)
83
- .map(d => d.uri)
84
- .toArray()
85
- logger.debug(
86
- `[ServerRpc] received request to build:
87
- changed (total ${changed.length}):${docs.map(d => '\n - ' + d).join('')}
88
- deleted (total ${deleted.length}):${deleted.map(d => '\n - ' + d.toString()).join('\n')}`,
89
- )
90
-
91
- if (!isFirstBuild && (changed.length + deleted.length) > 0) {
92
- await Promise.allSettled(
93
- [...changed, ...deleted].map(async d => {
94
- const uri = d.toString()
95
- logger.debug(`clear diagnostics for ${uri}`)
96
- try {
97
- await connection.sendDiagnostics({
98
- uri,
99
- diagnostics: [],
100
- })
101
- } catch (e) {
102
- // Ignore
103
- logger.warn(`error clearing diagnostics for ${uri}: ${e}`)
104
- }
105
- }),
106
- )
107
- }
108
- isFirstBuild = false
109
- await interruptAndCheck(cancelToken)
110
- await DocumentBuilder.update(changed, deleted, cancelToken)
111
- }),
112
- connection.onRequest(locate, params => {
113
- switch (true) {
114
- case 'element' in params:
115
- return modelLocator.locateElement(params.element, params.property ?? 'name')
116
- case 'relation' in params:
117
- return modelLocator.locateRelation(params.relation)
118
- case 'view' in params:
119
- return modelLocator.locateView(params.view)
120
- case 'deployment' in params:
121
- return modelLocator.locateDeploymentElement(params.deployment, params.property ?? 'name')
122
- default:
123
- nonexhaustive(params)
124
- }
125
- }),
126
- connection.onRequest(changeView, async (request, _cancelToken) => {
127
- return await modelEditor.applyChange(request)
128
- }),
129
- Disposable.create(() => {
130
- notifyModelParsed.cancel()
131
- }),
132
- )
133
- }
134
- }
package/src/ast.ts DELETED
@@ -1,556 +0,0 @@
1
- import type * as c4 from '@likec4/core'
2
- import { DefaultArrowType, DefaultLineStyle, DefaultRelationshipColor, LinkedList, nonexhaustive } from '@likec4/core'
3
- import type { AstNode, AstNodeDescription, DiagnosticInfo, LangiumDocument, MultiMap } from 'langium'
4
- import { DocumentState } from 'langium'
5
- import { clamp, isBoolean, isDefined, isNullish, isTruthy } from 'remeda'
6
- import type { ConditionalPick, SetRequired, ValueOf, Writable } from 'type-fest'
7
- import type { Diagnostic } from 'vscode-languageserver-types'
8
- import type { LikeC4Grammar } from './generated/ast'
9
- import * as ast from './generated/ast'
10
- import { LikeC4LanguageMetaData } from './generated/module'
11
- import { elementRef } from './utils/elementRef'
12
- import type { IsValidFn } from './validation'
13
-
14
- export { ast }
15
-
16
- const idattr = Symbol.for('idattr')
17
-
18
- declare module './generated/ast' {
19
- export interface Element {
20
- [idattr]?: c4.Fqn | undefined
21
- }
22
- export interface ElementView {
23
- [idattr]?: c4.ViewId | undefined
24
- }
25
- export interface DynamicView {
26
- [idattr]?: c4.ViewId | undefined
27
- }
28
- export interface DeploymentView {
29
- [idattr]?: c4.ViewId | undefined
30
- }
31
- export interface DeploymentNode {
32
- [idattr]?: c4.Fqn | undefined
33
- }
34
- export interface DeployedInstance {
35
- [idattr]?: c4.Fqn | undefined
36
- }
37
- }
38
-
39
- type ParsedElementStyle = {
40
- shape?: c4.ElementShape
41
- icon?: c4.IconUrl
42
- color?: c4.Color
43
- border?: c4.BorderStyle
44
- opacity?: number
45
- multiple?: boolean
46
- size?: c4.ShapeSize
47
- padding?: c4.SpacingSize
48
- textSize?: c4.TextSize
49
- }
50
-
51
- export interface ParsedAstSpecification {
52
- tags: Set<c4.Tag>
53
- elements: Record<c4.ElementKind, {
54
- technology?: string
55
- notation?: string
56
- style: ParsedElementStyle
57
- }>
58
- relationships: Record<
59
- c4.RelationshipKind,
60
- {
61
- technology?: string
62
- notation?: string
63
- color?: c4.Color
64
- line?: c4.RelationshipLineType
65
- head?: c4.RelationshipArrowType
66
- tail?: c4.RelationshipArrowType
67
- }
68
- >
69
- colors: Record<
70
- c4.CustomColor,
71
- {
72
- color: c4.HexColorLiteral
73
- }
74
- >
75
- deployments: Record<c4.DeploymentNodeKind, c4.DeploymentNodeKindSpecification>
76
- }
77
-
78
- export interface ParsedAstElement {
79
- id: c4.Fqn
80
- astPath: string
81
- kind: c4.ElementKind
82
- title: string
83
- description?: string
84
- technology?: string
85
- tags?: c4.NonEmptyArray<c4.Tag>
86
- links?: c4.NonEmptyArray<ParsedLink>
87
- style: ParsedElementStyle
88
- metadata?: { [key: string]: string }
89
- }
90
-
91
- export interface ParsedAstExtendElement {
92
- id: c4.Fqn
93
- astPath: string
94
- tags?: c4.NonEmptyArray<c4.Tag>
95
- links?: c4.NonEmptyArray<ParsedLink>
96
- metadata?: { [key: string]: string }
97
- }
98
-
99
- export interface ParsedAstRelation {
100
- id: c4.RelationId
101
- astPath: string
102
- source: c4.Fqn
103
- target: c4.Fqn
104
- kind?: c4.RelationshipKind
105
- tags?: c4.NonEmptyArray<c4.Tag>
106
- title: string
107
- description?: string
108
- technology?: string
109
- color?: c4.Color
110
- line?: c4.RelationshipLineType
111
- head?: c4.RelationshipArrowType
112
- tail?: c4.RelationshipArrowType
113
- links?: c4.NonEmptyArray<ParsedLink>
114
- navigateTo?: c4.ViewId
115
- metadata?: { [key: string]: string }
116
- }
117
-
118
- // Alias for easier refactoring
119
- export type ParsedAstDeployment = c4.DeploymentElement
120
- export namespace ParsedAstDeployment {
121
- export type Node = c4.DeploymentNode
122
- export type Instance = c4.DeployedInstance
123
- }
124
- export type ParsedAstDeploymentRelation = c4.DeploymentRelation & {
125
- astPath: string
126
- }
127
-
128
- // Alias for refactoring
129
- export type ParsedAstGlobals = Writable<c4.ModelGlobals>
130
-
131
- export interface ParsedAstElementView {
132
- __: 'element'
133
- id: c4.ViewId
134
- viewOf?: c4.Fqn
135
- extends?: c4.ViewId
136
- astPath: string
137
- title: string | null
138
- description: string | null
139
- tags: c4.NonEmptyArray<c4.Tag> | null
140
- links: c4.NonEmptyArray<ParsedLink> | null
141
- rules: c4.ViewRule[]
142
- manualLayout?: c4.ViewManualLayout
143
- }
144
-
145
- export interface ParsedAstDynamicView {
146
- __: 'dynamic'
147
- id: c4.ViewId
148
- astPath: string
149
- title: string | null
150
- description: string | null
151
- tags: c4.NonEmptyArray<c4.Tag> | null
152
- links: c4.NonEmptyArray<ParsedLink> | null
153
- steps: c4.DynamicViewStepOrParallel[]
154
- rules: Array<c4.DynamicViewRule>
155
- manualLayout?: c4.ViewManualLayout
156
- }
157
-
158
- export interface ParsedAstDeploymentView {
159
- __: 'deployment'
160
- id: c4.ViewId
161
- astPath: string
162
- title: string | null
163
- description: string | null
164
- tags: c4.NonEmptyArray<c4.Tag> | null
165
- links: c4.NonEmptyArray<ParsedLink> | null
166
- rules: Array<c4.DeploymentViewRule>
167
- }
168
-
169
- export type ParsedAstView = ParsedAstElementView | ParsedAstDynamicView | ParsedAstDeploymentView
170
- export const ViewOps = {
171
- writeId<T extends ast.LikeC4View>(node: T, id: c4.ViewId): T {
172
- node[idattr] = id
173
- return node
174
- },
175
- readId(node: ast.LikeC4View): c4.ViewId | undefined {
176
- return node[idattr]
177
- },
178
- }
179
-
180
- export interface ParsedLink {
181
- title?: string
182
- url: string
183
- }
184
-
185
- export const ElementOps = {
186
- writeId(node: ast.Element | ast.DeploymentElement, id: c4.Fqn | null) {
187
- if (isNullish(id)) {
188
- node[idattr] = undefined
189
- } else {
190
- node[idattr] = id
191
- }
192
- return node
193
- },
194
- readId(node: ast.Element | ast.DeploymentElement) {
195
- return node[idattr]
196
- },
197
- }
198
-
199
- export interface DocFqnIndexAstNodeDescription extends AstNodeDescription {
200
- fqn: c4.Fqn
201
- }
202
-
203
- export interface DeploymentAstNodeDescription extends AstNodeDescription {
204
- // Fullname of the artifact or node
205
- fqn: string
206
- }
207
-
208
- // export type LikeC4AstNode = ast.LikeC4AstType[keyof ast.LikeC4AstType]
209
- export type LikeC4AstNode = ValueOf<ConditionalPick<ast.LikeC4AstType, AstNode>>
210
- type LikeC4DocumentDiagnostic = Diagnostic & DiagnosticInfo<LikeC4AstNode>
211
-
212
- export interface LikeC4DocumentProps {
213
- diagnostics?: Array<LikeC4DocumentDiagnostic>
214
- c4Specification?: ParsedAstSpecification
215
- c4Elements?: ParsedAstElement[]
216
- c4ExtendElements?: ParsedAstExtendElement[]
217
- c4Relations?: ParsedAstRelation[]
218
- c4Globals?: ParsedAstGlobals
219
- c4Views?: ParsedAstView[]
220
- c4Deployments?: ParsedAstDeployment[]
221
- c4DeploymentRelations?: ParsedAstDeploymentRelation[]
222
- // Fqn -> Element
223
- c4fqnIndex?: MultiMap<c4.Fqn, DocFqnIndexAstNodeDescription>
224
- }
225
-
226
- type LikeC4GrammarDocument = Omit<LangiumDocument<LikeC4Grammar>, 'diagnostics'>
227
-
228
- export interface LikeC4LangiumDocument extends LikeC4GrammarDocument, LikeC4DocumentProps {}
229
- export interface FqnIndexedDocument extends SetRequired<LikeC4LangiumDocument, 'c4fqnIndex'> {}
230
-
231
- export interface ParsedLikeC4LangiumDocument extends LikeC4GrammarDocument, Required<LikeC4DocumentProps> {}
232
-
233
- export function isLikeC4LangiumDocument(doc: LangiumDocument): doc is LikeC4LangiumDocument {
234
- return doc.textDocument.languageId === LikeC4LanguageMetaData.languageId
235
- }
236
-
237
- export function isFqnIndexedDocument(doc: LangiumDocument): doc is FqnIndexedDocument {
238
- return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !!doc.c4fqnIndex
239
- }
240
-
241
- export function isParsedLikeC4LangiumDocument(
242
- doc: LangiumDocument,
243
- ): doc is ParsedLikeC4LangiumDocument {
244
- return (
245
- isLikeC4LangiumDocument(doc)
246
- && doc.state == DocumentState.Validated
247
- && !!doc.c4Specification
248
- && !!doc.c4Elements
249
- && !!doc.c4ExtendElements
250
- && !!doc.c4Relations
251
- && !!doc.c4Views
252
- && !!doc.c4fqnIndex
253
- && !!doc.c4Deployments
254
- && !!doc.c4DeploymentRelations
255
- )
256
- }
257
-
258
- export function* streamModel(doc: LikeC4LangiumDocument) {
259
- const traverseStack = LinkedList.from(doc.parseResult.value.models.flatMap(m => m.elements))
260
- const relations = [] as ast.Relation[]
261
- let el
262
- while ((el = traverseStack.shift())) {
263
- if (ast.isRelation(el)) {
264
- relations.push(el)
265
- continue
266
- }
267
- if (el.body && el.body.elements && el.body.elements.length > 0) {
268
- for (const child of el.body.elements) {
269
- traverseStack.push(child)
270
- }
271
- }
272
- yield el
273
- }
274
- yield* relations
275
- return
276
- }
277
-
278
- export function* streamDeploymentModel(doc: LikeC4LangiumDocument) {
279
- const traverseStack = LinkedList.from<ast.DeploymentRelation | ast.DeploymentElement>(
280
- doc.parseResult.value.deployments.flatMap(m => m.elements),
281
- )
282
- const relations = [] as ast.DeploymentRelation[]
283
- let el
284
- while ((el = traverseStack.shift())) {
285
- if (ast.isDeploymentRelation(el)) {
286
- relations.push(el)
287
- continue
288
- }
289
- if (ast.isDeploymentNode(el) && el.body && el.body.elements.length > 0) {
290
- for (const child of el.body.elements) {
291
- traverseStack.push(child)
292
- }
293
- }
294
- yield el
295
- }
296
- yield* relations
297
- return
298
- }
299
-
300
- export function resolveRelationPoints(node: ast.Relation): {
301
- source: ast.Element
302
- target: ast.Element
303
- } {
304
- const target = elementRef(node.target)
305
- if (!target) {
306
- throw new Error('RelationRefError: Invalid reference to target')
307
- }
308
- if (isDefined(node.source)) {
309
- const source = elementRef(node.source)
310
- if (!source) {
311
- throw new Error('RelationRefError: Invalid reference to source')
312
- }
313
- return {
314
- source,
315
- target,
316
- }
317
- }
318
- if (!ast.isElementBody(node.$container)) {
319
- throw new Error('RelationRefError: Invalid container for sourceless relation')
320
- }
321
- return {
322
- source: node.$container.$container,
323
- target,
324
- }
325
- }
326
-
327
- export function parseAstOpacityProperty({ value }: ast.OpacityProperty): number {
328
- const opacity = parseFloat(value)
329
- return isNaN(opacity) ? 100 : clamp(opacity, { min: 0, max: 100 })
330
- }
331
-
332
- export function parseAstSizeValue({ value }: { value: ast.SizeValue }): 'xs' | 'sm' | 'md' | 'lg' | 'xl' {
333
- switch (value) {
334
- case 'xs':
335
- case 'sm':
336
- case 'md':
337
- case 'lg':
338
- case 'xl':
339
- return value
340
- case 'xsmall':
341
- return 'xs'
342
- case 'small':
343
- return 'sm'
344
- case 'medium':
345
- return 'md'
346
- case 'large':
347
- return 'lg'
348
- case 'xlarge':
349
- return 'xl'
350
- default:
351
- nonexhaustive(value)
352
- }
353
- }
354
-
355
- export function toElementStyle(props: Array<ast.StyleProperty> | undefined, isValid: IsValidFn) {
356
- const result = {} as ParsedElementStyle
357
- if (!props || props.length === 0) {
358
- return result
359
- }
360
- for (const prop of props) {
361
- if (!isValid(prop)) {
362
- continue
363
- }
364
- switch (true) {
365
- case ast.isBorderProperty(prop): {
366
- if (isTruthy(prop.value)) {
367
- result.border = prop.value
368
- }
369
- break
370
- }
371
- case ast.isColorProperty(prop): {
372
- const color = toColor(prop)
373
- if (isTruthy(color)) {
374
- result.color = color
375
- }
376
- break
377
- }
378
- case ast.isShapeProperty(prop): {
379
- if (isTruthy(prop.value)) {
380
- result.shape = prop.value
381
- }
382
- break
383
- }
384
- case ast.isIconProperty(prop): {
385
- const icon = prop.libicon?.ref?.name ?? prop.value
386
- if (isTruthy(icon)) {
387
- result.icon = icon as c4.IconUrl
388
- }
389
- break
390
- }
391
- case ast.isOpacityProperty(prop): {
392
- result.opacity = parseAstOpacityProperty(prop)
393
- break
394
- }
395
- case ast.isMultipleProperty(prop): {
396
- result.multiple = isBoolean(prop.value) ? prop.value : false
397
- break
398
- }
399
- case ast.isShapeSizeProperty(prop): {
400
- if (isTruthy(prop.value)) {
401
- result.size = parseAstSizeValue(prop)
402
- }
403
- break
404
- }
405
- case ast.isPaddingSizeProperty(prop): {
406
- if (isTruthy(prop.value)) {
407
- result.padding = parseAstSizeValue(prop)
408
- }
409
- break
410
- }
411
- case ast.isTextSizeProperty(prop): {
412
- if (isTruthy(prop.value)) {
413
- result.textSize = parseAstSizeValue(prop)
414
- }
415
- break
416
- }
417
- default:
418
- nonexhaustive(prop)
419
- }
420
- }
421
- return result
422
- }
423
-
424
- export function toRelationshipStyle(props: ast.RelationshipStyleProperty[] | undefined, isValid: IsValidFn) {
425
- const result = {} as {
426
- color?: c4.Color
427
- line?: c4.RelationshipLineType
428
- head?: c4.RelationshipArrowType
429
- tail?: c4.RelationshipArrowType
430
- }
431
- if (!props || props.length === 0) {
432
- return result
433
- }
434
- for (const prop of props) {
435
- if (!isValid(prop)) {
436
- continue
437
- }
438
- switch (true) {
439
- case ast.isColorProperty(prop): {
440
- const color = toColor(prop)
441
- if (isTruthy(color)) {
442
- result.color = color
443
- }
444
- break
445
- }
446
- case ast.isLineProperty(prop): {
447
- result.line = prop.value
448
- break
449
- }
450
- case ast.isArrowProperty(prop): {
451
- switch (prop.key) {
452
- case 'head': {
453
- result.head = prop.value
454
- break
455
- }
456
- case 'tail': {
457
- result.tail = prop.value
458
- break
459
- }
460
- default: {
461
- nonexhaustive(prop)
462
- }
463
- }
464
- break
465
- }
466
- default: {
467
- nonexhaustive(prop)
468
- }
469
- }
470
- }
471
- return result
472
- }
473
-
474
- export function toRelationshipStyleExcludeDefaults(
475
- props: ast.SpecificationRelationshipKind['props'] | undefined,
476
- isValid: IsValidFn,
477
- ) {
478
- const { color, line, head, tail } = toRelationshipStyle(props?.filter(ast.isRelationshipStyleProperty), isValid)
479
- return {
480
- ...(color && color !== DefaultRelationshipColor ? { color } : {}),
481
- ...(line && line !== DefaultLineStyle ? { line } : {}),
482
- ...(head && head !== DefaultArrowType ? { head } : {}),
483
- ...(tail ? { tail } : {}),
484
- }
485
- }
486
-
487
- export function toColor(astNode: ast.ColorProperty): c4.Color | undefined {
488
- return astNode?.themeColor ?? (astNode?.customColor?.$refText as (c4.HexColorLiteral | undefined))
489
- }
490
-
491
- export function toAutoLayout(
492
- rule: ast.ViewRuleAutoLayout,
493
- ): c4.ViewRuleAutoLayout {
494
- const rankSep = rule.rankSep
495
- const nodeSep = rule.nodeSep
496
-
497
- let direction: c4.ViewRuleAutoLayout['direction']
498
- switch (rule.direction) {
499
- case 'TopBottom': {
500
- direction = 'TB'
501
- break
502
- }
503
- case 'BottomTop': {
504
- direction = 'BT'
505
- break
506
- }
507
- case 'LeftRight': {
508
- direction = 'LR'
509
- break
510
- }
511
- case 'RightLeft': {
512
- direction = 'RL'
513
- break
514
- }
515
- default:
516
- nonexhaustive(rule.direction)
517
- }
518
-
519
- return {
520
- direction,
521
- ...(nodeSep && { nodeSep }),
522
- ...(rankSep && { rankSep }),
523
- }
524
- }
525
-
526
- export function toAstViewLayoutDirection(c4: c4.ViewRuleAutoLayout['direction']): ast.ViewLayoutDirection {
527
- switch (c4) {
528
- case 'TB': {
529
- return 'TopBottom'
530
- }
531
- case 'BT': {
532
- return 'BottomTop'
533
- }
534
- case 'LR': {
535
- return 'LeftRight'
536
- }
537
- case 'RL': {
538
- return 'RightLeft'
539
- }
540
- default:
541
- nonexhaustive(c4)
542
- }
543
- }
544
-
545
- export function elementExpressionFromPredicate(predicate: ast.ElementPredicate): ast.ElementExpression {
546
- if (ast.isElementExpression(predicate)) {
547
- return predicate
548
- }
549
- if (ast.isElementPredicateWhere(predicate)) {
550
- return predicate.subject
551
- }
552
- if (ast.isElementPredicateWith(predicate)) {
553
- return elementExpressionFromPredicate(predicate.subject)
554
- }
555
- nonexhaustive(predicate)
556
- }