@likec4/language-server 0.26.0 → 0.28.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.
@@ -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
- invariant(astKind.$cstNode, 'SpecificationElementKind must have a CST node');
34
- invariant(astKind.kind.$cstNode, 'SpecificationElementKind name must have a CST node');
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
- invariant(astTag.$cstNode, 'TagSpec must have a CST node');
52
- invariant(astTag.tag.$cstNode, 'Tag name must have a CST node');
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 'rambdax';
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,11 +1,11 @@
1
1
  import { nameFromFqn, parentFqn } from '@likec4/core/utils';
2
- import { DocumentState, DONE_RESULT, MultiMap, StreamImpl } from 'langium';
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) && !isNil(doc.c4fqns);
8
+ return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !isNil(doc.c4fqns);
9
9
  }
10
10
  export class FqnIndex {
11
11
  services;
@@ -5,13 +5,13 @@ import { DocumentState, getDocument } from 'langium';
5
5
  import objectHash from 'object-hash';
6
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;
@@ -129,9 +129,9 @@ export class LikeC4ModelBuilder {
129
129
  */
130
130
  parseDocument(doc) {
131
131
  const { elements, relations, views, specification } = cleanParsedModel(doc);
132
- const spec = doc.parseResult.value.specification;
133
- if (spec) {
134
- for (const { kind, style } of spec.elementKinds) {
132
+ const specs = doc.parseResult.value.specification?.specs.filter(ast.isSpecificationElementKind);
133
+ if (specs) {
134
+ for (const { kind, style } of specs) {
135
135
  try {
136
136
  const styleProps = toElementStyle(style?.props);
137
137
  specification.kinds[kind.name] = {
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 { kind } of specification.elementKinds) {
14
- docExports.push(this.descriptions.createDescription(kind, kind.name, document));
15
- }
16
- for (const { tag } of specification.tags) {
17
- docExports.push(this.descriptions.createDescription(tag, tag.name, document));
18
- docExports.push(this.descriptions.createDescription(tag, '#' + tag.name, document));
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 ('name' in viewAst) {
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
@@ -1,3 +1,4 @@
1
1
  export * from './CodeLensProvider';
2
2
  export * from './WorkspaceManager';
3
+ export * from './DocumentLinkProvider';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,4 @@
1
1
  export * from './CodeLensProvider';
2
2
  export * from './WorkspaceManager';
3
+ export * from './DocumentLinkProvider';
3
4
  //# sourceMappingURL=index.js.map