@likec4/language-server 0.30.0 → 0.32.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.
package/dist/logger.d.ts CHANGED
@@ -6,4 +6,5 @@ export declare const logger: {
6
6
  error(message: string | Error | unknown): void;
7
7
  trace(message: string): void;
8
8
  };
9
+ export type Logger = typeof logger;
9
10
  //# sourceMappingURL=logger.d.ts.map
@@ -80,7 +80,7 @@ export class LikeC4DocumentSymbolProvider {
80
80
  return [];
81
81
  return [
82
82
  {
83
- kind: SymbolKind.Class,
83
+ kind: SymbolKind.Namespace,
84
84
  name: astSpec.name,
85
85
  range: cstModel.range,
86
86
  selectionRange: specKeywordNode.range,
@@ -97,7 +97,7 @@ export class LikeC4DocumentSymbolProvider {
97
97
  return [];
98
98
  return [
99
99
  {
100
- kind: SymbolKind.Class,
100
+ kind: SymbolKind.Namespace,
101
101
  name: astModel.name,
102
102
  range: cstModel.range,
103
103
  selectionRange: nameNode.range,
@@ -166,7 +166,7 @@ export class LikeC4DocumentSymbolProvider {
166
166
  return [];
167
167
  return [
168
168
  {
169
- kind: SymbolKind.Class,
169
+ kind: SymbolKind.Namespace,
170
170
  name: astViews.name,
171
171
  range: cst.range,
172
172
  selectionRange: nameNode.range,
@@ -26,11 +26,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
26
26
  });
27
27
  return;
28
28
  }
29
- if (ast.isRelation(node) ||
30
- ast.isRelationExpression(node) ||
31
- ast.isIncomingExpression(node) ||
32
- ast.isInOutExpression(node) ||
33
- ast.isOutgoingExpression(node)) {
29
+ if ('arr' in node) {
34
30
  acceptor({
35
31
  node,
36
32
  property: 'arr',
@@ -38,6 +34,20 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
38
34
  modifier: [SemanticTokenModifiers.defaultLibrary]
39
35
  });
40
36
  }
37
+ // if (
38
+ // ast.isRelation(node) ||
39
+ // ast.isRelationExpression(node) ||
40
+ // ast.isIncomingExpression(node) ||
41
+ // ast.isInOutExpression(node) ||
42
+ // ast.isOutgoingExpression(node)
43
+ // ) {
44
+ // acceptor({
45
+ // node,
46
+ // property: 'arr',
47
+ // type: SemanticTokenTypes.keyword,
48
+ // modifier: [SemanticTokenModifiers.defaultLibrary]
49
+ // })
50
+ // }
41
51
  if (ast.isElementKindExpression(node) || ast.isElementTagExpression(node)) {
42
52
  keyword('element');
43
53
  if (ast.isElementKindExpression(node)) {
@@ -98,16 +108,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
98
108
  });
99
109
  return;
100
110
  }
101
- if (ast.isAStyleProperty(node)) {
111
+ if (ast.isColorProperty(node) || ast.isShapeProperty(node)) {
102
112
  acceptor({
103
113
  node,
104
114
  property: 'key',
105
115
  type: SemanticTokenTypes.keyword
106
- // type: SemanticTokenTypes.property,
107
- // modifier: [
108
- // SemanticTokenModifiers.readonly,
109
- // SemanticTokenModifiers.declaration
110
- // ]
111
116
  });
112
117
  acceptor({
113
118
  node,
@@ -116,20 +121,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
116
121
  });
117
122
  return;
118
123
  }
119
- // ViewProperty | ElementStringProperty | RelationStringProperty | LinkProperty
120
- if (ast.isViewProperty(node) ||
121
- ast.isElementStringProperty(node) ||
122
- ast.isRelationStringProperty(node) ||
123
- ast.isLinkProperty(node)) {
124
+ if (ast.isLinkProperty(node) || ast.isIconProperty(node)) {
124
125
  acceptor({
125
126
  node,
126
127
  property: 'key',
127
128
  type: SemanticTokenTypes.keyword
128
- // type: SemanticTokenTypes.property,
129
- // modifier: [
130
- // SemanticTokenModifiers.readonly,
131
- // SemanticTokenModifiers.declaration
132
- // ]
133
129
  });
134
130
  acceptor({
135
131
  node,
@@ -138,6 +134,31 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
138
134
  });
139
135
  return;
140
136
  }
137
+ // ViewProperty | ElementStringProperty | RelationStringProperty | LinkProperty
138
+ // if (
139
+ // ast.isViewProperty(node) ||
140
+ // ast.isElementStringProperty(node) ||
141
+ // ast.isRelationStringProperty(node) ||
142
+ // ast.isLinkProperty(node) ||
143
+ // ast.isIconProperty(node)
144
+ // ) {
145
+ // acceptor({
146
+ // node,
147
+ // property: 'key',
148
+ // type: SemanticTokenTypes.keyword
149
+ // // type: SemanticTokenTypes.property,
150
+ // // modifier: [
151
+ // // SemanticTokenModifiers.readonly,
152
+ // // SemanticTokenModifiers.declaration
153
+ // // ]
154
+ // })
155
+ // acceptor({
156
+ // node,
157
+ // property: 'value',
158
+ // type: SemanticTokenTypes.string
159
+ // })
160
+ // return
161
+ // }
141
162
  // if (ast.isModel(node)) {
142
163
  // keyword('model')
143
164
  // return
@@ -1,4 +1,5 @@
1
- import { failExpectedNever, AsFqn } from '@likec4/core';
1
+ import { nonexhaustive } from '@likec4/core/errors';
2
+ import { AsFqn } from '@likec4/core/types';
2
3
  import { MultiMap } from 'langium';
3
4
  import { isEmpty, isNil } from 'remeda';
4
5
  import { ElementOps, ast } from '../ast';
@@ -34,7 +35,7 @@ export function computeDocumentFqn(document, services) {
34
35
  }
35
36
  continue;
36
37
  }
37
- failExpectedNever(el);
38
+ nonexhaustive(el);
38
39
  }
39
40
  }
40
41
  //# sourceMappingURL=fqn-computation.js.map
@@ -51,18 +51,18 @@ export class FqnIndex {
51
51
  }
52
52
  directChildrenOf(parent) {
53
53
  return new StreamImpl(() => {
54
- const children = new MultiMap(this.entries()
54
+ const children = this.entries()
55
55
  .filter(e => parentFqn(e.fqn) === parent)
56
56
  .map((e) => {
57
57
  const name = nameFromFqn(e.fqn);
58
58
  const entry = { ...e, name };
59
59
  return [name, entry];
60
60
  })
61
- .toArray());
62
- if (children.size === 0) {
61
+ .toArray();
62
+ if (children.length === 0) {
63
63
  return null;
64
64
  }
65
- return children
65
+ return new MultiMap(children)
66
66
  .entriesGroupedByKey()
67
67
  .flatMap(([_name, descrs]) => (descrs.length === 1 ? descrs : []))
68
68
  .iterator();
@@ -1,5 +1,6 @@
1
1
  import type * as c4 from '@likec4/core/types';
2
- import { ast, type LikeC4LangiumDocument } from '../ast';
2
+ import { ast } from '../ast';
3
+ import type { LikeC4LangiumDocument } from '../ast';
3
4
  import type { LikeC4Services } from '../module';
4
5
  export declare class LikeC4ModelBuilder {
5
6
  private services;
@@ -1,12 +1,10 @@
1
- import { ModelIndex, assignNavigateTo, computeView, invariant } from '@likec4/core';
2
- import { DefaultElementShape, DefaultThemeColor } from '@likec4/core/types';
3
- import { compareByFqnHierarchically, parentFqn } from '@likec4/core/utils';
1
+ import { ModelIndex, assignNavigateTo, compareByFqnHierarchically, computeView, invariant, isNonEmptyArray, nonexhaustive, parentFqn } from '@likec4/core';
4
2
  import { DocumentState, getDocument } from 'langium';
5
3
  import objectHash from 'object-hash';
6
4
  import { clone } from 'rambdax';
7
5
  import * as R from 'remeda';
8
6
  import stripIndent from 'strip-indent';
9
- import { ElementViewOps, ast, cleanParsedModel, isLikeC4LangiumDocument, isValidLikeC4LangiumDocument, resolveRelationPoints, streamModel, toAutoLayout, toElementStyle } from '../ast';
7
+ import { ElementViewOps, ast, cleanParsedModel, isLikeC4LangiumDocument, isValidLikeC4LangiumDocument, resolveRelationPoints, streamModel, toAutoLayout, toElementStyle, toElementStyleExcludeDefaults } from '../ast';
10
8
  import { elementRef, strictElementRefFqn } from '../elementRef';
11
9
  import { logger } from '../logger';
12
10
  import { Rpc } from '../protocol';
@@ -67,15 +65,15 @@ export class LikeC4ModelBuilder {
67
65
  kinds: {}
68
66
  };
69
67
  R.forEach(R.map(docs, R.prop('c4Specification')), spec => Object.assign(c4Specification.kinds, spec.kinds));
70
- const toModelElement = ({ astPath, ...parsed }) => {
68
+ const toModelElement = ({ astPath, tags, links, ...parsed }) => {
71
69
  const kind = c4Specification.kinds[parsed.kind];
72
70
  if (kind) {
73
71
  return {
74
- shape: kind.shape,
75
- color: kind.color,
72
+ ...kind,
76
73
  description: null,
77
74
  technology: null,
78
- tags: [],
75
+ tags: tags ?? null,
76
+ links: links ?? null,
79
77
  ...parsed
80
78
  };
81
79
  }
@@ -109,7 +107,7 @@ export class LikeC4ModelBuilder {
109
107
  const modelIndex = ModelIndex.from({ elements, relations });
110
108
  const toModelView = (view) => {
111
109
  // eslint-disable-next-line prefer-const
112
- let { astPath, rules, title, ...model } = view;
110
+ let { astPath, rules, title, description, tags, links, ...model } = view;
113
111
  if (!title && view.viewOf) {
114
112
  title = elements[view.viewOf]?.title;
115
113
  }
@@ -118,7 +116,10 @@ export class LikeC4ModelBuilder {
118
116
  }
119
117
  return computeView({
120
118
  ...model,
121
- ...(title && { title }),
119
+ title: title ?? null,
120
+ description: description ?? null,
121
+ tags: tags ?? null,
122
+ links: links ?? null,
122
123
  rules: clone(rules)
123
124
  }, modelIndex);
124
125
  };
@@ -144,11 +145,7 @@ export class LikeC4ModelBuilder {
144
145
  if (specs) {
145
146
  for (const { kind, style } of specs) {
146
147
  try {
147
- const styleProps = toElementStyle(style?.props);
148
- specification.kinds[kind.name] = {
149
- color: styleProps.color ?? DefaultThemeColor,
150
- shape: styleProps.shape ?? DefaultElementShape
151
- };
148
+ specification.kinds[kind.name] = toElementStyleExcludeDefaults(style?.props);
152
149
  }
153
150
  catch (e) {
154
151
  logger.warn(e);
@@ -174,7 +171,7 @@ export class LikeC4ModelBuilder {
174
171
  }
175
172
  continue;
176
173
  }
177
- failExpectedNever(el);
174
+ nonexhaustive(el);
178
175
  }
179
176
  const docviews = doc.parseResult.value.views?.views;
180
177
  if (docviews) {
@@ -197,25 +194,26 @@ export class LikeC4ModelBuilder {
197
194
  const id = this.resolveFqn(astNode);
198
195
  invariant(astNode.kind.ref, 'Element kind is not resolved: ' + astNode.name);
199
196
  const kind = astNode.kind.ref.name;
200
- const tags = (astNode.body && this.convertTags(astNode.body)) ?? [];
201
- const styleProps = astNode.body?.props.find(ast.isElementStyleProperties)?.props;
202
- const { color, shape } = toElementStyle(styleProps);
197
+ const tags = this.convertTags(astNode.body);
198
+ const stylePropsAst = astNode.body?.props.find(ast.isStyleProperties)?.props;
199
+ const styleProps = toElementStyleExcludeDefaults(stylePropsAst);
203
200
  const astPath = this.getAstNodePath(astNode);
204
201
  let [title, description, technology] = astNode.props;
205
202
  const bodyProps = astNode.body?.props.filter((p) => ast.isElementStringProperty(p)) ?? [];
206
203
  title = title ?? bodyProps.find(p => p.key === 'title')?.value;
207
204
  description = description ?? bodyProps.find(p => p.key === 'description')?.value;
208
205
  technology = technology ?? bodyProps.find(p => p.key === 'technology')?.value;
206
+ const links = astNode.body?.props.filter(ast.isLinkProperty).map(p => p.value);
209
207
  return {
210
208
  id,
211
209
  kind,
212
210
  astPath,
213
- title: title ?? astNode.name,
211
+ title: title ? stripIndent(title).trim() : astNode.name,
212
+ ...(tags && { tags }),
213
+ ...(links && isNonEmptyArray(links) && { links }),
214
214
  ...(technology && { technology }),
215
215
  ...(description && { description: stripIndent(description).trim() }),
216
- ...(tags.length > 0 ? { tags } : {}),
217
- ...(shape && shape !== DefaultElementShape ? { shape } : {}),
218
- ...(color && color !== DefaultThemeColor ? { color } : {})
216
+ ...styleProps
219
217
  };
220
218
  }
221
219
  parseRelation(astNode) {
@@ -329,14 +327,18 @@ export class LikeC4ModelBuilder {
329
327
  viewOf: viewOf ?? null
330
328
  });
331
329
  }
332
- const title = astNode.properties.find(p => p.key === 'title')?.value;
333
- const description = astNode.properties.find(p => p.key === 'description')?.value;
330
+ const title = astNode.props.find(p => p.key === 'title')?.value;
331
+ const description = astNode.props.find(p => p.key === 'description')?.value;
332
+ const tags = this.convertTags(astNode);
333
+ const links = astNode.props.filter(ast.isLinkProperty).map(p => p.value);
334
334
  return {
335
335
  id,
336
336
  astPath,
337
337
  ...(viewOf && { viewOf }),
338
338
  ...(title && { title }),
339
339
  ...(description && { description }),
340
+ ...(tags && { tags }),
341
+ ...(links && isNonEmptyArray(links) && { links }),
340
342
  rules: astNode.rules.map(n => this.parseViewRule(n))
341
343
  };
342
344
  }
@@ -351,8 +353,12 @@ export class LikeC4ModelBuilder {
351
353
  getAstNodePath(node) {
352
354
  return this.services.workspace.AstNodeLocator.getAstNodePath(node);
353
355
  }
354
- convertTags(el) {
355
- return el.tags?.value.map(tagRef => tagRef.ref?.name) ?? [];
356
+ convertTags(withTags) {
357
+ if (!withTags) {
358
+ return null;
359
+ }
360
+ const tags = withTags.tags?.value.flatMap(({ ref }) => (ref ? ref.name : []));
361
+ return tags && isNonEmptyArray(tags) ? tags : null;
356
362
  }
357
363
  scheduledCb = null;
358
364
  notifyClient(cancelToken) {
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.30.0",
4
+ "version": "0.32.0",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -55,16 +55,16 @@
55
55
  "dev": "run-p 'watch:*'",
56
56
  "lint": "run -T eslint src/ --fix",
57
57
  "clean": "run -T rimraf dist contrib",
58
- "test": "run -T vitest run",
59
- "test:watch": "run -T vitest"
58
+ "test": "vitest run",
59
+ "test:watch": "vitest"
60
60
  },
61
61
  "dependencies": {
62
- "@likec4/core": "0.30.0",
62
+ "@likec4/core": "0.32.0",
63
63
  "langium": "^1.2.1",
64
64
  "nanoid": "^4.0.2",
65
65
  "object-hash": "^3.0.0",
66
66
  "rambdax": "^9.1.1",
67
- "remeda": "^1.23.0",
67
+ "remeda": "^1.24.0",
68
68
  "strip-indent": "^4.0.0",
69
69
  "vscode-languageserver": "~8.1.0",
70
70
  "vscode-languageserver-protocol": "~3.17.3"
@@ -74,6 +74,7 @@
74
74
  "@types/object-hash": "^3.0.2",
75
75
  "langium-cli": "^1.2.1",
76
76
  "npm-run-all": "^4.1.5",
77
- "typescript": "^5.1.6"
77
+ "typescript": "^5.1.6",
78
+ "vitest": "^0.34.1"
78
79
  }
79
80
  }