@likec4/language-server 1.20.1 → 1.20.3
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/README.md +19 -0
- package/bin/likec4-language-server.mjs +5 -0
- package/dist/LikeC4FileSystem.js +9 -9
- package/dist/Rpc.d.ts +2 -4
- package/dist/Rpc.js +27 -36
- package/dist/ast.d.ts +1 -0
- package/dist/ast.js +5 -1
- package/dist/bundled.mjs +6041 -0
- package/dist/formatting/LikeC4Formatter.d.ts +9 -0
- package/dist/formatting/LikeC4Formatter.js +131 -14
- package/dist/generated/ast.d.ts +13 -2
- package/dist/generated/ast.js +18 -1
- package/dist/generated/grammar.js +1 -1
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +0 -4
- package/dist/lsp/CompletionProvider.js +11 -3
- package/dist/model/deployments-index.d.ts +2 -1
- package/dist/model/deployments-index.js +3 -10
- package/dist/model/fqn-index.d.ts +2 -1
- package/dist/model/fqn-index.js +24 -17
- package/dist/model/model-builder.d.ts +2 -1
- package/dist/model/model-builder.js +32 -30
- package/dist/model/model-parser.d.ts +1 -1
- package/dist/model/model-parser.js +9 -6
- package/dist/model/parser/PredicatesParser.js +7 -1
- package/dist/utils/disposable.d.ts +8 -0
- package/dist/utils/disposable.js +25 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/validation/_shared.js +4 -1
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +4 -1
- package/dist/validation/specification.d.ts +1 -0
- package/dist/validation/specification.js +30 -0
- package/package.json +33 -27
- package/src/LikeC4FileSystem.ts +14 -13
- package/src/Rpc.ts +28 -38
- package/src/ast.ts +6 -1
- package/src/formatting/LikeC4Formatter.ts +198 -17
- package/src/generated/ast.ts +35 -2
- package/src/generated/grammar.ts +1 -1
- package/src/like-c4.langium +14 -3
- package/src/logger.ts +3 -4
- package/src/lsp/CompletionProvider.ts +27 -18
- package/src/model/deployments-index.ts +4 -17
- package/src/model/fqn-index.ts +26 -19
- package/src/model/model-builder.ts +32 -31
- package/src/model/model-parser.ts +14 -11
- package/src/model/parser/PredicatesParser.ts +30 -24
- package/src/utils/disposable.ts +30 -0
- package/src/utils/index.ts +1 -0
- package/src/validation/_shared.ts +5 -2
- package/src/validation/index.ts +6 -2
- package/src/validation/specification.ts +34 -0
- package/contrib/likec4.tmLanguage.json +0 -73
- package/dist/like-c4.langium +0 -852
package/src/LikeC4FileSystem.ts
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
import { fdir } from 'fdir'
|
|
2
2
|
import { type FileSystemNode, URI } from 'langium'
|
|
3
3
|
import { NodeFileSystemProvider } from 'langium/node'
|
|
4
|
-
import {
|
|
4
|
+
import { LikeC4LanguageMetaData } from './generated/module'
|
|
5
5
|
import { logger } from './logger'
|
|
6
6
|
|
|
7
7
|
export const LikeC4FileSystem = {
|
|
8
8
|
fileSystemProvider: () => new SymLinkTraversingFileSystemProvider(),
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
const hasExtension = (path: string) => LikeC4LanguageMetaData.fileExtensions.some((ext) => path.endsWith(ext))
|
|
11
12
|
/**
|
|
12
13
|
* A file system provider that follows symbolic links.
|
|
13
14
|
* @see https://github.com/likec4/likec4/pull/1213
|
|
14
15
|
*/
|
|
15
16
|
class SymLinkTraversingFileSystemProvider extends NodeFileSystemProvider {
|
|
16
17
|
override async readDirectory(folderPath: URI): Promise<FileSystemNode[]> {
|
|
17
|
-
const crawled = await new fdir()
|
|
18
|
-
.withSymlinks()
|
|
19
|
-
.withFullPaths()
|
|
20
|
-
.crawl(folderPath.fsPath)
|
|
21
|
-
.withPromise()
|
|
22
18
|
const entries = [] as FileSystemNode[]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
try {
|
|
20
|
+
const crawled = await new fdir()
|
|
21
|
+
.withSymlinks()
|
|
22
|
+
.withFullPaths()
|
|
23
|
+
.filter(hasExtension)
|
|
24
|
+
.crawl(folderPath.fsPath)
|
|
25
|
+
.withPromise()
|
|
26
|
+
for (const path of crawled) {
|
|
26
27
|
entries.push({
|
|
27
|
-
isFile:
|
|
28
|
-
isDirectory:
|
|
28
|
+
isFile: true,
|
|
29
|
+
isDirectory: false,
|
|
29
30
|
uri: URI.file(path),
|
|
30
31
|
})
|
|
31
|
-
} catch (error) {
|
|
32
|
-
logger.error(error)
|
|
33
32
|
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logger.error(error)
|
|
34
35
|
}
|
|
35
36
|
return entries
|
|
36
37
|
}
|
package/src/Rpc.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { debounce } from 'remeda'
|
|
1
|
+
import { debounce, funnel } from 'remeda'
|
|
2
2
|
import { logError, logger } from './logger'
|
|
3
3
|
import type { LikeC4Services } from './module'
|
|
4
4
|
|
|
@@ -16,11 +16,12 @@ import {
|
|
|
16
16
|
locate,
|
|
17
17
|
onDidChangeModel,
|
|
18
18
|
} from './protocol'
|
|
19
|
+
import { ADisposable } from './utils'
|
|
19
20
|
|
|
20
|
-
export class Rpc
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
export class Rpc extends ADisposable {
|
|
22
|
+
constructor(private services: LikeC4Services) {
|
|
23
|
+
super()
|
|
24
|
+
}
|
|
24
25
|
|
|
25
26
|
init() {
|
|
26
27
|
const modelBuilder = this.services.likec4.ModelBuilder
|
|
@@ -36,30 +37,28 @@ export class Rpc implements Disposable {
|
|
|
36
37
|
const LangiumDocuments = this.services.shared.workspace.LangiumDocuments
|
|
37
38
|
const DocumentBuilder = this.services.shared.workspace.DocumentBuilder
|
|
38
39
|
|
|
39
|
-
const notifyModelParsed =
|
|
40
|
+
const notifyModelParsed = funnel(
|
|
40
41
|
() => {
|
|
41
42
|
connection.sendNotification(onDidChangeModel, '').catch(e => {
|
|
42
|
-
logger.
|
|
43
|
+
logger.warn(`[ServerRpc] error sending onDidChangeModel: ${e}`)
|
|
43
44
|
return Promise.resolve()
|
|
44
45
|
})
|
|
45
46
|
},
|
|
46
47
|
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
minQuietPeriodMs: 250,
|
|
49
|
+
maxBurstDurationMs: 1000,
|
|
50
|
+
minGapMs: 200,
|
|
50
51
|
},
|
|
51
52
|
)
|
|
52
53
|
|
|
53
54
|
let isFirstBuild = true
|
|
54
55
|
|
|
55
|
-
this.
|
|
56
|
-
Disposable.create(() => {
|
|
57
|
-
notifyModelParsed.cancel()
|
|
58
|
-
}),
|
|
56
|
+
this.onDispose(
|
|
59
57
|
modelBuilder.onModelParsed(() => notifyModelParsed.call()),
|
|
60
58
|
connection.onRequest(fetchComputedModel, async ({ cleanCaches }, cancelToken) => {
|
|
61
59
|
if (cleanCaches) {
|
|
62
60
|
this.services.WorkspaceCache.clear()
|
|
61
|
+
this.services.DocumentCache.clear()
|
|
63
62
|
}
|
|
64
63
|
const model = await modelBuilder.buildComputedModel(cancelToken)
|
|
65
64
|
return { model }
|
|
@@ -105,40 +104,31 @@ export class Rpc implements Disposable {
|
|
|
105
104
|
}
|
|
106
105
|
}),
|
|
107
106
|
)
|
|
108
|
-
await interruptAndCheck(cancelToken)
|
|
109
107
|
}
|
|
110
108
|
isFirstBuild = false
|
|
109
|
+
await interruptAndCheck(cancelToken)
|
|
111
110
|
await DocumentBuilder.update(changed, deleted, cancelToken)
|
|
112
111
|
}),
|
|
113
112
|
connection.onRequest(locate, params => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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)
|
|
122
124
|
}
|
|
123
|
-
if ('deployment' in params) {
|
|
124
|
-
return modelLocator.locateDeploymentElement(params.deployment, params.property ?? 'name')
|
|
125
|
-
}
|
|
126
|
-
nonexhaustive(params)
|
|
127
125
|
}),
|
|
128
126
|
connection.onRequest(changeView, async (request, _cancelToken) => {
|
|
129
127
|
return await modelEditor.applyChange(request)
|
|
130
128
|
}),
|
|
129
|
+
Disposable.create(() => {
|
|
130
|
+
notifyModelParsed.cancel()
|
|
131
|
+
}),
|
|
131
132
|
)
|
|
132
133
|
}
|
|
133
|
-
|
|
134
|
-
dispose() {
|
|
135
|
-
let item
|
|
136
|
-
while (item = this.disposables.pop()) {
|
|
137
|
-
try {
|
|
138
|
-
item.dispose()
|
|
139
|
-
} catch (e) {
|
|
140
|
-
logError(e)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
134
|
}
|
package/src/ast.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type * as c4 from '@likec4/core'
|
|
|
2
2
|
import { DefaultArrowType, DefaultLineStyle, DefaultRelationshipColor, LinkedList, nonexhaustive } from '@likec4/core'
|
|
3
3
|
import type { AstNode, AstNodeDescription, DiagnosticInfo, LangiumDocument, MultiMap } from 'langium'
|
|
4
4
|
import { DocumentState } from 'langium'
|
|
5
|
-
import { clamp, isDefined, isNullish, isTruthy } from 'remeda'
|
|
5
|
+
import { clamp, isBoolean, isDefined, isNullish, isTruthy } from 'remeda'
|
|
6
6
|
import type { ConditionalPick, SetRequired, ValueOf, Writable } from 'type-fest'
|
|
7
7
|
import type { Diagnostic } from 'vscode-languageserver-types'
|
|
8
8
|
import type { LikeC4Grammar } from './generated/ast'
|
|
@@ -42,6 +42,7 @@ type ParsedElementStyle = {
|
|
|
42
42
|
color?: c4.Color
|
|
43
43
|
border?: c4.BorderStyle
|
|
44
44
|
opacity?: number
|
|
45
|
+
multiple?: boolean
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export interface ParsedAstSpecification {
|
|
@@ -363,6 +364,10 @@ export function toElementStyle(props: Array<ast.StyleProperty> | undefined, isVa
|
|
|
363
364
|
result.opacity = parseAstOpacityProperty(prop)
|
|
364
365
|
break
|
|
365
366
|
}
|
|
367
|
+
case ast.isMultipleProperty(prop): {
|
|
368
|
+
result.multiple = isBoolean(prop.value) ? prop.value : false
|
|
369
|
+
break
|
|
370
|
+
}
|
|
366
371
|
default:
|
|
367
372
|
nonexhaustive(prop)
|
|
368
373
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AstNode, GrammarUtils } from 'langium'
|
|
2
|
-
import { AbstractFormatter, Formatting
|
|
1
|
+
import { type AstNode, type CompositeCstNode, GrammarUtils } from 'langium'
|
|
2
|
+
import { type NodeFormatter, AbstractFormatter, Formatting } from 'langium/lsp'
|
|
3
3
|
import { filter, isTruthy } from 'remeda'
|
|
4
4
|
import * as ast from '../generated/ast'
|
|
5
5
|
import * as utils from './utils'
|
|
@@ -9,7 +9,7 @@ const FormattingOptions = {
|
|
|
9
9
|
oneSpace: Formatting.oneSpace(),
|
|
10
10
|
noSpace: Formatting.noSpace(),
|
|
11
11
|
indent: Formatting.indent({ allowMore: true }),
|
|
12
|
-
noIndent: Formatting.noIndent()
|
|
12
|
+
noIndent: Formatting.noIndent(),
|
|
13
13
|
}
|
|
14
14
|
type Predicate<T extends AstNode> = (x: unknown) => x is T
|
|
15
15
|
|
|
@@ -29,12 +29,23 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
29
29
|
this.formatRelation(node)
|
|
30
30
|
this.formatMetadataProperty(node)
|
|
31
31
|
|
|
32
|
+
// Deployment
|
|
33
|
+
this.formatDeploymentNodeDeclaration(node)
|
|
34
|
+
this.formatDeployedInstance(node)
|
|
35
|
+
this.formatDeploymentRelation(node)
|
|
36
|
+
|
|
32
37
|
// Views
|
|
33
38
|
this.formatView(node)
|
|
34
39
|
this.formatViewRuleGroup(node)
|
|
35
40
|
this.formatViewRuleGlobalStyle(node)
|
|
41
|
+
this.formatViewRuleGlobalPredicate(node)
|
|
36
42
|
this.formatIncludeExcludeExpressions(node)
|
|
43
|
+
this.formatDeploymentViewRulePredicateExpressions(node)
|
|
37
44
|
this.formatWhereExpression(node)
|
|
45
|
+
this.formatWhereExpressionV2(node)
|
|
46
|
+
this.formatWhereRelationExpression(node)
|
|
47
|
+
this.formatWhereElementExpression(node)
|
|
48
|
+
this.formatRelationExpression(node)
|
|
38
49
|
this.formatAutolayoutProperty(node)
|
|
39
50
|
this.formatWithPredicate(node)
|
|
40
51
|
|
|
@@ -57,6 +68,23 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
57
68
|
})
|
|
58
69
|
}
|
|
59
70
|
|
|
71
|
+
protected formatDeploymentRelation(node: AstNode) {
|
|
72
|
+
this.on(node, ast.isDeploymentRelation, (n, f) => {
|
|
73
|
+
const sourceNodes = n?.source?.$cstNode ? [n?.source?.$cstNode] : []
|
|
74
|
+
|
|
75
|
+
f.cst(sourceNodes).append(FormattingOptions.oneSpace)
|
|
76
|
+
|
|
77
|
+
f.keywords(']->').prepend(FormattingOptions.noSpace)
|
|
78
|
+
f.keywords('-[').append(FormattingOptions.noSpace)
|
|
79
|
+
|
|
80
|
+
f.nodes(...filter([
|
|
81
|
+
n.target,
|
|
82
|
+
n.tags,
|
|
83
|
+
], isTruthy)).prepend(FormattingOptions.oneSpace)
|
|
84
|
+
f.properties('title', 'technology').prepend(FormattingOptions.oneSpace)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
protected formatRelation(node: AstNode) {
|
|
61
89
|
this.on(node, ast.isRelation, (n, f) => {
|
|
62
90
|
const sourceNodes = n?.source?.$cstNode ? [n?.source?.$cstNode] : []
|
|
@@ -67,7 +95,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
67
95
|
|
|
68
96
|
f.nodes(...filter([
|
|
69
97
|
n.target,
|
|
70
|
-
n.tags
|
|
98
|
+
n.tags,
|
|
71
99
|
], isTruthy)).prepend(FormattingOptions.oneSpace)
|
|
72
100
|
f.properties('title', 'technology').prepend(FormattingOptions.oneSpace)
|
|
73
101
|
})
|
|
@@ -110,9 +138,10 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
110
138
|
|| ast.isModelViews(node)
|
|
111
139
|
|| ast.isLikeC4Lib(node)
|
|
112
140
|
|| ast.isGlobals(node)
|
|
141
|
+
|| ast.isModelDeployments(node)
|
|
113
142
|
) {
|
|
114
143
|
const formatter = this.getNodeFormatter(node)
|
|
115
|
-
formatter.keywords('specification', 'model', 'views', 'likec4lib', 'global')
|
|
144
|
+
formatter.keywords('specification', 'model', 'views', 'likec4lib', 'global', 'deployments')
|
|
116
145
|
.prepend(FormattingOptions.noIndent)
|
|
117
146
|
}
|
|
118
147
|
}
|
|
@@ -123,9 +152,13 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
123
152
|
|| ast.isSpecificationRule(node)
|
|
124
153
|
|| ast.isSpecificationElementKind(node)
|
|
125
154
|
|| ast.isSpecificationRelationshipKind(node)
|
|
155
|
+
|| ast.isSpecificationDeploymentNodeKind(node)
|
|
126
156
|
|| ast.isGlobals(node)
|
|
127
157
|
|| ast.isGlobalStyle(node)
|
|
128
158
|
|| ast.isGlobalStyleGroup(node)
|
|
159
|
+
|| ast.isGlobalPredicateGroup(node)
|
|
160
|
+
|| ast.isGlobalDynamicPredicateGroup(node)
|
|
161
|
+
|| ast.isGlobalStyleGroup(node)
|
|
129
162
|
|| ast.isModel(node)
|
|
130
163
|
|| ast.isElementBody(node)
|
|
131
164
|
|| ast.isExtendElementBody(node)
|
|
@@ -135,12 +168,17 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
135
168
|
|| ast.isModelViews(node)
|
|
136
169
|
|| ast.isElementViewBody(node)
|
|
137
170
|
|| ast.isDynamicViewBody(node)
|
|
171
|
+
|| ast.isDeploymentViewBody(node)
|
|
138
172
|
|| ast.isViewRuleStyle(node)
|
|
139
173
|
|| ast.isViewRuleGroup(node)
|
|
140
174
|
|| ast.isCustomElementProperties(node)
|
|
141
175
|
|| ast.isCustomRelationProperties(node)
|
|
142
176
|
|| ast.isElementStyleProperty(node)
|
|
143
177
|
|| ast.isDynamicViewParallelSteps(node)
|
|
178
|
+
|| ast.isModelDeployments(node)
|
|
179
|
+
|| ast.isDeploymentNodeBody(node)
|
|
180
|
+
|| ast.isDeploymentRelationBody(node)
|
|
181
|
+
|| ast.isDeployedInstanceBody(node)
|
|
144
182
|
) {
|
|
145
183
|
const formatter = this.getNodeFormatter(node)
|
|
146
184
|
const openBrace = formatter.keywords('{')
|
|
@@ -182,6 +220,9 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
182
220
|
|
|
183
221
|
this.on(node, ast.isDynamicView)
|
|
184
222
|
?.keywords('dynamic', 'view').append(FormattingOptions.oneSpace)
|
|
223
|
+
|
|
224
|
+
this.on(node, ast.isDeploymentView)
|
|
225
|
+
?.keywords('deployment', 'view').append(FormattingOptions.oneSpace)
|
|
185
226
|
}
|
|
186
227
|
|
|
187
228
|
protected formatLeafProperty(node: AstNode) {
|
|
@@ -199,6 +240,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
199
240
|
|| ast.isShapeProperty(node)
|
|
200
241
|
|| ast.isBorderProperty(node)
|
|
201
242
|
|| ast.isOpacityProperty(node)
|
|
243
|
+
|| ast.isMultipleProperty(node)
|
|
202
244
|
) {
|
|
203
245
|
const formatter = this.getNodeFormatter(node)
|
|
204
246
|
const colon = formatter.keyword(':')
|
|
@@ -214,7 +256,8 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
214
256
|
'icon',
|
|
215
257
|
'shape',
|
|
216
258
|
'border',
|
|
217
|
-
'opacity'
|
|
259
|
+
'opacity',
|
|
260
|
+
'multiple',
|
|
218
261
|
)
|
|
219
262
|
|
|
220
263
|
if (colon.nodes.length === 0) {
|
|
@@ -301,6 +344,14 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
301
344
|
this.on(node, ast.isGlobalStyleGroup, (n, f) => {
|
|
302
345
|
f.keyword('styleGroup').append(FormattingOptions.oneSpace)
|
|
303
346
|
})
|
|
347
|
+
|
|
348
|
+
this.on(node, ast.isGlobalPredicateGroup, (n, f) => {
|
|
349
|
+
f.keyword('predicateGroup').append(FormattingOptions.oneSpace)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
this.on(node, ast.isGlobalDynamicPredicateGroup, (n, f) => {
|
|
353
|
+
f.keyword('dynamicPredicateGroup').append(FormattingOptions.oneSpace)
|
|
354
|
+
})
|
|
304
355
|
}
|
|
305
356
|
|
|
306
357
|
protected formatSpecificationRule(node: AstNode) {
|
|
@@ -308,10 +359,11 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
308
359
|
ast.isSpecificationElementKind(node)
|
|
309
360
|
|| ast.isSpecificationRelationshipKind(node)
|
|
310
361
|
|| ast.isSpecificationTag(node)
|
|
362
|
+
|| ast.isSpecificationDeploymentNodeKind(node)
|
|
311
363
|
) {
|
|
312
364
|
const formatter = this.getNodeFormatter(node)
|
|
313
365
|
|
|
314
|
-
formatter.keywords('element', 'relationship', 'tag')
|
|
366
|
+
formatter.keywords('element', 'relationship', 'tag', 'deploymentNode')
|
|
315
367
|
.append(FormattingOptions.oneSpace)
|
|
316
368
|
}
|
|
317
369
|
if (
|
|
@@ -331,6 +383,39 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
331
383
|
) {
|
|
332
384
|
formatter.keyword('with').prepend(FormattingOptions.oneSpace)
|
|
333
385
|
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
protected formatDeploymentNodeDeclaration(node: AstNode) {
|
|
389
|
+
this.on(node, ast.isDeploymentNode, (n, f) => {
|
|
390
|
+
const kind = GrammarUtils.findNodeForProperty(n.$cstNode, 'kind')
|
|
391
|
+
const name = GrammarUtils.findNodeForProperty(n.$cstNode, 'name')
|
|
392
|
+
|
|
393
|
+
if (name && kind) {
|
|
394
|
+
// system sys1
|
|
395
|
+
if (utils.compareRanges(name, kind) > 0) {
|
|
396
|
+
f.cst([kind]).append(FormattingOptions.oneSpace)
|
|
397
|
+
}
|
|
398
|
+
// sys1 = system
|
|
399
|
+
else {
|
|
400
|
+
f.cst([name]).append(FormattingOptions.oneSpace)
|
|
401
|
+
f.cst([kind]).prepend(FormattingOptions.oneSpace)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
f.properties('title').prepend(FormattingOptions.oneSpace)
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
protected formatDeployedInstance(node: AstNode) {
|
|
410
|
+
this.on(node, ast.isDeployedInstance, (n, f) => {
|
|
411
|
+
const eqNode = (<CompositeCstNode>n.$cstNode)?.content.find(c => c.text === '=')
|
|
412
|
+
if (eqNode) {
|
|
413
|
+
f.cst([eqNode]).surround(FormattingOptions.oneSpace)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
f.keyword('instanceOf').append(FormattingOptions.oneSpace)
|
|
417
|
+
f.property('title').prepend(FormattingOptions.oneSpace)
|
|
418
|
+
})
|
|
334
419
|
}
|
|
335
420
|
|
|
336
421
|
protected formatViewRuleGlobalStyle(node: AstNode) {
|
|
@@ -339,6 +424,16 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
339
424
|
})
|
|
340
425
|
}
|
|
341
426
|
|
|
427
|
+
protected formatViewRuleGlobalPredicate(node: AstNode) {
|
|
428
|
+
const formatter = this.getNodeFormatter(node)
|
|
429
|
+
if (
|
|
430
|
+
ast.isViewRuleGlobalPredicateRef(node)
|
|
431
|
+
|| ast.isDynamicViewGlobalPredicateRef(node)
|
|
432
|
+
) {
|
|
433
|
+
formatter.keywords('global', 'predicate').append(FormattingOptions.oneSpace)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
342
437
|
protected formatViewRuleGroup(node: AstNode) {
|
|
343
438
|
this.on(node, ast.isViewRuleGroup, (n, f) => {
|
|
344
439
|
f.keyword('group').append(FormattingOptions.oneSpace)
|
|
@@ -349,10 +444,18 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
349
444
|
this.on(node, ast.isViewRuleStyle)
|
|
350
445
|
?.keyword('style').append(FormattingOptions.oneSpace)
|
|
351
446
|
|
|
447
|
+
this.on(node, ast.isDeploymentViewRuleStyle)
|
|
448
|
+
?.keyword('style').append(FormattingOptions.oneSpace)
|
|
449
|
+
|
|
352
450
|
this.on(node, ast.isElementExpressionsIterator)
|
|
353
451
|
?.keyword(',')
|
|
354
452
|
.prepend(FormattingOptions.noSpace)
|
|
355
453
|
.append(FormattingOptions.oneSpace)
|
|
454
|
+
|
|
455
|
+
this.on(node, ast.isFqnExpressions)
|
|
456
|
+
?.keyword(',')
|
|
457
|
+
.prepend(FormattingOptions.noSpace)
|
|
458
|
+
.append(FormattingOptions.oneSpace)
|
|
356
459
|
}
|
|
357
460
|
|
|
358
461
|
protected formatWhereExpression(node: AstNode) {
|
|
@@ -363,27 +466,47 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
363
466
|
const formatter = this.getNodeFormatter(node)
|
|
364
467
|
formatter.keyword('where').append(FormattingOptions.oneSpace)
|
|
365
468
|
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
protected formatWhereExpressionV2(node: AstNode) {
|
|
366
472
|
if (
|
|
367
|
-
ast.
|
|
368
|
-
|| ast.
|
|
473
|
+
ast.isRelationPredicateOrWhereV2(node)
|
|
474
|
+
// || ast.isElementPredicateOrWhere(node)
|
|
369
475
|
) {
|
|
370
476
|
const formatter = this.getNodeFormatter(node)
|
|
371
|
-
formatter.
|
|
477
|
+
formatter.keyword('where').append(FormattingOptions.oneSpace)
|
|
372
478
|
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
protected formatWhereRelationExpression(node: AstNode) {
|
|
482
|
+
this.on(node, ast.isWhereRelationExpression, (n, f) => {
|
|
483
|
+
f.property('operator').surround(FormattingOptions.oneSpace)
|
|
484
|
+
})
|
|
485
|
+
this.on(node, ast.isWhereRelationNegation, (n, f) => {
|
|
486
|
+
f.keyword('not').append(FormattingOptions.oneSpace)
|
|
487
|
+
})
|
|
373
488
|
if (
|
|
374
|
-
ast.
|
|
375
|
-
|| ast.
|
|
489
|
+
ast.isWhereRelation(node)
|
|
490
|
+
|| ast.isWhereRelationTag(node)
|
|
491
|
+
|| ast.isWhereRelationKind(node)
|
|
376
492
|
) {
|
|
377
493
|
const formatter = this.getNodeFormatter(node)
|
|
378
|
-
formatter.
|
|
494
|
+
formatter.property('operator').surround(FormattingOptions.oneSpace)
|
|
495
|
+
formatter.property('not').surround(FormattingOptions.oneSpace)
|
|
379
496
|
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
protected formatWhereElementExpression(node: AstNode) {
|
|
500
|
+
this.on(node, ast.isWhereElementExpression, (n, f) => {
|
|
501
|
+
f.property('operator').surround(FormattingOptions.oneSpace)
|
|
502
|
+
})
|
|
503
|
+
this.on(node, ast.isWhereElementNegation, (n, f) => {
|
|
504
|
+
f.keyword('not').append(FormattingOptions.oneSpace)
|
|
505
|
+
})
|
|
380
506
|
if (
|
|
381
507
|
ast.isWhereElement(node)
|
|
382
508
|
|| ast.isWhereElementTag(node)
|
|
383
509
|
|| ast.isWhereElementKind(node)
|
|
384
|
-
|| ast.isWhereRelation(node)
|
|
385
|
-
|| ast.isWhereRelationTag(node)
|
|
386
|
-
|| ast.isWhereRelationKind(node)
|
|
387
510
|
) {
|
|
388
511
|
const formatter = this.getNodeFormatter(node)
|
|
389
512
|
formatter.property('operator').surround(FormattingOptions.oneSpace)
|
|
@@ -396,6 +519,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
396
519
|
ast.isDynamicViewRule(node)
|
|
397
520
|
|| ast.isIncludePredicate(node)
|
|
398
521
|
|| ast.isExcludePredicate(node)
|
|
522
|
+
|| ast.isDeploymentViewRulePredicate(node)
|
|
399
523
|
) {
|
|
400
524
|
const formatter = this.getNodeFormatter(node)
|
|
401
525
|
|
|
@@ -404,6 +528,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
404
528
|
.append(FormattingOptions.oneSpace)
|
|
405
529
|
}
|
|
406
530
|
}
|
|
531
|
+
|
|
407
532
|
if (
|
|
408
533
|
ast.isDynamicViewPredicateIterator(node)
|
|
409
534
|
|| ast.isPredicates(node)
|
|
@@ -422,6 +547,61 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
422
547
|
}
|
|
423
548
|
}
|
|
424
549
|
|
|
550
|
+
protected formatRelationExpression(node: AstNode) {
|
|
551
|
+
this.on(node, ast.isIncomingRelationExpr, (n, f) => {
|
|
552
|
+
f.keyword('->').append(FormattingOptions.oneSpace)
|
|
553
|
+
})
|
|
554
|
+
this.on(node, ast.isInOutRelationExpr, (n, f) => {
|
|
555
|
+
f.keyword('->').prepend(FormattingOptions.oneSpace)
|
|
556
|
+
})
|
|
557
|
+
this.on(node, ast.isOutgoingRelationExpr, (n, f) => {
|
|
558
|
+
f.keywords('->', '<->').prepend(FormattingOptions.oneSpace)
|
|
559
|
+
f.keywords('-[')
|
|
560
|
+
.prepend(FormattingOptions.oneSpace)
|
|
561
|
+
.append(FormattingOptions.noSpace)
|
|
562
|
+
f.keywords(']->')
|
|
563
|
+
.prepend(FormattingOptions.noSpace)
|
|
564
|
+
.append(FormattingOptions.oneSpace)
|
|
565
|
+
|
|
566
|
+
const kind = f.property('kind')
|
|
567
|
+
kind.nodes[0]?.text.startsWith('.') && kind.surround(FormattingOptions.oneSpace)
|
|
568
|
+
})
|
|
569
|
+
this.on(node, ast.isDirectedRelationExpr, (n, f) => {
|
|
570
|
+
f.property('target').prepend(FormattingOptions.oneSpace)
|
|
571
|
+
})
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
protected formatDeploymentViewRulePredicateExpressions(node: AstNode) {
|
|
575
|
+
if (
|
|
576
|
+
ast.isDynamicViewRule(node)
|
|
577
|
+
|| ast.isIncludePredicate(node)
|
|
578
|
+
|| ast.isExcludePredicate(node)
|
|
579
|
+
|| ast.isDeploymentViewRulePredicate(node)
|
|
580
|
+
) {
|
|
581
|
+
const formatter = this.getNodeFormatter(node)
|
|
582
|
+
|
|
583
|
+
if (!node.$cstNode || !utils.isMultiline(node.$cstNode)) {
|
|
584
|
+
formatter.keywords('include', 'exclude')
|
|
585
|
+
.append(FormattingOptions.oneSpace)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (
|
|
590
|
+
ast.isDeploymentViewRulePredicateExpression(node)
|
|
591
|
+
) {
|
|
592
|
+
const formatter = this.getNodeFormatter(node)
|
|
593
|
+
const parent = this.findPredicateExpressionRoot(node)
|
|
594
|
+
const isMultiline = parent?.$cstNode && utils.isMultiline(parent?.$cstNode)
|
|
595
|
+
|
|
596
|
+
if (isMultiline) {
|
|
597
|
+
formatter.property('value').prepend(FormattingOptions.indent)
|
|
598
|
+
}
|
|
599
|
+
formatter.keyword(',')
|
|
600
|
+
.prepend(FormattingOptions.noSpace)
|
|
601
|
+
.append(isMultiline ? FormattingOptions.newLine : FormattingOptions.oneSpace)
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
425
605
|
private findPredicateExpressionRoot(node: AstNode): AstNode | undefined {
|
|
426
606
|
let parent = node.$container
|
|
427
607
|
while (true) {
|
|
@@ -430,6 +610,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
430
610
|
|| ast.isDynamicViewRule(parent)
|
|
431
611
|
|| ast.isIncludePredicate(parent)
|
|
432
612
|
|| ast.isExcludePredicate(parent)
|
|
613
|
+
|| ast.isDeploymentViewRulePredicate(parent)
|
|
433
614
|
) {
|
|
434
615
|
return parent
|
|
435
616
|
}
|
|
@@ -441,7 +622,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
441
622
|
private on<T extends AstNode>(
|
|
442
623
|
node: AstNode,
|
|
443
624
|
predicate: Predicate<T>,
|
|
444
|
-
format?: (node: T, f: NodeFormatter<T>) => void
|
|
625
|
+
format?: (node: T, f: NodeFormatter<T>) => void,
|
|
445
626
|
): NodeFormatter<T> | undefined {
|
|
446
627
|
const formatter = predicate(node) ? this.getNodeFormatter(node) : undefined
|
|
447
628
|
|