@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.
- package/browser/package.json +4 -0
- package/browser-worker/package.json +4 -0
- package/dist/LikeC4LanguageServices.d.ts +1 -1
- package/dist/LikeC4LanguageServices.mjs +3 -2
- package/dist/Rpc.mjs +30 -24
- package/dist/ast.d.ts +4 -9
- package/dist/ast.mjs +0 -10
- package/dist/bundled.mjs +4158 -3687
- package/dist/documentation/documentation-provider.mjs +1 -1
- package/dist/filesystem/FileSystemWatcher.d.ts +2 -2
- package/dist/filesystem/index.d.ts +1 -1
- package/dist/formatting/LikeC4Formatter.mjs +42 -10
- package/dist/formatting/utils.d.ts +3 -3
- package/dist/formatting/utils.mjs +1 -1
- package/dist/generated/ast.d.ts +40 -19
- package/dist/generated/ast.mjs +71 -26
- package/dist/generated/grammar.mjs +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.mjs +3 -0
- package/dist/lsp/CompletionProvider.mjs +1 -1
- package/dist/lsp/DocumentLinkProvider.d.ts +1 -1
- package/dist/lsp/DocumentLinkProvider.mjs +1 -1
- package/dist/lsp/DocumentSymbolProvider.mjs +1 -1
- package/dist/lsp/HoverProvider.mjs +14 -2
- package/dist/mcp/NoopLikeC4MCPServer.d.ts +1 -1
- package/dist/mcp/NoopLikeC4MCPServer.mjs +1 -1
- package/dist/mcp/server/StdioLikeC4MCPServer.mjs +4 -1
- package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +3 -3
- package/dist/mcp/server/WithMCPServer.mjs +2 -2
- package/dist/mcp/tools/_common.mjs +2 -2
- package/dist/model/builder/MergedSpecification.d.ts +3 -3
- package/dist/model/builder/MergedSpecification.mjs +37 -59
- package/dist/model/builder/buildModel.mjs +14 -17
- package/dist/model/model-builder.d.ts +1 -1
- package/dist/model/model-builder.mjs +12 -9
- package/dist/model/model-locator.d.ts +5 -0
- package/dist/model/model-locator.mjs +40 -3
- package/dist/model/model-parser-where.mjs +1 -2
- package/dist/model/model-parser.d.ts +91 -47
- package/dist/model/parser/Base.d.ts +13 -7
- package/dist/model/parser/Base.mjs +32 -21
- package/dist/model/parser/DeploymentModelParser.d.ts +9 -5
- package/dist/model/parser/DeploymentModelParser.mjs +49 -47
- package/dist/model/parser/DeploymentViewParser.d.ts +9 -5
- package/dist/model/parser/DeploymentViewParser.mjs +1 -2
- package/dist/model/parser/FqnRefParser.d.ts +12 -6
- package/dist/model/parser/FqnRefParser.mjs +28 -15
- package/dist/model/parser/GlobalsParser.d.ts +16 -7
- package/dist/model/parser/GlobalsParser.mjs +5 -3
- package/dist/model/parser/ImportsParser.d.ts +8 -5
- package/dist/model/parser/ImportsParser.mjs +4 -2
- package/dist/model/parser/ModelParser.d.ts +9 -5
- package/dist/model/parser/ModelParser.mjs +42 -42
- package/dist/model/parser/PredicatesParser.d.ts +9 -5
- package/dist/model/parser/SpecificationParser.d.ts +8 -5
- package/dist/model/parser/SpecificationParser.mjs +17 -23
- package/dist/model/parser/ValueConverter.mjs +1 -1
- package/dist/model/parser/ViewsParser.d.ts +20 -7
- package/dist/model/parser/ViewsParser.mjs +125 -35
- package/dist/model-change/ModelChanges.d.ts +1 -1
- package/dist/module.mjs +3 -2
- package/dist/protocol.d.ts +28 -4
- package/dist/references/scope-computation.mjs +2 -3
- package/dist/references/scope-provider.d.ts +2 -2
- package/dist/references/scope-provider.mjs +8 -15
- package/dist/test/testServices.d.ts +2 -0
- package/dist/test/testServices.mjs +32 -35
- package/dist/utils/disposable.mjs +2 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/validation/_shared.d.ts +1 -1
- package/dist/validation/deployment-checks.d.ts +1 -1
- package/dist/validation/deployment-checks.mjs +4 -1
- package/dist/validation/dynamic-view.d.ts +3 -2
- package/dist/validation/dynamic-view.mjs +21 -2
- package/dist/validation/element-ref.d.ts +2 -2
- package/dist/validation/element-ref.mjs +1 -1
- package/dist/validation/imports.d.ts +0 -1
- package/dist/validation/imports.mjs +0 -5
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.mjs +19 -13
- package/dist/validation/view-predicates/relation-with.d.ts +1 -1
- package/dist/validation/view.d.ts +1 -1
- package/dist/view-utils/index.d.ts +0 -1
- package/dist/view-utils/index.mjs +0 -1
- package/dist/views/likec4-views.d.ts +6 -0
- package/dist/views/likec4-views.mjs +31 -18
- package/dist/workspace/ProjectsManager.d.ts +23 -31
- package/dist/workspace/ProjectsManager.mjs +78 -89
- package/dist/workspace/WorkspaceManager.mjs +1 -1
- package/likec4lib/package.json +4 -0
- package/package.json +25 -29
- package/protocol/package.json +4 -0
- package/dist/view-utils/resolve-relative-paths.d.ts +0 -2
- package/dist/view-utils/resolve-relative-paths.mjs +0 -78
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as c4 from "@likec4/core";
|
|
2
|
+
import { exact } from "@likec4/core";
|
|
2
3
|
import { nonNullable } from "@likec4/core/utils";
|
|
4
|
+
import { loggable } from "@likec4/log";
|
|
3
5
|
import { filter, isNonNullish, isNullish, isTruthy, mapToObj, omitBy, pipe } from "remeda";
|
|
4
|
-
import { ast, parseMarkdownAsString,
|
|
5
|
-
import {
|
|
6
|
+
import { ast, parseMarkdownAsString, toRelationshipStyle } from "../../ast.mjs";
|
|
7
|
+
import { serverLogger } from "../../logger.mjs";
|
|
6
8
|
import { removeIndent } from "./Base.mjs";
|
|
9
|
+
const logger = serverLogger.getChild("SpecificationParser");
|
|
7
10
|
export function SpecificationParser(B) {
|
|
8
11
|
return class SpecificationParser extends B {
|
|
9
12
|
parseSpecification() {
|
|
@@ -20,14 +23,14 @@ export function SpecificationParser(B) {
|
|
|
20
23
|
try {
|
|
21
24
|
Object.assign(c4Specification.elements, this.parseElementSpecificationNode(elementSpec));
|
|
22
25
|
} catch (e) {
|
|
23
|
-
|
|
26
|
+
logger.warn(loggable(e));
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
for (const deploymentNodeSpec of specifications.flatMap((s) => s.deploymentNodes.filter(isValid))) {
|
|
27
30
|
try {
|
|
28
31
|
Object.assign(c4Specification.deployments, this.parseElementSpecificationNode(deploymentNodeSpec));
|
|
29
32
|
} catch (e) {
|
|
30
|
-
|
|
33
|
+
logger.warn(loggable(e));
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
const relations_specs = specifications.flatMap((s) => s.relationships.filter(this.isValid));
|
|
@@ -49,10 +52,10 @@ export function SpecificationParser(B) {
|
|
|
49
52
|
);
|
|
50
53
|
c4Specification.relationships[kindName] = {
|
|
51
54
|
...bodyProps,
|
|
52
|
-
...
|
|
55
|
+
...toRelationshipStyle(props.filter(ast.isRelationshipStyleProperty), this.isValid)
|
|
53
56
|
};
|
|
54
57
|
} catch (e) {
|
|
55
|
-
|
|
58
|
+
logger.warn(loggable(e));
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
const tags_specs = specifications.flatMap((s) => s.tags.filter(this.isValid));
|
|
@@ -68,7 +71,7 @@ export function SpecificationParser(B) {
|
|
|
68
71
|
};
|
|
69
72
|
}
|
|
70
73
|
} catch (e) {
|
|
71
|
-
|
|
74
|
+
logger.warn(loggable(e));
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
const colors_specs = specifications.flatMap((s) => s.colors.filter(isValid));
|
|
@@ -83,7 +86,7 @@ export function SpecificationParser(B) {
|
|
|
83
86
|
color: nonNullable(this.parseColorLiteral(color), `Color "${colorName}" is not valid: ${color}`)
|
|
84
87
|
};
|
|
85
88
|
} catch (e) {
|
|
86
|
-
|
|
89
|
+
logger.warn(loggable(e));
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
}
|
|
@@ -101,25 +104,16 @@ export function SpecificationParser(B) {
|
|
|
101
104
|
filter((p) => this.isValid(p)),
|
|
102
105
|
mapToObj((p) => [p.key, p.value])
|
|
103
106
|
);
|
|
104
|
-
const
|
|
105
|
-
{
|
|
106
|
-
title: void 0,
|
|
107
|
-
description: void 0,
|
|
108
|
-
technology: void 0
|
|
109
|
-
},
|
|
110
|
-
bodyProps
|
|
111
|
-
);
|
|
107
|
+
const baseProps = this.parseBaseProps(bodyProps);
|
|
112
108
|
const notation = removeIndent(parseMarkdownAsString(bodyProps.notation));
|
|
113
109
|
return {
|
|
114
|
-
[kindName]: {
|
|
115
|
-
...
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
...notation && { notation },
|
|
119
|
-
...tags && { tags },
|
|
110
|
+
[kindName]: exact({
|
|
111
|
+
...baseProps,
|
|
112
|
+
notation,
|
|
113
|
+
tags: tags ?? void 0,
|
|
120
114
|
...links && c4.isNonEmptyArray(links) && { links },
|
|
121
115
|
style
|
|
122
|
-
}
|
|
116
|
+
})
|
|
123
117
|
};
|
|
124
118
|
}
|
|
125
119
|
};
|
|
@@ -3,7 +3,7 @@ export class LikeC4ValueConverter extends DefaultValueConverter {
|
|
|
3
3
|
runConverter(rule, input, cstNode) {
|
|
4
4
|
if (rule.name === "MarkdownString") {
|
|
5
5
|
if (input.startsWith('"""') && input.endsWith('"""') || input.startsWith(`'''`) && input.endsWith(`'''`)) {
|
|
6
|
-
input = input.slice(
|
|
6
|
+
input = input.slice(2, -2);
|
|
7
7
|
}
|
|
8
8
|
return ValueConverter.convertString(input);
|
|
9
9
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as c4 from '@likec4/core';
|
|
2
|
+
import type { Except, Writable } from 'type-fest';
|
|
2
3
|
import { type ParsedAstDynamicView, type ParsedAstElementView, ast } from '../../ast';
|
|
3
4
|
import type { WithDeploymentView } from './DeploymentViewParser';
|
|
4
5
|
import type { WithPredicates } from './PredicatesParser';
|
|
@@ -18,8 +19,16 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
18
19
|
parseDynamicElementView(astNode: ast.DynamicView, additionalStyles: ViewRuleStyleOrGlobalRef[]): ParsedAstDynamicView;
|
|
19
20
|
parseDynamicViewRule(astRule: ast.DynamicViewRule): c4.DynamicViewRule;
|
|
20
21
|
parseDynamicViewIncludePredicate(astRule: ast.DynamicViewIncludePredicate): c4.DynamicViewIncludeRule;
|
|
21
|
-
parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.
|
|
22
|
-
|
|
22
|
+
parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicStepsParallel;
|
|
23
|
+
/**
|
|
24
|
+
* @returns non-empty array in case of step chain A -> B -> C
|
|
25
|
+
*/
|
|
26
|
+
parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicStep | c4.DynamicStepsSeries;
|
|
27
|
+
recursiveParseDynamicStepChain(node: ast.DynamicStepChain, callstack?: Array<[source: c4.Fqn, target: c4.Fqn]>): c4.DynamicStep[];
|
|
28
|
+
parseDynamicStepSingle(node: ast.DynamicStepSingle): c4.DynamicStep;
|
|
29
|
+
parseAbstractDynamicStep(astnode: ast.AbstractDynamicStep): Writable<Except<c4.DynamicStep, "source", {
|
|
30
|
+
requireExactProps: true;
|
|
31
|
+
}>>;
|
|
23
32
|
parsePredicate(astNode: ast.ExpressionV2): c4.ModelExpression;
|
|
24
33
|
parseElementPredicate(astNode: ast.FqnExprOrWith): c4.ModelFqnExpr.Any;
|
|
25
34
|
parseElementPredicateOrWhere(astNode: ast.FqnExprOrWhere): c4.ModelFqnExpr.OrWhere;
|
|
@@ -42,6 +51,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
42
51
|
parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
|
|
43
52
|
parseRelationExprOrWith(astNode: ast.RelationExprOrWith): c4.RelationExpr.Any;
|
|
44
53
|
parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
|
|
54
|
+
parseCustomRelationProperties(custom: ast.CustomRelationProperties | undefined): Except<c4.RelationExpr.Custom["customRelation"], "expr">;
|
|
45
55
|
parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
|
|
46
56
|
parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
|
|
47
57
|
parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
|
|
@@ -70,16 +80,19 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
70
80
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
71
81
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
72
82
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
73
|
-
|
|
74
|
-
title?: string | undefined;
|
|
75
|
-
description?: string | undefined;
|
|
76
|
-
technology?: string | undefined;
|
|
77
|
-
}, bodyProps: {
|
|
83
|
+
parseBaseProps(props: {
|
|
78
84
|
title?: ast.MarkdownOrString | undefined;
|
|
85
|
+
summary?: ast.MarkdownOrString | undefined;
|
|
79
86
|
description?: ast.MarkdownOrString | undefined;
|
|
80
87
|
technology?: ast.MarkdownOrString | undefined;
|
|
88
|
+
}, override?: {
|
|
89
|
+
title?: string | undefined;
|
|
90
|
+
summary?: string | undefined;
|
|
91
|
+
description?: string | undefined;
|
|
92
|
+
technology?: string | undefined;
|
|
81
93
|
}): {
|
|
82
94
|
title?: string;
|
|
95
|
+
summary?: c4.MarkdownOrString;
|
|
83
96
|
description?: c4.MarkdownOrString;
|
|
84
97
|
technology?: string;
|
|
85
98
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as c4 from "@likec4/core";
|
|
2
2
|
import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
|
|
3
|
-
import {
|
|
3
|
+
import { loggable } from "@likec4/log";
|
|
4
|
+
import { filter, find, isDefined, isEmpty, isNonNullish, isNumber, isTruthy, last, mapToObj, pipe } from "remeda";
|
|
4
5
|
import {
|
|
5
6
|
ast,
|
|
6
7
|
parseMarkdownAsString,
|
|
@@ -8,11 +9,12 @@ import {
|
|
|
8
9
|
toColor,
|
|
9
10
|
ViewOps
|
|
10
11
|
} from "../../ast.mjs";
|
|
11
|
-
import { logger
|
|
12
|
+
import { logger as mainLogger } from "../../logger.mjs";
|
|
12
13
|
import { stringHash } from "../../utils/index.mjs";
|
|
13
14
|
import { elementRef } from "../../utils/elementRef.mjs";
|
|
14
15
|
import { parseViewManualLayout } from "../../view-utils/manual-layout.mjs";
|
|
15
16
|
import { removeIndent, toSingleLine } from "./Base.mjs";
|
|
17
|
+
const logger = mainLogger.getChild("ViewsParser");
|
|
16
18
|
export function ViewsParser(B) {
|
|
17
19
|
return class ViewsParser extends B {
|
|
18
20
|
parseViews() {
|
|
@@ -22,7 +24,7 @@ export function ViewsParser(B) {
|
|
|
22
24
|
try {
|
|
23
25
|
return isValid(s) ? this.parseViewRuleStyleOrGlobalRef(s) : [];
|
|
24
26
|
} catch (e) {
|
|
25
|
-
|
|
27
|
+
logger.warn(loggable(e));
|
|
26
28
|
return [];
|
|
27
29
|
}
|
|
28
30
|
});
|
|
@@ -50,7 +52,7 @@ export function ViewsParser(B) {
|
|
|
50
52
|
view2.title = folder + " / " + (view2.title || view2.id);
|
|
51
53
|
}
|
|
52
54
|
} catch (e) {
|
|
53
|
-
|
|
55
|
+
logger.warn(loggable(e));
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -77,8 +79,7 @@ export function ViewsParser(B) {
|
|
|
77
79
|
viewOf ?? ""
|
|
78
80
|
);
|
|
79
81
|
}
|
|
80
|
-
const { title = null, description = null } = this.
|
|
81
|
-
{},
|
|
82
|
+
const { title = null, description = null } = this.parseBaseProps(
|
|
82
83
|
pipe(
|
|
83
84
|
body.props,
|
|
84
85
|
filter((p) => this.isValid(p)),
|
|
@@ -103,7 +104,7 @@ export function ViewsParser(B) {
|
|
|
103
104
|
try {
|
|
104
105
|
return this.isValid(n) ? this.parseElementViewRule(n) : [];
|
|
105
106
|
} catch (e) {
|
|
106
|
-
|
|
107
|
+
logger.warn(loggable(e));
|
|
107
108
|
return [];
|
|
108
109
|
}
|
|
109
110
|
})
|
|
@@ -150,7 +151,7 @@ export function ViewsParser(B) {
|
|
|
150
151
|
exprs.unshift(expr);
|
|
151
152
|
}
|
|
152
153
|
} catch (e) {
|
|
153
|
-
|
|
154
|
+
logger.warn(loggable(e));
|
|
154
155
|
}
|
|
155
156
|
if (!prev) {
|
|
156
157
|
break;
|
|
@@ -190,7 +191,7 @@ export function ViewsParser(B) {
|
|
|
190
191
|
}
|
|
191
192
|
nonexhaustive(rule);
|
|
192
193
|
} catch (e) {
|
|
193
|
-
|
|
194
|
+
logger.warn(loggable(e));
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
197
|
return {
|
|
@@ -229,8 +230,7 @@ export function ViewsParser(B) {
|
|
|
229
230
|
astPath
|
|
230
231
|
);
|
|
231
232
|
}
|
|
232
|
-
const { title = null, description = null } = this.
|
|
233
|
-
{},
|
|
233
|
+
const { title = null, description = null } = this.parseBaseProps(
|
|
234
234
|
pipe(
|
|
235
235
|
props,
|
|
236
236
|
filter(ast.isViewStringProperty),
|
|
@@ -257,7 +257,7 @@ export function ViewsParser(B) {
|
|
|
257
257
|
try {
|
|
258
258
|
return isValid(n) ? this.parseDynamicViewRule(n) : [];
|
|
259
259
|
} catch (e) {
|
|
260
|
-
|
|
260
|
+
logger.warn(loggable(e));
|
|
261
261
|
return [];
|
|
262
262
|
}
|
|
263
263
|
}, [])
|
|
@@ -272,7 +272,7 @@ export function ViewsParser(B) {
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
} catch (e) {
|
|
275
|
-
|
|
275
|
+
logger.warn(loggable(e));
|
|
276
276
|
}
|
|
277
277
|
return acc;
|
|
278
278
|
}, []),
|
|
@@ -306,46 +306,113 @@ export function ViewsParser(B) {
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
} catch (e) {
|
|
309
|
-
|
|
309
|
+
logger.warn(loggable(e));
|
|
310
310
|
}
|
|
311
311
|
iter = iter.prev;
|
|
312
312
|
}
|
|
313
313
|
return { include };
|
|
314
314
|
}
|
|
315
315
|
parseDynamicParallelSteps(node) {
|
|
316
|
+
const parallelId = pathInsideDynamicView(node);
|
|
317
|
+
const __parallel = node.steps.map((step) => this.parseDynamicStep(step));
|
|
318
|
+
invariant(isNonEmptyArray(__parallel), "Dynamic parallel steps must have at least one step");
|
|
316
319
|
return {
|
|
317
|
-
|
|
320
|
+
parallelId,
|
|
321
|
+
__parallel
|
|
318
322
|
};
|
|
319
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* @returns non-empty array in case of step chain A -> B -> C
|
|
326
|
+
*/
|
|
320
327
|
parseDynamicStep(node) {
|
|
328
|
+
if (ast.isDynamicStepSingle(node)) {
|
|
329
|
+
invariant(this.isValid(node));
|
|
330
|
+
return this.parseDynamicStepSingle(node);
|
|
331
|
+
}
|
|
332
|
+
const __series = this.recursiveParseDynamicStepChain(node);
|
|
333
|
+
invariant(isNonEmptyArray(__series), "Dynamic step chain must have at least one step");
|
|
334
|
+
return {
|
|
335
|
+
seriesId: pathInsideDynamicView(node),
|
|
336
|
+
__series
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
recursiveParseDynamicStepChain(node, callstack) {
|
|
340
|
+
if (ast.isDynamicStepSingle(node.source)) {
|
|
341
|
+
if (!this.isValid(node.source)) {
|
|
342
|
+
return [];
|
|
343
|
+
}
|
|
344
|
+
const previous2 = this.parseDynamicStepSingle(node.source);
|
|
345
|
+
if (previous2.isBackward) {
|
|
346
|
+
return [];
|
|
347
|
+
}
|
|
348
|
+
const thisStep2 = {
|
|
349
|
+
...this.parseAbstractDynamicStep(node),
|
|
350
|
+
source: previous2.target
|
|
351
|
+
};
|
|
352
|
+
if (thisStep2.target === previous2.source) {
|
|
353
|
+
thisStep2.isBackward = true;
|
|
354
|
+
} else if (callstack) {
|
|
355
|
+
callstack.push([previous2.source, previous2.target]);
|
|
356
|
+
callstack.push([thisStep2.source, thisStep2.target]);
|
|
357
|
+
}
|
|
358
|
+
return [previous2, thisStep2];
|
|
359
|
+
}
|
|
360
|
+
callstack ??= [];
|
|
361
|
+
const allprevious = this.recursiveParseDynamicStepChain(node.source, callstack);
|
|
362
|
+
if (!isNonEmptyArray(allprevious) || !this.isValid(node)) {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
const previous = last(allprevious);
|
|
366
|
+
const thisStep = {
|
|
367
|
+
...this.parseAbstractDynamicStep(node),
|
|
368
|
+
source: previous.target
|
|
369
|
+
};
|
|
370
|
+
const index = callstack.findIndex(([source, target]) => source === thisStep.target && target === thisStep.source);
|
|
371
|
+
if (index !== -1) {
|
|
372
|
+
thisStep.isBackward = true;
|
|
373
|
+
callstack.splice(index, callstack.length - index);
|
|
374
|
+
} else {
|
|
375
|
+
callstack.push([thisStep.source, thisStep.target]);
|
|
376
|
+
}
|
|
377
|
+
return [...allprevious, thisStep];
|
|
378
|
+
}
|
|
379
|
+
parseDynamicStepSingle(node) {
|
|
321
380
|
const sourceEl = elementRef(node.source);
|
|
322
381
|
if (!sourceEl) {
|
|
323
382
|
throw new Error("Invalid reference to source");
|
|
324
383
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
let source = this.resolveFqn(sourceEl);
|
|
330
|
-
let target = this.resolveFqn(targetEl);
|
|
331
|
-
const title = removeIndent(node.title) ?? null;
|
|
332
|
-
let step = {
|
|
333
|
-
source,
|
|
334
|
-
target,
|
|
335
|
-
title
|
|
384
|
+
let baseStep = {
|
|
385
|
+
...this.parseAbstractDynamicStep(node),
|
|
386
|
+
source: this.resolveFqn(sourceEl)
|
|
336
387
|
};
|
|
337
388
|
if (node.isBackward) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
389
|
+
baseStep = {
|
|
390
|
+
...baseStep,
|
|
391
|
+
source: baseStep.target,
|
|
392
|
+
target: baseStep.source,
|
|
342
393
|
isBackward: true
|
|
343
394
|
};
|
|
344
395
|
}
|
|
345
|
-
|
|
346
|
-
|
|
396
|
+
return baseStep;
|
|
397
|
+
}
|
|
398
|
+
parseAbstractDynamicStep(astnode) {
|
|
399
|
+
const targetEl = elementRef(astnode.target);
|
|
400
|
+
if (!targetEl) {
|
|
401
|
+
throw new Error("Invalid reference to target");
|
|
402
|
+
}
|
|
403
|
+
const step = {
|
|
404
|
+
target: this.resolveFqn(targetEl),
|
|
405
|
+
astPath: pathInsideDynamicView(astnode)
|
|
406
|
+
};
|
|
407
|
+
const title = removeIndent(astnode.title);
|
|
408
|
+
if (title) {
|
|
409
|
+
step.title = title;
|
|
410
|
+
}
|
|
411
|
+
const kind = astnode.kind?.ref?.name ?? astnode.dotKind?.kind.ref?.name;
|
|
412
|
+
if (kind) {
|
|
413
|
+
step.kind = kind;
|
|
347
414
|
}
|
|
348
|
-
for (const prop of
|
|
415
|
+
for (const prop of astnode.custom?.props ?? []) {
|
|
349
416
|
try {
|
|
350
417
|
switch (true) {
|
|
351
418
|
case ast.isRelationNavigateToProperty(prop): {
|
|
@@ -358,7 +425,14 @@ export function ViewsParser(B) {
|
|
|
358
425
|
case ast.isRelationStringProperty(prop):
|
|
359
426
|
case ast.isNotationProperty(prop): {
|
|
360
427
|
if (isDefined(prop.value)) {
|
|
361
|
-
|
|
428
|
+
if (prop.key === "description") {
|
|
429
|
+
const value = removeIndent(prop.value);
|
|
430
|
+
if (value) {
|
|
431
|
+
step.description = value;
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
step[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) ?? "";
|
|
435
|
+
}
|
|
362
436
|
}
|
|
363
437
|
break;
|
|
364
438
|
}
|
|
@@ -391,10 +465,26 @@ export function ViewsParser(B) {
|
|
|
391
465
|
nonexhaustive(prop);
|
|
392
466
|
}
|
|
393
467
|
} catch (e) {
|
|
394
|
-
|
|
468
|
+
logger.warn(loggable(e));
|
|
395
469
|
}
|
|
396
470
|
}
|
|
397
471
|
return step;
|
|
398
472
|
}
|
|
399
473
|
};
|
|
400
474
|
}
|
|
475
|
+
function pathInsideDynamicView(_node) {
|
|
476
|
+
let node = _node;
|
|
477
|
+
let path = [];
|
|
478
|
+
while (!ast.isDynamicViewBody(node)) {
|
|
479
|
+
if (isNumber(node.$containerIndex)) {
|
|
480
|
+
path.unshift(
|
|
481
|
+
`@${node.$containerIndex}`
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
path.unshift(
|
|
485
|
+
`/${node.$containerProperty ?? "__invalid__"}`
|
|
486
|
+
);
|
|
487
|
+
node = node.$container;
|
|
488
|
+
}
|
|
489
|
+
return path.join("");
|
|
490
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Location, Range, TextEdit } from 'vscode-languageserver-types';
|
|
2
|
-
import {
|
|
2
|
+
import type { ParsedLikeC4LangiumDocument } from '../ast';
|
|
3
3
|
import type { LikeC4Services } from '../module';
|
|
4
4
|
import type { ChangeView } from '../protocol';
|
|
5
5
|
export declare class LikeC4ModelChanges {
|
package/dist/module.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { onNextTick } from "@likec4/core/utils";
|
|
1
2
|
import { GraphvizWasmAdapter, QueueGraphvizLayoter } from "@likec4/layouts";
|
|
2
3
|
import {
|
|
3
4
|
DocumentState,
|
|
@@ -144,9 +145,9 @@ export function createLanguageServices(context, module, module2, module3) {
|
|
|
144
145
|
shared.ServiceRegistry.register(likec4);
|
|
145
146
|
registerValidationChecks(likec4);
|
|
146
147
|
if (!context.connection) {
|
|
147
|
-
shared.workspace.ConfigurationProvider.initialized({});
|
|
148
|
+
void shared.workspace.ConfigurationProvider.initialized({});
|
|
148
149
|
} else {
|
|
149
|
-
likec4.Rpc.init();
|
|
150
|
+
onNextTick(() => likec4.Rpc.init());
|
|
150
151
|
}
|
|
151
152
|
return { shared, likec4 };
|
|
152
153
|
}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -176,18 +176,42 @@ export declare namespace BuildDocuments {
|
|
|
176
176
|
* If LSP has multiple projects, the projectId is required.
|
|
177
177
|
*/
|
|
178
178
|
export declare namespace Locate {
|
|
179
|
-
type Params =
|
|
179
|
+
type Params =
|
|
180
|
+
/**
|
|
181
|
+
* Locate an element by its fqn
|
|
182
|
+
*/
|
|
183
|
+
{
|
|
180
184
|
element: Fqn;
|
|
181
185
|
projectId?: string | undefined;
|
|
182
186
|
property?: string;
|
|
183
|
-
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Locate a relation by its id
|
|
190
|
+
*/
|
|
191
|
+
| {
|
|
184
192
|
projectId?: string | undefined;
|
|
185
193
|
relation: RelationId;
|
|
186
|
-
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Locate a deployment by its fqn
|
|
197
|
+
*/
|
|
198
|
+
| {
|
|
187
199
|
deployment: DeploymentFqn;
|
|
188
200
|
projectId?: string | undefined;
|
|
189
201
|
property?: string;
|
|
190
|
-
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Locate a step in a dynamic view by its astPath
|
|
205
|
+
*/
|
|
206
|
+
| {
|
|
207
|
+
view: ViewId;
|
|
208
|
+
astPath: string;
|
|
209
|
+
projectId?: string | undefined;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Locate a view by its id
|
|
213
|
+
*/
|
|
214
|
+
| {
|
|
191
215
|
view: ViewId;
|
|
192
216
|
projectId?: string | undefined;
|
|
193
217
|
};
|
|
@@ -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
|
|
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 {
|
|
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;
|