@likec4/language-server 0.33.1 → 0.35.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 (51) hide show
  1. package/contrib/likec4.monarch.ts +17 -3
  2. package/dist/ast.d.ts +24 -11
  3. package/dist/ast.js +12 -9
  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 +51 -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 +19 -24
  30. package/dist/model/model-parser.d.ts +27 -0
  31. package/dist/model/model-parser.js +293 -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-computation.js +11 -5
  37. package/dist/references/scope-provider.js +10 -4
  38. package/dist/registerProtocolHandlers.js +33 -17
  39. package/dist/shared/index.d.ts +0 -2
  40. package/dist/shared/index.js +0 -2
  41. package/dist/test/testServices.d.ts +2 -2
  42. package/dist/test/testServices.js +16 -10
  43. package/dist/utils.d.ts +2 -2
  44. package/dist/utils.js +2 -7
  45. package/dist/validation/element.d.ts +1 -1
  46. package/dist/validation/element.js +23 -3
  47. package/dist/validation/index.js +26 -0
  48. package/dist/validation/relation.d.ts +1 -1
  49. package/dist/validation/relation.js +32 -26
  50. package/package.json +10 -8
  51. /package/dist/{shared → lsp}/CodeLensProvider.js +0 -0
@@ -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>;
@@ -1,3 +1,4 @@
1
+ import { getDocument } from 'langium';
1
2
  export const elementChecks = (services) => {
2
3
  const fqnIndex = services.likec4.FqnIndex;
3
4
  return (el, accept) => {
@@ -9,13 +10,32 @@ export const elementChecks = (services) => {
9
10
  });
10
11
  return;
11
12
  }
12
- const withSameFqn = fqnIndex.byFqn(fqn).limit(2).count();
13
- if (withSameFqn > 1) {
13
+ const withSameFqn = fqnIndex
14
+ .byFqn(fqn)
15
+ .filter(v => v.el !== el)
16
+ .head();
17
+ if (withSameFqn) {
14
18
  accept('error', `Duplicate element name ${el.name !== fqn ? el.name + ' (' + fqn + ')' : el.name}`, {
15
19
  node: el,
16
- property: 'name'
20
+ property: 'name',
21
+ relatedInformation: [
22
+ {
23
+ location: {
24
+ range: withSameFqn.el.$cstNode.range,
25
+ uri: getDocument(withSameFqn.el).uri.toString()
26
+ },
27
+ message: `Already defined here`
28
+ }
29
+ ]
17
30
  });
18
31
  }
32
+ // for (let i = 3; i < el.props.length; i++) {
33
+ // accept('error', `Too many properties, max 3 allowed`, {
34
+ // node: el,
35
+ // property: 'props',
36
+ // index: i
37
+ // })
38
+ // }
19
39
  };
20
40
  };
21
41
  //# sourceMappingURL=element.js.map
@@ -1,8 +1,11 @@
1
+ import { Utils } from 'vscode-uri';
2
+ import { logger } from '../logger';
1
3
  import { elementChecks } from './element';
2
4
  import { relationChecks } from './relation';
3
5
  import { elementKindChecks, tagChecks } from './specification';
4
6
  import { viewChecks } from './view';
5
7
  export function registerValidationChecks(services) {
8
+ logger.info('registerValidationChecks');
6
9
  const registry = services.validation.ValidationRegistry;
7
10
  // const checks: ValidationChecks = {
8
11
  // Element: validator.checkElementNameDuplicates,
@@ -19,5 +22,28 @@ export function registerValidationChecks(services) {
19
22
  Relation: relationChecks(services),
20
23
  Tag: tagChecks(services)
21
24
  });
25
+ const connection = services.shared.lsp.Connection;
26
+ if (connection) {
27
+ logger.info('registerValidationChecks');
28
+ // wokraround for bug in langium
29
+ services.shared.workspace.DocumentBuilder.onUpdate((changed, deleted) => {
30
+ const message = [`[DocumentBuilder.onUpdate]`];
31
+ if (changed.length > 0) {
32
+ message.push(` changed:`);
33
+ changed.forEach(u => message.push(` - ${Utils.basename(u)}`));
34
+ }
35
+ if (deleted.length > 0) {
36
+ message.push(` deleted:`);
37
+ deleted.forEach(u => message.push(` - ${Utils.basename(u)}`));
38
+ }
39
+ logger.debug(message.join('\n'));
40
+ for (const uri of deleted) {
41
+ void connection.sendDiagnostics({
42
+ uri: uri.toString(),
43
+ diagnostics: []
44
+ });
45
+ }
46
+ });
47
+ }
22
48
  }
23
49
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
1
  import type { ValidationCheck } from 'langium';
2
- import type { ast } from '../ast';
2
+ import { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  export declare const relationChecks: (services: LikeC4Services) => ValidationCheck<ast.Relation>;
5
5
  //# sourceMappingURL=relation.d.ts.map
@@ -1,43 +1,49 @@
1
- import { BaseError } from '@likec4/core';
2
- import { isSameHierarchy } from '@likec4/core/utils';
3
- import { resolveRelationPoints } from '../ast';
1
+ import { isSameHierarchy } from '@likec4/core';
2
+ import { ast } from '../ast';
3
+ import { elementRef } from '../elementRef';
4
+ import { logError } from '../logger';
4
5
  export const relationChecks = (services) => {
5
6
  const fqnIndex = services.likec4.FqnIndex;
6
7
  return (el, accept) => {
7
8
  try {
8
- const coupling = resolveRelationPoints(el);
9
- const target = fqnIndex.getFqn(coupling.target);
10
- const source = fqnIndex.getFqn(coupling.source);
11
- if (!target || !source) {
12
- if (!target) {
13
- accept('error', 'Target not found', {
9
+ const targetEl = elementRef(el.target);
10
+ const target = targetEl && fqnIndex.getFqn(targetEl);
11
+ if (!target) {
12
+ accept('error', 'Target not found (not parsed/indexed yet)', {
13
+ node: el,
14
+ property: 'target'
15
+ });
16
+ }
17
+ let sourceEl;
18
+ if ('source' in el) {
19
+ sourceEl = elementRef(el.source);
20
+ }
21
+ else {
22
+ if (!ast.isElementBody(el.$container)) {
23
+ accept('error', 'Invalid relation, expected to have source defined or be inside the element', {
14
24
  node: el,
15
- property: 'target'
25
+ keyword: '->'
16
26
  });
17
27
  }
18
- if (!source) {
19
- accept('error', 'Source not found', {
20
- node: el,
21
- property: 'source'
22
- });
28
+ else {
29
+ sourceEl = el.$container.$container;
23
30
  }
24
- return;
25
31
  }
26
- if (isSameHierarchy(source, target)) {
27
- return accept('error', 'Invalid parent-child relation', {
28
- node: el
32
+ const source = sourceEl && fqnIndex.getFqn(sourceEl);
33
+ if (sourceEl && !source) {
34
+ accept('error', 'Source not found (not parsed/indexed yet)', {
35
+ node: el,
36
+ property: 'source'
29
37
  });
30
38
  }
31
- }
32
- catch (e) {
33
- if (e instanceof BaseError) {
34
- return accept('error', e.message, {
39
+ if (source && target && isSameHierarchy(source, target)) {
40
+ return accept('error', 'Invalid parent-child relationship', {
35
41
  node: el
36
42
  });
37
43
  }
38
- accept('error', 'Invalid relation', {
39
- node: el
40
- });
44
+ }
45
+ catch (e) {
46
+ logError(e);
41
47
  }
42
48
  };
43
49
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likec4/language-server",
3
3
  "description": "LikeC4 Language Server",
4
- "version": "0.33.1",
4
+ "version": "0.35.0",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -42,22 +42,24 @@
42
42
  "test:watch": "vitest"
43
43
  },
44
44
  "dependencies": {
45
- "@likec4/core": "0.33.1",
46
- "langium": "^1.2.1",
45
+ "@likec4/core": "0.35.0",
46
+ "langium": "^2.0.2",
47
47
  "nanoid": "^4.0.2",
48
48
  "object-hash": "^3.0.0",
49
49
  "rambdax": "^9.1.1",
50
50
  "remeda": "^1.24.0",
51
51
  "strip-indent": "^4.0.0",
52
52
  "vscode-languageserver": "~8.1.0",
53
- "vscode-languageserver-protocol": "~3.17.3"
53
+ "vscode-languageserver-protocol": "~3.17.3",
54
+ "vscode-uri": "~3.0.7"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@types/node": "^18.15.11",
57
58
  "@types/object-hash": "^3.0.2",
58
- "langium-cli": "^1.2.1",
59
+ "langium-cli": "^2.0.1",
59
60
  "npm-run-all": "^4.1.5",
60
- "typescript": "^5.1.6",
61
- "vitest": "^0.34.1"
62
- }
61
+ "typescript": "^5.2.2",
62
+ "vitest": "^0.34.3"
63
+ },
64
+ "packageManager": "yarn@3.6.3"
63
65
  }
File without changes