@likec4/generators 1.47.0 → 1.48.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/LICENSE +1 -1
- package/dist/index.d.mts +59 -0
- package/dist/index.mjs +589 -0
- package/package.json +20 -17
- package/src/react/generate-react-types.ts +2 -2
- package/dist/d2/generate-d2.d.ts +0 -3
- package/dist/d2/generate-d2.js +0 -87
- package/dist/d2/index.d.ts +0 -1
- package/dist/d2/index.js +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -7
- package/dist/mmd/generate-mmd.d.ts +0 -3
- package/dist/mmd/generate-mmd.js +0 -107
- package/dist/mmd/index.d.ts +0 -1
- package/dist/mmd/index.js +0 -1
- package/dist/model/generate-aux.d.ts +0 -4
- package/dist/model/generate-aux.js +0 -67
- package/dist/model/generate-likec4-model.d.ts +0 -4
- package/dist/model/generate-likec4-model.js +0 -22
- package/dist/model/generate-likec4.d.ts +0 -2
- package/dist/model/generate-likec4.js +0 -2
- package/dist/puml/generate-puml.d.ts +0 -3
- package/dist/puml/generate-puml.js +0 -170
- package/dist/puml/index.d.ts +0 -1
- package/dist/puml/index.js +0 -1
- package/dist/react/generate-react-types.d.ts +0 -4
- package/dist/react/generate-react-types.js +0 -64
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.js +0 -1
- package/dist/react-next/generate-react-next.d.ts +0 -20
- package/dist/react-next/generate-react-next.js +0 -102
- package/dist/react-next/index.d.ts +0 -1
- package/dist/react-next/index.js +0 -1
- package/dist/views-data-ts/generate-views-data.d.ts +0 -13
- package/dist/views-data-ts/generate-views-data.js +0 -130
- package/dist/views-data-ts/generateViewId.d.ts +0 -2
- package/dist/views-data-ts/generateViewId.js +0 -7
- package/dist/views-data-ts/index.d.ts +0 -1
- package/dist/views-data-ts/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/generators",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"src",
|
|
12
|
-
"
|
|
13
|
-
"!**/
|
|
14
|
-
"
|
|
12
|
+
"**/package.json",
|
|
13
|
+
"!**/__*/**",
|
|
14
|
+
"!**/*.spec.*",
|
|
15
|
+
"!**/*.snap",
|
|
15
16
|
"!**/*.map"
|
|
16
17
|
],
|
|
17
18
|
"repository": {
|
|
@@ -25,9 +26,9 @@
|
|
|
25
26
|
".": {
|
|
26
27
|
"sources": "./src/index.ts",
|
|
27
28
|
"default": {
|
|
28
|
-
"types": "./dist/index.d.
|
|
29
|
-
"import": "./dist/index.
|
|
30
|
-
"default": "./dist/index.
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"default": "./dist/index.mjs"
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
},
|
|
@@ -36,27 +37,29 @@
|
|
|
36
37
|
"access": "public"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
40
|
+
"remeda": "^2.32.0",
|
|
39
41
|
"json5": "^2.2.3",
|
|
40
42
|
"langium": "3.5.0",
|
|
41
|
-
"
|
|
42
|
-
"@likec4/
|
|
43
|
+
"@likec4/core": "1.48.0",
|
|
44
|
+
"@likec4/log": "1.48.0"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
|
-
"@types/node": "~22.19.
|
|
47
|
+
"@types/node": "~22.19.7",
|
|
46
48
|
"typescript": "5.9.3",
|
|
47
|
-
"
|
|
48
|
-
"vitest": "4.0.
|
|
49
|
-
"@likec4/
|
|
50
|
-
"@likec4/
|
|
49
|
+
"obuild": "^0.4.20",
|
|
50
|
+
"vitest": "4.0.18",
|
|
51
|
+
"@likec4/tsconfig": "1.48.0",
|
|
52
|
+
"@likec4/devops": "1.42.0"
|
|
51
53
|
},
|
|
52
54
|
"scripts": {
|
|
53
55
|
"typecheck": "tsc -b --verbose",
|
|
54
|
-
"build": "
|
|
56
|
+
"build": "obuild",
|
|
55
57
|
"lint": "run -T eslint src/ --fix",
|
|
56
58
|
"clean": "likec4ops clean",
|
|
59
|
+
"pack": "pnpm pack",
|
|
57
60
|
"test": "vitest run --no-isolate",
|
|
58
61
|
"test:watch": "vitest"
|
|
59
62
|
},
|
|
60
|
-
"types": "dist/index.d.
|
|
61
|
-
"module": "dist/index.
|
|
63
|
+
"types": "dist/index.d.mts",
|
|
64
|
+
"module": "dist/index.mjs"
|
|
62
65
|
}
|
|
@@ -19,7 +19,7 @@ export function generateReactTypes(model: AnyLikeC4Model, options: { useCorePack
|
|
|
19
19
|
import type { PropsWithChildren } from 'react'
|
|
20
20
|
import type { JSX } from 'react/jsx-runtime'
|
|
21
21
|
import type { LikeC4Model } from '${useCorePackage ? '@likec4/core' : 'likec4'}/model'
|
|
22
|
-
import type {
|
|
22
|
+
import type { LayoutedView } from '${useCorePackage ? '@likec4/core/types' : 'likec4/model'}'
|
|
23
23
|
import type {
|
|
24
24
|
LikeC4ViewProps as GenericLikeC4ViewProps,
|
|
25
25
|
ReactLikeC4Props as GenericReactLikeC4Props
|
|
@@ -31,7 +31,7 @@ declare function isLikeC4ViewId(value: unknown): value is $ViewId;
|
|
|
31
31
|
|
|
32
32
|
declare const likec4model: LikeC4Model<$Aux>;
|
|
33
33
|
declare function useLikeC4Model(): LikeC4Model<$Aux>;
|
|
34
|
-
declare function useLikeC4View(viewId: $ViewId):
|
|
34
|
+
declare function useLikeC4View(viewId: $ViewId): LayoutedView<$Aux>;
|
|
35
35
|
|
|
36
36
|
declare function LikeC4ModelProvider(props: PropsWithChildren): JSX.Element;
|
|
37
37
|
|
package/dist/d2/generate-d2.d.ts
DELETED
package/dist/d2/generate-d2.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { CompositeGeneratorNode, joinToNode, NL, toString } from "langium/generate";
|
|
2
|
-
import { isNullish as isNil } from "remeda";
|
|
3
|
-
const capitalizeFirstLetter = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
|
|
4
|
-
const fqnName = (nodeId) => nodeId.split(".").map(capitalizeFirstLetter).join("");
|
|
5
|
-
const nodeName = (node) => {
|
|
6
|
-
return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
|
|
7
|
-
};
|
|
8
|
-
const d2direction = ({ autoLayout }) => {
|
|
9
|
-
switch (autoLayout.direction) {
|
|
10
|
-
case "TB": {
|
|
11
|
-
return "down";
|
|
12
|
-
}
|
|
13
|
-
case "BT": {
|
|
14
|
-
return "up";
|
|
15
|
-
}
|
|
16
|
-
case "LR": {
|
|
17
|
-
return "right";
|
|
18
|
-
}
|
|
19
|
-
case "RL": {
|
|
20
|
-
return "left";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
const d2shape = ({ shape }) => {
|
|
25
|
-
switch (shape) {
|
|
26
|
-
case "queue":
|
|
27
|
-
case "cylinder":
|
|
28
|
-
case "rectangle":
|
|
29
|
-
case "document": {
|
|
30
|
-
return shape;
|
|
31
|
-
}
|
|
32
|
-
case "person": {
|
|
33
|
-
return "c4-person";
|
|
34
|
-
}
|
|
35
|
-
case "storage": {
|
|
36
|
-
return "stored_data";
|
|
37
|
-
}
|
|
38
|
-
case "bucket":
|
|
39
|
-
case "mobile":
|
|
40
|
-
case "browser": {
|
|
41
|
-
return "rectangle";
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
export function generateD2(viewmodel) {
|
|
46
|
-
const view = viewmodel.$view;
|
|
47
|
-
const { nodes, edges } = view;
|
|
48
|
-
const names = /* @__PURE__ */ new Map();
|
|
49
|
-
const printNode = (node, parentName) => {
|
|
50
|
-
const name = nodeName(node);
|
|
51
|
-
const fqnName2 = (parentName ? parentName + "." : "") + name;
|
|
52
|
-
names.set(node.id, fqnName2);
|
|
53
|
-
const label = JSON.stringify(node.title);
|
|
54
|
-
const shape = d2shape(node);
|
|
55
|
-
return new CompositeGeneratorNode().append(name, ": {", NL).indent({
|
|
56
|
-
indentedChildren: (indent) => indent.append("label: ", label, NL).appendIf(shape !== "rectangle", "shape: ", shape, NL).appendIf(
|
|
57
|
-
node.children.length > 0,
|
|
58
|
-
NL,
|
|
59
|
-
joinToNode(
|
|
60
|
-
nodes.filter((n) => n.parent === node.id),
|
|
61
|
-
(n) => printNode(n, fqnName2)
|
|
62
|
-
)
|
|
63
|
-
),
|
|
64
|
-
indentation: 2
|
|
65
|
-
}).append("}", NL);
|
|
66
|
-
};
|
|
67
|
-
const printEdge = (edge) => {
|
|
68
|
-
return new CompositeGeneratorNode().append(names.get(edge.source), " -> ", names.get(edge.target)).append((out) => edge.label && out.append(": ", JSON.stringify(edge.label)));
|
|
69
|
-
};
|
|
70
|
-
return toString(
|
|
71
|
-
new CompositeGeneratorNode().append("direction: ", d2direction(view), NL, NL).append(
|
|
72
|
-
joinToNode(
|
|
73
|
-
nodes.filter((n) => isNil(n.parent)),
|
|
74
|
-
(n) => printNode(n),
|
|
75
|
-
{
|
|
76
|
-
appendNewLineIfNotEmpty: true
|
|
77
|
-
}
|
|
78
|
-
)
|
|
79
|
-
).appendIf(
|
|
80
|
-
edges.length > 0,
|
|
81
|
-
NL,
|
|
82
|
-
joinToNode(edges, (e) => printEdge(e), {
|
|
83
|
-
appendNewLineIfNotEmpty: true
|
|
84
|
-
})
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
}
|
package/dist/d2/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './generate-d2';
|
package/dist/d2/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./generate-d2.js";
|
package/dist/index.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { generateD2 } from './d2/generate-d2';
|
|
2
|
-
export { generateMermaid } from './mmd/generate-mmd';
|
|
3
|
-
export { generateLikeC4Model } from './model/generate-likec4-model';
|
|
4
|
-
export { generatePuml } from './puml/generate-puml';
|
|
5
|
-
export { generateReactNext } from './react-next/generate-react-next';
|
|
6
|
-
export { generateReactTypes } from './react/generate-react-types';
|
|
7
|
-
export { generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs } from './views-data-ts/generate-views-data';
|
package/dist/index.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { generateD2 } from "./d2/generate-d2.js";
|
|
2
|
-
export { generateMermaid } from "./mmd/generate-mmd.js";
|
|
3
|
-
export { generateLikeC4Model } from "./model/generate-likec4-model.js";
|
|
4
|
-
export { generatePuml } from "./puml/generate-puml.js";
|
|
5
|
-
export { generateReactNext } from "./react-next/generate-react-next.js";
|
|
6
|
-
export { generateReactTypes } from "./react/generate-react-types.js";
|
|
7
|
-
export { generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs } from "./views-data-ts/generate-views-data.js";
|
package/dist/mmd/generate-mmd.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { nonexhaustive } from "@likec4/core";
|
|
2
|
-
import { CompositeGeneratorNode, joinToNode, NL, toString } from "langium/generate";
|
|
3
|
-
import { isNullish as isNil } from "remeda";
|
|
4
|
-
const capitalizeFirstLetter = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
|
|
5
|
-
const fqnName = (nodeId) => nodeId.split(".").map(capitalizeFirstLetter).join("");
|
|
6
|
-
const nodeName = (node) => {
|
|
7
|
-
return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
|
|
8
|
-
};
|
|
9
|
-
const toSingleQuotes = (str) => str.replace(/\\?"/g, `'`);
|
|
10
|
-
const mmdshape = ({ shape, title }) => {
|
|
11
|
-
const label = `label: ${JSON.stringify(title)}`;
|
|
12
|
-
switch (shape) {
|
|
13
|
-
case "queue": {
|
|
14
|
-
return `@{ shape: horizontal-cylinder, ${label} }`;
|
|
15
|
-
}
|
|
16
|
-
case "person": {
|
|
17
|
-
return `@{ icon: "fa:user", shape: rounded, ${label} }`;
|
|
18
|
-
}
|
|
19
|
-
case "storage": {
|
|
20
|
-
return `@{ shape: disk, ${label} }`;
|
|
21
|
-
}
|
|
22
|
-
case "cylinder": {
|
|
23
|
-
return `@{ shape: cylinder, ${label} }`;
|
|
24
|
-
}
|
|
25
|
-
case "mobile":
|
|
26
|
-
case "browser": {
|
|
27
|
-
return `@{ shape: rounded, ${label} }`;
|
|
28
|
-
}
|
|
29
|
-
case "bucket": {
|
|
30
|
-
return `@{ shape: trap-t, ${label} }`;
|
|
31
|
-
}
|
|
32
|
-
case "rectangle": {
|
|
33
|
-
return `@{ shape: rectangle, ${label} }`;
|
|
34
|
-
}
|
|
35
|
-
case "document": {
|
|
36
|
-
return `@{ shape: doc, ${label} }`;
|
|
37
|
-
}
|
|
38
|
-
default:
|
|
39
|
-
nonexhaustive(shape);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
export function generateMermaid(viewmodel) {
|
|
43
|
-
const view = viewmodel.$view;
|
|
44
|
-
const { nodes, edges } = view;
|
|
45
|
-
const names = /* @__PURE__ */ new Map();
|
|
46
|
-
const printNode = (node, parentName) => {
|
|
47
|
-
const name = nodeName(node);
|
|
48
|
-
const fqnName2 = (parentName ? parentName + "." : "") + name;
|
|
49
|
-
names.set(node.id, fqnName2);
|
|
50
|
-
const baseNode = new CompositeGeneratorNode();
|
|
51
|
-
if (node.children.length > 0) {
|
|
52
|
-
const label = toSingleQuotes(node.title);
|
|
53
|
-
baseNode.append("subgraph ", fqnName2, '["`', label, '`"]', NL).indent({
|
|
54
|
-
indentedChildren: [
|
|
55
|
-
joinToNode(
|
|
56
|
-
nodes.filter((n) => n.parent === node.id),
|
|
57
|
-
(n) => printNode(n, fqnName2),
|
|
58
|
-
{
|
|
59
|
-
appendNewLineIfNotEmpty: true
|
|
60
|
-
}
|
|
61
|
-
)
|
|
62
|
-
],
|
|
63
|
-
indentation: 2
|
|
64
|
-
}).append("end", NL);
|
|
65
|
-
} else {
|
|
66
|
-
baseNode.append(fqnName2, mmdshape(node));
|
|
67
|
-
}
|
|
68
|
-
return baseNode;
|
|
69
|
-
};
|
|
70
|
-
const printEdge = (edge) => {
|
|
71
|
-
return new CompositeGeneratorNode().append(
|
|
72
|
-
names.get(edge.source),
|
|
73
|
-
" -.",
|
|
74
|
-
edge.label ? ' "`' + toSingleQuotes(edge.label) + '`" .-' : "-",
|
|
75
|
-
"> ",
|
|
76
|
-
names.get(edge.target)
|
|
77
|
-
);
|
|
78
|
-
};
|
|
79
|
-
return toString(
|
|
80
|
-
new CompositeGeneratorNode().append(
|
|
81
|
-
"---",
|
|
82
|
-
NL,
|
|
83
|
-
`title: ${JSON.stringify(toSingleQuotes(viewmodel.titleOrId))}`,
|
|
84
|
-
NL,
|
|
85
|
-
"---",
|
|
86
|
-
NL
|
|
87
|
-
).append("graph ", view.autoLayout.direction, NL).indent({
|
|
88
|
-
indentedChildren: (indent) => {
|
|
89
|
-
indent.append(
|
|
90
|
-
joinToNode(
|
|
91
|
-
nodes.filter((n) => isNil(n.parent)),
|
|
92
|
-
(n) => printNode(n),
|
|
93
|
-
{
|
|
94
|
-
appendNewLineIfNotEmpty: true
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
).appendIf(
|
|
98
|
-
edges.length > 0,
|
|
99
|
-
joinToNode(edges, (e) => printEdge(e), {
|
|
100
|
-
appendNewLineIfNotEmpty: true
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
},
|
|
104
|
-
indentation: 2
|
|
105
|
-
})
|
|
106
|
-
);
|
|
107
|
-
}
|
package/dist/mmd/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './generate-mmd';
|
package/dist/mmd/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./generate-mmd.js";
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
compareNatural,
|
|
3
|
-
sortNaturalByFqn
|
|
4
|
-
} from "@likec4/core/utils";
|
|
5
|
-
import { keys, map, pipe, values } from "remeda";
|
|
6
|
-
function toUnion(elements) {
|
|
7
|
-
if (elements.length === 0) {
|
|
8
|
-
return "never";
|
|
9
|
-
}
|
|
10
|
-
let union = elements.sort(compareNatural).map((v) => ` | ${JSON.stringify(v)}`);
|
|
11
|
-
return union.join("\n").trimStart();
|
|
12
|
-
}
|
|
13
|
-
function elementIdToUnion(_elements) {
|
|
14
|
-
const elements = values(_elements);
|
|
15
|
-
if (elements.length === 0) {
|
|
16
|
-
return "never";
|
|
17
|
-
}
|
|
18
|
-
let union = pipe(
|
|
19
|
-
elements,
|
|
20
|
-
sortNaturalByFqn,
|
|
21
|
-
map((v) => ` | ${JSON.stringify(v.id)}`)
|
|
22
|
-
);
|
|
23
|
-
return union.join("\n").trimStart();
|
|
24
|
-
}
|
|
25
|
-
export function generateAux(model, options = {}) {
|
|
26
|
-
const { useCorePackage = false } = options;
|
|
27
|
-
return `
|
|
28
|
-
import type { Aux, SpecAux } from '${useCorePackage ? "@likec4/core/types" : "likec4/model"}';
|
|
29
|
-
|
|
30
|
-
export type $Specs = SpecAux<
|
|
31
|
-
// Element kinds
|
|
32
|
-
${toUnion(keys(model.specification.elements))},
|
|
33
|
-
// Deployment kinds
|
|
34
|
-
${toUnion(keys(model.specification.deployments ?? {}))},
|
|
35
|
-
// Relationship kinds
|
|
36
|
-
${toUnion(keys(model.specification.relationships ?? {}))},
|
|
37
|
-
// Tags
|
|
38
|
-
${toUnion(keys(model.specification.tags ?? {}))},
|
|
39
|
-
// Metadata keys
|
|
40
|
-
${toUnion(model.specification.metadataKeys ?? [])}
|
|
41
|
-
>
|
|
42
|
-
|
|
43
|
-
export type $Aux = Aux<
|
|
44
|
-
${JSON.stringify(model.stage)},
|
|
45
|
-
// Elements
|
|
46
|
-
${elementIdToUnion(model.$data.elements)},
|
|
47
|
-
// Deployments
|
|
48
|
-
${elementIdToUnion(model.$data.deployments.elements)},
|
|
49
|
-
// Views
|
|
50
|
-
${toUnion(keys(model.$data.views))},
|
|
51
|
-
// Project ID
|
|
52
|
-
${JSON.stringify(model.projectId)},
|
|
53
|
-
$Specs
|
|
54
|
-
>
|
|
55
|
-
|
|
56
|
-
export type $ElementId = $Aux['ElementId']
|
|
57
|
-
export type $DeploymentId = $Aux['DeploymentId']
|
|
58
|
-
export type $ViewId = $Aux['ViewId']
|
|
59
|
-
|
|
60
|
-
export type $ElementKind = $Aux['ElementKind']
|
|
61
|
-
export type $RelationKind = $Aux['RelationKind']
|
|
62
|
-
export type $DeploymentKind = $Aux['DeploymentKind']
|
|
63
|
-
export type $Tag = $Aux['Tag']
|
|
64
|
-
export type $Tags = readonly $Aux['Tag'][]
|
|
65
|
-
export type $MetadataKey = $Aux['MetadataKey']
|
|
66
|
-
`.trimStart();
|
|
67
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import JSON5 from "json5";
|
|
2
|
-
import { generateAux } from "./generate-aux.js";
|
|
3
|
-
export function generateLikeC4Model(model, options = {}) {
|
|
4
|
-
const aux = generateAux(model, options);
|
|
5
|
-
const { useCorePackage = false } = options;
|
|
6
|
-
return `
|
|
7
|
-
/* prettier-ignore-start */
|
|
8
|
-
/* eslint-disable */
|
|
9
|
-
|
|
10
|
-
/******************************************************************************
|
|
11
|
-
* This file was generated
|
|
12
|
-
* DO NOT EDIT MANUALLY!
|
|
13
|
-
******************************************************************************/
|
|
14
|
-
|
|
15
|
-
import { LikeC4Model } from '${useCorePackage ? "@likec4/core" : "likec4"}/model'
|
|
16
|
-
${aux}
|
|
17
|
-
|
|
18
|
-
export const likec4model: LikeC4Model<$Aux> = new LikeC4Model(${JSON5.stringify(model.$data, { space: 2, quote: "'" })} as any) as any
|
|
19
|
-
|
|
20
|
-
/* prettier-ignore-end */
|
|
21
|
-
`.trimStart();
|
|
22
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { nonexhaustive } from "@likec4/core";
|
|
2
|
-
import { RichText } from "@likec4/core/types";
|
|
3
|
-
import { CompositeGeneratorNode, joinToNode, NL, toString } from "langium/generate";
|
|
4
|
-
import { isEmptyish, isNullish as isNil } from "remeda";
|
|
5
|
-
const capitalizeFirstLetter = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
|
|
6
|
-
const fqnName = (nodeId) => {
|
|
7
|
-
return nodeId.split(/[.-]/).map(capitalizeFirstLetter).join("");
|
|
8
|
-
};
|
|
9
|
-
const nodeName = (node) => {
|
|
10
|
-
return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
|
|
11
|
-
};
|
|
12
|
-
const pumlColor = (color, customColorProvider, defaultColor = "#3b82f6") => {
|
|
13
|
-
if (color) {
|
|
14
|
-
return customColorProvider(color) ?? defaultColor;
|
|
15
|
-
}
|
|
16
|
-
return defaultColor;
|
|
17
|
-
};
|
|
18
|
-
const pumlDirection = ({ autoLayout }) => {
|
|
19
|
-
switch (autoLayout.direction) {
|
|
20
|
-
case "TB": {
|
|
21
|
-
return "top to bottom";
|
|
22
|
-
}
|
|
23
|
-
case "BT": {
|
|
24
|
-
console.warn("Bottom to top direction is not supported. Defaulting to top to bottom.");
|
|
25
|
-
return "top to bottom";
|
|
26
|
-
}
|
|
27
|
-
case "LR": {
|
|
28
|
-
return "left to right";
|
|
29
|
-
}
|
|
30
|
-
case "RL": {
|
|
31
|
-
console.warn("Right to left direction is not supported. Defaulting to left to right.");
|
|
32
|
-
return "left to right";
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
const pumlShape = ({ shape }) => {
|
|
37
|
-
switch (shape) {
|
|
38
|
-
case "queue":
|
|
39
|
-
case "rectangle":
|
|
40
|
-
case "person": {
|
|
41
|
-
return shape;
|
|
42
|
-
}
|
|
43
|
-
case "storage":
|
|
44
|
-
case "cylinder": {
|
|
45
|
-
return "database";
|
|
46
|
-
}
|
|
47
|
-
case "document":
|
|
48
|
-
case "mobile":
|
|
49
|
-
case "bucket":
|
|
50
|
-
case "browser": {
|
|
51
|
-
return "rectangle";
|
|
52
|
-
}
|
|
53
|
-
default:
|
|
54
|
-
nonexhaustive(shape);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
const escapeLabel = (label) => isEmptyish(label) ? null : JSON.stringify(label).slice(1, -1).replace(/\\"/g, '"');
|
|
58
|
-
export function generatePuml(viewmodel) {
|
|
59
|
-
const view = viewmodel.$view;
|
|
60
|
-
const colors = viewmodel.$model.$styles.theme.colors;
|
|
61
|
-
const { nodes, edges } = view;
|
|
62
|
-
const elemntColorProvider = (key) => (colorKey) => colorKey in colors ? colors[colorKey].elements[key] : void 0;
|
|
63
|
-
const relationshipsColorProvider = (key) => (colorKey) => colorKey in colors ? colors[colorKey].relationships[key] : void 0;
|
|
64
|
-
const names = /* @__PURE__ */ new Map();
|
|
65
|
-
const printHeader = () => {
|
|
66
|
-
return new CompositeGeneratorNode().append('title "', viewmodel.titleOrId, '"', NL).append(pumlDirection(view), " direction", NL);
|
|
67
|
-
};
|
|
68
|
-
const printTheme = () => {
|
|
69
|
-
return new CompositeGeneratorNode().append("hide stereotype", NL).append("skinparam ranksep ", "60", NL).append("skinparam nodesep ", "30", NL).append("skinparam {", NL).indent({
|
|
70
|
-
indentedChildren: (indent) => indent.append("arrowFontSize ", "10", NL).append("defaultTextAlignment ", "center", NL).append("wrapWidth ", "200", NL).append("maxMessageSize ", "100", NL).append("shadowing ", "false", NL),
|
|
71
|
-
indentation: 2
|
|
72
|
-
}).append("}", NL);
|
|
73
|
-
};
|
|
74
|
-
const printStereotypes = (node) => {
|
|
75
|
-
const shape = pumlShape(node);
|
|
76
|
-
const fqn = fqnName(node.id);
|
|
77
|
-
return new CompositeGeneratorNode().append("skinparam ", shape, "<<", fqn, ">>", "{", NL).indent({
|
|
78
|
-
indentedChildren: (indent) => indent.append("BackgroundColor ", pumlColor(node.color, elemntColorProvider("fill")), NL).append(
|
|
79
|
-
"FontColor ",
|
|
80
|
-
pumlColor(node.color, elemntColorProvider("hiContrast"), "#FFFFFF"),
|
|
81
|
-
NL
|
|
82
|
-
).append("BorderColor ", pumlColor(node.color, elemntColorProvider("stroke")), NL),
|
|
83
|
-
indentation: 2
|
|
84
|
-
}).append("}", NL);
|
|
85
|
-
};
|
|
86
|
-
const printNode = (node) => {
|
|
87
|
-
const shape = pumlShape(node);
|
|
88
|
-
const fqn = fqnName(node.id);
|
|
89
|
-
const label = escapeLabel(node.title) || nodeName(node);
|
|
90
|
-
const tech = escapeLabel(node.technology);
|
|
91
|
-
names.set(node.id, fqn);
|
|
92
|
-
const description = RichText.from(node.description);
|
|
93
|
-
return new CompositeGeneratorNode().append(shape, " ").append('"').append("==", label).appendIf(!!tech, `\\n<size:10>[`, tech, "]</size>").appendIf(description.nonEmpty, `\\n\\n`, escapeLabel(description.text)).append('"', " <<", fqn, ">> ", "as ", fqn, NL);
|
|
94
|
-
};
|
|
95
|
-
const printBoundary = (node) => {
|
|
96
|
-
const label = escapeLabel(node.title) || nodeName(node);
|
|
97
|
-
const fqn = fqnName(node.id);
|
|
98
|
-
names.set(node.id, fqn);
|
|
99
|
-
return new CompositeGeneratorNode().append('rectangle "', label, '" <<', fqn, ">> as ", fqn, " {", NL).indent({
|
|
100
|
-
indentedChildren: (indent) => indent.append(
|
|
101
|
-
"skinparam ",
|
|
102
|
-
"RectangleBorderColor<<",
|
|
103
|
-
fqn,
|
|
104
|
-
">> ",
|
|
105
|
-
pumlColor(node.color, elemntColorProvider("fill")),
|
|
106
|
-
NL
|
|
107
|
-
).append(
|
|
108
|
-
"skinparam ",
|
|
109
|
-
"RectangleFontColor<<",
|
|
110
|
-
fqn,
|
|
111
|
-
">> ",
|
|
112
|
-
pumlColor(node.color, elemntColorProvider("fill")),
|
|
113
|
-
NL
|
|
114
|
-
).append("skinparam ", "RectangleBorderStyle<<", fqn, ">> ", "dashed", NL, NL).append(joinToNode(
|
|
115
|
-
nodes.filter((n) => n.parent === node.id),
|
|
116
|
-
(c) => c.children.length > 0 ? printBoundary(c) : printNode(c)
|
|
117
|
-
)),
|
|
118
|
-
indentation: 2
|
|
119
|
-
}).append("}", NL);
|
|
120
|
-
};
|
|
121
|
-
const printEdge = (edge) => {
|
|
122
|
-
const tech = edge.technology || "";
|
|
123
|
-
const label = edge.label || tech;
|
|
124
|
-
const color = pumlColor(edge.color, relationshipsColorProvider("line"), "#777777");
|
|
125
|
-
const withColor = (text) => `<color:${color}>${text.replaceAll('"', `'`)}`;
|
|
126
|
-
const out = new CompositeGeneratorNode().append(
|
|
127
|
-
names.get(edge.source),
|
|
128
|
-
" .[",
|
|
129
|
-
color,
|
|
130
|
-
",thickness=2].> ",
|
|
131
|
-
names.get(edge.target)
|
|
132
|
-
);
|
|
133
|
-
if (label || tech) {
|
|
134
|
-
out.append(
|
|
135
|
-
" : ",
|
|
136
|
-
// Prepend color to each line
|
|
137
|
-
label.split("\n").map((l) => isEmptyish(l) ? l : withColor(l)).join("\\n")
|
|
138
|
-
);
|
|
139
|
-
if (tech && tech !== label) {
|
|
140
|
-
out.append("\\n<size:8>[", withColor(tech), "]</size>");
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return out.append(NL);
|
|
144
|
-
};
|
|
145
|
-
return toString(
|
|
146
|
-
new CompositeGeneratorNode().append("@startuml", NL).append(printHeader(), NL).append(printTheme(), NL).append(
|
|
147
|
-
joinToNode(
|
|
148
|
-
nodes.filter((n) => n.children.length == 0),
|
|
149
|
-
(n) => printStereotypes(n),
|
|
150
|
-
{
|
|
151
|
-
appendNewLineIfNotEmpty: true
|
|
152
|
-
}
|
|
153
|
-
)
|
|
154
|
-
).append(
|
|
155
|
-
joinToNode(
|
|
156
|
-
nodes.filter((n) => isNil(n.parent)),
|
|
157
|
-
(n) => n.children.length > 0 ? printBoundary(n) : printNode(n),
|
|
158
|
-
{
|
|
159
|
-
appendNewLineIfNotEmpty: true
|
|
160
|
-
}
|
|
161
|
-
)
|
|
162
|
-
).appendIf(
|
|
163
|
-
edges.length > 0,
|
|
164
|
-
NL,
|
|
165
|
-
joinToNode(edges, (e) => printEdge(e), {
|
|
166
|
-
appendNewLineIfNotEmpty: true
|
|
167
|
-
})
|
|
168
|
-
).append(`@enduml`, NL)
|
|
169
|
-
);
|
|
170
|
-
}
|
package/dist/puml/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { generatePuml } from './generate-puml';
|
package/dist/puml/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { generatePuml } from "./generate-puml.js";
|