@likec4/language-server 1.40.0 → 1.42.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 (94) 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 +4 -9
  7. package/dist/ast.mjs +0 -10
  8. package/dist/bundled.mjs +4158 -3687
  9. package/dist/documentation/documentation-provider.mjs +1 -1
  10. package/dist/filesystem/FileSystemWatcher.d.ts +2 -2
  11. package/dist/filesystem/index.d.ts +1 -1
  12. package/dist/formatting/LikeC4Formatter.mjs +42 -10
  13. package/dist/formatting/utils.d.ts +3 -3
  14. package/dist/formatting/utils.mjs +1 -1
  15. package/dist/generated/ast.d.ts +40 -19
  16. package/dist/generated/ast.mjs +71 -26
  17. package/dist/generated/grammar.mjs +1 -1
  18. package/dist/logger.d.ts +1 -1
  19. package/dist/logger.mjs +3 -0
  20. package/dist/lsp/CompletionProvider.mjs +1 -1
  21. package/dist/lsp/DocumentLinkProvider.d.ts +1 -1
  22. package/dist/lsp/DocumentLinkProvider.mjs +1 -1
  23. package/dist/lsp/DocumentSymbolProvider.mjs +1 -1
  24. package/dist/lsp/HoverProvider.mjs +14 -2
  25. package/dist/mcp/NoopLikeC4MCPServer.d.ts +1 -1
  26. package/dist/mcp/NoopLikeC4MCPServer.mjs +1 -1
  27. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +4 -1
  28. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +3 -3
  29. package/dist/mcp/server/WithMCPServer.mjs +2 -2
  30. package/dist/mcp/tools/_common.mjs +2 -2
  31. package/dist/model/builder/MergedSpecification.d.ts +3 -3
  32. package/dist/model/builder/MergedSpecification.mjs +37 -59
  33. package/dist/model/builder/buildModel.mjs +14 -17
  34. package/dist/model/model-builder.d.ts +1 -1
  35. package/dist/model/model-builder.mjs +12 -9
  36. package/dist/model/model-locator.d.ts +5 -0
  37. package/dist/model/model-locator.mjs +40 -3
  38. package/dist/model/model-parser-where.mjs +1 -2
  39. package/dist/model/model-parser.d.ts +91 -47
  40. package/dist/model/parser/Base.d.ts +13 -7
  41. package/dist/model/parser/Base.mjs +32 -21
  42. package/dist/model/parser/DeploymentModelParser.d.ts +9 -5
  43. package/dist/model/parser/DeploymentModelParser.mjs +49 -47
  44. package/dist/model/parser/DeploymentViewParser.d.ts +9 -5
  45. package/dist/model/parser/DeploymentViewParser.mjs +1 -2
  46. package/dist/model/parser/FqnRefParser.d.ts +12 -6
  47. package/dist/model/parser/FqnRefParser.mjs +28 -15
  48. package/dist/model/parser/GlobalsParser.d.ts +16 -7
  49. package/dist/model/parser/GlobalsParser.mjs +5 -3
  50. package/dist/model/parser/ImportsParser.d.ts +8 -5
  51. package/dist/model/parser/ImportsParser.mjs +4 -2
  52. package/dist/model/parser/ModelParser.d.ts +9 -5
  53. package/dist/model/parser/ModelParser.mjs +42 -42
  54. package/dist/model/parser/PredicatesParser.d.ts +9 -5
  55. package/dist/model/parser/SpecificationParser.d.ts +8 -5
  56. package/dist/model/parser/SpecificationParser.mjs +17 -23
  57. package/dist/model/parser/ValueConverter.mjs +1 -1
  58. package/dist/model/parser/ViewsParser.d.ts +20 -7
  59. package/dist/model/parser/ViewsParser.mjs +125 -35
  60. package/dist/model-change/ModelChanges.d.ts +1 -1
  61. package/dist/module.mjs +3 -2
  62. package/dist/protocol.d.ts +28 -4
  63. package/dist/references/scope-computation.mjs +2 -3
  64. package/dist/references/scope-provider.d.ts +2 -2
  65. package/dist/references/scope-provider.mjs +8 -15
  66. package/dist/test/testServices.d.ts +2 -0
  67. package/dist/test/testServices.mjs +32 -35
  68. package/dist/utils/disposable.mjs +2 -2
  69. package/dist/utils/index.mjs +1 -1
  70. package/dist/validation/_shared.d.ts +1 -1
  71. package/dist/validation/deployment-checks.d.ts +1 -1
  72. package/dist/validation/deployment-checks.mjs +4 -1
  73. package/dist/validation/dynamic-view.d.ts +3 -2
  74. package/dist/validation/dynamic-view.mjs +21 -2
  75. package/dist/validation/element-ref.d.ts +2 -2
  76. package/dist/validation/element-ref.mjs +1 -1
  77. package/dist/validation/imports.d.ts +0 -1
  78. package/dist/validation/imports.mjs +0 -5
  79. package/dist/validation/index.d.ts +1 -1
  80. package/dist/validation/index.mjs +19 -13
  81. package/dist/validation/view-predicates/relation-with.d.ts +1 -1
  82. package/dist/validation/view.d.ts +1 -1
  83. package/dist/view-utils/index.d.ts +0 -1
  84. package/dist/view-utils/index.mjs +0 -1
  85. package/dist/views/likec4-views.d.ts +6 -0
  86. package/dist/views/likec4-views.mjs +31 -18
  87. package/dist/workspace/ProjectsManager.d.ts +23 -31
  88. package/dist/workspace/ProjectsManager.mjs +78 -89
  89. package/dist/workspace/WorkspaceManager.mjs +1 -1
  90. package/likec4lib/package.json +4 -0
  91. package/package.json +25 -29
  92. package/protocol/package.json +4 -0
  93. package/dist/view-utils/resolve-relative-paths.d.ts +0 -2
  94. package/dist/view-utils/resolve-relative-paths.mjs +0 -78
@@ -25,31 +25,29 @@ export function createTestServices(options) {
25
25
  async function initialize() {
26
26
  if (isInitialized) return;
27
27
  isInitialized = true;
28
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
29
- services.shared.workspace.ConfigurationProvider.updateConfiguration({
30
- settings: { likec4: { formatting: { quoteStyle: "single" } } }
31
- });
32
- services.shared.workspace.WorkspaceManager.initialize({
33
- capabilities: {},
34
- processId: null,
35
- rootUri: workspaceFolder.uri,
36
- workspaceFolders: [workspaceFolder]
37
- });
38
- await services.shared.workspace.WorkspaceManager.initializeWorkspace([workspaceFolder]);
39
- if (projectConfig) {
40
- const projectFolderUri = Utils.resolvePath(workspaceUri, "src");
41
- services.shared.workspace.ProjectsManager.registerProject({
42
- config: {
43
- name: projectConfig?.name || "test-project",
44
- title: projectConfig?.title || "Test Project",
45
- contactPerson: projectConfig?.contactPerson || "Unknown",
46
- imageAliases: projectConfig?.imageAliases || {},
47
- exclude: projectConfig?.exclude || ["node_modules"]
48
- },
49
- folderUri: projectFolderUri
50
- });
51
- }
28
+ services.shared.workspace.ConfigurationProvider.updateConfiguration({
29
+ settings: { likec4: { formatting: { quoteStyle: "single" } } }
52
30
  });
31
+ services.shared.workspace.WorkspaceManager.initialize({
32
+ capabilities: {},
33
+ processId: null,
34
+ rootUri: workspaceFolder.uri,
35
+ workspaceFolders: [workspaceFolder]
36
+ });
37
+ await services.shared.workspace.WorkspaceManager.initializeWorkspace([workspaceFolder]);
38
+ if (projectConfig) {
39
+ const projectFolderUri = Utils.resolvePath(workspaceUri, "src");
40
+ await services.shared.workspace.ProjectsManager.registerProject({
41
+ config: {
42
+ name: projectConfig?.name || "test-project",
43
+ title: projectConfig?.title || "Test Project",
44
+ contactPerson: projectConfig?.contactPerson || "Unknown",
45
+ imageAliases: projectConfig?.imageAliases || {},
46
+ exclude: projectConfig?.exclude || ["node_modules"]
47
+ },
48
+ folderUri: projectFolderUri
49
+ });
50
+ }
53
51
  }
54
52
  const addDocument = async (input, uri) => {
55
53
  await initialize();
@@ -65,18 +63,18 @@ export function createTestServices(options) {
65
63
  langiumDocuments.addDocument(document);
66
64
  return document;
67
65
  };
66
+ const removeDocument = async (doc) => {
67
+ const uri = doc instanceof URI ? doc : doc.uri;
68
+ await documentBuilder.update([], [uri]);
69
+ };
68
70
  const parse = async (input, uri) => {
69
71
  const document = await addDocument(input, uri);
70
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
71
- await documentBuilder.build([document], { validation: false });
72
- });
72
+ await documentBuilder.build([document], { validation: false });
73
73
  return document;
74
74
  };
75
75
  const validate = async (input, uri) => {
76
76
  const document = typeof input === "string" ? await addDocument(input, uri) : input;
77
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
78
- await documentBuilder.build([document], { validation: true });
79
- });
77
+ await documentBuilder.build([document], { validation: true });
80
78
  const diagnostics = document.diagnostics ?? [];
81
79
  const warnings = diagnostics.flatMap((d) => d.severity === DiagnosticSeverity.Warning ? d.message : []);
82
80
  const errors = diagnostics.flatMap((d) => d.severity === DiagnosticSeverity.Error ? d.message : []);
@@ -88,10 +86,8 @@ export function createTestServices(options) {
88
86
  };
89
87
  };
90
88
  const format = async (input, uri) => {
91
- const document = typeof input === "string" ? await parse(input, uri) : input;
92
- await services.shared.workspace.WorkspaceLock.write(async (_cancelToken) => {
93
- await documentBuilder.build([document], { validation: true });
94
- });
89
+ const document = typeof input === "string" ? await parse(stripIndent(input), uri) : input;
90
+ await documentBuilder.build([document], { validation: true });
95
91
  const edits = await formatter?.formatDocument(
96
92
  document,
97
93
  {
@@ -139,6 +135,7 @@ export function createTestServices(options) {
139
135
  return {
140
136
  services,
141
137
  addDocument,
138
+ removeDocument,
142
139
  parse,
143
140
  validate,
144
141
  validateAll,
@@ -158,7 +155,7 @@ export async function createMultiProjectTestServices(data) {
158
155
  const projects = {};
159
156
  for (const [name, files] of entries(data)) {
160
157
  const folderUri = UriUtils.joinPath(URI.parse(workspace), "src", name);
161
- services.shared.workspace.ProjectsManager.registerProject({
158
+ await services.shared.workspace.ProjectsManager.registerProject({
162
159
  config: {
163
160
  name,
164
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
  }