@likec4/language-server 1.23.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4FileSystem.d.ts +1 -0
- package/dist/LikeC4FileSystem.js +8 -1
- package/dist/Rpc.js +10 -7
- package/dist/ast.d.ts +13 -29
- package/dist/ast.js +3 -70
- package/dist/bundled.mjs +2466 -2641
- package/dist/generated/ast.d.ts +36 -8
- package/dist/generated/ast.js +44 -2
- package/dist/generated/grammar.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/likec4lib.d.ts +2 -0
- package/dist/likec4lib.js +3 -0
- package/dist/lsp/CodeLensProvider.js +7 -4
- package/dist/lsp/CompletionProvider.js +20 -2
- package/dist/lsp/DocumentLinkProvider.d.ts +3 -3
- package/dist/lsp/DocumentLinkProvider.js +14 -5
- package/dist/lsp/DocumentSymbolProvider.d.ts +1 -1
- package/dist/lsp/DocumentSymbolProvider.js +5 -2
- package/dist/lsp/HoverProvider.js +20 -7
- package/dist/lsp/SemanticTokenProvider.js +18 -1
- package/dist/model/builder/MergedExtends.d.ts +12 -0
- package/dist/model/builder/MergedExtends.js +67 -0
- package/dist/model/builder/MergedSpecification.d.ts +29 -0
- package/dist/model/builder/MergedSpecification.js +203 -0
- package/dist/model/builder/buildModel.d.ts +3 -0
- package/dist/model/builder/buildModel.js +194 -0
- package/dist/model/deployments-index.d.ts +6 -56
- package/dist/model/deployments-index.js +59 -137
- package/dist/model/fqn-index.d.ts +47 -17
- package/dist/model/fqn-index.js +155 -68
- package/dist/model/index.d.ts +0 -1
- package/dist/model/index.js +0 -1
- package/dist/model/model-builder.d.ts +13 -9
- package/dist/model/model-builder.js +101 -547
- package/dist/model/model-locator.d.ts +1 -0
- package/dist/model/model-locator.js +7 -9
- package/dist/model/model-parser.d.ts +24 -18
- package/dist/model/model-parser.js +51 -31
- package/dist/model/parser/Base.d.ts +3 -3
- package/dist/model/parser/Base.js +15 -9
- package/dist/model/parser/DeploymentModelParser.d.ts +4 -3
- package/dist/model/parser/DeploymentModelParser.js +54 -3
- package/dist/model/parser/DeploymentViewParser.d.ts +3 -2
- package/dist/model/parser/FqnRefParser.d.ts +2 -2
- package/dist/model/parser/GlobalsParser.d.ts +3 -2
- package/dist/model/parser/ModelParser.d.ts +4 -4
- package/dist/model/parser/ModelParser.js +45 -4
- package/dist/model/parser/PredicatesParser.d.ts +2 -2
- package/dist/model/parser/SpecificationParser.d.ts +2 -2
- package/dist/model/parser/ViewsParser.d.ts +3 -2
- package/dist/module.d.ts +2 -3
- package/dist/module.js +2 -3
- package/dist/references/scope-computation.d.ts +1 -1
- package/dist/references/scope-computation.js +14 -11
- package/dist/references/scope-provider.d.ts +16 -4
- package/dist/references/scope-provider.js +64 -30
- package/dist/test/testServices.d.ts +2 -1
- package/dist/test/testServices.js +17 -14
- package/dist/utils/elementRef.d.ts +1 -1
- package/dist/utils/elementRef.js +3 -3
- package/dist/validation/deployment-checks.d.ts +1 -0
- package/dist/validation/deployment-checks.js +12 -0
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +8 -1
- package/dist/views/configurable-layouter.js +3 -3
- package/dist/views/likec4-views.d.ts +1 -0
- package/dist/views/likec4-views.js +11 -11
- package/package.json +6 -7
- package/dist/bundled.d.ts +0 -8
- package/dist/bundled.js +0 -25
- package/dist/model/fqn-computation.d.ts +0 -3
- package/dist/model/fqn-computation.js +0 -72
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { LikeC4FileSystem } from './LikeC4FileSystem';
|
|
|
2
2
|
import { type LikeC4Services, type LikeC4SharedServices } from './module';
|
|
3
3
|
export { getLspConnectionSink, logger as lspLogger } from './logger';
|
|
4
4
|
export type { DocumentParser, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
|
|
5
|
+
export { isLikeC4Builtin } from './likec4lib';
|
|
5
6
|
export { createCustomLanguageServices, createLanguageServices, LikeC4Module } from './module';
|
|
6
7
|
export type { LikeC4Services, LikeC4SharedServices } from './module';
|
|
7
8
|
export type { LikeC4Views } from './views';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getTelemetrySink, logger } from "./logger.js";
|
|
|
6
6
|
import { createCustomLanguageServices } from "./module.js";
|
|
7
7
|
import { ConfigurableLayouter } from "./views/configurable-layouter.js";
|
|
8
8
|
export { getLspConnectionSink, logger as lspLogger } from "./logger.js";
|
|
9
|
+
export { isLikeC4Builtin } from "./likec4lib.js";
|
|
9
10
|
export { createCustomLanguageServices, createLanguageServices, LikeC4Module } from "./module.js";
|
|
10
11
|
export { LikeC4FileSystem };
|
|
11
12
|
export async function startLanguageServer() {
|
package/dist/likec4lib.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type URI } from 'langium';
|
|
1
2
|
import { LibIcons } from './generated-lib/icons';
|
|
2
3
|
export declare const Scheme = "likec4builtin";
|
|
3
4
|
export declare const Uri: "likec4builtin:///likec4/lib/icons.c4";
|
|
4
5
|
export { LibIcons as Content };
|
|
6
|
+
export declare function isLikeC4Builtin(uri: URI): boolean;
|
package/dist/likec4lib.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { DocumentState } from "langium";
|
|
2
|
-
import {
|
|
1
|
+
import { DocumentState, interruptAndCheck } from "langium";
|
|
2
|
+
import { isLikeC4LangiumDocument, ViewOps } from "../ast.js";
|
|
3
3
|
import { logger } from "../logger.js";
|
|
4
4
|
export class LikeC4CodeLensProvider {
|
|
5
5
|
constructor(services) {
|
|
6
6
|
this.services = services;
|
|
7
7
|
}
|
|
8
8
|
async provideCodeLens(doc, _params, cancelToken) {
|
|
9
|
+
if (!isLikeC4LangiumDocument(doc)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
9
12
|
if (doc.state !== DocumentState.Validated) {
|
|
10
13
|
logger.debug(`Waiting for document ${doc.uri.path} to be validated`);
|
|
11
14
|
await this.services.shared.workspace.DocumentBuilder.waitUntil(DocumentState.Validated, doc.uri, cancelToken);
|
|
12
15
|
logger.debug(`Document ${doc.uri.path} is validated`);
|
|
13
16
|
}
|
|
14
|
-
if (
|
|
15
|
-
|
|
17
|
+
if (cancelToken) {
|
|
18
|
+
await interruptAndCheck(cancelToken);
|
|
16
19
|
}
|
|
17
20
|
const views = doc.parseResult.value.views.flatMap((v) => v.views);
|
|
18
21
|
return views.flatMap((ast) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ThemeColors } from "@likec4/core";
|
|
1
2
|
import { AstUtils } from "langium";
|
|
2
3
|
import {
|
|
3
4
|
DefaultCompletionProvider
|
|
@@ -12,7 +13,8 @@ const STYLE_FIELDS = [
|
|
|
12
13
|
"border",
|
|
13
14
|
"opacity",
|
|
14
15
|
"multiple",
|
|
15
|
-
"size"
|
|
16
|
+
"size",
|
|
17
|
+
"textSize"
|
|
16
18
|
].join(",");
|
|
17
19
|
export class LikeC4CompletionProvider extends DefaultCompletionProvider {
|
|
18
20
|
completionOptions = {
|
|
@@ -45,6 +47,22 @@ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
|
|
|
45
47
|
insertText: `${keyword.value} '\${0}'`
|
|
46
48
|
});
|
|
47
49
|
}
|
|
50
|
+
if (keyword.value === "color") {
|
|
51
|
+
return acceptor(context, {
|
|
52
|
+
label: keyword.value,
|
|
53
|
+
kind: CompletionItemKind.Property,
|
|
54
|
+
insertTextFormat: InsertTextFormat.Snippet,
|
|
55
|
+
insertText: `${keyword.value} \${1|${ThemeColors.join(",")}|}$0`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (keyword.value === "opacity") {
|
|
59
|
+
return acceptor(context, {
|
|
60
|
+
label: keyword.value,
|
|
61
|
+
kind: CompletionItemKind.Property,
|
|
62
|
+
insertTextFormat: InsertTextFormat.Snippet,
|
|
63
|
+
insertText: `${keyword.value} \${0:100}%`
|
|
64
|
+
});
|
|
65
|
+
}
|
|
48
66
|
if (["views", "specification", "model", "deployment", "with"].includes(keyword.value)) {
|
|
49
67
|
return acceptor(context, {
|
|
50
68
|
label: keyword.value,
|
|
@@ -123,7 +141,7 @@ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
|
|
|
123
141
|
detail: `Extend another view`,
|
|
124
142
|
kind: CompletionItemKind.Class,
|
|
125
143
|
insertTextFormat: InsertTextFormat.Snippet,
|
|
126
|
-
insertText: "extend $
|
|
144
|
+
insertText: "extend $1 {\n $0\n}"
|
|
127
145
|
});
|
|
128
146
|
}
|
|
129
147
|
if (keyword.value === "autoLayout") {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { LangiumDocument
|
|
1
|
+
import type { LangiumDocument } from 'langium';
|
|
2
2
|
import type { DocumentLinkProvider } from 'langium/lsp';
|
|
3
|
-
import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver';
|
|
3
|
+
import type { CancellationToken, DocumentLink, DocumentLinkParams } from 'vscode-languageserver';
|
|
4
4
|
import type { LikeC4Services } from '../module';
|
|
5
5
|
export declare class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
|
|
6
6
|
private services;
|
|
7
7
|
constructor(services: LikeC4Services);
|
|
8
|
-
getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams):
|
|
8
|
+
getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams, cancelToken?: CancellationToken): Promise<DocumentLink[]>;
|
|
9
9
|
resolveLink(doc: LangiumDocument, link: string): string;
|
|
10
10
|
relativeLink(doc: LangiumDocument, link: string): string | null;
|
|
11
11
|
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import { AstUtils, GrammarUtils } from "langium";
|
|
1
|
+
import { AstUtils, DocumentState, GrammarUtils, interruptAndCheck } from "langium";
|
|
2
2
|
import { hasLeadingSlash, hasProtocol, isRelative, withoutBase, withoutLeadingSlash } from "ufo";
|
|
3
|
-
import { ast,
|
|
4
|
-
import { logWarnError } from "../logger.js";
|
|
3
|
+
import { ast, isLikeC4LangiumDocument } from "../ast.js";
|
|
4
|
+
import { logger, logWarnError } from "../logger.js";
|
|
5
|
+
const log = logger.getChild("DocumentLinkProvider");
|
|
5
6
|
export class LikeC4DocumentLinkProvider {
|
|
6
7
|
constructor(services) {
|
|
7
8
|
this.services = services;
|
|
8
9
|
}
|
|
9
|
-
getDocumentLinks(doc, _params) {
|
|
10
|
-
if (!
|
|
10
|
+
async getDocumentLinks(doc, _params, cancelToken) {
|
|
11
|
+
if (!isLikeC4LangiumDocument(doc)) {
|
|
11
12
|
return [];
|
|
12
13
|
}
|
|
14
|
+
if (doc.state !== DocumentState.Validated) {
|
|
15
|
+
log.debug(`Waiting for document ${doc.uri.path} to be validated`);
|
|
16
|
+
await this.services.shared.workspace.DocumentBuilder.waitUntil(DocumentState.Validated, doc.uri, cancelToken);
|
|
17
|
+
log.debug(`Document ${doc.uri.path} is validated`);
|
|
18
|
+
}
|
|
19
|
+
if (cancelToken) {
|
|
20
|
+
await interruptAndCheck(cancelToken);
|
|
21
|
+
}
|
|
13
22
|
return AstUtils.streamAllContents(doc.parseResult.value).filter(ast.isLinkProperty).map((n) => {
|
|
14
23
|
try {
|
|
15
24
|
const range = GrammarUtils.findNodeForProperty(n.$cstNode, "value")?.range;
|
|
@@ -25,7 +25,7 @@ export declare class LikeC4DocumentSymbolProvider implements DocumentSymbolProvi
|
|
|
25
25
|
protected getTagSymbol(astTag: ast.SpecificationTag): DocumentSymbol | null;
|
|
26
26
|
protected getLibIconSymbol(astTag: ast.LibIcon): DocumentSymbol | null;
|
|
27
27
|
protected getViewSymbol(astView: ast.LikeC4View): DocumentSymbol[];
|
|
28
|
-
protected getDeploymentElementSymbol(el: ast.DeploymentElement | ast.DeploymentRelation): DocumentSymbol[];
|
|
28
|
+
protected getDeploymentElementSymbol(el: ast.DeploymentElement | ast.DeploymentRelation | ast.ExtendDeployment): DocumentSymbol[];
|
|
29
29
|
protected getDeploymentNodeSymbol(astElement: ast.DeploymentNode): DocumentSymbol[];
|
|
30
30
|
protected getDeployedInstanceSymbol(astElement: ast.DeployedInstance): DocumentSymbol[];
|
|
31
31
|
protected symbolKind(node: AstNode): SymbolKind;
|
|
@@ -4,7 +4,7 @@ import { filter, isEmpty, isTruthy, map, pipe } from "remeda";
|
|
|
4
4
|
import { SymbolKind } from "vscode-languageserver-types";
|
|
5
5
|
import { ast } from "../ast.js";
|
|
6
6
|
import { logWarnError } from "../logger.js";
|
|
7
|
-
import {
|
|
7
|
+
import { readStrictFqn } from "../utils/elementRef.js";
|
|
8
8
|
export class LikeC4DocumentSymbolProvider {
|
|
9
9
|
constructor(services) {
|
|
10
10
|
this.services = services;
|
|
@@ -137,7 +137,7 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
137
137
|
return [
|
|
138
138
|
{
|
|
139
139
|
kind: this.symbolKind(astElement),
|
|
140
|
-
name:
|
|
140
|
+
name: readStrictFqn(astElement.element),
|
|
141
141
|
range: cst.range,
|
|
142
142
|
selectionRange: nameNode.range,
|
|
143
143
|
children: body.elements.flatMap((e) => this.getElementsSymbol(e))
|
|
@@ -226,6 +226,9 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
226
226
|
if (ast.isDeployedInstance(el)) {
|
|
227
227
|
return this.getDeployedInstanceSymbol(el);
|
|
228
228
|
}
|
|
229
|
+
if (ast.isExtendDeployment(el)) {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
229
232
|
} catch (e) {
|
|
230
233
|
logWarnError(e);
|
|
231
234
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AstUtils } from "langium";
|
|
2
2
|
import { AstNodeHoverProvider } from "langium/lsp";
|
|
3
|
-
import stripIndent from "strip-indent";
|
|
4
3
|
import { ast } from "../ast.js";
|
|
5
4
|
export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
6
5
|
parser;
|
|
@@ -15,9 +14,7 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
|
15
14
|
return {
|
|
16
15
|
contents: {
|
|
17
16
|
kind: "markdown",
|
|
18
|
-
value:
|
|
19
|
-
tag: \`${node.name}\`
|
|
20
|
-
`)
|
|
17
|
+
value: "tag `" + node.name + "`"
|
|
21
18
|
}
|
|
22
19
|
};
|
|
23
20
|
}
|
|
@@ -28,7 +25,7 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
|
28
25
|
if (el.title !== node.name) {
|
|
29
26
|
lines.push(`### ${el.title}`);
|
|
30
27
|
}
|
|
31
|
-
lines.push("
|
|
28
|
+
lines.push("deployment node `" + el.kind + "` ");
|
|
32
29
|
return {
|
|
33
30
|
contents: {
|
|
34
31
|
kind: "markdown",
|
|
@@ -42,7 +39,7 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
|
42
39
|
const el = this.locator.getParsedElement(instance.element);
|
|
43
40
|
const lines = [instance.id + " ", `instance of \`${instance.element}\``];
|
|
44
41
|
if (el) {
|
|
45
|
-
lines.push(`### ${el.title}`, "
|
|
42
|
+
lines.push(`### ${el.title}`, "element kind `" + el.kind + "` ");
|
|
46
43
|
}
|
|
47
44
|
return {
|
|
48
45
|
contents: {
|
|
@@ -51,12 +48,28 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
|
51
48
|
}
|
|
52
49
|
};
|
|
53
50
|
}
|
|
51
|
+
if (ast.isElementKind(node)) {
|
|
52
|
+
return {
|
|
53
|
+
contents: {
|
|
54
|
+
kind: "markdown",
|
|
55
|
+
value: "element kind `" + node.name + "`"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (ast.isDeploymentNodeKind(node)) {
|
|
60
|
+
return {
|
|
61
|
+
contents: {
|
|
62
|
+
kind: "markdown",
|
|
63
|
+
value: "deployment node `" + node.name + "`"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
54
67
|
if (ast.isElement(node)) {
|
|
55
68
|
const el = this.locator.getParsedElement(node);
|
|
56
69
|
if (!el) {
|
|
57
70
|
return;
|
|
58
71
|
}
|
|
59
|
-
const lines = [el.id, `### ${el.title}`, "
|
|
72
|
+
const lines = [el.id, `### ${el.title}`, "element kind `" + el.kind + "` "];
|
|
60
73
|
return {
|
|
61
74
|
contents: {
|
|
62
75
|
kind: "markdown",
|
|
@@ -191,7 +191,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
191
191
|
});
|
|
192
192
|
return "prune";
|
|
193
193
|
}
|
|
194
|
-
if (ast.isFqnRef(node)) {
|
|
194
|
+
if (ast.isFqnRef(node) || ast.isStrictFqnRef(node)) {
|
|
195
195
|
acceptor({
|
|
196
196
|
node,
|
|
197
197
|
property: "value",
|
|
@@ -334,6 +334,23 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
334
334
|
type: SemanticTokenTypes.keyword,
|
|
335
335
|
modifier: []
|
|
336
336
|
});
|
|
337
|
+
if (ast.isElement(node)) {
|
|
338
|
+
if (node.props.length > 0) {
|
|
339
|
+
acceptor({
|
|
340
|
+
node,
|
|
341
|
+
property: "props",
|
|
342
|
+
type: SemanticTokenTypes.string
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (node.title) {
|
|
348
|
+
acceptor({
|
|
349
|
+
node,
|
|
350
|
+
property: "title",
|
|
351
|
+
type: SemanticTokenTypes.string
|
|
352
|
+
});
|
|
353
|
+
}
|
|
337
354
|
}
|
|
338
355
|
highlightView(node, acceptor) {
|
|
339
356
|
if (node.name) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type * as c4 from '@likec4/core';
|
|
2
|
+
import type { ParsedAstExtend } from '../../ast';
|
|
3
|
+
export declare class MergedExtends {
|
|
4
|
+
private mergedData;
|
|
5
|
+
merge(parsedExtends: ParsedAstExtend[]): void;
|
|
6
|
+
apply<E extends {
|
|
7
|
+
id: c4.Fqn;
|
|
8
|
+
tags?: c4.NonEmptyArray<c4.Tag> | null;
|
|
9
|
+
links?: c4.NonEmptyArray<c4.Link> | null;
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
}>(el: E): E;
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasAtLeast,
|
|
3
|
+
isEmpty,
|
|
4
|
+
unique
|
|
5
|
+
} from "remeda";
|
|
6
|
+
export class MergedExtends {
|
|
7
|
+
mergedData = /* @__PURE__ */ new Map();
|
|
8
|
+
merge(parsedExtends) {
|
|
9
|
+
for (const parsedExtend of parsedExtends) {
|
|
10
|
+
const { id, links, tags, metadata } = parsedExtend;
|
|
11
|
+
const existing = this.mergedData.get(id) ?? {
|
|
12
|
+
links: [],
|
|
13
|
+
tags: [],
|
|
14
|
+
metadata: {}
|
|
15
|
+
};
|
|
16
|
+
if (links) {
|
|
17
|
+
existing.links.push(...links);
|
|
18
|
+
}
|
|
19
|
+
if (tags) {
|
|
20
|
+
existing.tags = unique([
|
|
21
|
+
...existing.tags,
|
|
22
|
+
...tags
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
if (metadata) {
|
|
26
|
+
existing.metadata = {
|
|
27
|
+
...existing.metadata,
|
|
28
|
+
...metadata
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
this.mergedData.set(id, existing);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
apply(el) {
|
|
35
|
+
const extendData = this.mergedData.get(el.id);
|
|
36
|
+
if (!extendData) {
|
|
37
|
+
return el;
|
|
38
|
+
}
|
|
39
|
+
let links = extendData.links;
|
|
40
|
+
if (el.links && el.links.length > 0) {
|
|
41
|
+
links = [
|
|
42
|
+
...el.links,
|
|
43
|
+
...links
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
let tags = extendData.tags;
|
|
47
|
+
if (el.tags && el.tags.length > 0) {
|
|
48
|
+
tags = unique([
|
|
49
|
+
...el.tags,
|
|
50
|
+
...tags
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
let metadata = extendData.metadata;
|
|
54
|
+
if (el.metadata) {
|
|
55
|
+
metadata = {
|
|
56
|
+
...el.metadata,
|
|
57
|
+
...extendData.metadata
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
...el,
|
|
62
|
+
tags: hasAtLeast(tags, 1) ? tags : null,
|
|
63
|
+
links: hasAtLeast(links, 1) ? links : null,
|
|
64
|
+
...!isEmpty(metadata) && { metadata }
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as c4 from '@likec4/core';
|
|
2
|
+
import type { ParsedAstDeploymentRelation, ParsedAstElement, ParsedAstRelation, ParsedAstSpecification, ParsedLikeC4LangiumDocument } from '../../ast';
|
|
3
|
+
/**
|
|
4
|
+
* The `MergedSpecification` class is responsible for merging multiple parsed
|
|
5
|
+
* LikeC4Langium documents into a single specification. It consolidates tags,
|
|
6
|
+
* elements, deployments, relationships, and colors from the provided documents
|
|
7
|
+
* and provides methods to convert parsed models into C4 model elements and relations.
|
|
8
|
+
*/
|
|
9
|
+
export declare class MergedSpecification {
|
|
10
|
+
readonly specs: ParsedAstSpecification;
|
|
11
|
+
readonly globals: c4.ModelGlobals;
|
|
12
|
+
constructor(docs: ParsedLikeC4LangiumDocument[]);
|
|
13
|
+
/**
|
|
14
|
+
* Converts a parsed model into a C4 model element.
|
|
15
|
+
*/
|
|
16
|
+
toModelElement: ({ tags, links, style: { color, shape, icon, opacity, border, size, multiple, padding, textSize, }, id, kind, title, description, technology, metadata, }: ParsedAstElement) => c4.Element | null;
|
|
17
|
+
/**
|
|
18
|
+
* Converts a parsed model into a C4 model relation.
|
|
19
|
+
*/
|
|
20
|
+
toModelRelation: ({ astPath, source, target, kind, links, id, ...model }: ParsedAstRelation) => c4.ModelRelation | null;
|
|
21
|
+
/**
|
|
22
|
+
* Converts a parsed deployment model into a C4 deployment model
|
|
23
|
+
*/
|
|
24
|
+
toDeploymentElement: (parsed: c4.DeploymentElement) => c4.DeploymentElement | null;
|
|
25
|
+
/**
|
|
26
|
+
* Converts a parsed deployment relation into a C4 deployment relation.
|
|
27
|
+
*/
|
|
28
|
+
toDeploymentRelation: ({ astPath, source, target, kind, links, id, ...model }: ParsedAstDeploymentRelation) => c4.DeploymentRelation | null;
|
|
29
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeploymentElement
|
|
3
|
+
} from "@likec4/core";
|
|
4
|
+
import {
|
|
5
|
+
isBoolean,
|
|
6
|
+
isEmpty,
|
|
7
|
+
isNonNullish,
|
|
8
|
+
isNumber
|
|
9
|
+
} from "remeda";
|
|
10
|
+
import { logger, logWarnError } from "../../logger.js";
|
|
11
|
+
export class MergedSpecification {
|
|
12
|
+
specs = {
|
|
13
|
+
tags: /* @__PURE__ */ new Set(),
|
|
14
|
+
elements: {},
|
|
15
|
+
deployments: {},
|
|
16
|
+
relationships: {},
|
|
17
|
+
colors: {}
|
|
18
|
+
};
|
|
19
|
+
globals = {
|
|
20
|
+
predicates: {},
|
|
21
|
+
dynamicPredicates: {},
|
|
22
|
+
styles: {}
|
|
23
|
+
};
|
|
24
|
+
constructor(docs) {
|
|
25
|
+
for (const doc of docs) {
|
|
26
|
+
const {
|
|
27
|
+
c4Specification: spec,
|
|
28
|
+
c4Globals
|
|
29
|
+
} = doc;
|
|
30
|
+
spec.tags.forEach((t) => this.specs.tags.add(t));
|
|
31
|
+
Object.assign(this.specs.elements, spec.elements);
|
|
32
|
+
Object.assign(this.specs.relationships, spec.relationships);
|
|
33
|
+
Object.assign(this.specs.colors, spec.colors);
|
|
34
|
+
Object.assign(this.specs.deployments, spec.deployments);
|
|
35
|
+
Object.assign(this.globals.predicates, c4Globals.predicates);
|
|
36
|
+
Object.assign(this.globals.dynamicPredicates, c4Globals.dynamicPredicates);
|
|
37
|
+
Object.assign(this.globals.styles, c4Globals.styles);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Converts a parsed model into a C4 model element.
|
|
42
|
+
*/
|
|
43
|
+
toModelElement = ({
|
|
44
|
+
tags,
|
|
45
|
+
links,
|
|
46
|
+
style: {
|
|
47
|
+
color,
|
|
48
|
+
shape,
|
|
49
|
+
icon,
|
|
50
|
+
opacity,
|
|
51
|
+
border,
|
|
52
|
+
size,
|
|
53
|
+
multiple,
|
|
54
|
+
padding,
|
|
55
|
+
textSize
|
|
56
|
+
},
|
|
57
|
+
id,
|
|
58
|
+
kind,
|
|
59
|
+
title,
|
|
60
|
+
description,
|
|
61
|
+
technology,
|
|
62
|
+
metadata
|
|
63
|
+
}) => {
|
|
64
|
+
try {
|
|
65
|
+
const __kind = this.specs.elements[kind];
|
|
66
|
+
if (!__kind) {
|
|
67
|
+
logger.warn`No kind '${kind}' found for ${id}`;
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
color ??= __kind.style.color;
|
|
71
|
+
shape ??= __kind.style.shape;
|
|
72
|
+
icon ??= __kind.style.icon;
|
|
73
|
+
opacity ??= __kind.style.opacity;
|
|
74
|
+
border ??= __kind.style.border;
|
|
75
|
+
technology ??= __kind.technology;
|
|
76
|
+
multiple ??= __kind.style.multiple;
|
|
77
|
+
size ??= __kind.style.size;
|
|
78
|
+
padding ??= __kind.style.padding;
|
|
79
|
+
textSize ??= __kind.style.textSize;
|
|
80
|
+
return {
|
|
81
|
+
...color && { color },
|
|
82
|
+
...shape && { shape },
|
|
83
|
+
...icon && { icon },
|
|
84
|
+
...metadata && !isEmpty(metadata) && { metadata },
|
|
85
|
+
...__kind.notation && { notation: __kind.notation },
|
|
86
|
+
style: {
|
|
87
|
+
...border && { border },
|
|
88
|
+
...size && { size },
|
|
89
|
+
...padding && { padding },
|
|
90
|
+
...textSize && { textSize },
|
|
91
|
+
...isBoolean(multiple) && { multiple },
|
|
92
|
+
...isNumber(opacity) && { opacity }
|
|
93
|
+
},
|
|
94
|
+
links: links ?? null,
|
|
95
|
+
tags: tags ?? null,
|
|
96
|
+
technology: technology ?? null,
|
|
97
|
+
description: description ?? null,
|
|
98
|
+
title,
|
|
99
|
+
kind,
|
|
100
|
+
id
|
|
101
|
+
};
|
|
102
|
+
} catch (e) {
|
|
103
|
+
logWarnError(e);
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Converts a parsed model into a C4 model relation.
|
|
109
|
+
*/
|
|
110
|
+
toModelRelation = ({
|
|
111
|
+
astPath,
|
|
112
|
+
source,
|
|
113
|
+
target,
|
|
114
|
+
kind,
|
|
115
|
+
links,
|
|
116
|
+
id,
|
|
117
|
+
...model
|
|
118
|
+
}) => {
|
|
119
|
+
if (isNonNullish(kind) && this.specs.relationships[kind]) {
|
|
120
|
+
return {
|
|
121
|
+
...this.specs.relationships[kind],
|
|
122
|
+
...model,
|
|
123
|
+
...links && { links },
|
|
124
|
+
source,
|
|
125
|
+
target,
|
|
126
|
+
kind,
|
|
127
|
+
id
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
...links && { links },
|
|
132
|
+
...model,
|
|
133
|
+
source,
|
|
134
|
+
target,
|
|
135
|
+
id
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Converts a parsed deployment model into a C4 deployment model
|
|
140
|
+
*/
|
|
141
|
+
toDeploymentElement = (parsed) => {
|
|
142
|
+
if (!DeploymentElement.isDeploymentNode(parsed)) {
|
|
143
|
+
return parsed;
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const __kind = this.specs.deployments[parsed.kind];
|
|
147
|
+
if (!__kind) {
|
|
148
|
+
logger.warn`No kind ${parsed.kind} found for ${parsed.id}`;
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
let {
|
|
152
|
+
technology = __kind.technology,
|
|
153
|
+
notation = __kind.notation,
|
|
154
|
+
style
|
|
155
|
+
} = parsed;
|
|
156
|
+
return {
|
|
157
|
+
...parsed,
|
|
158
|
+
...notation && { notation },
|
|
159
|
+
...technology && { technology },
|
|
160
|
+
style: {
|
|
161
|
+
border: "dashed",
|
|
162
|
+
opacity: 10,
|
|
163
|
+
...__kind.style,
|
|
164
|
+
...style
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
} catch (e) {
|
|
168
|
+
logWarnError(e);
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Converts a parsed deployment relation into a C4 deployment relation.
|
|
174
|
+
*/
|
|
175
|
+
toDeploymentRelation = ({
|
|
176
|
+
astPath,
|
|
177
|
+
source,
|
|
178
|
+
target,
|
|
179
|
+
kind,
|
|
180
|
+
links,
|
|
181
|
+
id,
|
|
182
|
+
...model
|
|
183
|
+
}) => {
|
|
184
|
+
if (isNonNullish(kind) && this.specs.relationships[kind]) {
|
|
185
|
+
return {
|
|
186
|
+
...this.specs.relationships[kind],
|
|
187
|
+
...model,
|
|
188
|
+
...links && { links },
|
|
189
|
+
source,
|
|
190
|
+
target,
|
|
191
|
+
kind,
|
|
192
|
+
id
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
...links && { links },
|
|
197
|
+
...model,
|
|
198
|
+
source,
|
|
199
|
+
target,
|
|
200
|
+
id
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
}
|