@likec4/language-server 0.45.0 → 0.46.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.
Files changed (37) hide show
  1. package/contrib/likec4.monarch.ts +9 -8
  2. package/dist/Rpc.js +14 -60
  3. package/dist/ast.d.ts +9 -10
  4. package/dist/ast.js +14 -22
  5. package/dist/elementRef.d.ts +5 -11
  6. package/dist/elementRef.js +5 -32
  7. package/dist/generated/ast.d.ts +62 -60
  8. package/dist/generated/ast.js +59 -33
  9. package/dist/generated/grammar.d.ts +1 -1
  10. package/dist/generated/grammar.js +1 -1
  11. package/dist/generated/module.d.ts +1 -1
  12. package/dist/generated/module.js +1 -0
  13. package/dist/lsp/CodeLensProvider.js +2 -1
  14. package/dist/lsp/DocumentSymbolProvider.d.ts +1 -1
  15. package/dist/lsp/DocumentSymbolProvider.js +8 -5
  16. package/dist/lsp/SemanticTokenProvider.js +29 -63
  17. package/dist/model/fqn-computation.js +5 -5
  18. package/dist/model/fqn-index.d.ts +2 -1
  19. package/dist/model/fqn-index.js +26 -31
  20. package/dist/model/model-builder.js +20 -11
  21. package/dist/model/model-locator.js +4 -11
  22. package/dist/model/model-parser.d.ts +6 -3
  23. package/dist/model/model-parser.js +41 -36
  24. package/dist/module.js +4 -0
  25. package/dist/protocol.d.ts +0 -3
  26. package/dist/protocol.js +1 -4
  27. package/dist/references/scope-computation.js +19 -17
  28. package/dist/references/scope-provider.js +19 -19
  29. package/dist/shared/NodeKindProvider.d.ts +13 -0
  30. package/dist/shared/NodeKindProvider.js +29 -0
  31. package/dist/test/testServices.js +8 -8
  32. package/dist/utils.js +1 -1
  33. package/dist/validation/index.js +13 -3
  34. package/dist/validation/relation.js +12 -18
  35. package/dist/validation/specification.d.ts +3 -0
  36. package/dist/validation/specification.js +30 -0
  37. package/package.json +9 -9
@@ -44,12 +44,15 @@ export class LikeC4DocumentSymbolProvider {
44
44
  constructor(services) {
45
45
  this.services = services;
46
46
  }
47
- getSymbols(document) {
48
- const { specification, model, views } = document.parseResult.value;
47
+ getSymbols({
48
+ parseResult: {
49
+ value: { specifications, models, views }
50
+ }
51
+ }) {
49
52
  return [
50
- () => specification && this.getSpecSymbol(specification),
51
- () => model && this.getModelSymbol(model),
52
- () => views && this.getModelViewsSymbol(views)
53
+ ...specifications.map((s) => () => this.getSpecSymbol(s)),
54
+ ...models.map((s) => () => this.getModelSymbol(s)),
55
+ ...views.map((s) => () => this.getModelViewsSymbol(s))
53
56
  ].flatMap((fn) => {
54
57
  try {
55
58
  return fn() ?? [];
@@ -1,38 +1,21 @@
1
1
  import { AbstractSemanticTokenProvider } from "langium";
2
2
  import { SemanticTokenModifiers, SemanticTokenTypes } from "vscode-languageserver-protocol";
3
3
  import { ast } from "../ast.js";
4
- import { isElementRefHead } from "../elementRef.js";
5
4
  export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
6
5
  highlightElement(node, acceptor) {
7
- const keyword = (keyword2, _index) => acceptor({
8
- node,
9
- keyword: keyword2,
10
- type: SemanticTokenTypes.keyword,
11
- modifier: [SemanticTokenModifiers.defaultLibrary]
12
- });
13
- if ("arr" in node) {
14
- acceptor({
15
- node,
16
- property: "arr",
17
- type: SemanticTokenTypes.keyword,
18
- modifier: [SemanticTokenModifiers.defaultLibrary]
19
- });
20
- }
21
6
  if (ast.isRelation(node) && "kind" in node) {
22
- keyword("-[");
23
7
  acceptor({
24
8
  node,
25
9
  property: "kind",
26
10
  type: SemanticTokenTypes.type,
27
11
  modifier: [SemanticTokenModifiers.definition]
28
12
  });
29
- keyword("]->");
30
13
  }
31
- if (ast.isElementRef(node) || ast.isStrictElementRef(node)) {
14
+ if (ast.isElementRef(node) || ast.isFqnElementRef(node)) {
32
15
  acceptor({
33
16
  node,
34
17
  property: "el",
35
- type: isElementRefHead(node) ? SemanticTokenTypes.variable : SemanticTokenTypes.property
18
+ type: node.parent ? SemanticTokenTypes.property : SemanticTokenTypes.variable
36
19
  });
37
20
  }
38
21
  if (ast.isElementViewRef(node)) {
@@ -42,6 +25,13 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
42
25
  type: SemanticTokenTypes.variable
43
26
  });
44
27
  }
28
+ if (ast.isElementRefExpression(node) && node.isDescedants) {
29
+ acceptor({
30
+ node,
31
+ keyword: ".*",
32
+ type: SemanticTokenTypes.variable
33
+ });
34
+ }
45
35
  if (ast.isWildcardExpression(node)) {
46
36
  acceptor({
47
37
  node,
@@ -49,40 +39,26 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
49
39
  type: SemanticTokenTypes.variable
50
40
  });
51
41
  }
52
- if (ast.isElementKindExpression(node) || ast.isElementTagExpression(node)) {
53
- keyword("element");
54
- if (ast.isElementKindExpression(node)) {
55
- keyword("kind");
56
- acceptor({
57
- node,
58
- property: "kind",
59
- type: SemanticTokenTypes.type,
60
- modifier: [SemanticTokenModifiers.definition]
61
- });
62
- }
63
- if (ast.isElementTagExpression(node)) {
64
- keyword("tag");
65
- acceptor({
66
- node,
67
- property: "tag",
68
- type: SemanticTokenTypes.type,
69
- modifier: [SemanticTokenModifiers.definition]
70
- });
71
- }
72
- }
73
- if (ast.isRelation(node)) {
74
- if ("title" in node) {
75
- acceptor({
76
- node,
77
- property: "title",
78
- type: SemanticTokenTypes.string
79
- });
80
- }
81
- }
82
- if (ast.isElementKind(node)) {
42
+ if (ast.isElementKindExpression(node)) {
83
43
  acceptor({
84
44
  node,
85
- property: "name",
45
+ property: "kind",
46
+ type: SemanticTokenTypes.type,
47
+ modifier: [SemanticTokenModifiers.definition]
48
+ });
49
+ }
50
+ if (ast.isElementTagExpression(node)) {
51
+ acceptor({
52
+ node,
53
+ property: "tag",
54
+ type: SemanticTokenTypes.type,
55
+ modifier: [SemanticTokenModifiers.definition]
56
+ });
57
+ }
58
+ if (ast.isSpecificationElementKind(node)) {
59
+ acceptor({
60
+ node,
61
+ property: "kind",
86
62
  type: SemanticTokenTypes.type,
87
63
  modifier: [SemanticTokenModifiers.definition]
88
64
  });
@@ -103,20 +79,15 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
103
79
  modifier: [SemanticTokenModifiers.definition]
104
80
  });
105
81
  }
106
- if (ast.isRelationshipKind(node)) {
82
+ if (ast.isSpecificationRelationshipKind(node)) {
107
83
  acceptor({
108
84
  node,
109
- property: "name",
85
+ property: "kind",
110
86
  type: SemanticTokenTypes.type,
111
87
  modifier: [SemanticTokenModifiers.definition]
112
88
  });
113
89
  }
114
90
  if (ast.isColorProperty(node) || ast.isShapeProperty(node) || ast.isArrowProperty(node) || ast.isLineProperty(node)) {
115
- acceptor({
116
- node,
117
- property: "key",
118
- type: SemanticTokenTypes.keyword
119
- });
120
91
  acceptor({
121
92
  node,
122
93
  property: "value",
@@ -124,11 +95,6 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
124
95
  });
125
96
  }
126
97
  if (ast.isLinkProperty(node) || ast.isIconProperty(node)) {
127
- acceptor({
128
- node,
129
- property: "key",
130
- type: SemanticTokenTypes.keyword
131
- });
132
98
  acceptor({
133
99
  node,
134
100
  property: "value",
@@ -2,15 +2,15 @@ import { AsFqn, nonexhaustive } from "@likec4/core";
2
2
  import { MultiMap } from "langium";
3
3
  import { isEmpty, isNil } from "remeda";
4
4
  import { ElementOps, ast } from "../ast.js";
5
- import { fqnElementRef } from "../elementRef.js";
5
+ import { getFqnElementRef } from "../elementRef.js";
6
6
  export function computeDocumentFqn(document, services) {
7
7
  const c4fqns = document.c4fqns = new MultiMap();
8
- const { model } = document.parseResult.value;
9
- if (!model?.elements) {
8
+ const elements = document.parseResult.value.models.flatMap((m) => m.elements);
9
+ if (elements.length === 0) {
10
10
  return;
11
11
  }
12
12
  const locator = services.workspace.AstNodeLocator;
13
- const traverseStack = model.elements.map((el) => [el, null]);
13
+ const traverseStack = elements.map((el) => [el, null]);
14
14
  let pair;
15
15
  while (pair = traverseStack.shift()) {
16
16
  const [el, parent] = pair;
@@ -19,7 +19,7 @@ export function computeDocumentFqn(document, services) {
19
19
  }
20
20
  if (ast.isExtendElement(el)) {
21
21
  if (!isNil(el.body) && !isEmpty(el.body.elements)) {
22
- const fqn = fqnElementRef(el.element);
22
+ const fqn = getFqnElementRef(el.element);
23
23
  el.body.elements.forEach((child) => traverseStack.push([child, fqn]));
24
24
  }
25
25
  continue;
@@ -15,9 +15,10 @@ export interface FqnIndexEntry {
15
15
  path: string;
16
16
  }
17
17
  export declare class FqnIndex {
18
+ private services;
18
19
  protected langiumDocuments: LangiumDocuments;
19
20
  constructor(services: LikeC4Services);
20
- private documents;
21
+ get documents(): Stream<FqnIndexedDocument>;
21
22
  private entries;
22
23
  getFqn(el: ast.Element): Fqn | null;
23
24
  byFqn(fqn: Fqn): Stream<FqnIndexEntry>;
@@ -1,5 +1,5 @@
1
1
  import { nameFromFqn, parentFqn } from "@likec4/core";
2
- import { DONE_RESULT, DocumentState, MultiMap, StreamImpl, stream } from "langium";
2
+ import { DONE_RESULT, DocumentState, MultiMap, StreamImpl, getDocument, stream } from "langium";
3
3
  import { isNil } from "remeda";
4
4
  import { ElementOps, isLikeC4LangiumDocument } from "../ast.js";
5
5
  import { logError, logger } from "../logger.js";
@@ -9,40 +9,21 @@ export function isFqnIndexedDocument(doc) {
9
9
  return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !isNil(doc.c4fqns);
10
10
  }
11
11
  export class FqnIndex {
12
- langiumDocuments;
13
12
  constructor(services) {
13
+ this.services = services;
14
14
  this.langiumDocuments = services.shared.workspace.LangiumDocuments;
15
- services.shared.workspace.DocumentBuilder.onUpdate((changed, deleted) => {
16
- const message = [`[FqnIndex] onUpdate`];
17
- if (changed.length > 0) {
18
- message.push(` changed:`);
19
- changed.forEach((u) => message.push(` - ${u}`));
20
- }
21
- if (deleted.length > 0) {
22
- message.push(` deleted:`);
23
- deleted.forEach((u) => message.push(` - ${u}`));
24
- }
25
- logger.debug(message.join("\n"));
26
- for (const uri of changed) {
27
- if (this.langiumDocuments.hasDocument(uri)) {
28
- const doc = this.langiumDocuments.getOrCreateDocument(uri);
29
- if (isLikeC4LangiumDocument(doc)) {
30
- delete doc.c4fqns;
31
- delete doc.c4Elements;
32
- delete doc.c4Specification;
33
- delete doc.c4Relations;
34
- delete doc.c4Views;
35
- }
36
- }
37
- }
38
- });
39
15
  services.shared.workspace.DocumentBuilder.onBuildPhase(
40
16
  DocumentState.IndexedContent,
41
- (docs, _cancelToken) => {
17
+ async (docs, _cancelToken) => {
42
18
  logger.debug(`[FqnIndex] onIndexedContent ${docs.length}:
43
19
  ` + printDocs(docs));
44
20
  for (const doc of docs) {
45
21
  if (isLikeC4LangiumDocument(doc)) {
22
+ delete doc.c4fqns;
23
+ delete doc.c4Elements;
24
+ delete doc.c4Specification;
25
+ delete doc.c4Relations;
26
+ delete doc.c4Views;
46
27
  try {
47
28
  computeDocumentFqn(doc, services);
48
29
  } catch (e) {
@@ -50,14 +31,17 @@ export class FqnIndex {
50
31
  }
51
32
  }
52
33
  }
34
+ return Promise.resolve();
53
35
  }
54
36
  );
37
+ logger.debug(`[FqnIndex] Created`);
55
38
  }
56
- documents() {
39
+ langiumDocuments;
40
+ get documents() {
57
41
  return this.langiumDocuments.all.filter(isFqnIndexedDocument);
58
42
  }
59
43
  entries(filterByFqn = () => true) {
60
- return this.documents().flatMap(
44
+ return this.documents.flatMap(
61
45
  (doc) => doc.c4fqns.entries().filter(([fqn]) => filterByFqn(fqn)).map(([fqn, entry]) => {
62
46
  const el = entry.el.deref();
63
47
  if (el) {
@@ -68,10 +52,21 @@ export class FqnIndex {
68
52
  );
69
53
  }
70
54
  getFqn(el) {
71
- return el.fqn ?? ElementOps.readId(el) ?? null;
55
+ let fqn = ElementOps.readId(el) ?? null;
56
+ if (fqn) {
57
+ const doc = getDocument(el);
58
+ if (isFqnIndexedDocument(doc) && doc.c4fqns.has(fqn)) {
59
+ return fqn;
60
+ }
61
+ const path = this.services.workspace.AstNodeLocator.getAstNodePath(el);
62
+ logError(`Clean cached FQN ${fqn} at ${path}`);
63
+ ElementOps.writeId(el, null);
64
+ fqn = null;
65
+ }
66
+ return fqn;
72
67
  }
73
68
  byFqn(fqn) {
74
- return this.documents().flatMap((doc) => {
69
+ return this.documents.flatMap((doc) => {
75
70
  return doc.c4fqns.get(fqn).flatMap((entry) => {
76
71
  const el = entry.el.deref();
77
72
  if (el) {
@@ -4,10 +4,7 @@ import {
4
4
  parentFqn
5
5
  } from "@likec4/core";
6
6
  import { LikeC4ModelGraph, computeView } from "@likec4/graph";
7
- import {
8
- DocumentState,
9
- interruptAndCheck
10
- } from "langium";
7
+ import { DocumentState } from "langium";
11
8
  import * as R from "remeda";
12
9
  import { Disposable } from "vscode-languageserver";
13
10
  import { isValidLikeC4LangiumDocument } from "../ast.js";
@@ -161,16 +158,24 @@ export class LikeC4ModelBuilder {
161
158
  this.services = services;
162
159
  this.langiumDocuments = services.shared.workspace.LangiumDocuments;
163
160
  const parser = services.likec4.ModelParser;
161
+ services.shared.workspace.DocumentBuilder.onUpdate((changed, deleted) => {
162
+ if (deleted.length > 0) {
163
+ this.notifyListeners(deleted);
164
+ }
165
+ });
164
166
  services.shared.workspace.DocumentBuilder.onBuildPhase(
165
167
  DocumentState.Validated,
166
- async (docs, cancelToken) => {
168
+ async (docs, _cancelToken) => {
169
+ logger.debug(`[ModelBuilder] onValidated (${docs.length} docs)
170
+ ${printDocs(docs)}`);
167
171
  const parsed = parser.parse(docs).map((d) => d.uri);
168
- await interruptAndCheck(cancelToken);
169
172
  if (parsed.length > 0) {
170
173
  this.notifyListeners(parsed);
171
174
  }
175
+ return Promise.resolve();
172
176
  }
173
177
  );
178
+ logger.debug(`[ModelBuilder] Created`);
174
179
  }
175
180
  langiumDocuments;
176
181
  listeners = [];
@@ -200,11 +205,15 @@ ${printDocs(docs)}`);
200
205
  return null;
201
206
  }
202
207
  const index = new LikeC4ModelGraph(model);
203
- const views = R.pipe(
204
- R.values(model.views),
205
- R.map((view) => computeView(view, index).view),
206
- R.compact
207
- );
208
+ const views = [];
209
+ for (const view of R.values(model.views)) {
210
+ const result = computeView(view, index);
211
+ if (!result.isSuccess) {
212
+ logWarnError(result.error);
213
+ continue;
214
+ }
215
+ views.push(result.view);
216
+ }
208
217
  assignNavigateTo(views);
209
218
  return {
210
219
  elements: model.elements,
@@ -1,5 +1,4 @@
1
- import { InvalidModelError } from "@likec4/core";
2
- import { findNodeForProperty, getDocument } from "langium";
1
+ import { findNodeForKeyword, findNodeForProperty, getDocument } from "langium";
3
2
  import { ast, isParsedLikeC4LangiumDocument } from "../ast.js";
4
3
  export class LikeC4ModelLocator {
5
4
  constructor(services) {
@@ -61,20 +60,14 @@ export class LikeC4ModelLocator {
61
60
  };
62
61
  }
63
62
  }
64
- if (node.arr == null) {
65
- throw new InvalidModelError("Relation.arr is not defined, but should be");
66
- }
67
- const targetNode = findNodeForProperty(node.$cstNode, "arr");
68
- if (!targetNode) {
69
- return null;
70
- }
71
- return {
63
+ const targetNode = (node.kind ? findNodeForProperty(node.$cstNode, "kind") : findNodeForKeyword(node.$cstNode, "->")) ?? findNodeForProperty(node.$cstNode, "target");
64
+ return targetNode ? {
72
65
  uri: doc.uri.toString(),
73
66
  range: {
74
67
  start: targetNode.range.start,
75
68
  end: targetNode.range.end
76
69
  }
77
- };
70
+ } : null;
78
71
  }
79
72
  return null;
80
73
  }
@@ -1,6 +1,6 @@
1
1
  import { type c4 } from '@likec4/core';
2
2
  import type { LangiumDocument } from 'langium';
3
- import type { LikeC4LangiumDocument } from '../ast';
3
+ import type { LikeC4LangiumDocument, ParsedLikeC4LangiumDocument } from '../ast';
4
4
  import { ast } from '../ast';
5
5
  import type { LikeC4Services } from '../module';
6
6
  export type ModelParsedListener = () => void;
@@ -8,10 +8,13 @@ export declare class LikeC4ModelParser {
8
8
  private services;
9
9
  private fqnIndex;
10
10
  constructor(services: LikeC4Services);
11
- parse(doc: LangiumDocument | LangiumDocument[]): LikeC4LangiumDocument[];
12
- protected parseLikeC4Document(doc: LikeC4LangiumDocument): void;
11
+ parse(doc: LangiumDocument | LangiumDocument[]): ParsedLikeC4LangiumDocument[];
12
+ protected parseLikeC4Document(_doc: LikeC4LangiumDocument): ParsedLikeC4LangiumDocument;
13
+ private parseSpecification;
14
+ private parseModel;
13
15
  private parseElement;
14
16
  private parseRelation;
17
+ private parseViews;
15
18
  private parseElementExpression;
16
19
  private parseExpression;
17
20
  private parseViewRule;
@@ -14,44 +14,47 @@ import {
14
14
  toElementStyleExcludeDefaults,
15
15
  toRelationshipStyleExcludeDefaults
16
16
  } from "../ast.js";
17
- import { elementRef, fqnElementRef } from "../elementRef.js";
17
+ import { elementRef, getFqnElementRef } from "../elementRef.js";
18
18
  import { logError, logWarnError, logger } from "../logger.js";
19
- import { printDocs } from "../utils.js";
20
19
  export class LikeC4ModelParser {
21
20
  constructor(services) {
22
21
  this.services = services;
23
22
  this.fqnIndex = services.likec4.FqnIndex;
23
+ logger.debug(`[ModelParser] Created`);
24
24
  }
25
25
  fqnIndex;
26
26
  parse(doc) {
27
27
  const docs = Array.isArray(doc) ? doc : [doc];
28
- logger.debug(`[ModelParser] onValidated (${docs.length} docs)
29
- ${printDocs(docs)}`);
30
28
  const result = [];
31
29
  for (const doc2 of docs) {
32
30
  if (!isLikeC4LangiumDocument(doc2)) {
33
31
  continue;
34
32
  }
35
33
  try {
36
- this.parseLikeC4Document(doc2);
37
- result.push(doc2);
34
+ result.push(this.parseLikeC4Document(doc2));
38
35
  } catch (cause) {
39
36
  logError(new InvalidModelError(`Error parsing document ${doc2.uri.toString()}`, { cause }));
40
37
  }
41
38
  }
42
39
  return result;
43
40
  }
44
- parseLikeC4Document(doc) {
45
- const { elements, relations, views, specification } = cleanParsedModel(doc);
46
- const specs = doc.parseResult.value.specification?.elements;
47
- if (specs) {
48
- for (const { kind, style } of specs) {
49
- if (kind.name in specification.kinds) {
50
- logger.warn(`Duplicate specification for kind ${kind.name}`);
41
+ parseLikeC4Document(_doc) {
42
+ const doc = cleanParsedModel(_doc);
43
+ this.parseSpecification(doc);
44
+ this.parseModel(doc);
45
+ this.parseViews(doc);
46
+ return doc;
47
+ }
48
+ parseSpecification({ parseResult, c4Specification }) {
49
+ const element_specs = parseResult.value.specifications.flatMap((s) => s.elements);
50
+ if (element_specs.length > 0) {
51
+ for (const { kind, style } of element_specs) {
52
+ if (kind.name in c4Specification.kinds) {
53
+ logger.warn(`Duplicate specification for element kind ${kind.name}`);
51
54
  continue;
52
55
  }
53
56
  try {
54
- specification.kinds[kind.name] = toElementStyleExcludeDefaults(
57
+ c4Specification.kinds[kind.name] = toElementStyleExcludeDefaults(
55
58
  style?.props
56
59
  );
57
60
  } catch (e) {
@@ -59,24 +62,26 @@ ${printDocs(docs)}`);
59
62
  }
60
63
  }
61
64
  }
62
- const relations_specs = doc.parseResult.value.specification?.relationships;
63
- if (relations_specs) {
65
+ const relations_specs = parseResult.value.specifications.flatMap((s) => s.relationships);
66
+ if (relations_specs.length > 0) {
64
67
  for (const { kind, props } of relations_specs) {
65
- if (kind.name in specification.relationships) {
66
- logger.warn(`Duplicate specification for kind ${kind.name}`);
68
+ if (kind.name in c4Specification.relationships) {
69
+ logger.warn(`Duplicate specification for relationship kind ${kind.name}`);
67
70
  continue;
68
71
  }
69
72
  try {
70
- specification.relationships[kind.name] = toRelationshipStyleExcludeDefaults(props);
73
+ c4Specification.relationships[kind.name] = toRelationshipStyleExcludeDefaults(props);
71
74
  } catch (e) {
72
75
  logWarnError(e);
73
76
  }
74
77
  }
75
78
  }
79
+ }
80
+ parseModel(doc) {
76
81
  for (const el of streamModel(doc)) {
77
82
  if (ast.isElement(el)) {
78
83
  try {
79
- elements.push(this.parseElement(el));
84
+ doc.c4Elements.push(this.parseElement(el));
80
85
  } catch (e) {
81
86
  logWarnError(e);
82
87
  }
@@ -84,7 +89,7 @@ ${printDocs(docs)}`);
84
89
  }
85
90
  if (ast.isRelation(el)) {
86
91
  try {
87
- relations.push(this.parseRelation(el));
92
+ doc.c4Relations.push(this.parseRelation(el));
88
93
  } catch (e) {
89
94
  logWarnError(e);
90
95
  }
@@ -92,18 +97,6 @@ ${printDocs(docs)}`);
92
97
  }
93
98
  nonexhaustive(el);
94
99
  }
95
- const docviews = doc.parseResult.value.views?.views;
96
- if (docviews) {
97
- for (const view of docviews) {
98
- try {
99
- const v = this.parseElementView(view);
100
- ElementViewOps.writeId(view, v.id);
101
- views.push(v);
102
- } catch (e) {
103
- logWarnError(e);
104
- }
105
- }
106
- }
107
100
  }
108
101
  parseElement(astNode) {
109
102
  const id = this.resolveFqn(astNode);
@@ -137,10 +130,10 @@ ${printDocs(docs)}`);
137
130
  const coupling = resolveRelationPoints(astNode);
138
131
  const target = this.resolveFqn(coupling.target);
139
132
  const source = this.resolveFqn(coupling.source);
140
- const tags = this.convertTags(astNode.body);
133
+ const tags = this.convertTags(astNode);
141
134
  const kind = astNode.kind?.ref?.name;
142
135
  const astPath = this.getAstNodePath(astNode);
143
- const title = astNode.title ?? astNode.body?.props.find((p) => p.key === "title")?.value ?? "";
136
+ const title = astNode.title ?? astNode.props.find((p) => p.key === "title")?.value ?? "";
144
137
  const id = objectHash({
145
138
  astPath,
146
139
  source,
@@ -156,6 +149,17 @@ ${printDocs(docs)}`);
156
149
  ...tags && { tags }
157
150
  };
158
151
  }
152
+ parseViews(doc) {
153
+ const views = doc.parseResult.value.views.flatMap((v) => v.views);
154
+ for (const view of views) {
155
+ try {
156
+ const v = this.parseElementView(view);
157
+ doc.c4Views.push(v);
158
+ } catch (e) {
159
+ logWarnError(e);
160
+ }
161
+ }
162
+ }
159
163
  parseElementExpression(astNode) {
160
164
  if (ast.isWildcardExpression(astNode)) {
161
165
  return {
@@ -275,6 +279,7 @@ ${printDocs(docs)}`);
275
279
  }
276
280
  })
277
281
  };
282
+ ElementViewOps.writeId(astNode, basic.id);
278
283
  if ("viewOf" in astNode) {
279
284
  const viewOfEl = elementRef(astNode.viewOf);
280
285
  const viewOf = viewOfEl && this.resolveFqn(viewOfEl);
@@ -296,7 +301,7 @@ ${printDocs(docs)}`);
296
301
  }
297
302
  resolveFqn(node) {
298
303
  if (ast.isExtendElement(node)) {
299
- return fqnElementRef(node.element);
304
+ return getFqnElementRef(node.element);
300
305
  }
301
306
  const fqn = this.fqnIndex.getFqn(node);
302
307
  invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
package/dist/module.js CHANGED
@@ -16,6 +16,7 @@ import { Rpc } from "./Rpc.js";
16
16
  import { registerValidationChecks } from "./validation/index.js";
17
17
  import { logger } from "./logger.js";
18
18
  import { serializeError } from "@likec4/core";
19
+ import { NodeKindProvider } from "./shared/NodeKindProvider.js";
19
20
  function bind(Type) {
20
21
  return (services) => new Type(services);
21
22
  }
@@ -41,6 +42,9 @@ export const LikeC4Module = {
41
42
  }
42
43
  };
43
44
  const LikeC4SharedModule = {
45
+ lsp: {
46
+ NodeKindProvider: () => new NodeKindProvider()
47
+ }
44
48
  // workspace: {
45
49
  // WorkspaceManager: services => new LikeC4WorkspaceManager(services)
46
50
  // }
@@ -13,9 +13,6 @@ export declare const computeView: RequestType<{
13
13
  }, {
14
14
  view: ComputedView | null;
15
15
  }, void>;
16
- export declare const rebuild: RequestType0<{
17
- docs: DocumentUri[];
18
- }, void>;
19
16
  interface BuildDocumentsParams {
20
17
  docs: DocumentUri[];
21
18
  }
package/dist/protocol.js CHANGED
@@ -7,8 +7,5 @@ export const fetchModel = new RequestType0("likec4/fetchModel");
7
7
  export const computeView = new RequestType(
8
8
  "likec4/computeView"
9
9
  );
10
- export const rebuild = new RequestType0("likec4/rebuildModel");
11
- export const buildDocuments = new RequestType(
12
- "likec4/buildDocuments"
13
- );
10
+ export const buildDocuments = new RequestType("likec4/build");
14
11
  export const locate = new RequestType("likec4/locate");