@likec4/language-server 1.41.0 → 1.42.1

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 (85) hide show
  1. package/browser/package.json +4 -0
  2. package/browser-worker/package.json +4 -0
  3. package/dist/LikeC4LanguageServices.d.ts +1 -1
  4. package/dist/LikeC4LanguageServices.mjs +3 -2
  5. package/dist/Rpc.mjs +30 -24
  6. package/dist/ast.d.ts +1 -7
  7. package/dist/ast.mjs +0 -10
  8. package/dist/bundled.mjs +4125 -3660
  9. package/dist/documentation/documentation-provider.mjs +1 -1
  10. package/dist/filesystem/FileSystemWatcher.d.ts +2 -2
  11. package/dist/filesystem/LikeC4FileSystem.mjs +10 -4
  12. package/dist/filesystem/index.d.ts +1 -1
  13. package/dist/formatting/LikeC4Formatter.mjs +41 -10
  14. package/dist/formatting/utils.d.ts +3 -3
  15. package/dist/formatting/utils.mjs +1 -1
  16. package/dist/generated/ast.d.ts +35 -16
  17. package/dist/generated/ast.mjs +69 -26
  18. package/dist/generated/grammar.mjs +1 -1
  19. package/dist/lsp/CompletionProvider.mjs +1 -1
  20. package/dist/lsp/DocumentLinkProvider.d.ts +1 -1
  21. package/dist/lsp/DocumentLinkProvider.mjs +1 -1
  22. package/dist/lsp/DocumentSymbolProvider.mjs +1 -1
  23. package/dist/mcp/NoopLikeC4MCPServer.d.ts +1 -1
  24. package/dist/mcp/NoopLikeC4MCPServer.mjs +1 -1
  25. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +4 -1
  26. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +3 -3
  27. package/dist/mcp/server/WithMCPServer.mjs +2 -2
  28. package/dist/mcp/tools/_common.mjs +2 -2
  29. package/dist/model/builder/MergedSpecification.d.ts +3 -3
  30. package/dist/model/builder/MergedSpecification.mjs +13 -39
  31. package/dist/model/builder/buildModel.mjs +14 -17
  32. package/dist/model/model-builder.d.ts +1 -1
  33. package/dist/model/model-builder.mjs +12 -9
  34. package/dist/model/model-locator.d.ts +5 -0
  35. package/dist/model/model-locator.mjs +40 -3
  36. package/dist/model/model-parser-where.mjs +1 -2
  37. package/dist/model/model-parser.d.ts +19 -2
  38. package/dist/model/parser/Base.mjs +8 -8
  39. package/dist/model/parser/DeploymentModelParser.d.ts +1 -0
  40. package/dist/model/parser/DeploymentModelParser.mjs +7 -7
  41. package/dist/model/parser/DeploymentViewParser.d.ts +1 -0
  42. package/dist/model/parser/FqnRefParser.d.ts +2 -0
  43. package/dist/model/parser/FqnRefParser.mjs +16 -11
  44. package/dist/model/parser/GlobalsParser.d.ts +8 -2
  45. package/dist/model/parser/ModelParser.d.ts +1 -0
  46. package/dist/model/parser/ModelParser.mjs +16 -11
  47. package/dist/model/parser/PredicatesParser.d.ts +1 -0
  48. package/dist/model/parser/SpecificationParser.mjs +4 -4
  49. package/dist/model/parser/ViewsParser.d.ts +12 -2
  50. package/dist/model/parser/ViewsParser.mjs +123 -31
  51. package/dist/model-change/ModelChanges.d.ts +1 -1
  52. package/dist/module.mjs +3 -2
  53. package/dist/protocol.d.ts +28 -4
  54. package/dist/references/scope-computation.mjs +2 -3
  55. package/dist/references/scope-provider.d.ts +2 -2
  56. package/dist/references/scope-provider.mjs +8 -15
  57. package/dist/test/testServices.d.ts +2 -0
  58. package/dist/test/testServices.mjs +10 -11
  59. package/dist/utils/disposable.mjs +2 -2
  60. package/dist/utils/index.mjs +1 -1
  61. package/dist/validation/_shared.d.ts +1 -1
  62. package/dist/validation/deployment-checks.d.ts +1 -1
  63. package/dist/validation/deployment-checks.mjs +4 -1
  64. package/dist/validation/dynamic-view.d.ts +3 -2
  65. package/dist/validation/dynamic-view.mjs +21 -2
  66. package/dist/validation/element-ref.d.ts +2 -2
  67. package/dist/validation/element-ref.mjs +1 -1
  68. package/dist/validation/imports.d.ts +0 -1
  69. package/dist/validation/imports.mjs +0 -5
  70. package/dist/validation/index.d.ts +1 -1
  71. package/dist/validation/index.mjs +19 -13
  72. package/dist/validation/view-predicates/relation-with.d.ts +1 -1
  73. package/dist/validation/view.d.ts +1 -1
  74. package/dist/view-utils/index.d.ts +0 -1
  75. package/dist/view-utils/index.mjs +0 -1
  76. package/dist/views/likec4-views.d.ts +6 -0
  77. package/dist/views/likec4-views.mjs +31 -18
  78. package/dist/workspace/ProjectsManager.d.ts +23 -31
  79. package/dist/workspace/ProjectsManager.mjs +78 -89
  80. package/dist/workspace/WorkspaceManager.mjs +1 -1
  81. package/likec4lib/package.json +4 -0
  82. package/package.json +24 -28
  83. package/protocol/package.json +4 -0
  84. package/dist/view-utils/resolve-relative-paths.d.ts +0 -2
  85. package/dist/view-utils/resolve-relative-paths.mjs +0 -78
@@ -27,8 +27,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
27
27
  views,
28
28
  globals,
29
29
  likec4lib,
30
- deployments,
31
- imports
30
+ deployments
32
31
  } = document.parseResult.value;
33
32
  this.exportLibrary(likec4lib, docExports, document);
34
33
  this.exportSpecification(specifications, docExports, document);
@@ -205,7 +204,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
205
204
  let imported = imports;
206
205
  while (imported) {
207
206
  descendants.push(
208
- this.descriptions.createDescription(imported, imported.imported.$refText, document)
207
+ this.descriptions.createDescription(imported, imported.imported.$refText)
209
208
  );
210
209
  imported = imported.prev;
211
210
  }
@@ -1,6 +1,6 @@
1
1
  import { type ProjectId } from '@likec4/core';
2
2
  import { type AstNodeDescription, type ReferenceInfo, type Scope, type Stream, DefaultScopeProvider } from 'langium';
3
- import { type AstNodeDescriptionWithFqn, ast } from '../ast';
3
+ import { ast } from '../ast';
4
4
  import type { DeploymentsIndex, FqnIndex } from '../model';
5
5
  import type { LikeC4Services } from '../module';
6
6
  import type { IndexManager } from '../workspace';
@@ -10,7 +10,7 @@ export declare class LikeC4ScopeProvider extends DefaultScopeProvider {
10
10
  protected readonly indexManager: IndexManager;
11
11
  constructor(services: LikeC4Services);
12
12
  getScope(context: ReferenceInfo): Scope;
13
- protected genUniqueDescedants(of: () => ast.Element | ast.DeploymentNode | undefined): Generator<Stream<AstNodeDescriptionWithFqn>, void, any>;
13
+ protected genUniqueDescedants(of: () => ast.Element | ast.DeploymentNode | undefined): Generator<Stream<import("../ast").AstNodeDescriptionWithFqn>, void, any>;
14
14
  protected genScopeExtendElement({ element }: ast.ExtendElement): Generator<AstNodeDescription>;
15
15
  protected genScopeElementView({ viewOf, extends: ext }: ast.ElementView): Generator<AstNodeDescription>;
16
16
  protected getScopeForStrictFqnRef(projectId: ProjectId, container: ast.StrictFqnRef, context: ReferenceInfo): any;
@@ -2,12 +2,10 @@ import { nonexhaustive } from "@likec4/core";
2
2
  import {
3
3
  AstUtils,
4
4
  DefaultScopeProvider,
5
- DONE_RESULT,
6
5
  EMPTY_SCOPE,
7
6
  EMPTY_STREAM,
8
7
  MapScope,
9
8
  stream,
10
- StreamImpl,
11
9
  StreamScope
12
10
  } from "langium";
13
11
  import { ast, isFqnRefInsideGlobals, isFqnRefInsideModel } from "../ast.mjs";
@@ -81,6 +79,14 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
81
79
  *genScopeExtendElement({ element }) {
82
80
  if (element.el.$nodeDescription) {
83
81
  yield element.el.$nodeDescription;
82
+ yield {
83
+ ...element.el.$nodeDescription,
84
+ name: "this"
85
+ };
86
+ yield {
87
+ ...element.el.$nodeDescription,
88
+ name: "it"
89
+ };
84
90
  }
85
91
  yield* this.genUniqueDescedants(() => elementRef(element));
86
92
  }
@@ -231,16 +237,3 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
231
237
  return this.getProjectScope(projectId, referenceType, context);
232
238
  }
233
239
  }
234
- function lazyStream(fn) {
235
- return new StreamImpl(
236
- () => {
237
- return fn().iterator();
238
- },
239
- (iterator) => {
240
- if (iterator) {
241
- return iterator.next();
242
- }
243
- return DONE_RESULT;
244
- }
245
- );
246
- }
@@ -1,5 +1,6 @@
1
1
  import type { LikeC4ProjectJsonConfig } from '@likec4/config';
2
2
  import type { ComputedLikeC4ModelData } from '@likec4/core';
3
+ import { type LangiumDocument } from 'langium';
3
4
  import type { LiteralUnion } from 'type-fest';
4
5
  import { URI } from 'vscode-uri';
5
6
  import type { LikeC4LangiumDocument } from '../ast';
@@ -9,6 +10,7 @@ export declare function createTestServices(options?: {
9
10
  }): {
10
11
  services: any;
11
12
  addDocument: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
13
+ removeDocument: (doc: LangiumDocument | URI) => Promise<void>;
12
14
  parse: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
13
15
  validate: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<{
14
16
  document: LikeC4LangiumDocument;
@@ -63,18 +63,18 @@ export function createTestServices(options) {
63
63
  langiumDocuments.addDocument(document);
64
64
  return document;
65
65
  };
66
+ const removeDocument = async (doc) => {
67
+ const uri = doc instanceof URI ? doc : doc.uri;
68
+ await documentBuilder.update([], [uri]);
69
+ };
66
70
  const parse = async (input, uri) => {
67
71
  const document = await addDocument(input, uri);
68
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
69
- await documentBuilder.build([document], { validation: false });
70
- });
72
+ await documentBuilder.build([document], { validation: false });
71
73
  return document;
72
74
  };
73
75
  const validate = async (input, uri) => {
74
76
  const document = typeof input === "string" ? await addDocument(input, uri) : input;
75
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
76
- await documentBuilder.build([document], { validation: true });
77
- });
77
+ await documentBuilder.build([document], { validation: true });
78
78
  const diagnostics = document.diagnostics ?? [];
79
79
  const warnings = diagnostics.flatMap((d) => d.severity === DiagnosticSeverity.Warning ? d.message : []);
80
80
  const errors = diagnostics.flatMap((d) => d.severity === DiagnosticSeverity.Error ? d.message : []);
@@ -86,10 +86,8 @@ export function createTestServices(options) {
86
86
  };
87
87
  };
88
88
  const format = async (input, uri) => {
89
- const document = typeof input === "string" ? await parse(input, uri) : input;
90
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
91
- await documentBuilder.build([document], { validation: true });
92
- });
89
+ const document = typeof input === "string" ? await parse(stripIndent(input), uri) : input;
90
+ await documentBuilder.build([document], { validation: true });
93
91
  const edits = await formatter?.formatDocument(
94
92
  document,
95
93
  {
@@ -137,6 +135,7 @@ export function createTestServices(options) {
137
135
  return {
138
136
  services,
139
137
  addDocument,
138
+ removeDocument,
140
139
  parse,
141
140
  validate,
142
141
  validateAll,
@@ -156,7 +155,7 @@ export async function createMultiProjectTestServices(data) {
156
155
  const projects = {};
157
156
  for (const [name, files] of entries(data)) {
158
157
  const folderUri = UriUtils.joinPath(URI.parse(workspace), "src", name);
159
- services.shared.workspace.ProjectsManager.registerProject({
158
+ await services.shared.workspace.ProjectsManager.registerProject({
160
159
  config: {
161
160
  name,
162
161
  exclude: ["node_modules"]
@@ -1,4 +1,4 @@
1
- import { logError } from "../logger.mjs";
1
+ import { logWarnError } from "../logger.mjs";
2
2
  export class ADisposable {
3
3
  toDispose = [];
4
4
  isDisposed = false;
@@ -13,7 +13,7 @@ export class ADisposable {
13
13
  try {
14
14
  item.dispose();
15
15
  } catch (e) {
16
- logError(e);
16
+ logWarnError(e);
17
17
  }
18
18
  }
19
19
  }
@@ -16,7 +16,7 @@ export function safeCall(fn) {
16
16
  export function performanceNow() {
17
17
  try {
18
18
  return performance.now();
19
- } catch (e) {
19
+ } catch {
20
20
  return Date.now();
21
21
  }
22
22
  }
@@ -1,3 +1,3 @@
1
- import { type AstNode, type ValidationCheck } from 'langium';
1
+ import type { AstNode, ValidationCheck } from 'langium';
2
2
  export declare const RESERVED_WORDS: string[];
3
3
  export declare function tryOrLog<T extends AstNode>(fn: ValidationCheck<T>): ValidationCheck<T>;
@@ -4,4 +4,4 @@ import type { LikeC4Services } from '../module';
4
4
  export declare const deploymentNodeChecks: (services: LikeC4Services) => ValidationCheck<ast.DeploymentNode>;
5
5
  export declare const deployedInstanceChecks: (services: LikeC4Services) => ValidationCheck<ast.DeployedInstance>;
6
6
  export declare const deploymentRelationChecks: (services: LikeC4Services) => ValidationCheck<ast.DeploymentRelation>;
7
- export declare const extendDeploymentChecks: (services: LikeC4Services) => ValidationCheck<ast.ExtendDeployment>;
7
+ export declare const extendDeploymentChecks: (_services: LikeC4Services) => ValidationCheck<ast.ExtendDeployment>;
@@ -1,6 +1,8 @@
1
1
  import { FqnRef, isSameHierarchy, nonNullable } from "@likec4/core";
2
+ import { loggable } from "@likec4/log";
2
3
  import { AstUtils } from "langium";
3
4
  import { ast } from "../ast.mjs";
5
+ import { logger } from "../logger.mjs";
4
6
  import { projectIdFrom } from "../utils/index.mjs";
5
7
  import { RESERVED_WORDS, tryOrLog } from "./_shared.mjs";
6
8
  const { getDocument } = AstUtils;
@@ -88,6 +90,7 @@ export const deploymentRelationChecks = (services) => {
88
90
  try {
89
91
  sourceFqnRef = parser._resolveDeploymentRelationSource(el);
90
92
  } catch (e) {
93
+ logger.warn(loggable(e));
91
94
  accept("error", "DeploymentRelation source not resolved", {
92
95
  node: el,
93
96
  property: "source"
@@ -130,7 +133,7 @@ export const deploymentRelationChecks = (services) => {
130
133
  }
131
134
  });
132
135
  };
133
- export const extendDeploymentChecks = (services) => {
136
+ export const extendDeploymentChecks = (_services) => {
134
137
  return tryOrLog((el, accept) => {
135
138
  const target = el.deploymentNode.value.ref;
136
139
  if (!target || !ast.isDeploymentNode(target)) {
@@ -1,5 +1,6 @@
1
1
  import { type ValidationCheck } from 'langium';
2
2
  import { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
- export declare const dynamicViewStep: (services: LikeC4Services) => ValidationCheck<ast.DynamicViewStep>;
5
- export declare const dynamicViewDisplayVariant: (services: LikeC4Services) => ValidationCheck<ast.DynamicViewDisplayVariantProperty>;
4
+ export declare const dynamicViewStepSingle: (services: LikeC4Services) => ValidationCheck<ast.DynamicStepSingle>;
5
+ export declare const dynamicViewStepChain: (services: LikeC4Services) => ValidationCheck<ast.DynamicStepChain>;
6
+ export declare const dynamicViewDisplayVariant: (_services: LikeC4Services) => ValidationCheck<ast.DynamicViewDisplayVariantProperty>;
@@ -4,7 +4,7 @@ import { isEmpty } from "remeda";
4
4
  import { ast } from "../ast.mjs";
5
5
  import { elementRef } from "../utils/elementRef.mjs";
6
6
  import { tryOrLog } from "./_shared.mjs";
7
- export const dynamicViewStep = (services) => {
7
+ export const dynamicViewStepSingle = (services) => {
8
8
  const fqnIndex = services.likec4.FqnIndex;
9
9
  return tryOrLog((el, accept) => {
10
10
  const sourceEl = elementRef(el.source);
@@ -30,7 +30,26 @@ export const dynamicViewStep = (services) => {
30
30
  }
31
31
  });
32
32
  };
33
- export const dynamicViewDisplayVariant = (services) => {
33
+ export const dynamicViewStepChain = (services) => {
34
+ const fqnIndex = services.likec4.FqnIndex;
35
+ return tryOrLog((el, accept) => {
36
+ const source = el.source;
37
+ if (ast.isDynamicStepSingle(source) && source.isBackward) {
38
+ accept("error", "Invalid chain after backward step", {
39
+ node: el
40
+ });
41
+ }
42
+ const targetEl = elementRef(el.target);
43
+ const target = targetEl && fqnIndex.getFqn(targetEl);
44
+ if (!target) {
45
+ accept("error", "Target not found (not parsed/indexed yet)", {
46
+ node: el,
47
+ property: "target"
48
+ });
49
+ }
50
+ });
51
+ };
52
+ export const dynamicViewDisplayVariant = (_services) => {
34
53
  return tryOrLog((prop, accept) => {
35
54
  if (isEmpty(prop.value) || prop.value !== "diagram" && prop.value !== "sequence") {
36
55
  accept("error", 'Invalid display variant: "diagram" or "sequence" are allowed', {
@@ -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
- export declare const checkElementRef: (services: LikeC4Services) => ValidationCheck<ast.ElementRef>;
4
+ export declare const checkElementRef: (_services: LikeC4Services) => ValidationCheck<ast.ElementRef>;
@@ -1,6 +1,6 @@
1
1
  import { isReferenceToDeploymentModel } from "../utils/index.mjs";
2
2
  import { tryOrLog } from "./_shared.mjs";
3
- export const checkElementRef = (services) => {
3
+ export const checkElementRef = (_services) => {
4
4
  return tryOrLog((el, accept) => {
5
5
  if (isReferenceToDeploymentModel(el.modelElement)) {
6
6
  accept("error", "Only model elements allowed here", {
@@ -2,4 +2,3 @@ import { type ValidationCheck } from 'langium';
2
2
  import type { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  export declare const checkImportsFromPoject: (services: LikeC4Services) => ValidationCheck<ast.ImportsFromPoject>;
5
- export declare const checkImported: (services: LikeC4Services) => ValidationCheck<ast.Imported>;
@@ -23,8 +23,3 @@ export const checkImportsFromPoject = (services) => {
23
23
  }
24
24
  });
25
25
  };
26
- export const checkImported = (services) => {
27
- const fqnIndex = services.likec4.FqnIndex;
28
- return tryOrLog((el, accept) => {
29
- });
30
- };
@@ -4,7 +4,7 @@ import type { LikeC4Services } from '../module';
4
4
  export { LikeC4DocumentValidator } from './DocumentValidator';
5
5
  type Guard<N extends AstNode> = (n: AstNode) => n is N;
6
6
  type Guarded<G> = G extends Guard<infer N> ? N : never;
7
- declare const isValidatableAstNode: (n: AstNode) => n is ast.HexColor | ast.RGBAColor | ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewDisplayVariantProperty | ast.LinkProperty | ast.ViewStringProperty | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.MetadataBody | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.RelationStringProperty | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.SpecificationRelationshipKind | ast.GlobalStyle | ast.SpecificationColor | ast.NavigateToProperty | ast.DynamicViewStep | ast.ElementRef | ast.DeploymentRelation | ast.Tags | ast.SpecificationDeploymentNodeKind | ast.DynamicViewParallelSteps | ast.GlobalDynamicPredicateGroup | ast.Relation | ast.SpecificationElementKind | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyleGroup | ast.SpecificationTag | ast.ImportsFromPoject | ast.SpecificationRule;
7
+ declare const isValidatableAstNode: (n: AstNode) => n is ast.HexColor | ast.RGBAColor | ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewDisplayVariantProperty | ast.LinkProperty | ast.ViewStringProperty | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.DynamicStepChain | ast.DynamicStepSingle | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.MetadataBody | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.RelationStringProperty | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.DynamicViewParallelSteps | ast.ElementRef | ast.SpecificationRelationshipKind | ast.GlobalStyle | ast.SpecificationColor | ast.NavigateToProperty | ast.DeploymentRelation | ast.Tags | ast.SpecificationDeploymentNodeKind | ast.GlobalDynamicPredicateGroup | ast.Relation | ast.SpecificationElementKind | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyleGroup | ast.SpecificationTag | ast.ImportsFromPoject | ast.SpecificationRule;
8
8
  type ValidatableAstNode = Guarded<typeof isValidatableAstNode>;
9
9
  export declare function checksFromDiagnostics(doc: LikeC4LangiumDocument): {
10
10
  isValid: (n: ValidatableAstNode) => boolean;
@@ -1,3 +1,5 @@
1
+ import { onNextTick } from "@likec4/core/utils";
2
+ import { loggable } from "@likec4/log";
1
3
  import { DocumentState } from "langium";
2
4
  import { isNullish } from "remeda";
3
5
  import { DiagnosticSeverity } from "vscode-languageserver-types";
@@ -9,10 +11,10 @@ import {
9
11
  deploymentRelationChecks,
10
12
  extendDeploymentChecks
11
13
  } from "./deployment-checks.mjs";
12
- import { dynamicViewDisplayVariant, dynamicViewStep } from "./dynamic-view.mjs";
14
+ import { dynamicViewDisplayVariant, dynamicViewStepChain, dynamicViewStepSingle } from "./dynamic-view.mjs";
13
15
  import { checkElement } from "./element.mjs";
14
16
  import { checkElementRef } from "./element-ref.mjs";
15
- import { checkImported, checkImportsFromPoject } from "./imports.mjs";
17
+ import { checkImportsFromPoject } from "./imports.mjs";
16
18
  import {
17
19
  colorLiteralRuleChecks,
18
20
  iconPropertyRuleChecks,
@@ -57,7 +59,8 @@ const isValidatableAstNode = validatableAstNodeGuards([
57
59
  ast.isFqnExpr,
58
60
  ast.isRelationExpr,
59
61
  ast.isDynamicViewParallelSteps,
60
- ast.isDynamicViewStep,
62
+ ast.isDynamicStepChain,
63
+ ast.isDynamicStepSingle,
61
64
  ast.isDeploymentViewRule,
62
65
  ast.isDeploymentViewRulePredicate,
63
66
  ast.isExpressionV2,
@@ -141,7 +144,8 @@ export function registerValidationChecks(services) {
141
144
  GlobalPredicateGroup: checkGlobalPredicate(services),
142
145
  GlobalDynamicPredicateGroup: checkGlobalPredicate(services),
143
146
  GlobalStyleId: checkGlobalStyleId(services),
144
- DynamicViewStep: dynamicViewStep(services),
147
+ DynamicStepSingle: dynamicViewStepSingle(services),
148
+ DynamicStepChain: dynamicViewStepChain(services),
145
149
  LikeC4View: viewChecks(services),
146
150
  Element: checkElement(services),
147
151
  ElementRef: checkElementRef(services),
@@ -155,20 +159,22 @@ export function registerValidationChecks(services) {
155
159
  IncomingRelationExpr: checkIncomingRelationExpr(services),
156
160
  OutgoingRelationExpr: checkOutgoingRelationExpr(services),
157
161
  ImportsFromPoject: checkImportsFromPoject(services),
158
- Imported: checkImported(services),
162
+ // Imported: checkImported(services),
159
163
  ColorLiteral: colorLiteralRuleChecks(services),
160
164
  DynamicViewDisplayVariantProperty: dynamicViewDisplayVariant(services)
161
165
  });
162
166
  const connection = services.shared.lsp.Connection;
163
167
  if (connection) {
164
- services.shared.workspace.DocumentBuilder.onUpdate((_, deleted) => {
165
- for (const uri of deleted) {
166
- logger.debug(`clear diagnostics for deleted ${uri.path}`);
167
- void connection.sendDiagnostics({
168
- uri: uri.toString(),
169
- diagnostics: []
170
- });
171
- }
168
+ onNextTick(() => {
169
+ services.shared.workspace.DocumentBuilder.onUpdate((_, deleted) => {
170
+ for (const uri of deleted) {
171
+ logger.debug(`clear diagnostics for deleted ${uri.path}`);
172
+ connection.sendDiagnostics({
173
+ uri: uri.toString(),
174
+ diagnostics: []
175
+ }).catch((e) => logger.error(loggable(e)));
176
+ }
177
+ });
172
178
  });
173
179
  }
174
180
  }
@@ -1,4 +1,4 @@
1
- import { type ValidationCheck } from 'langium';
1
+ import type { ValidationCheck } from 'langium';
2
2
  import { ast } from '../../ast';
3
3
  import type { LikeC4Services } from '../../module';
4
4
  export declare const checkRelationExprWith: (_services: LikeC4Services) => ValidationCheck<ast.RelationExprWith>;
@@ -1,4 +1,4 @@
1
- import { type ValidationCheck } from 'langium';
1
+ import type { ValidationCheck } from 'langium';
2
2
  import { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  export declare const viewChecks: (services: LikeC4Services) => ValidationCheck<ast.LikeC4View>;
@@ -1,2 +1 @@
1
1
  export * from './assignNavigateTo';
2
- export * from './resolve-relative-paths';
@@ -1,2 +1 @@
1
1
  export * from "./assignNavigateTo.mjs";
2
- export * from "./resolve-relative-paths.mjs";
@@ -44,6 +44,10 @@ export interface LikeC4Views {
44
44
  export declare class DefaultLikeC4Views implements LikeC4Views {
45
45
  private services;
46
46
  private cache;
47
+ /**
48
+ * Set of viewIds with reported errors
49
+ * value is `${projectId}-${viewId}`
50
+ */
47
51
  private viewsWithReportedErrors;
48
52
  private ModelBuilder;
49
53
  constructor(services: LikeC4Services);
@@ -57,5 +61,7 @@ export declare class DefaultLikeC4Views implements LikeC4Views {
57
61
  * Open a view in the preview panel.
58
62
  */
59
63
  openView(viewId: ViewId, projectId: ProjectId): Promise<void>;
64
+ private reportViewError;
65
+ private viewSucceed;
60
66
  }
61
67
  export {};
@@ -1,6 +1,6 @@
1
1
  import { loggable } from "@likec4/log";
2
2
  import { values } from "remeda";
3
- import { logError, logger as rootLogger, logWarnError } from "../logger.mjs";
3
+ import { logger as rootLogger, logWarnError } from "../logger.mjs";
4
4
  import { performanceMark } from "../utils/index.mjs";
5
5
  const viewsLogger = rootLogger.getChild("views");
6
6
  export class DefaultLikeC4Views {
@@ -9,6 +9,10 @@ export class DefaultLikeC4Views {
9
9
  this.ModelBuilder = services.likec4.ModelBuilder;
10
10
  }
11
11
  cache = /* @__PURE__ */ new WeakMap();
12
+ /**
13
+ * Set of viewIds with reported errors
14
+ * value is `${projectId}-${viewId}`
15
+ */
12
16
  viewsWithReportedErrors = /* @__PURE__ */ new Set();
13
17
  ModelBuilder;
14
18
  get layouter() {
@@ -25,10 +29,11 @@ export class DefaultLikeC4Views {
25
29
  return [];
26
30
  }
27
31
  const m0 = performanceMark();
28
- const logger = projectId ? viewsLogger.getChild(projectId) : viewsLogger;
32
+ projectId ??= likeC4Model.project.id;
33
+ const logger = viewsLogger.getChild(projectId);
29
34
  logger.debug`layoutAll: ${views.length} views`;
30
35
  const tasks = [];
31
- const specification = likeC4Model.$data.specification;
36
+ const styles = likeC4Model.$styles;
32
37
  const results = [];
33
38
  for (const view of views) {
34
39
  let cached = this.cache.get(view);
@@ -39,15 +44,14 @@ export class DefaultLikeC4Views {
39
44
  }
40
45
  tasks.push({
41
46
  view,
42
- specification
47
+ styles
43
48
  });
44
49
  }
45
50
  if (tasks.length > 0) {
46
51
  await this.layouter.batchLayout({
47
52
  batch: tasks,
48
53
  onSuccess: (task, result) => {
49
- this.viewsWithReportedErrors.delete(task.view.id);
50
- this.cache.set(task.view, result);
54
+ this.viewSucceed(task.view, projectId, result);
51
55
  results.push(result);
52
56
  },
53
57
  onError: (task, error) => {
@@ -65,7 +69,8 @@ export class DefaultLikeC4Views {
65
69
  async layoutView(viewId, projectId, cancelToken) {
66
70
  const model = await this.ModelBuilder.buildLikeC4Model(projectId, cancelToken);
67
71
  const view = model.findView(viewId)?.$view;
68
- const logger = projectId ? viewsLogger.getChild(projectId) : viewsLogger;
72
+ projectId ??= model.project.id;
73
+ const logger = viewsLogger.getChild(projectId);
69
74
  if (!view) {
70
75
  logger.warn`layoutView ${viewId} not found`;
71
76
  return null;
@@ -73,25 +78,21 @@ export class DefaultLikeC4Views {
73
78
  let cached = this.cache.get(view);
74
79
  if (cached) {
75
80
  logger.debug`layout ${viewId} from cache`;
76
- return await Promise.resolve(cached);
81
+ return await Promise.resolve().then(() => cached);
77
82
  }
78
83
  try {
79
84
  const m0 = performanceMark();
80
85
  const result = await this.layouter.layout({
81
86
  view,
82
- specification: model.$data.specification
87
+ styles: model.$styles
83
88
  });
84
- this.viewsWithReportedErrors.delete(viewId);
85
- this.cache.set(view, result);
89
+ this.viewSucceed(view, projectId, result);
86
90
  logger.debug(`layout {viewId} ready in ${m0.pretty}`, { viewId });
87
91
  return result;
88
92
  } catch (e) {
89
- if (!this.viewsWithReportedErrors.has(viewId)) {
90
- const errMessage = loggable(e);
91
- this.services.shared.lsp.Connection?.window.showErrorMessage(`LikeC4: ${errMessage}`);
92
- this.viewsWithReportedErrors.add(viewId);
93
- logError(e);
94
- }
93
+ const errMessage = loggable(e);
94
+ logger.warn(errMessage);
95
+ this.reportViewError(view, projectId, errMessage);
95
96
  return Promise.reject(e);
96
97
  }
97
98
  }
@@ -113,7 +114,7 @@ export class DefaultLikeC4Views {
113
114
  const tasks = views.map(async (view) => {
114
115
  const { dot, svg } = await this.layouter.svg({
115
116
  view,
116
- specification: likeC4Model.$data.specification
117
+ styles: likeC4Model.$styles
117
118
  });
118
119
  return {
119
120
  id: view.id,
@@ -139,6 +140,18 @@ export class DefaultLikeC4Views {
139
140
  async openView(viewId, projectId) {
140
141
  await this.services.Rpc.openView({ viewId, projectId });
141
142
  }
143
+ reportViewError(view, projectId, error) {
144
+ const key = `${projectId}-${view.id}`;
145
+ if (!this.viewsWithReportedErrors.has(key)) {
146
+ this.services.shared.lsp.Connection?.window.showErrorMessage(`LikeC4: ${error}`);
147
+ this.viewsWithReportedErrors.add(key);
148
+ }
149
+ }
150
+ viewSucceed(view, projectId, result) {
151
+ const key = `${projectId}-${view.id}`;
152
+ this.viewsWithReportedErrors.delete(key);
153
+ this.cache.set(view, result);
154
+ }
142
155
  // async overviewGraph(): Promise<OverviewGraph> {
143
156
  // const KEY = 'OverviewGraph'
144
157
  // const cache = this.services.ValidatedWorkspaceCache as WorkspaceCache<string, OverviewGraph>
@@ -1,6 +1,7 @@
1
- import { type LikeC4ProjectConfig } from '@likec4/config';
2
- import type { NonEmptyReadonlyArray, ProjectId } from '@likec4/core';
3
- import { type Cancellation, type FileSystemNode, type LangiumDocument, URI, WorkspaceCache } from 'langium';
1
+ import { type LikeC4ProjectConfig, type LikeC4ProjectConfigInput } from '@likec4/config';
2
+ import type { NonEmptyReadonlyArray } from '@likec4/core';
3
+ import type { scalar } from '@likec4/core/types';
4
+ import { type Cancellation, type LangiumDocument, URI, WorkspaceCache } from 'langium';
4
5
  import type { Tagged } from 'type-fest';
5
6
  import type { LikeC4SharedServices } from '../module';
6
7
  /**
@@ -10,14 +11,14 @@ import type { LikeC4SharedServices } from '../module';
10
11
  export type ProjectFolder = Tagged<string, 'ProjectFolder'>;
11
12
  export declare function ProjectFolder(folder: URI | string): ProjectFolder;
12
13
  interface ProjectData {
13
- id: ProjectId;
14
+ id: scalar.ProjectId;
14
15
  config: LikeC4ProjectConfig;
15
16
  folder: ProjectFolder;
16
17
  folderUri: URI;
17
18
  exclude?: (path: string) => boolean;
18
19
  }
19
20
  export interface Project {
20
- id: ProjectId;
21
+ id: scalar.ProjectId;
21
22
  folderUri: URI;
22
23
  config: LikeC4ProjectConfig;
23
24
  }
@@ -28,21 +29,7 @@ export declare class ProjectsManager {
28
29
  * The global project ID used for all documents
29
30
  * that are not part of a specific project.
30
31
  */
31
- static readonly DefaultProjectId: ProjectId;
32
- private static DefaultProject;
33
- /**
34
- * The mapping between project config files and project IDs.
35
- */
36
- private projectIdToFolder;
37
- /**
38
- * Registered projects.
39
- * Sorted descending by the number of segments in the folder path.
40
- * This ensures that the most specific project is used for a document.
41
- */
42
- private _projects;
43
- private excludedDocuments;
44
- private get defaultGlobalProject();
45
- private reloadProjectsLimiter;
32
+ static readonly DefaultProjectId: scalar.ProjectId;
46
33
  constructor(services: LikeC4SharedServices);
47
34
  /**
48
35
  * Returns:
@@ -51,16 +38,16 @@ export declare class ProjectsManager {
51
38
  * - the ID of the only project
52
39
  * - undefined if there are multiple projects.
53
40
  */
54
- get defaultProjectId(): ProjectId | undefined;
55
- set defaultProjectId(id: ProjectId | undefined);
56
- get all(): NonEmptyReadonlyArray<ProjectId>;
57
- getProject(arg: ProjectId | LangiumDocument): Project;
41
+ get defaultProjectId(): scalar.ProjectId | undefined;
42
+ set defaultProjectId(id: string | scalar.ProjectId | undefined);
43
+ get all(): NonEmptyReadonlyArray<scalar.ProjectId>;
44
+ getProject(arg: scalar.ProjectId | LangiumDocument): Project;
58
45
  /**
59
46
  * Validates and ensures the project ID.
60
47
  * If no project ID is specified, returns default project ID
61
48
  * If there are multiple projects and default project is not set, throws an error
62
49
  */
63
- ensureProjectId(projectId?: ProjectId | undefined): ProjectId;
50
+ ensureProjectId(projectId?: scalar.ProjectId | undefined): scalar.ProjectId;
64
51
  hasMultipleProjects(): boolean;
65
52
  /**
66
53
  * Checks if the specified document should be excluded from processing.
@@ -77,20 +64,25 @@ export declare class ProjectsManager {
77
64
  *
78
65
  * @param entry The file system entry to check
79
66
  */
80
- loadConfigFile(entry: FileSystemNode): Promise<ProjectData | undefined>;
67
+ registerConfigFile(configFile: URI): Promise<ProjectData | undefined>;
81
68
  /**
82
69
  * Registers (or reloads) likec4 project by config file or config object.
83
70
  * If there is some project registered at same folder, it will be reloaded.
84
71
  */
85
72
  registerProject(opts: URI | {
86
- config: LikeC4ProjectConfig;
73
+ config: LikeC4ProjectConfigInput;
87
74
  folderUri: URI | string;
88
75
  }): Promise<ProjectData>;
89
- belongsTo(document: LangiumDocument | URI | string): ProjectId;
90
- reloadProjects(token?: Cancellation.CancellationToken): Promise<void>;
91
- protected uniqueProjectId(name: string): ProjectId;
76
+ /**
77
+ * Registers (or reloads) likec4 project by config file or config object.
78
+ * If there is some project registered at same folder, it will be reloaded.
79
+ */
80
+ private _registerProject;
81
+ belongsTo(document: LangiumDocument | URI | string): scalar.ProjectId;
82
+ reloadProjects(): Promise<void>;
83
+ protected uniqueProjectId(name: string): scalar.ProjectId;
92
84
  protected resetProjectIds(): void;
93
- protected rebuidDocuments(): Promise<void>;
85
+ protected rebuidDocuments(cancelToken?: Cancellation.CancellationToken): Promise<void>;
94
86
  protected findProjectForDocument(documentUri: string): any;
95
87
  protected get mappingsToProject(): WorkspaceCache<string, Pick<ProjectData, 'id' | 'config' | 'exclude'>>;
96
88
  }