@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.
Files changed (39) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.d.mts +59 -0
  3. package/dist/index.mjs +589 -0
  4. package/package.json +20 -17
  5. package/src/react/generate-react-types.ts +2 -2
  6. package/dist/d2/generate-d2.d.ts +0 -3
  7. package/dist/d2/generate-d2.js +0 -87
  8. package/dist/d2/index.d.ts +0 -1
  9. package/dist/d2/index.js +0 -1
  10. package/dist/index.d.ts +0 -7
  11. package/dist/index.js +0 -7
  12. package/dist/mmd/generate-mmd.d.ts +0 -3
  13. package/dist/mmd/generate-mmd.js +0 -107
  14. package/dist/mmd/index.d.ts +0 -1
  15. package/dist/mmd/index.js +0 -1
  16. package/dist/model/generate-aux.d.ts +0 -4
  17. package/dist/model/generate-aux.js +0 -67
  18. package/dist/model/generate-likec4-model.d.ts +0 -4
  19. package/dist/model/generate-likec4-model.js +0 -22
  20. package/dist/model/generate-likec4.d.ts +0 -2
  21. package/dist/model/generate-likec4.js +0 -2
  22. package/dist/puml/generate-puml.d.ts +0 -3
  23. package/dist/puml/generate-puml.js +0 -170
  24. package/dist/puml/index.d.ts +0 -1
  25. package/dist/puml/index.js +0 -1
  26. package/dist/react/generate-react-types.d.ts +0 -4
  27. package/dist/react/generate-react-types.js +0 -64
  28. package/dist/react/index.d.ts +0 -1
  29. package/dist/react/index.js +0 -1
  30. package/dist/react-next/generate-react-next.d.ts +0 -20
  31. package/dist/react-next/generate-react-next.js +0 -102
  32. package/dist/react-next/index.d.ts +0 -1
  33. package/dist/react-next/index.js +0 -1
  34. package/dist/views-data-ts/generate-views-data.d.ts +0 -13
  35. package/dist/views-data-ts/generate-views-data.js +0 -130
  36. package/dist/views-data-ts/generateViewId.d.ts +0 -2
  37. package/dist/views-data-ts/generateViewId.js +0 -7
  38. package/dist/views-data-ts/index.d.ts +0 -1
  39. package/dist/views-data-ts/index.js +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023-2025 Denis Davydkov
3
+ Copyright (c) 2023-2026 Denis Davydkov
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,59 @@
1
+ import { DiagramView } from "@likec4/core";
2
+ import { aux } from "@likec4/core/types";
3
+ import { AnyLikeC4Model, LikeC4Model, LikeC4ViewModel } from "@likec4/core/model";
4
+
5
+ //#region src/d2/generate-d2.d.ts
6
+ declare function generateD2(viewmodel: LikeC4ViewModel<aux.Unknown>): string;
7
+ //#endregion
8
+ //#region src/mmd/generate-mmd.d.ts
9
+ declare function generateMermaid(viewmodel: LikeC4ViewModel<aux.Unknown>): string;
10
+ //#endregion
11
+ //#region src/model/generate-likec4-model.d.ts
12
+ declare function generateLikeC4Model(model: LikeC4Model<any>, options?: {
13
+ useCorePackage?: boolean;
14
+ }): string;
15
+ //#endregion
16
+ //#region src/puml/generate-puml.d.ts
17
+ declare function generatePuml(viewmodel: LikeC4ViewModel<aux.Unknown>): string;
18
+ //#endregion
19
+ //#region src/react-next/generate-react-next.d.ts
20
+ /**
21
+ * @deprecated in favor packages/likec4/src/cli/codegen/react/index.ts
22
+ */
23
+ declare function generateReactNext(views: Iterable<DiagramView>): {
24
+ viewsData: {
25
+ fileName: string;
26
+ js: string;
27
+ dts: string;
28
+ };
29
+ components: {
30
+ js: string;
31
+ dts: string;
32
+ fileName: string;
33
+ };
34
+ index: {
35
+ js: string;
36
+ dts: string;
37
+ };
38
+ };
39
+ //#endregion
40
+ //#region src/react/generate-react-types.d.ts
41
+ declare function generateReactTypes(model: AnyLikeC4Model, options?: {
42
+ useCorePackage?: boolean;
43
+ }): string;
44
+ //#endregion
45
+ //#region src/views-data-ts/generate-views-data.d.ts
46
+ /**
47
+ * Generate *.js file with views data
48
+ */
49
+ declare function generateViewsDataJs(diagrams: Iterable<DiagramView>): string;
50
+ /**
51
+ * Generate *.ts file with views data
52
+ */
53
+ declare function generateViewsDataTs(diagrams: Iterable<DiagramView>): string;
54
+ /**
55
+ * Generate *.d.ts
56
+ */
57
+ declare function generateViewsDataDTs(diagrams: Iterable<DiagramView>): string;
58
+ //#endregion
59
+ export { generateD2, generateLikeC4Model, generateMermaid, generatePuml, generateReactNext, generateReactTypes, generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs };
package/dist/index.mjs ADDED
@@ -0,0 +1,589 @@
1
+ import { CompositeGeneratorNode, NL, expandToNode, joinToNode, toString } from "langium/generate";
2
+ import { isEmptyish, isNullish, keys, map, pipe, values } from "remeda";
3
+ import { nonexhaustive } from "@likec4/core";
4
+ import JSON5 from "json5";
5
+ import { compareNatural, invariant, sortNaturalByFqn } from "@likec4/core/utils";
6
+ import { RichText } from "@likec4/core/types";
7
+
8
+ //#region src/d2/generate-d2.ts
9
+ const capitalizeFirstLetter$2 = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
10
+ const fqnName$2 = (nodeId) => nodeId.split(".").map(capitalizeFirstLetter$2).join("");
11
+ const nodeName$2 = (node) => {
12
+ return fqnName$2(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
13
+ };
14
+ const d2direction = ({ autoLayout }) => {
15
+ switch (autoLayout.direction) {
16
+ case "TB": return "down";
17
+ case "BT": return "up";
18
+ case "LR": return "right";
19
+ case "RL": return "left";
20
+ }
21
+ };
22
+ const d2shape = ({ shape }) => {
23
+ switch (shape) {
24
+ case "queue":
25
+ case "cylinder":
26
+ case "rectangle":
27
+ case "document": return shape;
28
+ case "person": return "c4-person";
29
+ case "storage": return "stored_data";
30
+ case "bucket":
31
+ case "mobile":
32
+ case "browser": return "rectangle";
33
+ }
34
+ };
35
+ function generateD2(viewmodel) {
36
+ const view = viewmodel.$view;
37
+ const { nodes, edges } = view;
38
+ const names = /* @__PURE__ */ new Map();
39
+ const printNode = (node, parentName) => {
40
+ const name = nodeName$2(node);
41
+ const fqnName = (parentName ? parentName + "." : "") + name;
42
+ names.set(node.id, fqnName);
43
+ const label = JSON.stringify(node.title);
44
+ const shape = d2shape(node);
45
+ return new CompositeGeneratorNode().append(name, ": {", NL).indent({
46
+ indentedChildren: (indent) => indent.append("label: ", label, NL).appendIf(shape !== "rectangle", "shape: ", shape, NL).appendIf(node.children.length > 0, NL, joinToNode(nodes.filter((n) => n.parent === node.id), (n) => printNode(n, fqnName))),
47
+ indentation: 2
48
+ }).append("}", NL);
49
+ };
50
+ const printEdge = (edge) => {
51
+ return new CompositeGeneratorNode().append(names.get(edge.source), " -> ", names.get(edge.target)).append((out) => edge.label && out.append(": ", JSON.stringify(edge.label)));
52
+ };
53
+ return toString(new CompositeGeneratorNode().append("direction: ", d2direction(view), NL, NL).append(joinToNode(nodes.filter((n) => isNullish(n.parent)), (n) => printNode(n), { appendNewLineIfNotEmpty: true })).appendIf(edges.length > 0, NL, joinToNode(edges, (e) => printEdge(e), { appendNewLineIfNotEmpty: true })));
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/mmd/generate-mmd.ts
58
+ const capitalizeFirstLetter$1 = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
59
+ const fqnName$1 = (nodeId) => nodeId.split(".").map(capitalizeFirstLetter$1).join("");
60
+ const nodeName$1 = (node) => {
61
+ return fqnName$1(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
62
+ };
63
+ const toSingleQuotes = (str) => str.replace(/\\?"/g, `'`);
64
+ const mmdshape = ({ shape, title }) => {
65
+ const label = `label: ${JSON.stringify(title)}`;
66
+ switch (shape) {
67
+ case "queue": return `@{ shape: horizontal-cylinder, ${label} }`;
68
+ case "person": return `@{ icon: "fa:user", shape: rounded, ${label} }`;
69
+ case "storage": return `@{ shape: disk, ${label} }`;
70
+ case "cylinder": return `@{ shape: cylinder, ${label} }`;
71
+ case "mobile":
72
+ case "browser": return `@{ shape: rounded, ${label} }`;
73
+ case "bucket": return `@{ shape: trap-t, ${label} }`;
74
+ case "rectangle": return `@{ shape: rectangle, ${label} }`;
75
+ case "document": return `@{ shape: doc, ${label} }`;
76
+ default: nonexhaustive(shape);
77
+ }
78
+ };
79
+ function generateMermaid(viewmodel) {
80
+ const view = viewmodel.$view;
81
+ const { nodes, edges } = view;
82
+ const names = /* @__PURE__ */ new Map();
83
+ const printNode = (node, parentName) => {
84
+ const name = nodeName$1(node);
85
+ const fqnName = (parentName ? parentName + "." : "") + name;
86
+ names.set(node.id, fqnName);
87
+ const baseNode = new CompositeGeneratorNode();
88
+ if (node.children.length > 0) {
89
+ const label = toSingleQuotes(node.title);
90
+ baseNode.append("subgraph ", fqnName, "[\"`", label, "`\"]", NL).indent({
91
+ indentedChildren: [joinToNode(nodes.filter((n) => n.parent === node.id), (n) => printNode(n, fqnName), { appendNewLineIfNotEmpty: true })],
92
+ indentation: 2
93
+ }).append("end", NL);
94
+ } else baseNode.append(fqnName, mmdshape(node));
95
+ return baseNode;
96
+ };
97
+ const printEdge = (edge) => {
98
+ return new CompositeGeneratorNode().append(names.get(edge.source), " -.", edge.label ? " \"`" + toSingleQuotes(edge.label) + "`\" .-" : "-", "> ", names.get(edge.target));
99
+ };
100
+ return toString(new CompositeGeneratorNode().append("---", NL, `title: ${JSON.stringify(toSingleQuotes(viewmodel.titleOrId))}`, NL, "---", NL).append("graph ", view.autoLayout.direction, NL).indent({
101
+ indentedChildren: (indent) => {
102
+ indent.append(joinToNode(nodes.filter((n) => isNullish(n.parent)), (n) => printNode(n), { appendNewLineIfNotEmpty: true })).appendIf(edges.length > 0, joinToNode(edges, (e) => printEdge(e), { appendNewLineIfNotEmpty: true }));
103
+ },
104
+ indentation: 2
105
+ }));
106
+ }
107
+
108
+ //#endregion
109
+ //#region src/model/generate-aux.ts
110
+ function toUnion(elements) {
111
+ if (elements.length === 0) return "never";
112
+ return elements.sort(compareNatural).map((v) => ` | ${JSON.stringify(v)}`).join("\n").trimStart();
113
+ }
114
+ function elementIdToUnion(_elements) {
115
+ const elements = values(_elements);
116
+ if (elements.length === 0) return "never";
117
+ return pipe(elements, sortNaturalByFqn, map((v) => ` | ${JSON.stringify(v.id)}`)).join("\n").trimStart();
118
+ }
119
+ function generateAux(model, options = {}) {
120
+ const { useCorePackage = false } = options;
121
+ return `
122
+ import type { Aux, SpecAux } from '${useCorePackage ? "@likec4/core/types" : "likec4/model"}';
123
+
124
+ export type $Specs = SpecAux<
125
+ // Element kinds
126
+ ${toUnion(keys(model.specification.elements))},
127
+ // Deployment kinds
128
+ ${toUnion(keys(model.specification.deployments ?? {}))},
129
+ // Relationship kinds
130
+ ${toUnion(keys(model.specification.relationships ?? {}))},
131
+ // Tags
132
+ ${toUnion(keys(model.specification.tags ?? {}))},
133
+ // Metadata keys
134
+ ${toUnion(model.specification.metadataKeys ?? [])}
135
+ >
136
+
137
+ export type $Aux = Aux<
138
+ ${JSON.stringify(model.stage)},
139
+ // Elements
140
+ ${elementIdToUnion(model.$data.elements)},
141
+ // Deployments
142
+ ${elementIdToUnion(model.$data.deployments.elements)},
143
+ // Views
144
+ ${toUnion(keys(model.$data.views))},
145
+ // Project ID
146
+ ${JSON.stringify(model.projectId)},
147
+ $Specs
148
+ >
149
+
150
+ export type $ElementId = $Aux['ElementId']
151
+ export type $DeploymentId = $Aux['DeploymentId']
152
+ export type $ViewId = $Aux['ViewId']
153
+
154
+ export type $ElementKind = $Aux['ElementKind']
155
+ export type $RelationKind = $Aux['RelationKind']
156
+ export type $DeploymentKind = $Aux['DeploymentKind']
157
+ export type $Tag = $Aux['Tag']
158
+ export type $Tags = readonly $Aux['Tag'][]
159
+ export type $MetadataKey = $Aux['MetadataKey']
160
+ `.trimStart();
161
+ }
162
+
163
+ //#endregion
164
+ //#region src/model/generate-likec4-model.ts
165
+ function generateLikeC4Model(model, options = {}) {
166
+ const aux = generateAux(model, options);
167
+ const { useCorePackage = false } = options;
168
+ return `
169
+ /* prettier-ignore-start */
170
+ /* eslint-disable */
171
+
172
+ /******************************************************************************
173
+ * This file was generated
174
+ * DO NOT EDIT MANUALLY!
175
+ ******************************************************************************/
176
+
177
+ import { LikeC4Model } from '${useCorePackage ? "@likec4/core" : "likec4"}/model'
178
+ ${aux}
179
+
180
+ export const likec4model: LikeC4Model<$Aux> = new LikeC4Model(${JSON5.stringify(model.$data, {
181
+ space: 2,
182
+ quote: "'"
183
+ })} as any) as any
184
+
185
+ /* prettier-ignore-end */
186
+ `.trimStart();
187
+ }
188
+
189
+ //#endregion
190
+ //#region src/puml/generate-puml.ts
191
+ const capitalizeFirstLetter = (value) => value.charAt(0).toLocaleUpperCase() + value.slice(1);
192
+ const fqnName = (nodeId) => {
193
+ return nodeId.split(/[.-]/).map(capitalizeFirstLetter).join("");
194
+ };
195
+ const nodeName = (node) => {
196
+ return fqnName(node.parent ? node.id.slice(node.parent.length + 1) : node.id);
197
+ };
198
+ const pumlColor = (color, customColorProvider, defaultColor = "#3b82f6") => {
199
+ if (color) return customColorProvider(color) ?? defaultColor;
200
+ return defaultColor;
201
+ };
202
+ const pumlDirection = ({ autoLayout }) => {
203
+ switch (autoLayout.direction) {
204
+ case "TB": return "top to bottom";
205
+ case "BT":
206
+ console.warn("Bottom to top direction is not supported. Defaulting to top to bottom.");
207
+ return "top to bottom";
208
+ case "LR": return "left to right";
209
+ case "RL":
210
+ console.warn("Right to left direction is not supported. Defaulting to left to right.");
211
+ return "left to right";
212
+ }
213
+ };
214
+ const pumlShape = ({ shape }) => {
215
+ switch (shape) {
216
+ case "queue":
217
+ case "rectangle":
218
+ case "person": return shape;
219
+ case "storage":
220
+ case "cylinder": return "database";
221
+ case "document":
222
+ case "mobile":
223
+ case "bucket":
224
+ case "browser": return "rectangle";
225
+ default: nonexhaustive(shape);
226
+ }
227
+ };
228
+ const escapeLabel = (label) => isEmptyish(label) ? null : JSON.stringify(label).slice(1, -1).replace(/\\"/g, "\"");
229
+ function generatePuml(viewmodel) {
230
+ const view = viewmodel.$view;
231
+ const colors = viewmodel.$model.$styles.theme.colors;
232
+ const { nodes, edges } = view;
233
+ const elemntColorProvider = (key) => (colorKey) => colorKey in colors ? colors[colorKey].elements[key] : void 0;
234
+ const relationshipsColorProvider = (key) => (colorKey) => colorKey in colors ? colors[colorKey].relationships[key] : void 0;
235
+ const names = /* @__PURE__ */ new Map();
236
+ const printHeader = () => {
237
+ return new CompositeGeneratorNode().append("title \"", viewmodel.titleOrId, "\"", NL).append(pumlDirection(view), " direction", NL);
238
+ };
239
+ const printTheme = () => {
240
+ return new CompositeGeneratorNode().append("hide stereotype", NL).append("skinparam ranksep ", "60", NL).append("skinparam nodesep ", "30", NL).append("skinparam {", NL).indent({
241
+ indentedChildren: (indent) => indent.append("arrowFontSize ", "10", NL).append("defaultTextAlignment ", "center", NL).append("wrapWidth ", "200", NL).append("maxMessageSize ", "100", NL).append("shadowing ", "false", NL),
242
+ indentation: 2
243
+ }).append("}", NL);
244
+ };
245
+ const printStereotypes = (node) => {
246
+ const shape = pumlShape(node);
247
+ const fqn = fqnName(node.id);
248
+ return new CompositeGeneratorNode().append("skinparam ", shape, "<<", fqn, ">>", "{", NL).indent({
249
+ indentedChildren: (indent) => indent.append("BackgroundColor ", pumlColor(node.color, elemntColorProvider("fill")), NL).append("FontColor ", pumlColor(node.color, elemntColorProvider("hiContrast"), "#FFFFFF"), NL).append("BorderColor ", pumlColor(node.color, elemntColorProvider("stroke")), NL),
250
+ indentation: 2
251
+ }).append("}", NL);
252
+ };
253
+ const printNode = (node) => {
254
+ const shape = pumlShape(node);
255
+ const fqn = fqnName(node.id);
256
+ const label = escapeLabel(node.title) || nodeName(node);
257
+ const tech = escapeLabel(node.technology);
258
+ names.set(node.id, fqn);
259
+ const description = RichText.from(node.description);
260
+ 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);
261
+ };
262
+ const printBoundary = (node) => {
263
+ const label = escapeLabel(node.title) || nodeName(node);
264
+ const fqn = fqnName(node.id);
265
+ names.set(node.id, fqn);
266
+ return new CompositeGeneratorNode().append("rectangle \"", label, "\" <<", fqn, ">> as ", fqn, " {", NL).indent({
267
+ indentedChildren: (indent) => indent.append("skinparam ", "RectangleBorderColor<<", fqn, ">> ", pumlColor(node.color, elemntColorProvider("fill")), NL).append("skinparam ", "RectangleFontColor<<", fqn, ">> ", pumlColor(node.color, elemntColorProvider("fill")), NL).append("skinparam ", "RectangleBorderStyle<<", fqn, ">> ", "dashed", NL, NL).append(joinToNode(nodes.filter((n) => n.parent === node.id), (c) => c.children.length > 0 ? printBoundary(c) : printNode(c))),
268
+ indentation: 2
269
+ }).append("}", NL);
270
+ };
271
+ const printEdge = (edge) => {
272
+ const tech = edge.technology || "";
273
+ const label = edge.label || tech;
274
+ const color = pumlColor(edge.color, relationshipsColorProvider("line"), "#777777");
275
+ const withColor = (text) => `<color:${color}>${text.replaceAll("\"", `'`)}`;
276
+ const out = new CompositeGeneratorNode().append(names.get(edge.source), " .[", color, ",thickness=2].> ", names.get(edge.target));
277
+ if (label || tech) {
278
+ out.append(" : ", label.split("\n").map((l) => isEmptyish(l) ? l : withColor(l)).join("\\n"));
279
+ if (tech && tech !== label) out.append("\\n<size:8>[", withColor(tech), "]</size>");
280
+ }
281
+ return out.append(NL);
282
+ };
283
+ return toString(new CompositeGeneratorNode().append("@startuml", NL).append(printHeader(), NL).append(printTheme(), NL).append(joinToNode(nodes.filter((n) => n.children.length == 0), (n) => printStereotypes(n), { appendNewLineIfNotEmpty: true })).append(joinToNode(nodes.filter((n) => isNullish(n.parent)), (n) => n.children.length > 0 ? printBoundary(n) : printNode(n), { appendNewLineIfNotEmpty: true })).appendIf(edges.length > 0, NL, joinToNode(edges, (e) => printEdge(e), { appendNewLineIfNotEmpty: true })).append(`@enduml`, NL));
284
+ }
285
+
286
+ //#endregion
287
+ //#region src/views-data-ts/generateViewId.ts
288
+ function generateViewId(views) {
289
+ return joinToNode(views, (view) => expandToNode`${JSON5.stringify(view.id)}`, { separator: " | " });
290
+ }
291
+
292
+ //#endregion
293
+ //#region src/views-data-ts/generate-views-data.ts
294
+ /**
295
+ * Generate *.js file with views data
296
+ */
297
+ function generateViewsDataJs(diagrams) {
298
+ const views = Array.from(diagrams);
299
+ const out = new CompositeGeneratorNode();
300
+ out.appendTemplate`
301
+ /******************************************************************************
302
+ * This file was generated
303
+ * DO NOT EDIT MANUALLY!
304
+ ******************************************************************************/
305
+ /* prettier-ignore-start */
306
+ /* eslint-disable */
307
+
308
+ `.append(NL, NL);
309
+ if (views.length == 0) {
310
+ out.append("export const LikeC4Views = {}", NL);
311
+ return toString(out);
312
+ }
313
+ out.appendTemplate`
314
+ export const LikeC4Views = {
315
+ `.indent({
316
+ indentation: 2,
317
+ indentedChildren(indented) {
318
+ indented.appendNewLineIf(views.length > 1).append(joinToNode(views, (view) => expandToNode`${JSON5.stringify(view.id)}: ${JSON5.stringify(view)}`, {
319
+ separator: ",",
320
+ appendNewLineIfNotEmpty: true
321
+ }));
322
+ }
323
+ }).append("}", NL, NL).appendTemplate`
324
+
325
+ export function isLikeC4ViewId(value) {
326
+ return (
327
+ value != null &&
328
+ typeof value === 'string' &&
329
+ !!LikeC4Views[value]
330
+ )
331
+ }
332
+
333
+ /* prettier-ignore-end */
334
+ `.append(NL);
335
+ return toString(out);
336
+ }
337
+ /**
338
+ * Generate *.ts file with views data
339
+ */
340
+ function generateViewsDataTs(diagrams) {
341
+ const views = Array.from(diagrams);
342
+ const out = new CompositeGeneratorNode();
343
+ out.appendTemplate`
344
+ /******************************************************************************
345
+ * This file was generated
346
+ * DO NOT EDIT MANUALLY!
347
+ ******************************************************************************/
348
+ /* prettier-ignore-start */
349
+ /* eslint-disable */
350
+
351
+ // @ts-nocheck
352
+
353
+ import type { DiagramView } from 'likec4'
354
+ `.append(NL, NL);
355
+ if (views.length === 0) {
356
+ out.append("export {}", NL);
357
+ return toString(out);
358
+ }
359
+ out.appendTemplate`
360
+ export type LikeC4ViewId = ${generateViewId(views)};
361
+ export const LikeC4Views = {
362
+ `.indent({
363
+ indentation: 2,
364
+ indentedChildren(indented) {
365
+ indented.appendNewLineIf(views.length > 1).append(joinToNode(views, (view) => expandToNode`${JSON5.stringify(view.id)}: (${JSON5.stringify(view)} as unknown) as DiagramView`, {
366
+ separator: ",",
367
+ appendNewLineIfNotEmpty: true
368
+ }));
369
+ }
370
+ }).append("} as const satisfies Record<LikeC4ViewId, DiagramView>", NL, NL).appendTemplate`
371
+ export type LikeC4Views = typeof LikeC4Views
372
+
373
+ export function isLikeC4ViewId(value: unknown): value is LikeC4ViewId {
374
+ return (
375
+ value != null &&
376
+ typeof value === 'string' &&
377
+ !!LikeC4Views[value]
378
+ )
379
+ }
380
+
381
+ /* prettier-ignore-end */
382
+ `.append(NL);
383
+ return toString(out);
384
+ }
385
+ /**
386
+ * Generate *.d.ts
387
+ */
388
+ function generateViewsDataDTs(diagrams) {
389
+ const views = Array.from(diagrams);
390
+ const out = new CompositeGeneratorNode();
391
+ out.appendTemplate`
392
+ /******************************************************************************
393
+ * This file was generated
394
+ * DO NOT EDIT MANUALLY!
395
+ ******************************************************************************/
396
+ /* prettier-ignore-start */
397
+ /* eslint-disable */
398
+
399
+ import type { DiagramView } from 'likec4'
400
+ `.append(NL, NL);
401
+ if (views.length == 0) {
402
+ out.append("export {}", NL);
403
+ return toString(out);
404
+ }
405
+ out.appendTemplate`
406
+ export type LikeC4ViewId = ${generateViewId(views)};
407
+ export type LikeC4Views = Record<LikeC4ViewId, DiagramView>
408
+
409
+ export declare const LikeC4Views: LikeC4Views
410
+ export declare function isLikeC4ViewId(value: unknown): value is LikeC4ViewId
411
+
412
+ /* prettier-ignore-end */
413
+ `.append(NL);
414
+ return toString(out);
415
+ }
416
+
417
+ //#endregion
418
+ //#region src/react-next/generate-react-next.ts
419
+ /**
420
+ * @deprecated in favor packages/likec4/src/cli/codegen/react/index.ts
421
+ */
422
+ function generateReactNext(views) {
423
+ return {
424
+ viewsData: {
425
+ fileName: "likec4-views-data",
426
+ js: generateViewsDataJs(views),
427
+ dts: generateViewsDataDTs(views)
428
+ },
429
+ components: {
430
+ fileName: "likec4-components",
431
+ ...generateComponents()
432
+ },
433
+ index: generateIndex()
434
+ };
435
+ }
436
+ function generateComponents() {
437
+ const js = new CompositeGeneratorNode().appendTemplate`
438
+ /******************************************************************************
439
+ * This file was generated
440
+ * DO NOT EDIT MANUALLY!
441
+ ******************************************************************************/
442
+ /* prettier-ignore-start */
443
+ /* eslint-disable */
444
+ import { createElement } from "react";
445
+ import { LikeC4Diagram, EmbeddedLikeC4Diagram } from "@likec4/diagram";
446
+ import { LikeC4Views } from "./likec4-views-data";
447
+ export function LikeC4View({ viewId, ...props }) {
448
+ const view = LikeC4Views[viewId];
449
+ if (!view) {
450
+ throw new Error(\`LikeC4View NotFound: "\${viewId}"\`);
451
+ }
452
+ return createElement(LikeC4Diagram, { view: view, ...props });
453
+ }
454
+ export function EmbeddedLikeC4View({ viewId, ...props }) {
455
+ return createElement(EmbeddedLikeC4Diagram, { viewId: viewId, views: LikeC4Views, ...props });
456
+ }
457
+ /* prettier-ignore-end */
458
+ `;
459
+ const dts = new CompositeGeneratorNode().appendTemplate`
460
+ /// <reference types="react" />
461
+ /******************************************************************************
462
+ * This file was generated
463
+ * DO NOT EDIT MANUALLY!
464
+ ******************************************************************************/
465
+ /* prettier-ignore-start */
466
+ /* eslint-disable */
467
+
468
+ import type { LikeC4DiagramProps, EmbeddedLikeC4DiagramProps } from "@likec4/diagram";
469
+ import type { LikeC4ViewId } from "./likec4-views-data";
470
+
471
+ export type LikeC4ViewProps = {
472
+ viewId: LikeC4ViewId;
473
+ } & Omit<LikeC4DiagramProps, "view">;
474
+
475
+ export declare function LikeC4View({ viewId, ...props }: LikeC4ViewProps): JSX.Element;
476
+
477
+ export type EmbeddedLikeC4ViewProps = {
478
+ viewId: LikeC4ViewId;
479
+ } & Omit<EmbeddedLikeC4DiagramProps, "viewId" | "views">;
480
+
481
+ export declare function EmbeddedLikeC4View({ viewId, ...props }: EmbeddedLikeC4ViewProps): JSX.Element;
482
+ /* prettier-ignore-end */
483
+ `;
484
+ return {
485
+ js: toString(js),
486
+ dts: toString(dts)
487
+ };
488
+ }
489
+ function generateIndex() {
490
+ const js = new CompositeGeneratorNode().appendTemplate`
491
+ /* prettier-ignore-start */
492
+ /* eslint-disable */
493
+
494
+ // You are safe to edit/move these style imports,
495
+ // but they are required
496
+ import "@mantine/core/styles.css";
497
+ import "@likec4/diagram/style.css";
498
+
499
+ export * from "./likec4-components";
500
+
501
+ // OR with lazy loading:
502
+ //
503
+ // import { lazy } from "react";
504
+ // export const LikeC4View = lazy(async () => await import("./likec4-components").then(m => ({default: m.LikeC4View})));
505
+ // export const EmbeddedLikeC4View = lazy(async () => await import("./likec4-components").then(m => ({default: m.EmbeddedLikeC4View})));
506
+
507
+ /* prettier-ignore-end */
508
+ `;
509
+ const dts = new CompositeGeneratorNode().appendTemplate`
510
+ /* prettier-ignore-start */
511
+ /* eslint-disable */
512
+
513
+ export * from "./likec4-components";
514
+
515
+ /* prettier-ignore-end */
516
+ `;
517
+ return {
518
+ js: toString(js),
519
+ dts: toString(dts)
520
+ };
521
+ }
522
+
523
+ //#endregion
524
+ //#region src/react/generate-react-types.ts
525
+ function generateReactTypes(model, options = {}) {
526
+ const { useCorePackage = false } = options;
527
+ invariant(!model.isParsed(), "can not generate react types for parsed model");
528
+ const aux = generateAux(model, options);
529
+ return `
530
+ /* prettier-ignore-start */
531
+ /* eslint-disable */
532
+
533
+ /******************************************************************************
534
+ * This file was generated
535
+ * DO NOT EDIT MANUALLY!
536
+ ******************************************************************************/
537
+
538
+ import type { PropsWithChildren } from 'react'
539
+ import type { JSX } from 'react/jsx-runtime'
540
+ import type { LikeC4Model } from '${useCorePackage ? "@likec4/core" : "likec4"}/model'
541
+ import type { LayoutedView } from '${useCorePackage ? "@likec4/core/types" : "likec4/model"}'
542
+ import type {
543
+ LikeC4ViewProps as GenericLikeC4ViewProps,
544
+ ReactLikeC4Props as GenericReactLikeC4Props
545
+ } from 'likec4/react'
546
+
547
+ ${aux}
548
+
549
+ declare function isLikeC4ViewId(value: unknown): value is $ViewId;
550
+
551
+ declare const likec4model: LikeC4Model<$Aux>;
552
+ declare function useLikeC4Model(): LikeC4Model<$Aux>;
553
+ declare function useLikeC4View(viewId: $ViewId): LayoutedView<$Aux>;
554
+
555
+ declare function LikeC4ModelProvider(props: PropsWithChildren): JSX.Element;
556
+
557
+ type IconRendererProps = {
558
+ node: {
559
+ id: string
560
+ title: string
561
+ icon?: string | undefined
562
+ }
563
+ }
564
+ declare function RenderIcon(props: IconRendererProps): JSX.Element;
565
+
566
+ type LikeC4ViewProps = GenericLikeC4ViewProps<$Aux>;
567
+ declare function LikeC4View({viewId, ...props}: LikeC4ViewProps): JSX.Element;
568
+
569
+ type ReactLikeC4Props = GenericReactLikeC4Props<$Aux>
570
+ declare function ReactLikeC4({viewId, ...props}: ReactLikeC4Props): JSX.Element;
571
+
572
+ export {
573
+ type LikeC4ViewProps,
574
+ type ReactLikeC4Props,
575
+ isLikeC4ViewId,
576
+ useLikeC4Model,
577
+ useLikeC4View,
578
+ likec4model,
579
+ LikeC4ModelProvider,
580
+ LikeC4View,
581
+ RenderIcon,
582
+ ReactLikeC4
583
+ }
584
+ /* prettier-ignore-end */
585
+ `.trimStart();
586
+ }
587
+
588
+ //#endregion
589
+ export { generateD2, generateLikeC4Model, generateMermaid, generatePuml, generateReactNext, generateReactTypes, generateViewsDataDTs, generateViewsDataJs, generateViewsDataTs };