@likec4/language-server 0.37.1 → 0.41.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 (60) hide show
  1. package/contrib/likec4.monarch.ts +5 -5
  2. package/contrib/likec4.tmLanguage.json +1 -1
  3. package/dist/Rpc.d.ts +7 -0
  4. package/dist/Rpc.js +130 -0
  5. package/dist/ast.d.ts +20 -0
  6. package/dist/ast.js +169 -141
  7. package/dist/elementRef.js +31 -44
  8. package/dist/generated/ast.d.ts +48 -7
  9. package/dist/generated/ast.js +344 -315
  10. package/dist/generated/grammar.js +2 -3177
  11. package/dist/generated/module.js +13 -18
  12. package/dist/index.js +2 -3
  13. package/dist/logger.js +39 -42
  14. package/dist/lsp/CodeLensProvider.js +28 -32
  15. package/dist/lsp/DocumentLinkProvider.js +26 -33
  16. package/dist/lsp/DocumentSymbolProvider.js +165 -167
  17. package/dist/lsp/HoverProvider.js +35 -48
  18. package/dist/lsp/SemanticTokenProvider.js +160 -201
  19. package/dist/lsp/index.js +5 -6
  20. package/dist/model/fqn-computation.js +39 -40
  21. package/dist/model/fqn-index.js +117 -141
  22. package/dist/model/index.js +5 -6
  23. package/dist/model/model-builder.d.ts +10 -5
  24. package/dist/model/model-builder.js +247 -176
  25. package/dist/model/model-locator.d.ts +1 -1
  26. package/dist/model/model-locator.js +102 -100
  27. package/dist/model/model-parser.d.ts +2 -6
  28. package/dist/model/model-parser.js +284 -286
  29. package/dist/module.d.ts +4 -1
  30. package/dist/module.js +69 -60
  31. package/dist/protocol.d.ts +16 -19
  32. package/dist/protocol.js +14 -22
  33. package/dist/references/index.js +2 -3
  34. package/dist/references/scope-computation.js +72 -69
  35. package/dist/references/scope-provider.js +126 -116
  36. package/dist/shared/WorkspaceManager.d.ts +2 -3
  37. package/dist/shared/WorkspaceManager.js +13 -16
  38. package/dist/shared/index.js +1 -2
  39. package/dist/test/index.js +1 -2
  40. package/dist/test/testServices.js +73 -61
  41. package/dist/utils.d.ts +1 -0
  42. package/dist/utils.js +4 -3
  43. package/dist/validation/element.d.ts +1 -0
  44. package/dist/validation/element.js +31 -38
  45. package/dist/validation/index.js +37 -46
  46. package/dist/validation/relation.js +46 -46
  47. package/dist/validation/specification.d.ts +1 -0
  48. package/dist/validation/specification.js +33 -30
  49. package/dist/validation/view.js +16 -22
  50. package/dist/view-utils/assignNavigateTo.d.ts +3 -0
  51. package/dist/view-utils/assignNavigateTo.js +20 -0
  52. package/dist/view-utils/index.d.ts +4 -0
  53. package/dist/view-utils/index.js +3 -0
  54. package/dist/view-utils/resolve-extended-views.d.ts +7 -0
  55. package/dist/view-utils/resolve-extended-views.js +41 -0
  56. package/dist/view-utils/resolve-relative-paths.d.ts +3 -0
  57. package/dist/view-utils/resolve-relative-paths.js +76 -0
  58. package/package.json +33 -18
  59. package/dist/registerProtocolHandlers.d.ts +0 -3
  60. package/dist/registerProtocolHandlers.js +0 -112
@@ -1,147 +1,123 @@
1
- import { nameFromFqn, parentFqn } from '@likec4/core';
2
- import { DONE_RESULT, DocumentState, MultiMap, StreamImpl, stream } from 'langium';
3
- import { isNil } from 'remeda';
4
- import { ElementOps, isLikeC4LangiumDocument } from '../ast';
5
- import { logError, logger } from '../logger';
6
- import { printDocs } from '../utils';
7
- import { computeDocumentFqn } from './fqn-computation';
1
+ import { nameFromFqn, parentFqn } from "@likec4/core";
2
+ import { DONE_RESULT, DocumentState, MultiMap, StreamImpl, stream } from "langium";
3
+ import { isNil } from "remeda";
4
+ import { ElementOps, isLikeC4LangiumDocument } from "../ast.js";
5
+ import { logError, logger } from "../logger.js";
6
+ import { printDocs } from "../utils.js";
7
+ import { computeDocumentFqn } from "./fqn-computation.js";
8
8
  export function isFqnIndexedDocument(doc) {
9
- return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !isNil(doc.c4fqns);
9
+ return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !isNil(doc.c4fqns);
10
10
  }
11
11
  export class FqnIndex {
12
- langiumDocuments;
13
- constructor(services) {
14
- this.langiumDocuments = services.shared.workspace.LangiumDocuments;
15
- // services.shared.workspace.DocumentBuilder.onUpdate((changed,deleted) => {
16
- // logger.debug('') // empty line to separate batches
17
- // logger.debug(`[DocumentBuilder.onUpdate]`)
18
- // if (changed.length > 0) {
19
- // logger.debug(` changed:\n` + changed.map(u => ' - ' + Utils.basename(u)).join('\n'))
20
- // }
21
- // if (deleted.length > 0) {
22
- // logger.debug(` deleted:\n` + deleted.map(u => ' - ' + Utils.basename(u)).join('\n'))
23
- // }
24
- // })
25
- services.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.Changed, (docs, _cancelToken) => {
26
- logger.debug(`[FqnIndex] onChanged (${docs.length} docs):\n` + printDocs(docs));
27
- for (const doc of docs) {
28
- if (isLikeC4LangiumDocument(doc)) {
29
- delete doc.c4fqns;
30
- delete doc.c4Elements;
31
- delete doc.c4Specification;
32
- delete doc.c4Relations;
33
- delete doc.c4Views;
34
- }
12
+ langiumDocuments;
13
+ constructor(services) {
14
+ this.langiumDocuments = services.shared.workspace.LangiumDocuments;
15
+ services.shared.workspace.DocumentBuilder.onBuildPhase(
16
+ DocumentState.Changed,
17
+ (docs, _cancelToken) => {
18
+ logger.debug(`[FqnIndex] onChanged (${docs.length} docs):
19
+ ` + printDocs(docs));
20
+ for (const doc of docs) {
21
+ if (isLikeC4LangiumDocument(doc)) {
22
+ delete doc.c4fqns;
23
+ delete doc.c4Elements;
24
+ delete doc.c4Specification;
25
+ delete doc.c4Relations;
26
+ delete doc.c4Views;
27
+ }
28
+ }
29
+ }
30
+ );
31
+ services.shared.workspace.DocumentBuilder.onBuildPhase(
32
+ DocumentState.IndexedContent,
33
+ (docs, _cancelToken) => {
34
+ logger.debug(`[FqnIndex] onIndexedContent ${docs.length}:
35
+ ` + printDocs(docs));
36
+ for (const doc of docs) {
37
+ if (isLikeC4LangiumDocument(doc)) {
38
+ try {
39
+ computeDocumentFqn(doc, services);
40
+ } catch (e) {
41
+ logError(e);
35
42
  }
43
+ }
44
+ }
45
+ }
46
+ );
47
+ }
48
+ documents() {
49
+ return this.langiumDocuments.all.filter(isFqnIndexedDocument);
50
+ }
51
+ entries(filterByFqn = () => true) {
52
+ return this.documents().flatMap(
53
+ (doc) => doc.c4fqns.entries().filter(([fqn]) => filterByFqn(fqn)).map(([fqn, entry]) => {
54
+ const el = entry.el.deref();
55
+ if (el) {
56
+ return { ...entry, fqn, el, doc };
57
+ }
58
+ return null;
59
+ }).nonNullable()
60
+ );
61
+ }
62
+ getFqn(el) {
63
+ return el.fqn ?? ElementOps.readId(el) ?? null;
64
+ }
65
+ byFqn(fqn) {
66
+ return this.documents().flatMap((doc) => {
67
+ return doc.c4fqns.get(fqn).flatMap((entry) => {
68
+ const el = entry.el.deref();
69
+ if (el) {
70
+ return [{ fqn, el, doc, path: entry.path, name: entry.name }];
71
+ }
72
+ return [];
73
+ });
74
+ });
75
+ }
76
+ directChildrenOf(parent) {
77
+ return stream([parent]).flatMap((_parent) => {
78
+ const children = this.entries((fqn) => parentFqn(fqn) === _parent).map((entry) => [entry.name, entry]).toArray();
79
+ if (children.length === 0) {
80
+ return [];
81
+ }
82
+ return new MultiMap(children).entriesGroupedByKey().flatMap(([_name, descrs]) => descrs.length === 1 ? descrs : []).iterator();
83
+ });
84
+ }
85
+ /**
86
+ * Returns descedant elements with unique names in the scope
87
+ */
88
+ uniqueDescedants(parent) {
89
+ return new StreamImpl(
90
+ () => {
91
+ const prefix = `${parent}.`;
92
+ const childrenNames = /* @__PURE__ */ new Set();
93
+ const descedants = [];
94
+ const nested = new MultiMap();
95
+ this.entries((f) => f.startsWith(prefix)).forEach((e) => {
96
+ const name = nameFromFqn(e.fqn);
97
+ const entry = { ...e, name };
98
+ if (parentFqn(e.fqn) === parent) {
99
+ childrenNames.add(name);
100
+ nested.add(name, entry);
101
+ } else {
102
+ descedants.push(entry);
103
+ }
36
104
  });
37
- services.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, (docs, _cancelToken) => {
38
- logger.debug(`[FqnIndex] onIndexedContent ${docs.length}:\n` + printDocs(docs));
39
- for (const doc of docs) {
40
- if (isLikeC4LangiumDocument(doc)) {
41
- try {
42
- computeDocumentFqn(doc, services);
43
- }
44
- catch (e) {
45
- logError(e);
46
- }
47
- }
48
- }
49
- });
50
- }
51
- documents() {
52
- return this.langiumDocuments.all.filter(isFqnIndexedDocument);
53
- }
54
- entries(filterByFqn = () => true) {
55
- return this.documents().flatMap(doc => doc.c4fqns
56
- .entries()
57
- .filter(([fqn]) => filterByFqn(fqn))
58
- .map(([fqn, entry]) => {
59
- const el = entry.el.deref();
60
- if (el) {
61
- return { ...entry, fqn, el, doc };
62
- }
63
- return null;
64
- })
65
- .nonNullable());
66
- }
67
- getFqn(el) {
68
- return el.fqn ?? ElementOps.readId(el) ?? null;
69
- // if (fqn) {
70
- // const doc = getDocument(el)
71
- // if (isFqnIndexedDocument(doc) && doc.c4fqns.has(fqn)) {
72
- // return fqn
73
- // }
74
- // const path = this.services.workspace.AstNodeLocator.getAstNodePath(el)
75
- // logError(`Clean cached FQN ${fqn} at ${path}`)
76
- // ElementOps.writeId(el, null)
77
- // fqn = null
78
- // }
79
- // return fqn
80
- }
81
- byFqn(fqn) {
82
- return this.documents().flatMap(doc => {
83
- return doc.c4fqns.get(fqn).flatMap(entry => {
84
- const el = entry.el.deref();
85
- if (el) {
86
- return [{ fqn, el, doc, path: entry.path, name: entry.name }];
87
- }
88
- return [];
89
- });
90
- });
91
- }
92
- directChildrenOf(parent) {
93
- return stream([parent]).flatMap(_parent => {
94
- const children = this.entries(fqn => parentFqn(fqn) === _parent)
95
- .map((entry) => [entry.name, entry])
96
- .toArray();
97
- if (children.length === 0) {
98
- return [];
99
- }
100
- return new MultiMap(children)
101
- .entriesGroupedByKey()
102
- .flatMap(([_name, descrs]) => (descrs.length === 1 ? descrs : []))
103
- .iterator();
104
- });
105
- }
106
- /**
107
- * Returns descedant elements with unique names in the scope
108
- */
109
- uniqueDescedants(parent) {
110
- return new StreamImpl(() => {
111
- const prefix = `${parent}.`;
112
- const childrenNames = new Set();
113
- const descedants = [];
114
- const nested = new MultiMap();
115
- this.entries(f => f.startsWith(prefix)).forEach(e => {
116
- const name = nameFromFqn(e.fqn);
117
- const entry = { ...e, name };
118
- // To keep direct children always
119
- if (parentFqn(e.fqn) === parent) {
120
- childrenNames.add(name);
121
- nested.add(name, entry);
122
- }
123
- else {
124
- descedants.push(entry);
125
- }
126
- });
127
- if (nested.size + descedants.length === 0) {
128
- return null;
129
- }
130
- for (const descedant of descedants) {
131
- if (!childrenNames.has(descedant.name)) {
132
- nested.add(descedant.name, descedant);
133
- }
134
- }
135
- return nested
136
- .entriesGroupedByKey()
137
- .flatMap(([_name, descrs]) => (descrs.length === 1 ? descrs : []))
138
- .iterator();
139
- }, iterator => {
140
- if (iterator) {
141
- return iterator.next();
142
- }
143
- return DONE_RESULT;
144
- });
145
- }
105
+ if (nested.size + descedants.length === 0) {
106
+ return null;
107
+ }
108
+ for (const descedant of descedants) {
109
+ if (!childrenNames.has(descedant.name)) {
110
+ nested.add(descedant.name, descedant);
111
+ }
112
+ }
113
+ return nested.entriesGroupedByKey().flatMap(([_name, descrs]) => descrs.length === 1 ? descrs : []).iterator();
114
+ },
115
+ (iterator) => {
116
+ if (iterator) {
117
+ return iterator.next();
118
+ }
119
+ return DONE_RESULT;
120
+ }
121
+ );
122
+ }
146
123
  }
147
- //# sourceMappingURL=fqn-index.js.map
@@ -1,6 +1,5 @@
1
- export * from './fqn-computation';
2
- export * from './fqn-index';
3
- export * from './model-builder';
4
- export * from './model-locator';
5
- export * from './model-parser';
6
- //# sourceMappingURL=index.js.map
1
+ export * from "./fqn-computation.js";
2
+ export * from "./fqn-index.js";
3
+ export * from "./model-builder.js";
4
+ export * from "./model-locator.js";
5
+ export * from "./model-parser.js";
@@ -1,16 +1,21 @@
1
1
  import { type ViewID, type c4 } from '@likec4/core';
2
+ import type { URI } from 'langium';
3
+ import { Disposable } from 'vscode-languageserver';
2
4
  import type { LikeC4Services } from '../module';
5
+ type ModelParsedListener = (docs: URI[]) => void;
3
6
  export declare class LikeC4ModelBuilder {
4
7
  private services;
5
8
  private langiumDocuments;
6
- private readonly cachedModel;
9
+ private workspaceManager;
10
+ private listeners;
7
11
  constructor(services: LikeC4Services);
8
- private cleanCache;
9
- private documents;
12
+ get workspaceUri(): string | null;
10
13
  buildRawModel(): c4.LikeC4RawModel | null;
11
14
  buildModel(): c4.LikeC4Model | null;
12
15
  computeView(viewId: ViewID): c4.ComputedView | null;
13
- private scheduledCb;
14
- private notifyClient;
16
+ onModelParsed(callback: ModelParsedListener): Disposable;
17
+ private documents;
18
+ private notifyListeners;
15
19
  }
20
+ export {};
16
21
  //# sourceMappingURL=model-builder.d.ts.map