@likec4/language-server 1.20.1 → 1.20.2
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 +5924 -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/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/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
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Disposable } from 'langium'
|
|
2
|
+
import { logError } from '../logger'
|
|
3
|
+
|
|
4
|
+
export abstract class ADisposable implements Disposable {
|
|
5
|
+
protected toDispose: Disposable[] = []
|
|
6
|
+
protected isDisposed = false
|
|
7
|
+
|
|
8
|
+
onDispose(...disposable: Disposable[]): void {
|
|
9
|
+
this.toDispose.push(...disposable)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
dispose(): void {
|
|
13
|
+
this.throwIfDisposed()
|
|
14
|
+
this.isDisposed = true
|
|
15
|
+
let item: Disposable | undefined
|
|
16
|
+
while (item = this.toDispose.pop()) {
|
|
17
|
+
try {
|
|
18
|
+
item.dispose()
|
|
19
|
+
} catch (e) {
|
|
20
|
+
logError(e)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
protected throwIfDisposed(): void {
|
|
26
|
+
if (this.isDisposed) {
|
|
27
|
+
throw new Error('This has already been disposed')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -9,17 +9,20 @@ export const RESERVED_WORDS = [
|
|
|
9
9
|
'self',
|
|
10
10
|
'super',
|
|
11
11
|
'likec4lib',
|
|
12
|
-
'global'
|
|
12
|
+
'global',
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
export function tryOrLog<T extends AstNode>(fn: ValidationCheck<T>): ValidationCheck<T> {
|
|
16
|
-
return async (node: T, accept: ValidationAcceptor, cancelToken: CancellationToken)
|
|
16
|
+
return async function tryOrLogFn(node: T, accept: ValidationAcceptor, cancelToken: CancellationToken) {
|
|
17
17
|
try {
|
|
18
18
|
const result = fn(node, accept, cancelToken)
|
|
19
19
|
if (isPromise(result)) {
|
|
20
20
|
await result
|
|
21
21
|
}
|
|
22
|
+
return
|
|
22
23
|
} catch (e) {
|
|
24
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
25
|
+
accept('error', `Validation failed: ${message}`, { node })
|
|
23
26
|
logWarnError(e)
|
|
24
27
|
}
|
|
25
28
|
}
|
package/src/validation/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AstNode, DocumentState } from 'langium'
|
|
2
2
|
import { isNullish } from 'remeda'
|
|
3
3
|
import { DiagnosticSeverity } from 'vscode-languageserver-types'
|
|
4
4
|
import { type LikeC4AstNode, type LikeC4LangiumDocument, ast } from '../ast'
|
|
@@ -11,6 +11,7 @@ import { elementChecks } from './element'
|
|
|
11
11
|
import { iconPropertyRuleChecks, notesPropertyRuleChecks, opacityPropertyRuleChecks } from './property-checks'
|
|
12
12
|
import { relationBodyChecks, relationChecks } from './relation'
|
|
13
13
|
import {
|
|
14
|
+
deploymentNodeKindChecks,
|
|
14
15
|
elementKindChecks,
|
|
15
16
|
globalPredicateChecks,
|
|
16
17
|
globalsChecks,
|
|
@@ -97,7 +98,9 @@ const findInvalidContainer = (node: LikeC4AstNode): ValidatableAstNode | undefin
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
export function checksFromDiagnostics(doc: LikeC4LangiumDocument) {
|
|
100
|
-
const errors = doc.
|
|
101
|
+
const errors = doc.state >= DocumentState.Validated
|
|
102
|
+
? (doc.diagnostics?.filter(d => d.severity === DiagnosticSeverity.Error) ?? [])
|
|
103
|
+
: []
|
|
101
104
|
const invalidNodes = new WeakSet()
|
|
102
105
|
for (const { node } of errors) {
|
|
103
106
|
if (isNullish(node) || invalidNodes.has(node)) {
|
|
@@ -123,6 +126,7 @@ export function registerValidationChecks(services: LikeC4Services) {
|
|
|
123
126
|
const registry = services.validation.ValidationRegistry
|
|
124
127
|
registry.register<ast.LikeC4AstType>({
|
|
125
128
|
DeployedInstance: deployedInstanceChecks(services),
|
|
129
|
+
DeploymentNodeKind: deploymentNodeKindChecks(services),
|
|
126
130
|
DeploymentNode: deploymentNodeChecks(services),
|
|
127
131
|
DeploymentRelation: deploymentRelationChecks(services),
|
|
128
132
|
FqnRefExpr: fqnRefExprChecks(services),
|
|
@@ -72,6 +72,40 @@ export const elementKindChecks = (services: LikeC4Services): ValidationCheck<ast
|
|
|
72
72
|
})
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export const deploymentNodeKindChecks = (services: LikeC4Services): ValidationCheck<ast.DeploymentNodeKind> => {
|
|
76
|
+
const index = services.shared.workspace.IndexManager
|
|
77
|
+
return tryOrLog((node, accept) => {
|
|
78
|
+
if (RESERVED_WORDS.includes(node.name)) {
|
|
79
|
+
accept('error', `Reserved word: ${node.name}`, {
|
|
80
|
+
node: node,
|
|
81
|
+
property: 'name',
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
const sameKind = index
|
|
85
|
+
.allElements(ast.DeploymentNodeKind)
|
|
86
|
+
.filter(n => n.name === node.name && n.node !== node)
|
|
87
|
+
.head()
|
|
88
|
+
if (sameKind) {
|
|
89
|
+
const isAnotherDoc = sameKind.documentUri !== AstUtils.getDocument(node).uri
|
|
90
|
+
accept('error', `Duplicate deploymentNode kind '${node.name}'`, {
|
|
91
|
+
node: node,
|
|
92
|
+
property: 'name',
|
|
93
|
+
...isAnotherDoc && {
|
|
94
|
+
relatedInformation: [
|
|
95
|
+
{
|
|
96
|
+
location: {
|
|
97
|
+
range: sameKind.nameSegment!.range,
|
|
98
|
+
uri: sameKind.documentUri.toString(),
|
|
99
|
+
},
|
|
100
|
+
message: `conflicting definition`,
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
75
109
|
export const tagChecks = (services: LikeC4Services): ValidationCheck<ast.Tag> => {
|
|
76
110
|
const index = services.shared.workspace.IndexManager
|
|
77
111
|
return tryOrLog((node, accept) => {
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "likec4",
|
|
3
|
-
"scopeName": "source.likec4",
|
|
4
|
-
"fileTypes": [
|
|
5
|
-
".c4",
|
|
6
|
-
".likec4",
|
|
7
|
-
".like-c4"
|
|
8
|
-
],
|
|
9
|
-
"patterns": [
|
|
10
|
-
{
|
|
11
|
-
"include": "#comments"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"name": "keyword.control.likec4",
|
|
15
|
-
"match": "\\b(BottomTop|LeftRight|RightLeft|TopBottom|amber|and|autoLayout|blue|border|browser|color|crow|cylinder|dashed|deployment|deploymentNode|description|diamond|dot|dotted|dynamic|dynamicPredicateGroup|element|element\\.kind|element\\.tag|exclude|extend|extends|global|gray|green|group|head|icon|icons|include|indigo|instance|instanceOf|is|kind|likec4lib|line|link|metadata|mobile|model|muted|navigateTo|node|none|normal|not|notation|notes|odiamond|odot|of|onormal|opacity|open|or|par|parallel|person|predicate|predicateGroup|primary|queue|rectangle|red|relationship|secondary|shape|sky|slate|solid|source|specification|storage|style|styleGroup|tag|tail|target|technology|title|vee|view|views|where|with)\\b"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"name": "string.quoted.double.likec4",
|
|
19
|
-
"begin": "\"",
|
|
20
|
-
"end": "\"",
|
|
21
|
-
"patterns": [
|
|
22
|
-
{
|
|
23
|
-
"include": "#string-character-escape"
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"name": "string.quoted.single.likec4",
|
|
29
|
-
"begin": "'",
|
|
30
|
-
"end": "'",
|
|
31
|
-
"patterns": [
|
|
32
|
-
{
|
|
33
|
-
"include": "#string-character-escape"
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
],
|
|
38
|
-
"repository": {
|
|
39
|
-
"comments": {
|
|
40
|
-
"patterns": [
|
|
41
|
-
{
|
|
42
|
-
"name": "comment.block.likec4",
|
|
43
|
-
"begin": "/\\*",
|
|
44
|
-
"beginCaptures": {
|
|
45
|
-
"0": {
|
|
46
|
-
"name": "punctuation.definition.comment.likec4"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
"end": "\\*/",
|
|
50
|
-
"endCaptures": {
|
|
51
|
-
"0": {
|
|
52
|
-
"name": "punctuation.definition.comment.likec4"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"begin": "//",
|
|
58
|
-
"beginCaptures": {
|
|
59
|
-
"1": {
|
|
60
|
-
"name": "punctuation.whitespace.comment.leading.likec4"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
"end": "(?=$)",
|
|
64
|
-
"name": "comment.line.likec4"
|
|
65
|
-
}
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"string-character-escape": {
|
|
69
|
-
"name": "constant.character.escape.likec4",
|
|
70
|
-
"match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|