@likec4/language-server 0.25.0 → 0.27.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 +3 -1
- package/contrib/likec4.tmLanguage.json +1 -1
- package/dist/generated/ast.d.ts +14 -4
- package/dist/generated/ast.js +10 -3
- package/dist/generated/grammar.js +278 -134
- package/dist/lsp/DocumentSymbolProvider.js +16 -22
- package/dist/model/fqn-computation.js +1 -1
- package/dist/model/fqn-index.d.ts +3 -2
- package/dist/model/fqn-index.js +52 -34
- package/dist/model/model-builder.js +26 -18
- package/dist/model/model-locator.js +8 -8
- package/dist/module.js +3 -2
- package/dist/references/scope-computation.js +15 -12
- package/dist/shared/DocumentLinkProvider.d.ts +8 -0
- package/dist/shared/DocumentLinkProvider.js +37 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* This program and the accompanying materials are made available under the
|
|
4
4
|
* terms of the MIT License, which is available in the project root.
|
|
5
5
|
******************************************************************************/
|
|
6
|
-
import invariant from 'tiny-invariant';
|
|
7
6
|
import { findNodeForProperty } from 'langium';
|
|
8
7
|
import { SymbolKind } from 'vscode-languageserver-protocol';
|
|
9
8
|
import { ast } from '../ast';
|
|
10
9
|
import { logger } from '../logger';
|
|
10
|
+
import { isEmpty } from 'remeda';
|
|
11
11
|
export class LikeC4DocumentSymbolProvider {
|
|
12
12
|
services;
|
|
13
13
|
constructor(services) {
|
|
@@ -28,10 +28,20 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
28
28
|
const specKeywordNode = findNodeForProperty(cstModel, 'name');
|
|
29
29
|
if (!specKeywordNode)
|
|
30
30
|
return [];
|
|
31
|
-
const specSymbols =
|
|
31
|
+
const specSymbols = astSpec.specs.flatMap(nd => {
|
|
32
|
+
if (ast.isSpecificationElementKind(nd)) {
|
|
33
|
+
return getElementKindSymbol(nd) ?? [];
|
|
34
|
+
}
|
|
35
|
+
else if (ast.isSpecificationTag(nd)) {
|
|
36
|
+
return getTagSymbol(nd) ?? [];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
});
|
|
32
42
|
const getElementKindSymbol = (astKind) => {
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
if (!astKind.$cstNode || !astKind.kind.$cstNode || isEmpty(astKind.kind.name))
|
|
44
|
+
return null;
|
|
35
45
|
return {
|
|
36
46
|
kind: SymbolKind.Class,
|
|
37
47
|
name: astKind.kind.name,
|
|
@@ -39,17 +49,9 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
39
49
|
selectionRange: astKind.kind.$cstNode.range
|
|
40
50
|
};
|
|
41
51
|
};
|
|
42
|
-
for (const astKind of astSpec.elementKinds) {
|
|
43
|
-
try {
|
|
44
|
-
specSymbols.push(getElementKindSymbol(astKind));
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
logger.error(e);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
52
|
const getTagSymbol = (astTag) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
if (!astTag.$cstNode || !astTag.tag.$cstNode || isEmpty(astTag.tag.name))
|
|
54
|
+
return null;
|
|
53
55
|
return {
|
|
54
56
|
kind: SymbolKind.EnumMember,
|
|
55
57
|
name: '#' + astTag.tag.name,
|
|
@@ -57,14 +59,6 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
57
59
|
selectionRange: astTag.tag.$cstNode.range
|
|
58
60
|
};
|
|
59
61
|
};
|
|
60
|
-
for (const astTag of astSpec.tags) {
|
|
61
|
-
try {
|
|
62
|
-
specSymbols.push(getTagSymbol(astTag));
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
logger.error(e);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
62
|
if (specSymbols.length === 0)
|
|
69
63
|
return [];
|
|
70
64
|
return [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { failExpectedNever } from '@likec4/core';
|
|
2
2
|
import { Fqn } from '@likec4/core/types';
|
|
3
3
|
import { MultiMap } from 'langium';
|
|
4
|
-
import { isEmpty, isNil } from '
|
|
4
|
+
import { isEmpty, isNil } from 'remeda';
|
|
5
5
|
import { ElementOps, ast } from '../ast';
|
|
6
6
|
import { strictElementRefFqn } from '../elementRef';
|
|
7
7
|
export function computeDocumentFqn(document, services) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Fqn } from '@likec4/core/types';
|
|
2
|
-
import type { LangiumDocuments } from 'langium';
|
|
2
|
+
import type { LangiumDocument, LangiumDocuments } from 'langium';
|
|
3
3
|
import { StreamImpl } from 'langium';
|
|
4
4
|
import type { ast } from '../ast';
|
|
5
5
|
import { type LikeC4LangiumDocument } from '../ast';
|
|
@@ -7,6 +7,7 @@ import type { LikeC4Services } from '../module';
|
|
|
7
7
|
type FqnIndexedDocument = Omit<LikeC4LangiumDocument, 'c4fqns'> & {
|
|
8
8
|
c4fqns: NonNullable<LikeC4LangiumDocument['c4fqns']>;
|
|
9
9
|
};
|
|
10
|
+
export declare function isFqnIndexedDocument(doc: LangiumDocument): doc is FqnIndexedDocument;
|
|
10
11
|
export interface FqnIndexEntry {
|
|
11
12
|
fqn: Fqn;
|
|
12
13
|
name: string;
|
|
@@ -24,7 +25,7 @@ export declare class FqnIndex {
|
|
|
24
25
|
path: string;
|
|
25
26
|
doc: FqnIndexedDocument;
|
|
26
27
|
}>;
|
|
27
|
-
directChildrenOf(parent: Fqn):
|
|
28
|
+
directChildrenOf(parent: Fqn): StreamImpl<IterableIterator<FqnIndexEntry> | null, FqnIndexEntry>;
|
|
28
29
|
uniqueDescedants(parent: Fqn): StreamImpl<IterableIterator<FqnIndexEntry> | null, FqnIndexEntry>;
|
|
29
30
|
}
|
|
30
31
|
export {};
|
package/dist/model/fqn-index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { nameFromFqn, parentFqn } from '@likec4/core/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { DONE_RESULT, DocumentState, MultiMap, StreamImpl } from 'langium';
|
|
3
3
|
import { isNil } from 'remeda';
|
|
4
4
|
import { ElementOps, isLikeC4LangiumDocument } from '../ast';
|
|
5
5
|
import { logger } from '../logger';
|
|
6
6
|
import { computeDocumentFqn } from './fqn-computation';
|
|
7
|
-
|
|
7
|
+
export function isFqnIndexedDocument(doc) {
|
|
8
|
+
return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !isNil(doc.c4fqns);
|
|
9
|
+
}
|
|
8
10
|
export class FqnIndex {
|
|
9
11
|
services;
|
|
10
12
|
langiumDocuments;
|
|
@@ -31,54 +33,70 @@ export class FqnIndex {
|
|
|
31
33
|
return this.documents().flatMap(doc => doc.c4fqns.entries().map(([fqn, path]) => ({ fqn, path, doc })));
|
|
32
34
|
}
|
|
33
35
|
get(el) {
|
|
34
|
-
|
|
35
|
-
if (fqn) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
return fqn
|
|
36
|
+
return ElementOps.readId(el) ?? null;
|
|
37
|
+
// if (fqn) {
|
|
38
|
+
// const doc = getDocument(el)
|
|
39
|
+
// if (isFqnIndexedDocument(doc) && doc.c4fqns.has(fqn)) {
|
|
40
|
+
// return fqn
|
|
41
|
+
// }
|
|
42
|
+
// const path = this.services.workspace.AstNodeLocator.getAstNodePath(el)
|
|
43
|
+
// logger.error(`Clean cached FQN ${fqn} at ${path}`)
|
|
44
|
+
// ElementOps.writeId(el, null)
|
|
45
|
+
// fqn = null
|
|
46
|
+
// }
|
|
47
|
+
// return fqn
|
|
46
48
|
}
|
|
47
49
|
byFqn(fqn) {
|
|
48
|
-
return this.documents()
|
|
49
|
-
.flatMap(doc => {
|
|
50
|
+
return this.documents().flatMap(doc => {
|
|
50
51
|
return doc.c4fqns.get(fqn).map(path => ({ path, doc }));
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
directChildrenOf(parent) {
|
|
54
|
-
return
|
|
55
|
-
.entries()
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
return new StreamImpl(() => {
|
|
56
|
+
const children = new MultiMap(this.entries()
|
|
57
|
+
.filter(e => parentFqn(e.fqn) === parent)
|
|
58
|
+
.map((e) => {
|
|
59
|
+
const name = nameFromFqn(e.fqn);
|
|
60
|
+
const entry = { ...e, name };
|
|
61
|
+
return [name, entry];
|
|
62
|
+
})
|
|
63
|
+
.toArray());
|
|
64
|
+
if (children.size === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return children
|
|
68
|
+
.entriesGroupedByKey()
|
|
69
|
+
.flatMap(([_name, descrs]) => (descrs.length === 1 ? descrs : []))
|
|
70
|
+
.iterator();
|
|
71
|
+
}, iterator => {
|
|
72
|
+
if (iterator) {
|
|
73
|
+
return iterator.next();
|
|
74
|
+
}
|
|
75
|
+
return DONE_RESULT;
|
|
76
|
+
});
|
|
58
77
|
}
|
|
59
78
|
uniqueDescedants(parent) {
|
|
60
79
|
return new StreamImpl(() => {
|
|
61
80
|
const prefix = `${parent}.`;
|
|
62
|
-
const children = [];
|
|
63
81
|
const childrenNames = new Set();
|
|
64
82
|
const descedants = [];
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
const nested = new MultiMap();
|
|
84
|
+
this.entries()
|
|
85
|
+
.filter(e => e.fqn.startsWith(prefix))
|
|
86
|
+
.forEach(e => {
|
|
87
|
+
const name = nameFromFqn(e.fqn);
|
|
88
|
+
const entry = { ...e, name };
|
|
89
|
+
if (parentFqn(e.fqn) === parent) {
|
|
90
|
+
childrenNames.add(name);
|
|
91
|
+
nested.add(name, entry);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
descedants.push(entry);
|
|
76
95
|
}
|
|
77
96
|
});
|
|
78
|
-
if (
|
|
97
|
+
if (nested.size + descedants.length === 0) {
|
|
79
98
|
return null;
|
|
80
99
|
}
|
|
81
|
-
const nested = new MultiMap(children.map(entry => [entry.name, entry]));
|
|
82
100
|
for (const descedant of descedants) {
|
|
83
101
|
if (!childrenNames.has(descedant.name)) {
|
|
84
102
|
nested.add(descedant.name, descedant);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModelIndex, assignNavigateTo, computeView } from '@likec4/core';
|
|
2
2
|
import { DefaultElementShape, DefaultThemeColor } from '@likec4/core/types';
|
|
3
3
|
import { compareByFqnHierarchically, parentFqn } from '@likec4/core/utils';
|
|
4
4
|
import { DocumentState, getDocument } from 'langium';
|
|
5
5
|
import objectHash from 'object-hash';
|
|
6
|
-
import { clone
|
|
6
|
+
import { clone } from 'rambdax';
|
|
7
7
|
import * as R from 'remeda';
|
|
8
|
+
import stripIndent from 'strip-indent';
|
|
8
9
|
import invariant from 'tiny-invariant';
|
|
9
10
|
import { ElementViewOps, ast, cleanParsedModel, isLikeC4LangiumDocument, isValidLikeC4LangiumDocument, resolveRelationPoints, streamModel, toAutoLayout, toElementStyle } from '../ast';
|
|
10
11
|
import { elementRef, strictElementRefFqn } from '../elementRef';
|
|
11
12
|
import { logger } from '../logger';
|
|
12
13
|
import { Rpc } from '../protocol';
|
|
13
14
|
import { failExpectedNever } from '../utils';
|
|
14
|
-
import stripIndent from 'strip-indent';
|
|
15
15
|
export class LikeC4ModelBuilder {
|
|
16
16
|
services;
|
|
17
17
|
fqnIndex;
|
|
@@ -47,7 +47,7 @@ export class LikeC4ModelBuilder {
|
|
|
47
47
|
return this.services.shared.lsp.Connection;
|
|
48
48
|
}
|
|
49
49
|
documents() {
|
|
50
|
-
return this.langiumDocuments.all.
|
|
50
|
+
return this.langiumDocuments.all.filter(isValidLikeC4LangiumDocument).toArray();
|
|
51
51
|
}
|
|
52
52
|
buildModel() {
|
|
53
53
|
const docs = this.documents();
|
|
@@ -73,10 +73,6 @@ export class LikeC4ModelBuilder {
|
|
|
73
73
|
}
|
|
74
74
|
return null;
|
|
75
75
|
};
|
|
76
|
-
const toModelRelation = (rel) => {
|
|
77
|
-
const { astPath, ...model } = rel;
|
|
78
|
-
return model;
|
|
79
|
-
};
|
|
80
76
|
const elements = R.pipe(R.flatMap(docs, d => d.c4Elements), R.map(toModelElement), R.compact, R.sort(compareByFqnHierarchically), R.reduce((acc, el) => {
|
|
81
77
|
const parent = parentFqn(el.id);
|
|
82
78
|
if (!parent || parent in acc) {
|
|
@@ -88,7 +84,18 @@ export class LikeC4ModelBuilder {
|
|
|
88
84
|
}
|
|
89
85
|
return acc;
|
|
90
86
|
}, {}));
|
|
91
|
-
const
|
|
87
|
+
const toModelRelation = ({ astPath, source, target, ...model }) => {
|
|
88
|
+
if (source in elements && target in elements) {
|
|
89
|
+
return {
|
|
90
|
+
source,
|
|
91
|
+
target,
|
|
92
|
+
...model
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
};
|
|
97
|
+
const relations = R.pipe(R.flatMap(docs, d => d.c4Relations), R.map(toModelRelation), R.compact, R.mapToObj(r => [r.id, r]));
|
|
98
|
+
const modelIndex = ModelIndex.from({ elements, relations });
|
|
92
99
|
const toModelView = (view) => {
|
|
93
100
|
// eslint-disable-next-line prefer-const
|
|
94
101
|
let { astPath, rules, title, ...model } = view;
|
|
@@ -98,18 +105,19 @@ export class LikeC4ModelBuilder {
|
|
|
98
105
|
if (!title && view.id === 'index') {
|
|
99
106
|
title = 'Landscape view';
|
|
100
107
|
}
|
|
101
|
-
return {
|
|
108
|
+
return computeView({
|
|
102
109
|
...model,
|
|
103
110
|
...(title && { title }),
|
|
104
111
|
rules: clone(rules)
|
|
105
|
-
};
|
|
112
|
+
}, modelIndex);
|
|
106
113
|
};
|
|
107
|
-
const views = R.pipe(
|
|
108
|
-
|
|
114
|
+
const views = R.pipe(R.flatMap(docs, d => d.c4Views), R.map(toModelView), R.compact);
|
|
115
|
+
assignNavigateTo(views);
|
|
116
|
+
return {
|
|
109
117
|
elements,
|
|
110
118
|
relations,
|
|
111
|
-
views
|
|
112
|
-
}
|
|
119
|
+
views: R.mapToObj(views, v => [v.id, v])
|
|
120
|
+
};
|
|
113
121
|
}
|
|
114
122
|
catch (e) {
|
|
115
123
|
logger.error(e);
|
|
@@ -121,9 +129,9 @@ export class LikeC4ModelBuilder {
|
|
|
121
129
|
*/
|
|
122
130
|
parseDocument(doc) {
|
|
123
131
|
const { elements, relations, views, specification } = cleanParsedModel(doc);
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
for (const { kind, style } of
|
|
132
|
+
const specs = doc.parseResult.value.specification?.specs.filter(ast.isSpecificationElementKind);
|
|
133
|
+
if (specs) {
|
|
134
|
+
for (const { kind, style } of specs) {
|
|
127
135
|
try {
|
|
128
136
|
const styleProps = toElementStyle(style?.props);
|
|
129
137
|
specification.kinds[kind.name] = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ast, isParsedLikeC4LangiumDocument } from '../ast';
|
|
1
|
+
import { findNodeForProperty, getDocument } from 'langium';
|
|
2
|
+
import { ElementOps, ast, isParsedLikeC4LangiumDocument } from '../ast';
|
|
3
3
|
export class LikeC4ModelLocator {
|
|
4
4
|
services;
|
|
5
5
|
fqnIndex;
|
|
@@ -10,21 +10,21 @@ export class LikeC4ModelLocator {
|
|
|
10
10
|
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
11
11
|
}
|
|
12
12
|
documents() {
|
|
13
|
-
return this.langiumDocuments.all.
|
|
13
|
+
return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument);
|
|
14
14
|
}
|
|
15
15
|
getParsedElement(astNode) {
|
|
16
|
+
const fqn = ElementOps.readId(astNode) ?? null;
|
|
17
|
+
if (!fqn)
|
|
18
|
+
return null;
|
|
16
19
|
const doc = getDocument(astNode);
|
|
17
20
|
if (!isParsedLikeC4LangiumDocument(doc)) {
|
|
18
21
|
return null;
|
|
19
22
|
}
|
|
20
|
-
const fqn = this.fqnIndex.get(astNode);
|
|
21
|
-
if (!fqn)
|
|
22
|
-
return null;
|
|
23
23
|
return doc.c4Elements.find(e => e.id === fqn) ?? null;
|
|
24
24
|
}
|
|
25
25
|
locateElement(fqn, property = 'name') {
|
|
26
26
|
for (const doc of this.documents()) {
|
|
27
|
-
if (
|
|
27
|
+
if (!doc.c4fqns?.has(fqn)) {
|
|
28
28
|
continue;
|
|
29
29
|
}
|
|
30
30
|
const element = doc.c4Elements.find(e => e.id === fqn);
|
|
@@ -68,7 +68,7 @@ export class LikeC4ModelLocator {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
const targetNode =
|
|
71
|
+
const targetNode = findNodeForProperty(node.$cstNode, 'arr');
|
|
72
72
|
if (!targetNode) {
|
|
73
73
|
return null;
|
|
74
74
|
}
|
package/dist/module.js
CHANGED
|
@@ -4,7 +4,7 @@ import { LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenP
|
|
|
4
4
|
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
|
|
5
5
|
import { LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
|
|
6
6
|
import { registerProtocolHandlers } from './registerProtocolHandlers';
|
|
7
|
-
import { LikeC4CodeLensProvider, LikeC4WorkspaceManager } from './shared';
|
|
7
|
+
import { LikeC4CodeLensProvider, LikeC4DocumentLinkProvider, LikeC4WorkspaceManager } from './shared';
|
|
8
8
|
import { registerValidationChecks } from './validation';
|
|
9
9
|
import { logger } from './logger';
|
|
10
10
|
function bind(Type) {
|
|
@@ -36,7 +36,8 @@ const LikeC4SharedModule = {
|
|
|
36
36
|
WorkspaceManager: services => new LikeC4WorkspaceManager(services)
|
|
37
37
|
},
|
|
38
38
|
lsp: {
|
|
39
|
-
CodeLensProvider: services => new LikeC4CodeLensProvider(services)
|
|
39
|
+
CodeLensProvider: services => new LikeC4CodeLensProvider(services),
|
|
40
|
+
DocumentLinkProvider: services => new LikeC4DocumentLinkProvider(services)
|
|
40
41
|
}
|
|
41
42
|
};
|
|
42
43
|
export function createLanguageServices(context) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DefaultScopeComputation, MultiMap } from 'langium';
|
|
2
2
|
import { ast } from '../ast';
|
|
3
|
+
import { isEmpty } from 'remeda';
|
|
3
4
|
export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
4
5
|
services;
|
|
5
6
|
constructor(services) {
|
|
@@ -9,28 +10,30 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
9
10
|
computeExports(document, _cancelToken) {
|
|
10
11
|
const { specification, model, views } = document.parseResult.value;
|
|
11
12
|
const docExports = [];
|
|
12
|
-
if (specification) {
|
|
13
|
-
for (const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
if (specification && specification.specs.length > 0) {
|
|
14
|
+
for (const spec of specification.specs) {
|
|
15
|
+
if (ast.isSpecificationElementKind(spec) && spec.kind && !isEmpty(spec.kind.name)) {
|
|
16
|
+
docExports.push(this.descriptions.createDescription(spec.kind, spec.kind.name, document));
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (ast.isSpecificationTag(spec) && spec.tag && !isEmpty(spec.tag.name)) {
|
|
20
|
+
docExports.push(this.descriptions.createDescription(spec.tag, spec.tag.name, document));
|
|
21
|
+
docExports.push(this.descriptions.createDescription(spec.tag, '#' + spec.tag.name, document));
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
}
|
|
21
|
-
// Filled later by FqnIndex (on IndexedContent phase)
|
|
22
|
-
document.c4fqns = undefined;
|
|
23
26
|
// Only root model elements are exported
|
|
24
27
|
if (model && model.elements.length > 0) {
|
|
25
28
|
for (const elAst of model.elements) {
|
|
26
|
-
if (ast.isElement(elAst)) {
|
|
29
|
+
if (ast.isElement(elAst) && !isEmpty(elAst.name)) {
|
|
27
30
|
docExports.push(this.descriptions.createDescription(elAst, elAst.name, document));
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
if (views && views.views.length > 0) {
|
|
32
35
|
for (const viewAst of views.views) {
|
|
33
|
-
if (
|
|
36
|
+
if (viewAst.name && !isEmpty(viewAst.name)) {
|
|
34
37
|
docExports.push(this.descriptions.createDescription(viewAst, viewAst.name, document));
|
|
35
38
|
}
|
|
36
39
|
}
|
|
@@ -54,7 +57,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
54
57
|
continue;
|
|
55
58
|
}
|
|
56
59
|
let subcontainer;
|
|
57
|
-
if (ast.isElement(el)) {
|
|
60
|
+
if (ast.isElement(el) && !isEmpty(el.name)) {
|
|
58
61
|
localScope.add(el.name, this.descriptions.createDescription(el, el.name, document));
|
|
59
62
|
subcontainer = el.body;
|
|
60
63
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LangiumDocument, LangiumSharedServices, MaybePromise, DocumentLinkProvider } from 'langium';
|
|
2
|
+
import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver-protocol';
|
|
3
|
+
export declare class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
|
|
4
|
+
private services;
|
|
5
|
+
constructor(services: LangiumSharedServices);
|
|
6
|
+
getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams): MaybePromise<DocumentLink[]>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=DocumentLinkProvider.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { findNodeForProperty, streamAllContents } from 'langium/lib/utils';
|
|
2
|
+
import { ast, isParsedLikeC4LangiumDocument } from '../ast';
|
|
3
|
+
import { logger } from '../logger';
|
|
4
|
+
export class LikeC4DocumentLinkProvider {
|
|
5
|
+
services;
|
|
6
|
+
constructor(services) {
|
|
7
|
+
this.services = services;
|
|
8
|
+
//
|
|
9
|
+
}
|
|
10
|
+
getDocumentLinks(doc, _params) {
|
|
11
|
+
if (!isParsedLikeC4LangiumDocument(doc)) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const base = new URL(doc.uri.toString());
|
|
15
|
+
return streamAllContents(doc.parseResult.value)
|
|
16
|
+
.filter(ast.isLinkProperty)
|
|
17
|
+
.flatMap((n) => {
|
|
18
|
+
try {
|
|
19
|
+
const u = new URL(n.value, base);
|
|
20
|
+
const valueCst = findNodeForProperty(n.$cstNode, 'value');
|
|
21
|
+
if (!valueCst) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
range: valueCst.range,
|
|
26
|
+
target: u.toString()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
logger.error(e);
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
.toArray();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=DocumentLinkProvider.js.map
|
package/dist/shared/index.d.ts
CHANGED
package/dist/shared/index.js
CHANGED