@likec4/language-server 0.33.1 → 0.34.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 (49) hide show
  1. package/contrib/likec4.monarch.ts +17 -3
  2. package/dist/ast.d.ts +24 -11
  3. package/dist/ast.js +11 -8
  4. package/dist/elementRef.d.ts +1 -1
  5. package/dist/elementRef.js +2 -3
  6. package/dist/generated/ast.d.ts +29 -10
  7. package/dist/generated/ast.js +20 -1
  8. package/dist/generated/grammar.d.ts +1 -1
  9. package/dist/generated/grammar.js +11 -11
  10. package/dist/generated/module.d.ts +7 -3
  11. package/dist/generated/module.js +3 -3
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/logger.d.ts +6 -4
  15. package/dist/logger.js +34 -6
  16. package/dist/{shared → lsp}/CodeLensProvider.d.ts +3 -3
  17. package/dist/{shared → lsp}/DocumentLinkProvider.d.ts +3 -2
  18. package/dist/{shared → lsp}/DocumentLinkProvider.js +3 -3
  19. package/dist/lsp/DocumentSymbolProvider.js +3 -3
  20. package/dist/lsp/index.d.ts +2 -0
  21. package/dist/lsp/index.js +2 -0
  22. package/dist/model/fqn-computation.js +6 -3
  23. package/dist/model/fqn-index.d.ts +4 -7
  24. package/dist/model/fqn-index.js +36 -21
  25. package/dist/model/index.d.ts +1 -0
  26. package/dist/model/index.js +1 -0
  27. package/dist/model/model-builder.d.ts +1 -18
  28. package/dist/model/model-builder.js +111 -340
  29. package/dist/model/model-locator.js +5 -9
  30. package/dist/model/model-parser.d.ts +27 -0
  31. package/dist/model/model-parser.js +281 -0
  32. package/dist/module.d.ts +2 -1
  33. package/dist/module.js +20 -29
  34. package/dist/protocol.d.ts +8 -16
  35. package/dist/protocol.js +2 -6
  36. package/dist/references/scope-provider.js +2 -3
  37. package/dist/registerProtocolHandlers.js +19 -16
  38. package/dist/shared/index.d.ts +0 -2
  39. package/dist/shared/index.js +0 -2
  40. package/dist/test/testServices.d.ts +2 -2
  41. package/dist/test/testServices.js +16 -10
  42. package/dist/utils.d.ts +2 -2
  43. package/dist/utils.js +2 -7
  44. package/dist/validation/element.d.ts +1 -1
  45. package/dist/validation/element.js +16 -3
  46. package/dist/validation/index.js +26 -0
  47. package/dist/validation/relation.js +3 -10
  48. package/package.json +6 -5
  49. /package/dist/{shared → lsp}/CodeLensProvider.js +0 -0
@@ -0,0 +1,281 @@
1
+ import { InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core';
2
+ import { DocumentState, getDocument, interruptAndCheck } from 'langium';
3
+ import objectHash from 'object-hash';
4
+ import stripIndent from 'strip-indent';
5
+ import { Disposable } from 'vscode-languageserver-protocol';
6
+ import { ElementViewOps, ast, cleanParsedModel, isLikeC4LangiumDocument, resolveRelationPoints, streamModel, toAutoLayout, toElementStyle, toElementStyleExcludeDefaults } from '../ast';
7
+ import { elementRef, strictElementRefFqn } from '../elementRef';
8
+ import { logError, logWarnError, logger } from '../logger';
9
+ import { printDocs } from '../utils';
10
+ export class LikeC4ModelParser {
11
+ services;
12
+ fqnIndex;
13
+ listeners = [];
14
+ constructor(services) {
15
+ this.services = services;
16
+ this.fqnIndex = services.likec4.FqnIndex;
17
+ services.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.Validated, async (docs, cancelToken) => await this.onValidated(docs, cancelToken));
18
+ }
19
+ onParsed(callback) {
20
+ this.listeners.push(callback);
21
+ return Disposable.create(() => {
22
+ const index = this.listeners.indexOf(callback);
23
+ if (index >= 0) {
24
+ this.listeners.splice(index, 1);
25
+ }
26
+ });
27
+ }
28
+ async onValidated(docs, cancelToken) {
29
+ let countOfChangedDocs = 0;
30
+ logger.debug(`[ModelParser] onValidated (${docs.length} docs)\n${printDocs(docs)}`);
31
+ for (const doc of docs) {
32
+ if (!isLikeC4LangiumDocument(doc)) {
33
+ continue;
34
+ }
35
+ countOfChangedDocs++;
36
+ try {
37
+ await this.parseDocument(doc, cancelToken);
38
+ }
39
+ catch (cause) {
40
+ logError(new InvalidModelError(`Error parsing document ${doc.uri.toString()}`, { cause }));
41
+ }
42
+ }
43
+ if (countOfChangedDocs > 0) {
44
+ this.notifyListeners();
45
+ }
46
+ }
47
+ async parseDocument(doc, cancelToken) {
48
+ const { elements, relations, views, specification } = cleanParsedModel(doc);
49
+ const specs = doc.parseResult.value.specification?.specs.filter(ast.isSpecificationElementKind);
50
+ if (specs) {
51
+ for (const { kind, style } of specs) {
52
+ try {
53
+ specification.kinds[kind.name] = toElementStyleExcludeDefaults(style?.props);
54
+ }
55
+ catch (e) {
56
+ logWarnError(e);
57
+ }
58
+ }
59
+ }
60
+ await interruptAndCheck(cancelToken);
61
+ for (const el of streamModel(doc)) {
62
+ if (ast.isElement(el)) {
63
+ try {
64
+ elements.push(this.parseElement(el));
65
+ }
66
+ catch (e) {
67
+ logWarnError(e);
68
+ }
69
+ continue;
70
+ }
71
+ if (ast.isRelation(el)) {
72
+ try {
73
+ relations.push(this.parseRelation(el));
74
+ }
75
+ catch (e) {
76
+ logWarnError(e);
77
+ }
78
+ continue;
79
+ }
80
+ nonexhaustive(el);
81
+ }
82
+ await interruptAndCheck(cancelToken);
83
+ const docviews = doc.parseResult.value.views?.views;
84
+ if (docviews) {
85
+ for (const view of docviews) {
86
+ try {
87
+ const v = this.parseElementView(view);
88
+ ElementViewOps.writeId(view, v.id);
89
+ views.push(v);
90
+ }
91
+ catch (e) {
92
+ logWarnError(e);
93
+ }
94
+ }
95
+ }
96
+ // const prevHash = doc.c4hash ?? ''
97
+ // doc.c4hash = c4hash(doc)
98
+ // return prevHash !== doc.c4hash
99
+ }
100
+ parseElement(astNode) {
101
+ const id = this.resolveFqn(astNode);
102
+ invariant(astNode.kind.ref, 'Element kind is not resolved: ' + astNode.name);
103
+ const kind = astNode.kind.ref.name;
104
+ const tags = this.convertTags(astNode.body);
105
+ const stylePropsAst = astNode.body?.props.find(ast.isStyleProperties)?.props;
106
+ const styleProps = toElementStyleExcludeDefaults(stylePropsAst);
107
+ const astPath = this.getAstNodePath(astNode);
108
+ let [title, description, technology] = astNode.props;
109
+ const bodyProps = astNode.body?.props.filter((p) => ast.isElementStringProperty(p)) ?? [];
110
+ title = title ?? bodyProps.find(p => p.key === 'title')?.value;
111
+ description = description ?? bodyProps.find(p => p.key === 'description')?.value;
112
+ technology = technology ?? bodyProps.find(p => p.key === 'technology')?.value;
113
+ const links = astNode.body?.props.filter(ast.isLinkProperty).map(p => p.value);
114
+ return {
115
+ id,
116
+ kind,
117
+ astPath,
118
+ title: title ? stripIndent(title).trim() : astNode.name,
119
+ ...(tags && { tags }),
120
+ ...(links && isNonEmptyArray(links) && { links }),
121
+ ...(technology && { technology }),
122
+ ...(description && { description: stripIndent(description).trim() }),
123
+ ...styleProps
124
+ };
125
+ }
126
+ parseRelation(astNode) {
127
+ const coupling = resolveRelationPoints(astNode);
128
+ const target = this.resolveFqn(coupling.target);
129
+ const source = this.resolveFqn(coupling.source);
130
+ const hashdata = {
131
+ astPath: this.getAstNodePath(astNode),
132
+ source,
133
+ target
134
+ };
135
+ const id = objectHash(hashdata);
136
+ const title = astNode.title ?? astNode.body?.props.find(p => p.key === 'title')?.value ?? '';
137
+ return {
138
+ id,
139
+ ...hashdata,
140
+ title
141
+ };
142
+ }
143
+ parseElementExpression(astNode) {
144
+ if (ast.isWildcardExpression(astNode)) {
145
+ return {
146
+ wildcard: true
147
+ };
148
+ }
149
+ if (ast.isElementKindExpression(astNode)) {
150
+ invariant(astNode.kind.ref, 'ElementKindExpression kind is not resolved: ' + astNode.$cstNode?.text);
151
+ return {
152
+ elementKind: astNode.kind.ref.name,
153
+ isEqual: astNode.isEqual
154
+ };
155
+ }
156
+ if (ast.isElementTagExpression(astNode)) {
157
+ invariant(astNode.tag.ref, 'ElementTagExpression tag is not resolved: ' + astNode.$cstNode?.text);
158
+ return {
159
+ elementTag: astNode.tag.ref.name,
160
+ isEqual: astNode.isEqual
161
+ };
162
+ }
163
+ if (ast.isElementRefExpression(astNode)) {
164
+ const element = elementRef(astNode.id);
165
+ invariant(element, 'Element not found ' + astNode.id.$cstNode?.text);
166
+ return {
167
+ element: this.resolveFqn(element),
168
+ isDescedants: astNode.isDescedants
169
+ };
170
+ }
171
+ nonexhaustive(astNode);
172
+ }
173
+ parseExpression(astNode) {
174
+ if (ast.isElementExpression(astNode)) {
175
+ return this.parseElementExpression(astNode);
176
+ }
177
+ if (ast.isIncomingExpression(astNode)) {
178
+ return {
179
+ incoming: this.parseElementExpression(astNode.target)
180
+ };
181
+ }
182
+ if (ast.isOutgoingExpression(astNode)) {
183
+ return {
184
+ outgoing: this.parseElementExpression(astNode.source)
185
+ };
186
+ }
187
+ if (ast.isInOutExpression(astNode)) {
188
+ return {
189
+ inout: this.parseElementExpression(astNode.inout.target)
190
+ };
191
+ }
192
+ if (ast.isRelationExpression(astNode)) {
193
+ return {
194
+ source: this.parseElementExpression(astNode.source),
195
+ target: this.parseElementExpression(astNode.target)
196
+ };
197
+ }
198
+ nonexhaustive(astNode);
199
+ }
200
+ parseViewRule(astRule) {
201
+ if (ast.isViewRuleExpression(astRule)) {
202
+ const exprs = astRule.expressions.map(n => this.parseExpression(n));
203
+ return {
204
+ isInclude: astRule.isInclude,
205
+ exprs
206
+ };
207
+ }
208
+ if (ast.isViewRuleStyle(astRule)) {
209
+ const styleProps = toElementStyle(astRule.props);
210
+ return {
211
+ targets: astRule.targets.map(n => this.parseElementExpression(n)),
212
+ style: {
213
+ ...styleProps
214
+ }
215
+ };
216
+ }
217
+ if (ast.isViewRuleAutoLayout(astRule)) {
218
+ return {
219
+ autoLayout: toAutoLayout(astRule.direction)
220
+ };
221
+ }
222
+ nonexhaustive(astRule);
223
+ }
224
+ parseElementView(astNode) {
225
+ const viewOfEl = astNode.viewOf && elementRef(astNode.viewOf);
226
+ const viewOf = viewOfEl && this.resolveFqn(viewOfEl);
227
+ const astPath = this.getAstNodePath(astNode);
228
+ let id = astNode.name;
229
+ if (!id) {
230
+ const doc = getDocument(astNode).uri.toString();
231
+ id = objectHash({
232
+ doc,
233
+ astPath,
234
+ viewOf: viewOf ?? null
235
+ });
236
+ }
237
+ const title = astNode.props.find(p => p.key === 'title')?.value;
238
+ const description = astNode.props.find(p => p.key === 'description')?.value;
239
+ const tags = this.convertTags(astNode);
240
+ const links = astNode.props.filter(ast.isLinkProperty).map(p => p.value);
241
+ return {
242
+ id,
243
+ astPath,
244
+ ...(viewOf && { viewOf }),
245
+ ...(title && { title }),
246
+ ...(description && { description }),
247
+ ...(tags && { tags }),
248
+ ...(links && isNonEmptyArray(links) && { links }),
249
+ rules: astNode.rules.map(n => this.parseViewRule(n))
250
+ };
251
+ }
252
+ resolveFqn(node) {
253
+ if (ast.isExtendElement(node)) {
254
+ return strictElementRefFqn(node.element);
255
+ }
256
+ const fqn = this.fqnIndex.getFqn(node);
257
+ invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
258
+ return fqn;
259
+ }
260
+ getAstNodePath(node) {
261
+ return this.services.workspace.AstNodeLocator.getAstNodePath(node);
262
+ }
263
+ convertTags(withTags) {
264
+ if (!withTags) {
265
+ return null;
266
+ }
267
+ const tags = withTags.tags?.value.flatMap(({ ref }) => (ref ? ref.name : []));
268
+ return tags && isNonEmptyArray(tags) ? tags : null;
269
+ }
270
+ notifyListeners() {
271
+ for (const listener of this.listeners) {
272
+ try {
273
+ listener();
274
+ }
275
+ catch (e) {
276
+ logError(e);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ //# sourceMappingURL=model-parser.js.map
package/dist/module.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import type { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, Module, PartialLangiumServices } from 'langium';
2
2
  import { LikeC4DocumentSymbolProvider } from './lsp';
3
- import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
3
+ import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
4
4
  /**
5
5
  * Declaration of custom services - add your own service classes here.
6
6
  */
7
7
  export interface LikeC4AddedServices {
8
8
  likec4: {
9
9
  FqnIndex: FqnIndex;
10
+ ModelParser: LikeC4ModelParser;
10
11
  ModelBuilder: LikeC4ModelBuilder;
11
12
  ModelLocator: LikeC4ModelLocator;
12
13
  };
package/dist/module.js CHANGED
@@ -1,25 +1,29 @@
1
1
  import { EmptyFileSystem, createDefaultModule, createDefaultSharedModule, inject } from 'langium';
2
2
  import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module';
3
- import { logger } from './logger';
4
- import { LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
5
- import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
3
+ import { LikeC4CodeLensProvider, LikeC4DocumentLinkProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
4
+ import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
6
5
  import { LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
7
6
  import { registerProtocolHandlers } from './registerProtocolHandlers';
8
- import { LikeC4CodeLensProvider, LikeC4DocumentLinkProvider, LikeC4WorkspaceManager } from './shared';
7
+ import { LikeC4WorkspaceManager } from './shared';
9
8
  import { registerValidationChecks } from './validation';
9
+ import { logger } from './logger';
10
+ import { serializeError } from '@likec4/core';
10
11
  function bind(Type) {
11
12
  return (services) => new Type(services);
12
13
  }
13
14
  export const LikeC4Module = {
14
15
  likec4: {
15
16
  FqnIndex: bind(FqnIndex),
17
+ ModelParser: bind(LikeC4ModelParser),
16
18
  ModelBuilder: bind(LikeC4ModelBuilder),
17
19
  ModelLocator: bind(LikeC4ModelLocator)
18
20
  },
19
21
  lsp: {
20
22
  DocumentSymbolProvider: bind(LikeC4DocumentSymbolProvider),
21
23
  SemanticTokenProvider: bind(LikeC4SemanticTokenProvider),
22
- HoverProvider: bind(LikeC4HoverProvider)
24
+ HoverProvider: bind(LikeC4HoverProvider),
25
+ CodeLensProvider: bind(LikeC4CodeLensProvider),
26
+ DocumentLinkProvider: bind(LikeC4DocumentLinkProvider)
23
27
  },
24
28
  //
25
29
  // // Formatter: bind(LikeC4Formatter),
@@ -31,44 +35,31 @@ export const LikeC4Module = {
31
35
  }
32
36
  };
33
37
  const LikeC4SharedModule = {
34
- ...LikeC4GeneratedSharedModule,
35
38
  workspace: {
36
39
  WorkspaceManager: services => new LikeC4WorkspaceManager(services)
37
- },
38
- lsp: {
39
- CodeLensProvider: services => new LikeC4CodeLensProvider(services),
40
- DocumentLinkProvider: services => new LikeC4DocumentLinkProvider(services)
41
40
  }
42
41
  };
43
42
  export function createLanguageServices(context) {
44
43
  const connection = context?.connection;
45
44
  if (connection) {
46
- const log = (method) => (message) => {
47
- try {
48
- console[method](message);
49
- connection.console[method](String(message));
50
- if (method === 'error') {
51
- connection.telemetry.logEvent({ eventName: 'error', message });
52
- }
53
- }
54
- catch (error) {
55
- console.error(error);
45
+ // eslint-disable-next-line @typescript-eslint/unbound-method
46
+ const original = logger.error.bind(logger);
47
+ logger.error = (arg) => {
48
+ if (typeof arg === 'string') {
49
+ original(arg);
50
+ connection.telemetry.logEvent({ eventName: 'error', error: arg });
51
+ return;
56
52
  }
57
- };
58
- logger.log = log('log');
59
- logger.info = log('info');
60
- logger.warn = log('warn');
61
- logger.error = log('error');
62
- logger.trace = logger.debug = (message) => {
63
- console.debug(message);
64
- connection.tracer.log(message);
53
+ const { message, error } = serializeError(arg);
54
+ original(error);
55
+ connection.telemetry.logEvent({ eventName: 'error', error: message });
65
56
  };
66
57
  }
67
58
  const moduleContext = {
68
59
  ...EmptyFileSystem,
69
60
  ...context
70
61
  };
71
- const shared = inject(createDefaultSharedModule(moduleContext), LikeC4SharedModule);
62
+ const shared = inject(createDefaultSharedModule(moduleContext), LikeC4GeneratedSharedModule, LikeC4SharedModule);
72
63
  const likec4 = inject(createDefaultModule({ shared }), LikeC4GeneratedModule, LikeC4Module);
73
64
  shared.ServiceRegistry.register(likec4);
74
65
  registerValidationChecks(likec4);
@@ -4,17 +4,15 @@ import { NotificationType, RequestType0, RequestType } from 'vscode-languageserv
4
4
  interface BuildDocumentsParams {
5
5
  docs: DocumentUri[];
6
6
  }
7
- export interface LocateElementParams {
7
+ export type LocateParams = {
8
8
  element: Fqn;
9
9
  property?: string;
10
- }
11
- export declare const locateElement: RequestType<LocateElementParams, Location | null, void>;
12
- export declare const locateRelation: RequestType<{
13
- id: RelationID;
14
- }, Location | null, void>;
15
- export declare const locateView: RequestType<{
16
- id: ViewID;
17
- }, Location | null, void>;
10
+ } | {
11
+ relation: RelationID;
12
+ } | {
13
+ view: ViewID;
14
+ };
15
+ export declare const locate: RequestType<LocateParams, Location | null, void>;
18
16
  export declare const Rpc: {
19
17
  readonly onDidChangeModel: NotificationType<string>;
20
18
  readonly fetchModel: RequestType0<{
@@ -24,13 +22,7 @@ export declare const Rpc: {
24
22
  docs: DocumentUri[];
25
23
  }, void>;
26
24
  readonly buildDocuments: RequestType<BuildDocumentsParams, void, void>;
27
- readonly locateElement: RequestType<LocateElementParams, Location | null, void>;
28
- readonly locateRelation: RequestType<{
29
- id: RelationID;
30
- }, Location | null, void>;
31
- readonly locateView: RequestType<{
32
- id: ViewID;
33
- }, Location | null, void>;
25
+ readonly locate: RequestType<LocateParams, Location | null, void>;
34
26
  };
35
27
  export {};
36
28
  //# sourceMappingURL=protocol.d.ts.map
package/dist/protocol.js CHANGED
@@ -6,17 +6,13 @@ const onDidChangeModel = new NotificationType('likec4/onDidChangeModel');
6
6
  const fetchModel = new RequestType0('likec4/fetchModel');
7
7
  const rebuild = new RequestType0('likec4/rebuildModel');
8
8
  const buildDocuments = new RequestType('likec4/buildDocuments');
9
- export const locateElement = new RequestType('likec4/locateElement');
10
- export const locateRelation = new RequestType('likec4/locateRelation');
11
- export const locateView = new RequestType('likec4/locateView');
9
+ export const locate = new RequestType('likec4/locate');
12
10
  //#endregion
13
11
  export const Rpc = {
14
12
  onDidChangeModel,
15
13
  fetchModel,
16
14
  rebuild,
17
15
  buildDocuments,
18
- locateElement,
19
- locateRelation,
20
- locateView
16
+ locate
21
17
  };
22
18
  //# sourceMappingURL=protocol.js.map
@@ -1,7 +1,7 @@
1
1
  import { DONE_RESULT, DefaultScopeProvider, EMPTY_STREAM, StreamImpl, StreamScope, getDocument, stream } from 'langium';
2
2
  import { ast } from '../ast';
3
3
  import { elementRef, isElementRefHead, parentStrictElementRef } from '../elementRef';
4
- import { logger } from '../logger';
4
+ import { logError } from '../logger';
5
5
  function toAstNodeDescription(entry) {
6
6
  return {
7
7
  documentUri: entry.doc.uri,
@@ -71,8 +71,7 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
71
71
  return this.computeScope(container, referenceType);
72
72
  }
73
73
  catch (e) {
74
- // console.error(e)
75
- logger.error(e);
74
+ logError(e);
76
75
  return this.getGlobalScope(referenceType);
77
76
  }
78
77
  }
@@ -1,6 +1,7 @@
1
1
  import { URI } from 'vscode-uri';
2
- import { logger } from './logger';
2
+ import { logger, logError } from './logger';
3
3
  import { Rpc } from './protocol';
4
+ import { nonexhaustive } from '@likec4/core';
4
5
  export function registerProtocolHandlers(services) {
5
6
  const connection = services.shared.lsp.Connection;
6
7
  if (!connection) {
@@ -16,13 +17,13 @@ export function registerProtocolHandlers(services) {
16
17
  }
17
18
  catch (e) {
18
19
  model = null;
19
- logger.error(e);
20
+ logError(e);
20
21
  }
21
22
  return Promise.resolve({ model });
22
23
  });
23
24
  connection.onRequest(Rpc.rebuild, async (cancelToken) => {
24
25
  const changed = LangiumDocuments.all.map(d => d.uri).toArray();
25
- logger.debug(`Rebuild all documents: [
26
+ logger.debug(`[ProtocolHandlers] rebuild all documents: [
26
27
  ${changed.map(d => d.toString()).join('\n ')}
27
28
  ]`);
28
29
  await services.shared.workspace.DocumentBuilder.update(changed, [], cancelToken);
@@ -32,12 +33,11 @@ export function registerProtocolHandlers(services) {
32
33
  });
33
34
  connection.onRequest(Rpc.buildDocuments, async ({ docs }, cancelToken) => {
34
35
  if (docs.length === 0) {
35
- logger.debug(`Received empty request to rebuild`);
36
+ logger.debug(`[ProtocolHandlers] received empty request to rebuild`);
36
37
  return;
37
38
  }
38
- logger.debug(`Received request to rebuild: [
39
- ${docs.join('\n ')}
40
- ]`);
39
+ logger.debug(`[ProtocolHandlers] received request to buildDocuments:
40
+ - ${docs.join('\n - ')}`);
41
41
  const changed = [];
42
42
  for (const d of docs) {
43
43
  try {
@@ -51,7 +51,7 @@ export function registerProtocolHandlers(services) {
51
51
  }
52
52
  }
53
53
  catch (e) {
54
- logger.error(e);
54
+ logError(e);
55
55
  }
56
56
  }
57
57
  if (changed.length !== docs.length) {
@@ -67,14 +67,17 @@ We rebuild: [
67
67
  }
68
68
  await services.shared.workspace.DocumentBuilder.update(changed, [], cancelToken);
69
69
  });
70
- connection.onRequest(Rpc.locateElement, ({ element, property }) => {
71
- return modelLocator.locateElement(element, property ?? 'name');
72
- });
73
- connection.onRequest(Rpc.locateRelation, ({ id }) => {
74
- return modelLocator.locateRelation(id);
75
- });
76
- connection.onRequest(Rpc.locateView, ({ id }) => {
77
- return modelLocator.locateView(id);
70
+ connection.onRequest(Rpc.locate, params => {
71
+ if ('element' in params) {
72
+ return modelLocator.locateElement(params.element, params.property ?? 'name');
73
+ }
74
+ if ('relation' in params) {
75
+ return modelLocator.locateRelation(params.relation);
76
+ }
77
+ if ('view' in params) {
78
+ return modelLocator.locateView(params.view);
79
+ }
80
+ nonexhaustive(params);
78
81
  });
79
82
  }
80
83
  //# sourceMappingURL=registerProtocolHandlers.js.map
@@ -1,4 +1,2 @@
1
- export * from './CodeLensProvider';
2
1
  export * from './WorkspaceManager';
3
- export * from './DocumentLinkProvider';
4
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,2 @@
1
- export * from './CodeLensProvider';
2
1
  export * from './WorkspaceManager';
3
- export * from './DocumentLinkProvider';
4
2
  //# sourceMappingURL=index.js.map
@@ -1,8 +1,8 @@
1
1
  import type { LikeC4LangiumDocument } from '../ast';
2
- export declare function createTestServices(): {
2
+ export declare function createTestServices(workspace?: string): {
3
3
  services: import("../module").LikeC4Services;
4
4
  parse: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
5
- validate: (input: string | LikeC4LangiumDocument) => Promise<{
5
+ validate: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<{
6
6
  document: LikeC4LangiumDocument;
7
7
  diagnostics: import("vscode-languageserver-types").Diagnostic[];
8
8
  errors: string[];
@@ -1,27 +1,33 @@
1
1
  import { createLanguageServices } from '../module';
2
2
  import { EmptyFileSystem } from 'langium';
3
- import { URI } from 'vscode-uri';
3
+ import { URI, Utils } from 'vscode-uri';
4
4
  import stripIndent from 'strip-indent';
5
- export function createTestServices() {
5
+ export function createTestServices(workspace = 'file:///test/workspace') {
6
6
  const services = createLanguageServices(EmptyFileSystem).likec4;
7
7
  const metaData = services.LanguageMetaData;
8
8
  const langiumDocuments = services.shared.workspace.LangiumDocuments;
9
9
  const documentBuilder = services.shared.workspace.DocumentBuilder;
10
10
  const modelBuilder = services.likec4.ModelBuilder;
11
- const initPromise = services.shared.workspace.WorkspaceManager.initializeWorkspace([]);
11
+ const workspaceUri = URI.parse(workspace);
12
+ const initPromise = services.shared.workspace.WorkspaceManager.initializeWorkspace([
13
+ {
14
+ name: 'test',
15
+ uri: workspaceUri.toString()
16
+ }
17
+ ]);
12
18
  let documentIndex = 1;
13
19
  const parse = async (input, uri) => {
14
20
  await initPromise;
15
- uri = uri ?? `${documentIndex++}${metaData.fileExtensions[0]}`;
16
- const document = services.shared.workspace.LangiumDocumentFactory.fromString(stripIndent(input), URI.file(uri));
21
+ const docUri = Utils.joinPath(workspaceUri, '/src/', uri ?? `${documentIndex++}${metaData.fileExtensions[0]}`);
22
+ const document = services.shared.workspace.LangiumDocumentFactory.fromString(stripIndent(input), docUri);
17
23
  langiumDocuments.addDocument(document);
18
- await documentBuilder.build([document], { validationChecks: 'none' });
24
+ await documentBuilder.build([document], { validation: false });
19
25
  return document;
20
26
  };
21
- const validate = async (input) => {
27
+ const validate = async (input, uri) => {
22
28
  await initPromise;
23
- const document = typeof input === 'string' ? await parse(input) : input;
24
- await documentBuilder.build([document], { validationChecks: 'all' });
29
+ const document = typeof input === 'string' ? await parse(input, uri) : input;
30
+ await documentBuilder.build([document], { validation: true });
25
31
  const diagnostics = document.diagnostics ?? [];
26
32
  const errors = diagnostics.map(d => d.message);
27
33
  return {
@@ -33,7 +39,7 @@ export function createTestServices() {
33
39
  const validateAll = async () => {
34
40
  await initPromise;
35
41
  const docs = langiumDocuments.all.toArray();
36
- await documentBuilder.build(docs, { validationChecks: 'all' });
42
+ await documentBuilder.build(docs, { validation: true });
37
43
  const diagnostics = docs.flatMap(doc => doc.diagnostics ?? []);
38
44
  const errors = diagnostics.map(d => d.message);
39
45
  return {
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export declare function failExpectedNever(arg: never): never;
2
- export declare function ignoreNeverInRuntime(arg: never): void;
1
+ import type { LangiumDocument } from 'langium';
2
+ export declare const printDocs: (docs: LangiumDocument[]) => string;
3
3
  //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js CHANGED
@@ -1,8 +1,3 @@
1
- export function failExpectedNever(arg) {
2
- throw new Error(`Unexpected value: ${JSON.stringify(arg)}`);
3
- }
4
- export function ignoreNeverInRuntime(arg) {
5
- console.warn(`Unexpected and ignored value: ${JSON.stringify(arg)}`);
6
- // throw new Error(`Unexpected value: ${arg}`);
7
- }
1
+ import { Utils } from 'vscode-uri';
2
+ export const printDocs = (docs) => docs.map(d => ' - ' + Utils.basename(d.uri)).join('\n');
8
3
  //# sourceMappingURL=utils.js.map
@@ -1,4 +1,4 @@
1
- import type { ValidationCheck } from 'langium';
1
+ import { type ValidationCheck } from 'langium';
2
2
  import type { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  export declare const elementChecks: (services: LikeC4Services) => ValidationCheck<ast.Element>;