@likec4/language-server 0.6.2 → 0.8.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 +31 -0
- package/contrib/likec4.tmLanguage.json +73 -0
- package/dist/ast.d.ts +75 -0
- package/dist/ast.js +143 -0
- package/dist/builtin.d.ts +5 -0
- package/dist/builtin.js +9 -0
- package/dist/elementRef.d.ts +7 -0
- package/dist/elementRef.js +40 -0
- package/dist/generated/ast.d.ts +364 -0
- package/dist/generated/ast.js +389 -0
- package/dist/generated/grammar.d.ts +7 -0
- package/dist/generated/grammar.js +2548 -0
- package/dist/generated/module.d.ts +10 -0
- package/dist/generated/module.js +27 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.js +21 -0
- package/dist/lsp/DocumentSymbolProvider.d.ts +22 -0
- package/dist/lsp/DocumentSymbolProvider.js +167 -0
- package/dist/lsp/HoverProvider.d.ts +9 -0
- package/dist/lsp/HoverProvider.js +55 -0
- package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
- package/dist/lsp/SemanticTokenProvider.js +222 -0
- package/dist/lsp/index.d.ts +4 -0
- package/dist/lsp/index.js +4 -0
- package/dist/model/fqn-index.d.ts +41 -0
- package/dist/model/fqn-index.js +119 -0
- package/dist/model/index.d.ts +4 -0
- package/dist/model/index.js +4 -0
- package/dist/model/model-builder.d.ts +27 -0
- package/dist/model/model-builder.js +339 -0
- package/dist/model/model-locator.d.ts +17 -0
- package/dist/model/model-locator.js +116 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.js +66 -0
- package/dist/protocol.d.ts +37 -0
- package/dist/protocol.js +20 -0
- package/dist/references/fqn-computation.d.ts +4 -0
- package/dist/references/fqn-computation.js +41 -0
- package/dist/references/index.d.ts +3 -0
- package/dist/references/index.js +3 -0
- package/dist/references/scope-computation.d.ts +14 -0
- package/dist/references/scope-computation.js +86 -0
- package/dist/references/scope-provider.d.ts +19 -0
- package/dist/references/scope-provider.js +120 -0
- package/dist/registerProtocolHandlers.d.ts +3 -0
- package/dist/registerProtocolHandlers.js +65 -0
- package/dist/shared/CodeLensProvider.d.ts +9 -0
- package/dist/shared/CodeLensProvider.js +36 -0
- package/dist/shared/WorkspaceManager.d.ts +14 -0
- package/dist/shared/WorkspaceManager.js +18 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.js +2 -0
- package/dist/test/testServices.d.ts +16 -0
- package/dist/test/testServices.js +58 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +8 -0
- package/dist/validation/element.d.ts +6 -0
- package/dist/validation/element.js +21 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +23 -0
- package/dist/validation/relation.d.ts +5 -0
- package/dist/validation/relation.js +54 -0
- package/dist/validation/specification.d.ts +6 -0
- package/dist/validation/specification.js +34 -0
- package/dist/validation/view.d.ts +5 -0
- package/dist/validation/view.js +21 -0
- package/package.json +26 -31
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Monarch syntax highlighting for the likec4 language.
|
|
2
|
+
export default {
|
|
3
|
+
keywords: [
|
|
4
|
+
'BottomTop','LeftRight','RightLeft','TopBottom','autoLayout','browser','color','cylinder','description','element','exclude','extend','include','it','model','muted','of','person','primary','queue','rectangle','secondary','shape','specification','storage','style','tag','technology','this','title','view','views'
|
|
5
|
+
],
|
|
6
|
+
operators: [
|
|
7
|
+
'*','->','.*'
|
|
8
|
+
],
|
|
9
|
+
symbols: /\*|->|\.\*/,
|
|
10
|
+
|
|
11
|
+
tokenizer: {
|
|
12
|
+
initial: [
|
|
13
|
+
{ regex: /[^\W\d_]/, action: { cases: { '@keywords': {"token":"keyword"}, '@default': {"token":"LETTER"} }} },
|
|
14
|
+
{ regex: /[0-9]/, action: {"token":"DIGIT"} },
|
|
15
|
+
{ regex: /[\t\r\n\v\f]/, action: {"token":"NEWLINE"} },
|
|
16
|
+
{ regex: /"[^"]*"|'[^']*'/, action: {"token":"string"} },
|
|
17
|
+
{ include: '@whitespace' },
|
|
18
|
+
{ regex: /@symbols/, action: { cases: { '@operators': {"token":"operator"}, '@default': {"token":""} }} },
|
|
19
|
+
],
|
|
20
|
+
whitespace: [
|
|
21
|
+
{ regex: /[^\S\r\n]/, action: {"token":"white"} },
|
|
22
|
+
{ regex: /\/\*/, action: {"token":"comment","next":"@comment"} },
|
|
23
|
+
{ regex: /\/\/[^\n\r]*/, action: {"token":"comment"} },
|
|
24
|
+
],
|
|
25
|
+
comment: [
|
|
26
|
+
{ regex: /[^\/\*]+/, action: {"token":"comment"} },
|
|
27
|
+
{ regex: /\*\//, action: {"token":"comment","next":"@pop"} },
|
|
28
|
+
{ regex: /[\/\*]/, action: {"token":"comment"} },
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
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|autoLayout|browser|color|cylinder|description|element|exclude|extend|include|it|model|muted|of|person|primary|queue|rectangle|secondary|shape|specification|storage|style|tag|technology|this|title|view|views)\\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
|
+
}
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import * as ast from './generated/ast';
|
|
3
|
+
import type { LangiumDocument, MultiMap } from 'langium';
|
|
4
|
+
import type { LikeC4Document } from './generated/ast';
|
|
5
|
+
import type * as c4 from '@likec4/core/types';
|
|
6
|
+
export { ast };
|
|
7
|
+
export declare function c4hash({ c4Specification, c4Elements, c4Relations, c4Views }: LikeC4LangiumDocument): string;
|
|
8
|
+
export interface ParsedAstSpecification {
|
|
9
|
+
kinds: Record<c4.ElementKind, {
|
|
10
|
+
shape: c4.ElementShape;
|
|
11
|
+
color: c4.ThemeColor;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export interface ParsedAstElement {
|
|
15
|
+
id: c4.Fqn;
|
|
16
|
+
astPath: string;
|
|
17
|
+
kind: c4.ElementKind;
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
technology?: string;
|
|
21
|
+
tags?: c4.Tag[];
|
|
22
|
+
shape?: c4.ElementShape;
|
|
23
|
+
color?: c4.ThemeColor;
|
|
24
|
+
}
|
|
25
|
+
export interface ParsedAstRelation {
|
|
26
|
+
id: c4.RelationID;
|
|
27
|
+
astPath: string;
|
|
28
|
+
source: c4.Fqn;
|
|
29
|
+
target: c4.Fqn;
|
|
30
|
+
title: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ParsedAstElementView {
|
|
33
|
+
id: c4.ViewID;
|
|
34
|
+
astPath: string;
|
|
35
|
+
viewOf?: c4.Fqn;
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
rules: c4.ViewRule[];
|
|
39
|
+
}
|
|
40
|
+
export declare const ElementViewOps: {
|
|
41
|
+
writeId(node: ast.ElementView, id: c4.ViewID): ast.ElementView;
|
|
42
|
+
readId(node: ast.ElementView): c4.ViewID | undefined;
|
|
43
|
+
};
|
|
44
|
+
export declare const ElementOps: {
|
|
45
|
+
writeId(node: ast.Element, id: c4.Fqn | null): ast.Element;
|
|
46
|
+
readId(node: ast.Element): c4.Fqn | undefined;
|
|
47
|
+
};
|
|
48
|
+
export interface LikeC4LangiumDocument extends LangiumDocument<LikeC4Document> {
|
|
49
|
+
c4hash?: string;
|
|
50
|
+
c4Specification: ParsedAstSpecification;
|
|
51
|
+
c4Elements: ParsedAstElement[];
|
|
52
|
+
c4Relations: ParsedAstRelation[];
|
|
53
|
+
c4Views: ParsedAstElementView[];
|
|
54
|
+
c4fqns?: MultiMap<c4.Fqn, string> | undefined;
|
|
55
|
+
}
|
|
56
|
+
export declare function cleanParsedModel(doc: LikeC4LangiumDocument): {
|
|
57
|
+
elements: ParsedAstElement[];
|
|
58
|
+
relations: ParsedAstRelation[];
|
|
59
|
+
views: ParsedAstElementView[];
|
|
60
|
+
specification: ParsedAstSpecification;
|
|
61
|
+
};
|
|
62
|
+
export declare function isLikeC4LangiumDocument(doc: LangiumDocument): doc is LikeC4LangiumDocument;
|
|
63
|
+
export declare function isParsedLikeC4LangiumDocument(doc: LangiumDocument): doc is LikeC4LangiumDocument;
|
|
64
|
+
export declare const isValidDocument: (doc: LangiumDocument) => doc is LikeC4LangiumDocument;
|
|
65
|
+
export declare function streamModel(doc: LikeC4LangiumDocument): Generator<ast.Element | ast.Relation, void, unknown>;
|
|
66
|
+
export declare function resolveRelationPoints(node: ast.Relation): {
|
|
67
|
+
source: ast.Element;
|
|
68
|
+
target: ast.Element;
|
|
69
|
+
};
|
|
70
|
+
export declare function toElementStyle(props?: ast.AStyleProperty[]): {
|
|
71
|
+
color?: c4.ThemeColor;
|
|
72
|
+
shape?: c4.ElementShape;
|
|
73
|
+
};
|
|
74
|
+
export declare function toAutoLayout(direction: ast.ViewRuleLayoutDirection): c4.ViewRuleAutoLayout['autoLayout'];
|
|
75
|
+
//# sourceMappingURL=ast.d.ts.map
|
package/dist/ast.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as ast from './generated/ast';
|
|
2
|
+
import { DocumentState } from 'langium';
|
|
3
|
+
import objectHash from 'object-hash';
|
|
4
|
+
import { elementRef } from './elementRef';
|
|
5
|
+
import { LikeC4LanguageMetaData } from './generated/module';
|
|
6
|
+
export { ast };
|
|
7
|
+
export function c4hash({ c4Specification, c4Elements, c4Relations, c4Views }) {
|
|
8
|
+
return objectHash({
|
|
9
|
+
c4Specification,
|
|
10
|
+
c4Elements,
|
|
11
|
+
c4Relations,
|
|
12
|
+
c4Views
|
|
13
|
+
}, {
|
|
14
|
+
respectType: false
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
const idattr = Symbol.for('idattr');
|
|
18
|
+
export const ElementViewOps = {
|
|
19
|
+
writeId(node, id) {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
node[idattr] = id;
|
|
22
|
+
return node;
|
|
23
|
+
},
|
|
24
|
+
readId(node) {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
return node[idattr];
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const ElementOps = {
|
|
30
|
+
writeId(node, id) {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
if (id === null) {
|
|
33
|
+
delete node[idattr];
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
node[idattr] = id;
|
|
37
|
+
}
|
|
38
|
+
return node;
|
|
39
|
+
},
|
|
40
|
+
readId(node) {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
return node[idattr];
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export function cleanParsedModel(doc) {
|
|
46
|
+
doc.c4Specification = {
|
|
47
|
+
kinds: {}
|
|
48
|
+
};
|
|
49
|
+
const elements = (doc.c4Elements = []);
|
|
50
|
+
const relations = (doc.c4Relations = []);
|
|
51
|
+
const views = (doc.c4Views = []);
|
|
52
|
+
return {
|
|
53
|
+
elements,
|
|
54
|
+
relations,
|
|
55
|
+
views,
|
|
56
|
+
specification: doc.c4Specification
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function isLikeC4LangiumDocument(doc) {
|
|
60
|
+
return doc.textDocument.languageId === LikeC4LanguageMetaData.languageId;
|
|
61
|
+
}
|
|
62
|
+
export function isParsedLikeC4LangiumDocument(doc) {
|
|
63
|
+
return (isLikeC4LangiumDocument(doc) &&
|
|
64
|
+
['c4Specification', 'c4Elements', 'c4Relations', 'c4Views'].every(key => key in doc));
|
|
65
|
+
}
|
|
66
|
+
export const isValidDocument = (doc) => {
|
|
67
|
+
if (!isLikeC4LangiumDocument(doc))
|
|
68
|
+
return false;
|
|
69
|
+
const { state, parseResult, diagnostics } = doc;
|
|
70
|
+
return (state === DocumentState.Validated &&
|
|
71
|
+
parseResult.lexerErrors.length === 0 &&
|
|
72
|
+
(!diagnostics || diagnostics.every(d => d.severity !== 1)));
|
|
73
|
+
};
|
|
74
|
+
export function* streamModel(doc) {
|
|
75
|
+
const elements = doc.parseResult.value.model?.elements ?? [];
|
|
76
|
+
const traverseStack = [...elements];
|
|
77
|
+
let el;
|
|
78
|
+
while ((el = traverseStack.shift())) {
|
|
79
|
+
if (ast.isExtendElement(el)) {
|
|
80
|
+
if (!!el.body) {
|
|
81
|
+
traverseStack.push(...el.body.elements);
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (ast.isElement(el) && el.body) {
|
|
86
|
+
traverseStack.push(...el.body.elements);
|
|
87
|
+
}
|
|
88
|
+
yield el;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function resolveRelationPoints(node) {
|
|
92
|
+
const target = elementRef(node.target);
|
|
93
|
+
if (!target) {
|
|
94
|
+
throw new Error('Skip relation due to invalid reference to target');
|
|
95
|
+
}
|
|
96
|
+
if (ast.isRelationWithSource(node)) {
|
|
97
|
+
const source = elementRef(node.source);
|
|
98
|
+
if (!source) {
|
|
99
|
+
throw new Error('Skip relation due to invalid reference to source');
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
source,
|
|
103
|
+
target
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (!ast.isElementBody(node.$container)) {
|
|
107
|
+
throw new Error('Skip relation due to invalid reference to source');
|
|
108
|
+
}
|
|
109
|
+
const source = node.$container.$container;
|
|
110
|
+
return {
|
|
111
|
+
source,
|
|
112
|
+
target
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function toElementStyle(props) {
|
|
116
|
+
const result = {};
|
|
117
|
+
const color = props?.find(ast.isColorProperty)?.value;
|
|
118
|
+
if (color) {
|
|
119
|
+
result.color = color;
|
|
120
|
+
}
|
|
121
|
+
const shape = props?.find(ast.isShapeProperty)?.value;
|
|
122
|
+
if (shape) {
|
|
123
|
+
result.shape = shape;
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
export function toAutoLayout(direction) {
|
|
128
|
+
switch (direction) {
|
|
129
|
+
case 'TopBottom': {
|
|
130
|
+
return 'TB';
|
|
131
|
+
}
|
|
132
|
+
case 'BottomTop': {
|
|
133
|
+
return 'BT';
|
|
134
|
+
}
|
|
135
|
+
case 'LeftRight': {
|
|
136
|
+
return 'LR';
|
|
137
|
+
}
|
|
138
|
+
case 'RightLeft': {
|
|
139
|
+
return 'RL';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=ast.js.map
|
package/dist/builtin.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type * as c4 from '@likec4/core/types';
|
|
2
|
+
import { ast } from './ast';
|
|
3
|
+
export declare function isElementRefHead(node: ast.ElementRef | ast.StrictElementRef): boolean;
|
|
4
|
+
export declare function elementRef(node: ast.ElementRef | ast.StrictElementRef): ast.Element | undefined;
|
|
5
|
+
export declare function strictElementRefFqn(node: ast.StrictElementRef): c4.Fqn;
|
|
6
|
+
export declare function parentStrictElementRef(node: ast.StrictElementRef): c4.Fqn;
|
|
7
|
+
//# sourceMappingURL=elementRef.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ast } from './ast';
|
|
2
|
+
import invariant from 'tiny-invariant';
|
|
3
|
+
import { failExpectedNever } from './utils';
|
|
4
|
+
export function isElementRefHead(node) {
|
|
5
|
+
if (ast.isElementRef(node)) {
|
|
6
|
+
return !ast.isElementRef(node.$container);
|
|
7
|
+
}
|
|
8
|
+
if (ast.isStrictElementRef(node)) {
|
|
9
|
+
return !ast.isStrictElementRef(node.$container);
|
|
10
|
+
}
|
|
11
|
+
failExpectedNever(node);
|
|
12
|
+
}
|
|
13
|
+
export function elementRef(node) {
|
|
14
|
+
invariant(isElementRefHead(node), 'Expected head ElementRef');
|
|
15
|
+
while (node.next) {
|
|
16
|
+
node = node.next;
|
|
17
|
+
}
|
|
18
|
+
return node.el.ref;
|
|
19
|
+
}
|
|
20
|
+
export function strictElementRefFqn(node) {
|
|
21
|
+
invariant(isElementRefHead(node), 'Expected head StrictElementRef');
|
|
22
|
+
const name = [node.el.$refText];
|
|
23
|
+
let child = node.next;
|
|
24
|
+
while (child) {
|
|
25
|
+
name.push(child.el.$refText);
|
|
26
|
+
child = child.next;
|
|
27
|
+
}
|
|
28
|
+
return name.join('.');
|
|
29
|
+
}
|
|
30
|
+
export function parentStrictElementRef(node) {
|
|
31
|
+
invariant(!isElementRefHead(node), 'Expected next StrictElementRef');
|
|
32
|
+
const path = [];
|
|
33
|
+
let parent = node.$container;
|
|
34
|
+
while (ast.isStrictElementRef(parent)) {
|
|
35
|
+
path.unshift(parent.el.$refText);
|
|
36
|
+
parent = parent.$container;
|
|
37
|
+
}
|
|
38
|
+
return path.join('.');
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=elementRef.js.map
|