@likec4/language-server 0.46.1 → 0.48.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.
- package/contrib/likec4.monarch.ts +5 -8
- package/contrib/likec4.tmLanguage.json +1 -1
- package/dist/ast.d.ts +8 -3
- package/dist/ast.js +12 -8
- package/dist/generated/ast.d.ts +152 -110
- package/dist/generated/ast.js +149 -94
- package/dist/generated/grammar.js +1 -1
- package/dist/lsp/DocumentSymbolProvider.d.ts +7 -2
- package/dist/lsp/DocumentSymbolProvider.js +63 -56
- package/dist/lsp/HoverProvider.js +2 -8
- package/dist/lsp/SemanticTokenProvider.d.ts +1 -1
- package/dist/lsp/SemanticTokenProvider.js +17 -25
- package/dist/model/fqn-index.d.ts +2 -7
- package/dist/model/fqn-index.js +14 -26
- package/dist/model/model-builder.js +5 -3
- package/dist/model/model-parser.d.ts +3 -2
- package/dist/model/model-parser.js +111 -51
- package/dist/module.js +3 -2
- package/dist/references/scope-computation.js +35 -15
- package/dist/references/scope-provider.d.ts +1 -2
- package/dist/references/scope-provider.js +17 -25
- package/dist/shared/NodeKindProvider.d.ts +4 -2
- package/dist/shared/NodeKindProvider.js +40 -13
- package/dist/shared/WorkspaceSymbolProvider.d.ts +4 -0
- package/dist/shared/WorkspaceSymbolProvider.js +3 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/test/testServices.d.ts +5 -0
- package/dist/test/testServices.js +25 -13
- package/dist/validation/index.js +22 -14
- package/dist/validation/specification.js +2 -1
- package/dist/validation/view-predicates/custom-element-expr.d.ts +5 -0
- package/dist/validation/view-predicates/custom-element-expr.js +16 -0
- package/dist/validation/view-predicates/incoming.d.ts +1 -1
- package/dist/validation/view-predicates/incoming.js +1 -1
- package/dist/validation/view-predicates/index.d.ts +1 -0
- package/dist/validation/view-predicates/index.js +1 -0
- package/dist/validation/view-predicates/outgoing.d.ts +1 -1
- package/dist/validation/view-predicates/outgoing.js +1 -1
- package/dist/validation/view.js +1 -1
- package/dist/view-utils/assignNavigateTo.js +3 -0
- package/package.json +6 -5
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { type AstNode, type AstNodeDescription } from 'langium';
|
|
1
|
+
import { type AstNode, type AstNodeDescription, type LangiumSharedServices } from 'langium';
|
|
2
2
|
import { CompletionItemKind, SymbolKind } from 'vscode-languageserver-protocol';
|
|
3
3
|
export declare class NodeKindProvider implements NodeKindProvider {
|
|
4
|
+
private services;
|
|
5
|
+
constructor(services: LangiumSharedServices);
|
|
4
6
|
/**
|
|
5
7
|
* Returns a `SymbolKind` as used by `WorkspaceSymbolProvider` or `DocumentSymbolProvider`.
|
|
6
8
|
*/
|
|
7
|
-
getSymbolKind(
|
|
9
|
+
getSymbolKind(node: AstNode | AstNodeDescription): SymbolKind;
|
|
8
10
|
/**
|
|
9
11
|
* Returns a `CompletionItemKind` as used by the `CompletionProvider`.
|
|
10
12
|
*/
|
|
@@ -1,29 +1,56 @@
|
|
|
1
|
-
import { isAstNode } from "langium";
|
|
2
1
|
import { CompletionItemKind, SymbolKind } from "vscode-languageserver-protocol";
|
|
3
2
|
import { ast } from "../ast.js";
|
|
4
3
|
export class NodeKindProvider {
|
|
4
|
+
constructor(services) {
|
|
5
|
+
this.services = services;
|
|
6
|
+
}
|
|
5
7
|
/**
|
|
6
8
|
* Returns a `SymbolKind` as used by `WorkspaceSymbolProvider` or `DocumentSymbolProvider`.
|
|
7
9
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
// prettier-ignore
|
|
11
|
+
getSymbolKind(node) {
|
|
12
|
+
const hasType = (type) => "type" in node && this.services.AstReflection.isSubtype(node.type, type);
|
|
13
|
+
switch (true) {
|
|
14
|
+
case (ast.isElement(node) || hasType(ast.Element) || (ast.isExtendElement(node) || hasType(ast.ExtendElement))): {
|
|
15
|
+
return SymbolKind.Constructor;
|
|
16
|
+
}
|
|
17
|
+
case (ast.isModel(node) || ast.isModelViews(node) || ast.isSpecificationRule(node) || hasType(ast.Model) || hasType(ast.ModelViews) || hasType(ast.SpecificationRule)): {
|
|
18
|
+
return SymbolKind.Namespace;
|
|
19
|
+
}
|
|
20
|
+
case (ast.isElementView(node) || hasType(ast.ElementView)): {
|
|
21
|
+
return SymbolKind.Class;
|
|
22
|
+
}
|
|
23
|
+
case (ast.isTag(node) || hasType(ast.Tag) || (ast.isSpecificationTag(node) || hasType(ast.SpecificationTag))): {
|
|
24
|
+
return SymbolKind.EnumMember;
|
|
25
|
+
}
|
|
26
|
+
case (ast.isRelationshipKind(node) || hasType(ast.RelationshipKind) || (ast.isSpecificationRelationshipKind(node) || hasType(ast.SpecificationRelationshipKind))): {
|
|
27
|
+
return SymbolKind.Event;
|
|
28
|
+
}
|
|
29
|
+
case (ast.isElementKind(node) || hasType(ast.ElementKind) || (ast.isSpecificationElementKind(node) || hasType(ast.SpecificationElementKind))): {
|
|
30
|
+
return SymbolKind.TypeParameter;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return SymbolKind.Constant;
|
|
10
34
|
}
|
|
11
35
|
/**
|
|
12
36
|
* Returns a `CompletionItemKind` as used by the `CompletionProvider`.
|
|
13
37
|
*/
|
|
14
38
|
getCompletionItemKind(node) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
case
|
|
39
|
+
switch (this.getSymbolKind(node)) {
|
|
40
|
+
case SymbolKind.Constructor:
|
|
41
|
+
return CompletionItemKind.Constructor;
|
|
42
|
+
case SymbolKind.Namespace:
|
|
43
|
+
return CompletionItemKind.Module;
|
|
44
|
+
case SymbolKind.Class:
|
|
21
45
|
return CompletionItemKind.Class;
|
|
22
|
-
|
|
23
|
-
case (ast.isTag(node) || hasType(ast.Tag)): {
|
|
46
|
+
case SymbolKind.EnumMember:
|
|
24
47
|
return CompletionItemKind.EnumMember;
|
|
25
|
-
|
|
48
|
+
case SymbolKind.TypeParameter:
|
|
49
|
+
return CompletionItemKind.TypeParameter;
|
|
50
|
+
case SymbolKind.Event:
|
|
51
|
+
return CompletionItemKind.Event;
|
|
52
|
+
default:
|
|
53
|
+
return CompletionItemKind.Constant;
|
|
26
54
|
}
|
|
27
|
-
return CompletionItemKind.Reference;
|
|
28
55
|
}
|
|
29
56
|
}
|
package/dist/shared/index.d.ts
CHANGED
package/dist/shared/index.js
CHANGED
|
@@ -5,12 +5,17 @@ export declare function createTestServices(workspace?: string): {
|
|
|
5
5
|
validate: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<{
|
|
6
6
|
document: LikeC4LangiumDocument;
|
|
7
7
|
diagnostics: import("vscode-languageserver-types").Diagnostic[];
|
|
8
|
+
warnings: string[];
|
|
8
9
|
errors: string[];
|
|
9
10
|
}>;
|
|
10
11
|
validateAll: () => Promise<{
|
|
11
12
|
diagnostics: import("vscode-languageserver-types").Diagnostic[];
|
|
12
13
|
errors: string[];
|
|
14
|
+
warnings: string[];
|
|
13
15
|
}>;
|
|
14
16
|
buildModel: () => Promise<import("@likec4/core").LikeC4Model>;
|
|
15
17
|
};
|
|
18
|
+
export type TestServices = ReturnType<typeof createTestServices>;
|
|
19
|
+
export type TestParseFn = TestServices['validate'];
|
|
20
|
+
export type TestValidateFn = TestServices['validate'];
|
|
16
21
|
//# sourceMappingURL=testServices.d.ts.map
|
|
@@ -2,6 +2,8 @@ import { createLanguageServices } from "../module.js";
|
|
|
2
2
|
import { EmptyFileSystem } from "langium";
|
|
3
3
|
import { URI, Utils } from "vscode-uri";
|
|
4
4
|
import stripIndent from "strip-indent";
|
|
5
|
+
import * as assert from "node:assert";
|
|
6
|
+
import { DiagnosticSeverity } from "vscode-languageserver-protocol";
|
|
5
7
|
export function createTestServices(workspace = "file:///test/workspace") {
|
|
6
8
|
const services = createLanguageServices(EmptyFileSystem).likec4;
|
|
7
9
|
const metaData = services.LanguageMetaData;
|
|
@@ -14,18 +16,15 @@ export function createTestServices(workspace = "file:///test/workspace") {
|
|
|
14
16
|
uri: workspaceUri.toString()
|
|
15
17
|
};
|
|
16
18
|
let isInitialized = false;
|
|
17
|
-
const init = async () => {
|
|
18
|
-
if (isInitialized)
|
|
19
|
-
return Promise.resolve();
|
|
20
|
-
isInitialized = true;
|
|
21
|
-
await services.shared.workspace.WorkspaceManager.initializeWorkspace([workspaceFolder]);
|
|
22
|
-
Object.assign(services.shared.workspace.WorkspaceManager, {
|
|
23
|
-
folders: [workspaceFolder]
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
19
|
let documentIndex = 1;
|
|
27
20
|
const parse = async (input, uri) => {
|
|
28
|
-
|
|
21
|
+
if (!isInitialized) {
|
|
22
|
+
isInitialized = true;
|
|
23
|
+
await services.shared.workspace.WorkspaceManager.initializeWorkspace([workspaceFolder]);
|
|
24
|
+
Object.assign(services.shared.workspace.WorkspaceManager, {
|
|
25
|
+
folders: [workspaceFolder]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
29
28
|
const docUri = Utils.resolvePath(
|
|
30
29
|
workspaceUri,
|
|
31
30
|
"./src/",
|
|
@@ -43,21 +42,34 @@ export function createTestServices(workspace = "file:///test/workspace") {
|
|
|
43
42
|
const document = typeof input === "string" ? await parse(input, uri) : input;
|
|
44
43
|
await documentBuilder.build([document], { validation: true });
|
|
45
44
|
const diagnostics = document.diagnostics ?? [];
|
|
46
|
-
const
|
|
45
|
+
const warnings = diagnostics.flatMap(
|
|
46
|
+
(d) => d.severity === DiagnosticSeverity.Warning ? d.message : []
|
|
47
|
+
);
|
|
48
|
+
const errors = diagnostics.flatMap(
|
|
49
|
+
(d) => d.severity === DiagnosticSeverity.Error ? d.message : []
|
|
50
|
+
);
|
|
47
51
|
return {
|
|
48
52
|
document,
|
|
49
53
|
diagnostics,
|
|
54
|
+
warnings,
|
|
50
55
|
errors
|
|
51
56
|
};
|
|
52
57
|
};
|
|
53
58
|
const validateAll = async () => {
|
|
54
59
|
const docs = langiumDocuments.all.toArray();
|
|
60
|
+
assert.ok(docs.length > 0, "no documents to validate");
|
|
55
61
|
await documentBuilder.build(docs, { validation: true });
|
|
56
62
|
const diagnostics = docs.flatMap((doc) => doc.diagnostics ?? []);
|
|
57
|
-
const
|
|
63
|
+
const warnings = diagnostics.flatMap(
|
|
64
|
+
(d) => d.severity === DiagnosticSeverity.Warning ? d.message : []
|
|
65
|
+
);
|
|
66
|
+
const errors = diagnostics.flatMap(
|
|
67
|
+
(d) => d.severity === DiagnosticSeverity.Error ? d.message : []
|
|
68
|
+
);
|
|
58
69
|
return {
|
|
59
70
|
diagnostics,
|
|
60
|
-
errors
|
|
71
|
+
errors,
|
|
72
|
+
warnings
|
|
61
73
|
};
|
|
62
74
|
};
|
|
63
75
|
const buildModel = async () => {
|
package/dist/validation/index.js
CHANGED
|
@@ -10,23 +10,31 @@ import {
|
|
|
10
10
|
tagChecks
|
|
11
11
|
} from "./specification.js";
|
|
12
12
|
import { viewChecks } from "./view.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
customElementExprChecks,
|
|
15
|
+
incomingExpressionChecks,
|
|
16
|
+
outgoingExpressionChecks
|
|
17
|
+
} from "./view-predicates/index.js";
|
|
14
18
|
export function registerValidationChecks(services) {
|
|
15
19
|
logger.info("registerValidationChecks");
|
|
16
20
|
const registry = services.validation.ValidationRegistry;
|
|
17
|
-
registry.register(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
registry.register(
|
|
22
|
+
{
|
|
23
|
+
SpecificationRule: specificationRuleChecks(services),
|
|
24
|
+
Model: modelRuleChecks(services),
|
|
25
|
+
ModelViews: modelViewsChecks(services),
|
|
26
|
+
ElementView: viewChecks(services),
|
|
27
|
+
Element: elementChecks(services),
|
|
28
|
+
ElementKind: elementKindChecks(services),
|
|
29
|
+
Relation: relationChecks(services),
|
|
30
|
+
Tag: tagChecks(services),
|
|
31
|
+
CustomElementExpr: customElementExprChecks(services),
|
|
32
|
+
RelationshipKind: relationshipChecks(services),
|
|
33
|
+
IncomingExpr: incomingExpressionChecks(services),
|
|
34
|
+
OutgoingExpr: outgoingExpressionChecks(services)
|
|
35
|
+
},
|
|
36
|
+
"slow"
|
|
37
|
+
);
|
|
30
38
|
const connection = services.shared.lsp.Connection;
|
|
31
39
|
if (connection) {
|
|
32
40
|
services.shared.workspace.DocumentBuilder.onUpdate((_, deleted) => {
|
|
@@ -44,7 +44,8 @@ export const elementKindChecks = (services) => {
|
|
|
44
44
|
export const tagChecks = (services) => {
|
|
45
45
|
const index = services.shared.workspace.IndexManager;
|
|
46
46
|
return (node, accept) => {
|
|
47
|
-
const
|
|
47
|
+
const tagname = "#" + node.name;
|
|
48
|
+
const sameKinds = index.allElements(ast.Tag).filter((n) => n.name === tagname).limit(2).count();
|
|
48
49
|
if (sameKinds > 1) {
|
|
49
50
|
accept("error", `Duplicate tag '${node.name}'`, {
|
|
50
51
|
node,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ValidationCheck } from 'langium';
|
|
2
|
+
import { ast } from '../../ast';
|
|
3
|
+
import type { LikeC4Services } from '../../module';
|
|
4
|
+
export declare const customElementExprChecks: (_services: LikeC4Services) => ValidationCheck<ast.CustomElementExpr>;
|
|
5
|
+
//# sourceMappingURL=custom-element-expr.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ast } from "../../ast.js";
|
|
2
|
+
export const customElementExprChecks = (_services) => {
|
|
3
|
+
return (el, accept) => {
|
|
4
|
+
if (ast.isExcludePredicate(el.$container)) {
|
|
5
|
+
accept("error", 'Invalid inside "exclude"', {
|
|
6
|
+
node: el
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
if (!ast.isElementRef(el.target)) {
|
|
10
|
+
accept("error", "Invalid target for customization", {
|
|
11
|
+
node: el,
|
|
12
|
+
property: "target"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ValidationCheck } from 'langium';
|
|
2
2
|
import { ast } from '../../ast';
|
|
3
3
|
import type { LikeC4Services } from '../../module';
|
|
4
|
-
export declare const incomingExpressionChecks: (_services: LikeC4Services) => ValidationCheck<ast.
|
|
4
|
+
export declare const incomingExpressionChecks: (_services: LikeC4Services) => ValidationCheck<ast.IncomingExpr>;
|
|
5
5
|
//# sourceMappingURL=incoming.d.ts.map
|
|
@@ -2,7 +2,7 @@ import { ast } from "../../ast.js";
|
|
|
2
2
|
import { isNil } from "remeda";
|
|
3
3
|
export const incomingExpressionChecks = (_services) => {
|
|
4
4
|
return (el, accept) => {
|
|
5
|
-
if (ast.
|
|
5
|
+
if (ast.isWildcardExpr(el.to) && ast.isViewRulePredicate(el.$container)) {
|
|
6
6
|
const view = el.$container.$container.$container;
|
|
7
7
|
if (isNil(view.viewOf)) {
|
|
8
8
|
accept("warning", "Predicate is ignored as it concerns all relationships", {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ValidationCheck } from 'langium';
|
|
2
2
|
import { ast } from '../../ast';
|
|
3
3
|
import type { LikeC4Services } from '../../module';
|
|
4
|
-
export declare const outgoingExpressionChecks: (_services: LikeC4Services) => ValidationCheck<ast.
|
|
4
|
+
export declare const outgoingExpressionChecks: (_services: LikeC4Services) => ValidationCheck<ast.OutgoingExpr>;
|
|
5
5
|
//# sourceMappingURL=outgoing.d.ts.map
|
|
@@ -2,7 +2,7 @@ import { ast } from "../../ast.js";
|
|
|
2
2
|
import { isNil } from "remeda";
|
|
3
3
|
export const outgoingExpressionChecks = (_services) => {
|
|
4
4
|
return (el, accept) => {
|
|
5
|
-
if (ast.
|
|
5
|
+
if (ast.isWildcardExpr(el.from)) {
|
|
6
6
|
const view = el.$container.$container.$container;
|
|
7
7
|
if (isNil(view.viewOf)) {
|
|
8
8
|
accept("warning", "Predicate is ignored as it concerns all relationships", {
|
package/dist/validation/view.js
CHANGED
|
@@ -7,7 +7,7 @@ export const viewChecks = (services) => {
|
|
|
7
7
|
if (!el.name) {
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
|
-
const anotherViews = index.allElements(ast.
|
|
10
|
+
const anotherViews = index.allElements(ast.ElementView).filter((n) => n.name === el.name).limit(2).count();
|
|
11
11
|
if (anotherViews > 1) {
|
|
12
12
|
accept("error", `Duplicate view '${el.name}'`, {
|
|
13
13
|
node: el,
|
|
@@ -10,6 +10,9 @@ export function assignNavigateTo(views) {
|
|
|
10
10
|
}
|
|
11
11
|
for (const { id, nodes } of views) {
|
|
12
12
|
for (const node of nodes) {
|
|
13
|
+
if (node.navigateTo) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
13
16
|
const navigateTo = find(allElementViews.get(node.id) ?? [], (v) => v !== id);
|
|
14
17
|
if (navigateTo) {
|
|
15
18
|
node.navigateTo = navigateTo;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/language-server",
|
|
3
3
|
"description": "LikeC4 Language Server",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.48.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
7
7
|
"homepage": "https://likec4.dev",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"test": "vitest run"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@likec4/core": "0.
|
|
54
|
-
"@likec4/graph": "0.
|
|
53
|
+
"@likec4/core": "0.48.0",
|
|
54
|
+
"@likec4/graph": "0.48.0",
|
|
55
55
|
"langium": "^2.1.2",
|
|
56
56
|
"object-hash": "^3.0.0",
|
|
57
57
|
"p-debounce": "^4.0.0",
|
|
@@ -59,13 +59,14 @@
|
|
|
59
59
|
"rambdax": "^9.1.1",
|
|
60
60
|
"remeda": "^1.29.0",
|
|
61
61
|
"strip-indent": "^4.0.0",
|
|
62
|
+
"type-fest": "^4.8.1",
|
|
62
63
|
"vscode-languageserver": "9.0.1",
|
|
63
64
|
"vscode-languageserver-protocol": "3.17.5",
|
|
64
65
|
"vscode-uri": "3.0.8"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@types/node": "^20.8.7",
|
|
68
|
-
"@types/object-hash": "^3.0.
|
|
69
|
+
"@types/object-hash": "^3.0.6",
|
|
69
70
|
"execa": "^8.0.1",
|
|
70
71
|
"langium-cli": "^2.1.0",
|
|
71
72
|
"npm-run-all": "^4.1.5",
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
"unbuild": "^2.0.0",
|
|
74
75
|
"vitest": "^0.34.6"
|
|
75
76
|
},
|
|
76
|
-
"packageManager": "yarn@4.0.
|
|
77
|
+
"packageManager": "yarn@4.0.2",
|
|
77
78
|
"volta": {
|
|
78
79
|
"extends": "../../package.json"
|
|
79
80
|
}
|