@likec4/generators 1.0.0-next.11 → 1.0.0-next.14

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.
@@ -0,0 +1,2 @@
1
+ import type { ComputedView } from '@likec4/core';
2
+ export declare function generateD2<V extends ComputedView>(view: V): string;
@@ -0,0 +1,75 @@
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) {
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 'person': {
30
+ return shape;
31
+ }
32
+ case 'storage': {
33
+ return 'stored_data';
34
+ }
35
+ case 'mobile':
36
+ case 'browser': {
37
+ return 'rectangle';
38
+ }
39
+ }
40
+ };
41
+ export function generateD2(view) {
42
+ const { nodes, edges } = view;
43
+ const names = new Map();
44
+ const printNode = (node, parentName) => {
45
+ const name = nodeName(node);
46
+ const fqnName = (parentName ? parentName + '.' : '') + name;
47
+ names.set(node.id, fqnName);
48
+ const label = JSON.stringify(node.title);
49
+ const shape = d2shape(node);
50
+ return new CompositeGeneratorNode()
51
+ .append(name, ': {', NL)
52
+ .indent({
53
+ indentedChildren: indent => indent
54
+ .append('label: ', label, NL)
55
+ .appendIf(shape !== 'rectangle', 'shape: ', shape, NL)
56
+ .appendIf(node.children.length > 0, NL, joinToNode(nodes.filter(n => n.parent === node.id), n => printNode(n, fqnName))),
57
+ indentation: 2
58
+ })
59
+ .append('}', NL);
60
+ };
61
+ // return `${names.get(edge.source)} -> ${names.get(edge.target)}${edge.label ? ': ' + edge.label : ''}`
62
+ const printEdge = (edge) => {
63
+ return new CompositeGeneratorNode()
64
+ .append(names.get(edge.source), ' -> ', names.get(edge.target))
65
+ .append(out => edge.label && out.append(': ', JSON.stringify(edge.label)));
66
+ };
67
+ return toString(new CompositeGeneratorNode()
68
+ .append('direction: ', d2direction(view), NL, NL)
69
+ .append(joinToNode(nodes.filter(n => isNil(n.parent)), n => printNode(n), {
70
+ appendNewLineIfNotEmpty: true
71
+ }))
72
+ .appendIf(edges.length > 0, NL, joinToNode(edges, e => printEdge(e), {
73
+ appendNewLineIfNotEmpty: true
74
+ })));
75
+ }
@@ -0,0 +1 @@
1
+ export * from './generate-d2';
@@ -0,0 +1 @@
1
+ export * from './generate-d2';
@@ -0,0 +1,5 @@
1
+ export { generateD2 } from './d2/generate-d2';
2
+ export { generateMermaid } from './mmd/generate-mmd';
3
+ export { generateReactNext } from './react-next/generate-react-next';
4
+ export { generateReact } from './react/generate-react';
5
+ export { generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs } from './views-data-ts/generate-views-data';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { generateD2 } from './d2/generate-d2';
2
+ export { generateMermaid } from './mmd/generate-mmd';
3
+ export { generateReactNext } from './react-next/generate-react-next';
4
+ export { generateReact } from './react/generate-react';
5
+ export { generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs } from './views-data-ts/generate-views-data';
@@ -0,0 +1,2 @@
1
+ import type { ComputedView } from '@likec4/core';
2
+ export declare function generateMermaid<V extends ComputedView>(view: V): string;
@@ -0,0 +1,72 @@
1
+ import { CompositeGeneratorNode, expandToNode, joinToNode, NL, NLEmpty, 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 mmdshape = ({ shape }) => {
9
+ switch (shape) {
10
+ case 'queue':
11
+ case 'cylinder':
12
+ return ['[(', ')]'];
13
+ case 'person': {
14
+ return ['[fa:fa-user ', ']'];
15
+ }
16
+ case 'storage':
17
+ return ['([', '])'];
18
+ case 'mobile':
19
+ case 'browser':
20
+ case 'rectangle': {
21
+ return ['[', ']'];
22
+ }
23
+ }
24
+ };
25
+ export function generateMermaid(view) {
26
+ const { nodes, edges } = view;
27
+ const names = new Map();
28
+ const printNode = (node, parentName) => {
29
+ const name = nodeName(node);
30
+ const fqnName = (parentName ? parentName + '.' : '') + name;
31
+ names.set(node.id, fqnName);
32
+ const label = node.title.replaceAll('\n', '\\n');
33
+ const shape = mmdshape(node);
34
+ const baseNode = new CompositeGeneratorNode();
35
+ if (node.children.length > 0) {
36
+ baseNode
37
+ .append('subgraph ', fqnName, '[', JSON.stringify(node.title), ']', NL)
38
+ .indent({
39
+ indentedChildren: [
40
+ joinToNode(nodes.filter(n => n.parent === node.id), n => printNode(n, fqnName), {
41
+ appendNewLineIfNotEmpty: true
42
+ })
43
+ ],
44
+ indentation: 2
45
+ })
46
+ .append('end', NL);
47
+ }
48
+ else {
49
+ baseNode.append(fqnName, shape[0], label, shape[1]);
50
+ }
51
+ return baseNode;
52
+ };
53
+ // return `${names.get(edge.source)} -> ${names.get(edge.target)}${edge.label ? ': ' + edge.label : ''}`
54
+ const printEdge = (edge) => {
55
+ return new CompositeGeneratorNode().append(names.get(edge.source), ' -.', edge.label ? ' "' + edge.label.replaceAll('\n', '\\n') + '" .-' : '-', '> ', names.get(edge.target));
56
+ };
57
+ return toString(new CompositeGeneratorNode()
58
+ .appendIf(view.title !== null && view.title.length > 0, '---', NL, `title: ${JSON.stringify(view.title)}`, NL, '---', NL)
59
+ .append('graph ', view.autoLayout, NL)
60
+ .indent({
61
+ indentedChildren: indent => {
62
+ indent
63
+ .append(joinToNode(nodes.filter(n => isNil(n.parent)), n => printNode(n), {
64
+ appendNewLineIfNotEmpty: true
65
+ }))
66
+ .appendIf(edges.length > 0, joinToNode(edges, e => printEdge(e), {
67
+ appendNewLineIfNotEmpty: true
68
+ }));
69
+ },
70
+ indentation: 2
71
+ }));
72
+ }
@@ -0,0 +1 @@
1
+ export * from './generate-mmd';
@@ -0,0 +1 @@
1
+ export * from './generate-mmd';
@@ -0,0 +1,2 @@
1
+ import type { DiagramView } from '@likec4/core';
2
+ export declare function generateReact(views: DiagramView[]): string;
@@ -1,30 +1,22 @@
1
- import type { DiagramView } from '@likec4/core'
2
- import JSON5 from 'json5'
3
- import { CompositeGeneratorNode, expandToNode, joinToNode, NL, toString } from 'langium/generate'
4
-
5
- const componentName = (value: string): string => {
6
- if (!value.charAt(0).match(/[a-zA-Z]/)) {
7
- value = 'View' + value
8
- }
9
- value = value.replaceAll('_', '')
10
- return value.charAt(0).toLocaleUpperCase() + value.slice(1)
11
- }
12
-
13
- export const generateViewId = (views: Iterable<DiagramView>) =>
14
- joinToNode(views, view => expandToNode`'${view.id}'`, {
15
- separator: ' | '
16
- })
17
-
18
- export function generateReact(views: DiagramView[]) {
19
- const components = views.map(({ id }) => {
20
- return {
21
- id,
22
- name: componentName(id)
1
+ import JSON5 from 'json5';
2
+ import { CompositeGeneratorNode, expandToNode, joinToNode, NL, toString } from 'langium/generate';
3
+ import { generateViewId } from '../views-data-ts/generateViewId';
4
+ const componentName = (value) => {
5
+ if (!value.charAt(0).match(/[a-zA-Z]/)) {
6
+ value = 'View' + value;
23
7
  }
24
- })
25
-
26
- const out = new CompositeGeneratorNode()
27
- out.appendTemplate`
8
+ value = value.replaceAll('_', '');
9
+ return value.charAt(0).toLocaleUpperCase() + value.slice(1);
10
+ };
11
+ export function generateReact(views) {
12
+ const components = views.map(({ id }) => {
13
+ return {
14
+ id,
15
+ name: componentName(id)
16
+ };
17
+ });
18
+ const out = new CompositeGeneratorNode();
19
+ out.appendTemplate `
28
20
  /******************************************************************************
29
21
  * This file was generated
30
22
  * DO NOT EDIT MANUALLY!
@@ -37,38 +29,25 @@ export function generateReact(views: DiagramView[]) {
37
29
 
38
30
  import type { DiagramView } from '@likec4/diagrams'
39
31
  import { LikeC4 } from '@likec4/diagrams'
40
- `.append(NL, NL)
41
-
42
- if (components.length == 0) {
43
- out.append('export {}', NL)
44
- return toString(out)
45
- }
46
-
47
- out.appendTemplate`
32
+ `.append(NL, NL);
33
+ if (components.length == 0) {
34
+ out.append('export {}', NL);
35
+ return toString(out);
36
+ }
37
+ out.appendTemplate `
48
38
  export type LikeC4ViewId = ${generateViewId(views)};
49
39
  export const LikeC4Views = {
50
40
  `
51
- .indent({
52
- indentation: 2,
53
- indentedChildren(indented) {
54
- indented.appendNewLineIf(views.length > 1).append(
55
- joinToNode(
56
- views,
57
- view =>
58
- expandToNode`${JSON5.stringify(view.id)}: (${
59
- JSON5.stringify(
60
- view
61
- )
62
- } as unknown) as DiagramView`,
63
- {
64
- separator: ',',
65
- appendNewLineIfNotEmpty: true
66
- }
67
- )
68
- )
69
- }
41
+ .indent({
42
+ indentation: 2,
43
+ indentedChildren(indented) {
44
+ indented.appendNewLineIf(views.length > 1).append(joinToNode(views, view => expandToNode `${JSON5.stringify(view.id)}: (${JSON5.stringify(view)} as unknown) as DiagramView`, {
45
+ separator: ',',
46
+ appendNewLineIfNotEmpty: true
47
+ }));
48
+ }
70
49
  })
71
- .append('} as const satisfies Record<LikeC4ViewId, DiagramView>', NL, NL).appendTemplate`
50
+ .append('} as const satisfies Record<LikeC4ViewId, DiagramView>', NL, NL).appendTemplate `
72
51
  export type LikeC4Views = typeof LikeC4Views
73
52
 
74
53
  export const {
@@ -113,7 +92,6 @@ export function generateReact(views: DiagramView[]) {
113
92
  } from '@likec4/diagrams'
114
93
 
115
94
  /* prettier-ignore-end */
116
- `.append(NL)
117
-
118
- return toString(out)
95
+ `.append(NL);
96
+ return toString(out);
119
97
  }
@@ -0,0 +1 @@
1
+ export { generateReact as default } from './generate-react';
@@ -0,0 +1 @@
1
+ export { generateReact as default } from './generate-react';
@@ -0,0 +1,17 @@
1
+ import type { DiagramView } from '@likec4/core';
2
+ export declare function generateReactNext(views: Iterable<DiagramView>): {
3
+ viewsData: {
4
+ fileName: string;
5
+ js: string;
6
+ dts: string;
7
+ };
8
+ components: {
9
+ js: string;
10
+ dts: string;
11
+ fileName: string;
12
+ };
13
+ index: {
14
+ js: string;
15
+ dts: string;
16
+ };
17
+ };
@@ -0,0 +1,102 @@
1
+ import { CompositeGeneratorNode, toString } from 'langium/generate';
2
+ import { generateViewsDataDTs, generateViewsDataJs } from '../views-data-ts/generate-views-data';
3
+ export function generateReactNext(views) {
4
+ return {
5
+ viewsData: {
6
+ fileName: 'likec4-views-data',
7
+ js: generateViewsDataJs(views),
8
+ dts: generateViewsDataDTs(views)
9
+ },
10
+ components: {
11
+ fileName: 'likec4-components',
12
+ ...generateComponents()
13
+ },
14
+ index: generateIndex()
15
+ };
16
+ }
17
+ function generateComponents() {
18
+ const js = new CompositeGeneratorNode().appendTemplate `
19
+ /******************************************************************************
20
+ * This file was generated
21
+ * DO NOT EDIT MANUALLY!
22
+ ******************************************************************************/
23
+ /* prettier-ignore-start */
24
+ /* eslint-disable */
25
+ import { createElement } from "react";
26
+ import { LikeC4Diagram, EmbeddedLikeC4Diagram } from "@likec4/diagram";
27
+ import { LikeC4Views } from "./likec4-views-data";
28
+ export function LikeC4View({ viewId, ...props }) {
29
+ const view = LikeC4Views[viewId];
30
+ if (!view) {
31
+ throw new Error(\`LikeC4View NotFound: "\${viewId}"\`);
32
+ }
33
+ return createElement(LikeC4Diagram, { view: view, ...props });
34
+ }
35
+ export function EmbeddedLikeC4View({ viewId, ...props }) {
36
+ return createElement(EmbeddedLikeC4Diagram, { viewId: viewId, views: LikeC4Views, ...props });
37
+ }
38
+ /* prettier-ignore-end */
39
+ `;
40
+ const dts = new CompositeGeneratorNode().appendTemplate `
41
+ /// <reference types="react" />
42
+ /******************************************************************************
43
+ * This file was generated
44
+ * DO NOT EDIT MANUALLY!
45
+ ******************************************************************************/
46
+ /* prettier-ignore-start */
47
+ /* eslint-disable */
48
+
49
+ import type { LikeC4DiagramProps, EmbeddedLikeC4DiagramProps } from "@likec4/diagram";
50
+ import type { LikeC4ViewId } from "./likec4-views-data";
51
+
52
+ export type LikeC4ViewProps = {
53
+ viewId: LikeC4ViewId;
54
+ } & Omit<LikeC4DiagramProps, "view">;
55
+
56
+ export declare function LikeC4View({ viewId, ...props }: LikeC4ViewProps): JSX.Element;
57
+
58
+ export type EmbeddedLikeC4ViewProps = {
59
+ viewId: LikeC4ViewId;
60
+ } & Omit<EmbeddedLikeC4DiagramProps, "viewId" | "views">;
61
+
62
+ export declare function EmbeddedLikeC4View({ viewId, ...props }: EmbeddedLikeC4ViewProps): JSX.Element;
63
+ /* prettier-ignore-end */
64
+ `;
65
+ return {
66
+ js: toString(js),
67
+ dts: toString(dts)
68
+ };
69
+ }
70
+ function generateIndex() {
71
+ const js = new CompositeGeneratorNode().appendTemplate `
72
+ /* prettier-ignore-start */
73
+ /* eslint-disable */
74
+
75
+ // You are safe to edit/move these style imports,
76
+ // but they are required
77
+ import "@mantine/core/styles.css";
78
+ import "@likec4/diagram/style.css";
79
+
80
+ export * from "./likec4-components";
81
+
82
+ // OR with lazy loading:
83
+ //
84
+ // import { lazy } from "react";
85
+ // export const LikeC4View = lazy(async () => await import("./likec4-components").then(m => ({default: m.LikeC4View})));
86
+ // export const EmbeddedLikeC4View = lazy(async () => await import("./likec4-components").then(m => ({default: m.EmbeddedLikeC4View})));
87
+
88
+ /* prettier-ignore-end */
89
+ `;
90
+ const dts = new CompositeGeneratorNode().appendTemplate `
91
+ /* prettier-ignore-start */
92
+ /* eslint-disable */
93
+
94
+ export * from "./likec4-components";
95
+
96
+ /* prettier-ignore-end */
97
+ `;
98
+ return {
99
+ js: toString(js),
100
+ dts: toString(dts)
101
+ };
102
+ }
@@ -0,0 +1 @@
1
+ export { generateReactNext as default } from './generate-react-next';
@@ -0,0 +1 @@
1
+ export { generateReactNext as default } from './generate-react-next';
@@ -0,0 +1,4 @@
1
+ import type { DiagramView } from '@likec4/core';
2
+ export declare function generateViewsDataJs(diagrams: Iterable<DiagramView>): string;
3
+ export declare function generateViewsDataTs(diagrams: Iterable<DiagramView>): string;
4
+ export declare function generateViewsDataDTs(diagrams: Iterable<DiagramView>): string;
@@ -0,0 +1,122 @@
1
+ import JSON5 from 'json5';
2
+ import { CompositeGeneratorNode, expandToNode, joinToNode, NL, toString } from 'langium/generate';
3
+ import { generateViewId } from './generateViewId';
4
+ export function generateViewsDataJs(diagrams) {
5
+ const views = Array.from(diagrams);
6
+ const out = new CompositeGeneratorNode();
7
+ out.appendTemplate `
8
+ /******************************************************************************
9
+ * This file was generated
10
+ * DO NOT EDIT MANUALLY!
11
+ ******************************************************************************/
12
+ /* prettier-ignore-start */
13
+ /* eslint-disable */
14
+
15
+ `.append(NL, NL);
16
+ if (views.length == 0) {
17
+ out.append('export const LikeC4Views = {}', NL);
18
+ return toString(out);
19
+ }
20
+ out.appendTemplate `
21
+ export const LikeC4Views = {
22
+ `
23
+ .indent({
24
+ indentation: 2,
25
+ indentedChildren(indented) {
26
+ indented.appendNewLineIf(views.length > 1).append(joinToNode(views, view => expandToNode `${JSON5.stringify(view.id)}: ${JSON5.stringify(view)}`, {
27
+ separator: ',',
28
+ appendNewLineIfNotEmpty: true
29
+ }));
30
+ }
31
+ })
32
+ .append('}', NL, NL).appendTemplate `
33
+
34
+ export function isLikeC4ViewId(value) {
35
+ return (
36
+ value != null &&
37
+ typeof value === 'string' &&
38
+ Object.hasOwn(LikeC4Views, value) &&
39
+ LikeC4Views[value] != null
40
+ )
41
+ }
42
+
43
+ /* prettier-ignore-end */
44
+ `.append(NL);
45
+ return toString(out);
46
+ }
47
+ export function generateViewsDataTs(diagrams) {
48
+ const views = Array.from(diagrams);
49
+ const out = new CompositeGeneratorNode();
50
+ out.appendTemplate `
51
+ /******************************************************************************
52
+ * This file was generated
53
+ * DO NOT EDIT MANUALLY!
54
+ ******************************************************************************/
55
+ /* prettier-ignore-start */
56
+ /* eslint-disable */
57
+
58
+ // @ts-nocheck
59
+
60
+ import type { DiagramView } from '@likec4/core'
61
+ `.append(NL, NL);
62
+ if (views.length === 0) {
63
+ out.append('export {}', NL);
64
+ return toString(out);
65
+ }
66
+ out.appendTemplate `
67
+ export type LikeC4ViewId = ${generateViewId(views)};
68
+ export const LikeC4Views = {
69
+ `
70
+ .indent({
71
+ indentation: 2,
72
+ indentedChildren(indented) {
73
+ indented.appendNewLineIf(views.length > 1).append(joinToNode(views, view => expandToNode `${JSON5.stringify(view.id)}: (${JSON5.stringify(view)} as unknown) as DiagramView`, {
74
+ separator: ',',
75
+ appendNewLineIfNotEmpty: true
76
+ }));
77
+ }
78
+ })
79
+ .append('} as const satisfies Record<LikeC4ViewId, DiagramView>', NL, NL).appendTemplate `
80
+ export type LikeC4Views = typeof LikeC4Views
81
+
82
+ export function isLikeC4ViewId(value: unknown): value is LikeC4ViewId {
83
+ return (
84
+ value != null &&
85
+ typeof value === 'string' &&
86
+ Object.hasOwn(LikeC4Views, value) &&
87
+ LikeC4Views[value] != null
88
+ )
89
+ }
90
+
91
+ /* prettier-ignore-end */
92
+ `.append(NL);
93
+ return toString(out);
94
+ }
95
+ export function generateViewsDataDTs(diagrams) {
96
+ const views = Array.from(diagrams);
97
+ const out = new CompositeGeneratorNode();
98
+ out.appendTemplate `
99
+ /******************************************************************************
100
+ * This file was generated
101
+ * DO NOT EDIT MANUALLY!
102
+ ******************************************************************************/
103
+ /* prettier-ignore-start */
104
+ /* eslint-disable */
105
+
106
+ import type { DiagramView } from '@likec4/core'
107
+ `.append(NL, NL);
108
+ if (views.length == 0) {
109
+ out.append('export {}', NL);
110
+ return toString(out);
111
+ }
112
+ out.appendTemplate `
113
+ export type LikeC4ViewId = ${generateViewId(views)};
114
+ export type LikeC4Views = Record<LikeC4ViewId, DiagramView>
115
+
116
+ export declare const LikeC4Views: LikeC4Views
117
+ export declare function isLikeC4ViewId(value: unknown): value is LikeC4ViewId
118
+
119
+ /* prettier-ignore-end */
120
+ `.append(NL);
121
+ return toString(out);
122
+ }
@@ -0,0 +1,2 @@
1
+ import type { DiagramView } from '@likec4/core';
2
+ export declare function generateViewId(views: Iterable<DiagramView>): import("langium/generate").CompositeGeneratorNode | undefined;
@@ -0,0 +1,6 @@
1
+ import { expandToNode, joinToNode } from 'langium/generate';
2
+ export function generateViewId(views) {
3
+ return joinToNode(views, view => expandToNode `'${view.id}'`, {
4
+ separator: ' | '
5
+ });
6
+ }
@@ -0,0 +1 @@
1
+ export * from './generate-views-data';
@@ -0,0 +1 @@
1
+ export * from './generate-views-data';
package/package.json CHANGED
@@ -1,15 +1,13 @@
1
1
  {
2
2
  "name": "@likec4/generators",
3
- "version": "1.0.0-next.11",
3
+ "version": "1.0.0-next.14",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",
7
7
  "author": "Denis Davydkov <denis@davydkov.com>",
8
8
  "files": [
9
- "src",
10
- "!**/__mocks__/**",
11
- "!**/*.spec.*",
12
- "!**/*.map"
9
+ "dist",
10
+ "!dist/src"
13
11
  ],
14
12
  "repository": {
15
13
  "type": "git",
@@ -19,31 +17,39 @@
19
17
  "type": "module",
20
18
  "sideEffects": false,
21
19
  "exports": {
22
- ".": "./src/index.ts"
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
23
24
  },
24
25
  "publishConfig": {
25
26
  "registry": "https://registry.npmjs.org",
26
- "access": "public"
27
+ "access": "public",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ }
33
+ }
27
34
  },
28
35
  "scripts": {
29
36
  "typecheck": "tsc --noEmit",
30
- "build": "unbuild",
31
- "prepack": "unbuild",
37
+ "build": "tsc -b",
38
+ "prepack": "tsc -p tsconfig.build.json",
32
39
  "lint": "run -T eslint src/ --fix",
33
40
  "clean": "run -T rimraf dist",
34
41
  "test": "run -T vitest run"
35
42
  },
36
43
  "dependencies": {
37
- "@likec4/core": "1.0.0-next.11",
44
+ "@likec4/core": "1.0.0-next.14",
38
45
  "json5": "^2.2.3",
39
46
  "langium": "^3.0.0",
40
47
  "remeda": "^1.56.0"
41
48
  },
42
49
  "devDependencies": {
43
- "@types/node": "^20.11.25",
44
- "typescript": "^5.4.3",
45
- "unbuild": "^2.0.0",
46
- "vitest": "^1.4.0"
50
+ "@types/node": "^20.12.7",
51
+ "typescript": "^5.4.5",
52
+ "vitest": "~1.4.0"
47
53
  },
48
54
  "packageManager": "yarn@4.1.1"
49
55
  }
@@ -1,106 +0,0 @@
1
- import type { ComputedEdge, ComputedNode, ComputedView, NodeId } from '@likec4/core'
2
- import { CompositeGeneratorNode, joinToNode, NL, toString } from 'langium/generate'
3
- import { isNullish as isNil } from 'remeda'
4
-
5
- const capitalizeFirstLetter = (value: string) => value.charAt(0).toLocaleUpperCase() + value.slice(1)
6
-
7
- const fqnName = (nodeId: string): string => nodeId.split('.').map(capitalizeFirstLetter).join('')
8
-
9
- const nodeName = (node: ComputedNode): string => {
10
- return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id)
11
- }
12
-
13
- const d2direction = ({ autoLayout }: ComputedView) => {
14
- switch (autoLayout) {
15
- case 'TB': {
16
- return 'down'
17
- }
18
- case 'BT': {
19
- return 'up'
20
- }
21
- case 'LR': {
22
- return 'right'
23
- }
24
- case 'RL': {
25
- return 'left'
26
- }
27
- }
28
- }
29
-
30
- const d2shape = ({ shape }: ComputedNode) => {
31
- switch (shape) {
32
- case 'queue':
33
- case 'cylinder':
34
- case 'rectangle':
35
- case 'person': {
36
- return shape
37
- }
38
- case 'storage': {
39
- return 'stored_data' as const
40
- }
41
- case 'mobile':
42
- case 'browser': {
43
- return 'rectangle' as const
44
- }
45
- }
46
- }
47
-
48
- export function generateD2<V extends ComputedView>(view: V) {
49
- const { nodes, edges } = view
50
- const names = new Map<NodeId, string>()
51
-
52
- const printNode = (node: ComputedNode, parentName?: string): CompositeGeneratorNode => {
53
- const name = nodeName(node)
54
- const fqnName = (parentName ? parentName + '.' : '') + name
55
- names.set(node.id, fqnName)
56
-
57
- const label = JSON.stringify(node.title)
58
- const shape = d2shape(node)
59
-
60
- return new CompositeGeneratorNode()
61
- .append(name, ': {', NL)
62
- .indent({
63
- indentedChildren: indent =>
64
- indent
65
- .append('label: ', label, NL)
66
- .appendIf(shape !== 'rectangle', 'shape: ', shape, NL)
67
- .appendIf(
68
- node.children.length > 0,
69
- NL,
70
- joinToNode(
71
- nodes.filter(n => n.parent === node.id),
72
- n => printNode(n, fqnName)
73
- )
74
- ),
75
- indentation: 2
76
- })
77
- .append('}', NL)
78
- }
79
- // return `${names.get(edge.source)} -> ${names.get(edge.target)}${edge.label ? ': ' + edge.label : ''}`
80
- const printEdge = (edge: ComputedEdge): CompositeGeneratorNode => {
81
- return new CompositeGeneratorNode()
82
- .append(names.get(edge.source), ' -> ', names.get(edge.target))
83
- .append(out => edge.label && out.append(': ', JSON.stringify(edge.label)))
84
- }
85
-
86
- return toString(
87
- new CompositeGeneratorNode()
88
- .append('direction: ', d2direction(view), NL, NL)
89
- .append(
90
- joinToNode(
91
- nodes.filter(n => isNil(n.parent)),
92
- n => printNode(n),
93
- {
94
- appendNewLineIfNotEmpty: true
95
- }
96
- )
97
- )
98
- .appendIf(
99
- edges.length > 0,
100
- NL,
101
- joinToNode(edges, e => printEdge(e), {
102
- appendNewLineIfNotEmpty: true
103
- })
104
- )
105
- )
106
- }
package/src/d2/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './generate-d2'
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export { generateD2 } from './d2/generate-d2'
2
- export { generateMermaid } from './mmd/generate-mmd'
3
- export { generateReact } from './react/generate-react'
4
- export { generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs } from './views-data-ts/generate-views-data'
@@ -1,110 +0,0 @@
1
- import type { ComputedEdge, ComputedNode, ComputedView, NodeId } from '@likec4/core'
2
- import { CompositeGeneratorNode, expandToNode, joinToNode, NL, NLEmpty, toString } from 'langium/generate'
3
- import { isNullish as isNil } from 'remeda'
4
-
5
- const capitalizeFirstLetter = (value: string) => value.charAt(0).toLocaleUpperCase() + value.slice(1)
6
-
7
- const fqnName = (nodeId: string): string => nodeId.split('.').map(capitalizeFirstLetter).join('')
8
-
9
- const nodeName = (node: ComputedNode): string => {
10
- return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id)
11
- }
12
-
13
- const mmdshape = ({ shape }: ComputedNode): [start: string, end: string] => {
14
- switch (shape) {
15
- case 'queue':
16
- case 'cylinder':
17
- return ['[(', ')]']
18
- case 'person': {
19
- return ['[fa:fa-user ', ']']
20
- }
21
- case 'storage':
22
- return ['([', '])']
23
- case 'mobile':
24
- case 'browser':
25
- case 'rectangle': {
26
- return ['[', ']']
27
- }
28
- }
29
- }
30
-
31
- export function generateMermaid<V extends ComputedView>(view: V) {
32
- const { nodes, edges } = view
33
- const names = new Map<NodeId, string>()
34
-
35
- const printNode = (node: ComputedNode, parentName?: string): CompositeGeneratorNode => {
36
- const name = nodeName(node)
37
- const fqnName = (parentName ? parentName + '.' : '') + name
38
- names.set(node.id, fqnName)
39
-
40
- const label = node.title.replaceAll('\n', '\\n')
41
- const shape = mmdshape(node)
42
-
43
- const baseNode = new CompositeGeneratorNode()
44
- if (node.children.length > 0) {
45
- baseNode
46
- .append('subgraph ', fqnName, '[', JSON.stringify(node.title), ']', NL)
47
- .indent({
48
- indentedChildren: [
49
- joinToNode(
50
- nodes.filter(n => n.parent === node.id),
51
- n => printNode(n, fqnName),
52
- {
53
- appendNewLineIfNotEmpty: true
54
- }
55
- )
56
- ],
57
- indentation: 2
58
- })
59
- .append('end', NL)
60
- } else {
61
- baseNode.append(fqnName, shape[0], label, shape[1])
62
- }
63
- return baseNode
64
- }
65
- // return `${names.get(edge.source)} -> ${names.get(edge.target)}${edge.label ? ': ' + edge.label : ''}`
66
- const printEdge = (edge: ComputedEdge): CompositeGeneratorNode => {
67
- return new CompositeGeneratorNode().append(
68
- names.get(edge.source),
69
- ' -.',
70
- edge.label ? ' "' + edge.label.replaceAll('\n', '\\n') + '" .-' : '-',
71
- '> ',
72
- names.get(edge.target)
73
- )
74
- }
75
-
76
- return toString(
77
- new CompositeGeneratorNode()
78
- .appendIf(
79
- view.title !== null && view.title.length > 0,
80
- '---',
81
- NL,
82
- `title: ${JSON.stringify(view.title)}`,
83
- NL,
84
- '---',
85
- NL
86
- )
87
- .append('graph ', view.autoLayout, NL)
88
- .indent({
89
- indentedChildren: indent => {
90
- indent
91
- .append(
92
- joinToNode(
93
- nodes.filter(n => isNil(n.parent)),
94
- n => printNode(n),
95
- {
96
- appendNewLineIfNotEmpty: true
97
- }
98
- )
99
- )
100
- .appendIf(
101
- edges.length > 0,
102
- joinToNode(edges, e => printEdge(e), {
103
- appendNewLineIfNotEmpty: true
104
- })
105
- )
106
- },
107
- indentation: 2
108
- })
109
- )
110
- }
package/src/mmd/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './generate-mmd'
@@ -1 +0,0 @@
1
- export * from './generate-react'
@@ -1,149 +0,0 @@
1
- import type { DiagramView } from '@likec4/core'
2
- import JSON5 from 'json5'
3
- import { CompositeGeneratorNode, expandToNode, joinToNode, NL, toString } from 'langium/generate'
4
- import { generateViewId } from '../react/generate-react'
5
-
6
- export function generateViewsDataJs(diagrams: Iterable<DiagramView>) {
7
- const views = Array.from(diagrams)
8
- const out = new CompositeGeneratorNode()
9
- out.appendTemplate`
10
- /******************************************************************************
11
- * This file was generated
12
- * DO NOT EDIT MANUALLY!
13
- ******************************************************************************/
14
- /* prettier-ignore-start */
15
- /* eslint-disable */
16
-
17
- `.append(NL, NL)
18
-
19
- if (views.length == 0) {
20
- out.append('export const LikeC4Views = {}', NL)
21
- return toString(out)
22
- }
23
-
24
- out.appendTemplate`
25
- export const LikeC4Views = {
26
- `
27
- .indent({
28
- indentation: 2,
29
- indentedChildren(indented) {
30
- indented.appendNewLineIf(views.length > 1).append(
31
- joinToNode(
32
- views,
33
- view => expandToNode`${JSON5.stringify(view.id)}: ${JSON5.stringify(view)}`,
34
- {
35
- separator: ',',
36
- appendNewLineIfNotEmpty: true
37
- }
38
- )
39
- )
40
- }
41
- })
42
- .append('}', NL, NL).appendTemplate`
43
-
44
- export function isLikeC4ViewId(value) {
45
- return (
46
- value != null &&
47
- typeof value === 'string' &&
48
- Object.hasOwn(LikeC4Views, value) &&
49
- LikeC4Views[value] != null
50
- )
51
- }
52
-
53
- /* prettier-ignore-end */
54
- `.append(NL)
55
- return toString(out)
56
- }
57
-
58
- export function generateViewsDataTs(diagrams: Iterable<DiagramView>) {
59
- const views = Array.from(diagrams)
60
- const out = new CompositeGeneratorNode()
61
- out.appendTemplate`
62
- /******************************************************************************
63
- * This file was generated
64
- * DO NOT EDIT MANUALLY!
65
- ******************************************************************************/
66
- /* prettier-ignore-start */
67
- /* eslint-disable */
68
-
69
- // @ts-nocheck
70
-
71
- import type { DiagramView } from '@likec4/core'
72
- `.append(NL, NL)
73
-
74
- if (views.length === 0) {
75
- out.append('export {}', NL)
76
- return toString(out)
77
- }
78
-
79
- out.appendTemplate`
80
- export type LikeC4ViewId = ${generateViewId(views)};
81
- export const LikeC4Views = {
82
- `
83
- .indent({
84
- indentation: 2,
85
- indentedChildren(indented) {
86
- indented.appendNewLineIf(views.length > 1).append(
87
- joinToNode(
88
- views,
89
- view =>
90
- expandToNode`${JSON5.stringify(view.id)}: (${
91
- JSON5.stringify(
92
- view
93
- )
94
- } as unknown) as DiagramView`,
95
- {
96
- separator: ',',
97
- appendNewLineIfNotEmpty: true
98
- }
99
- )
100
- )
101
- }
102
- })
103
- .append('} as const satisfies Record<LikeC4ViewId, DiagramView>', NL, NL).appendTemplate`
104
- export type LikeC4Views = typeof LikeC4Views
105
-
106
- export function isLikeC4ViewId(value: unknown): value is LikeC4ViewId {
107
- return (
108
- value != null &&
109
- typeof value === 'string' &&
110
- Object.hasOwn(LikeC4Views, value) &&
111
- LikeC4Views[value] != null
112
- )
113
- }
114
-
115
- /* prettier-ignore-end */
116
- `.append(NL)
117
- return toString(out)
118
- }
119
-
120
- export function generateViewsDataDTs(diagrams: Iterable<DiagramView>) {
121
- const views = Array.from(diagrams)
122
- const out = new CompositeGeneratorNode()
123
- out.appendTemplate`
124
- /******************************************************************************
125
- * This file was generated
126
- * DO NOT EDIT MANUALLY!
127
- ******************************************************************************/
128
- /* prettier-ignore-start */
129
- /* eslint-disable */
130
-
131
- import type { DiagramView } from '@likec4/core'
132
- `.append(NL, NL)
133
-
134
- if (views.length == 0) {
135
- out.append('export {}', NL)
136
- return toString(out)
137
- }
138
-
139
- out.appendTemplate`
140
- export type LikeC4ViewId = ${generateViewId(views)};
141
- export type LikeC4Views = Record<LikeC4ViewId, DiagramView>
142
-
143
- export declare const LikeC4Views: LikeC4Views
144
- export declare function isLikeC4ViewId(value: unknown): value is LikeC4ViewId
145
-
146
- /* prettier-ignore-end */
147
- `.append(NL)
148
- return toString(out)
149
- }
@@ -1 +0,0 @@
1
- export * from './generate-views-data'