@agilewallaby/c4-model 2.7.0 → 3.0.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/package.json +1 -1
- package/src/archetype.d.ts +9 -1
- package/src/buildModel.d.ts +7 -4
- package/src/container.d.ts +8 -1
- package/src/exportWorkspaceJson.d.ts +4 -0
- package/src/generateDiagrams.d.ts +1 -3
- package/src/index.cjs +408 -97
- package/src/index.d.ts +147 -46
- package/src/index.js +403 -95
- package/src/model.d.ts +13 -3
- package/src/softwareSystem.d.ts +8 -1
- package/src/structurizrDslWriter.d.ts +5 -0
- package/src/validateModel.d.ts +3 -0
- package/src/views.d.ts +63 -2
package/src/index.js
CHANGED
|
@@ -1,49 +1,3 @@
|
|
|
1
|
-
// libs/c4-model/src/archetype.ts
|
|
2
|
-
var ElementArchetype = class {
|
|
3
|
-
constructor(name, elementKind, definition, parent) {
|
|
4
|
-
this.name = name;
|
|
5
|
-
this.elementKind = elementKind;
|
|
6
|
-
this.parent = parent;
|
|
7
|
-
this.ownDescription = definition?.description;
|
|
8
|
-
this.ownTechnology = definition?.technology;
|
|
9
|
-
this.ownTags = definition?.tags ?? [];
|
|
10
|
-
this.description = this.ownDescription ?? parent?.description;
|
|
11
|
-
this.technology = this.ownTechnology ?? parent?.technology;
|
|
12
|
-
this.tags = [...parent?.tags ?? [], ...this.ownTags];
|
|
13
|
-
}
|
|
14
|
-
ownDescription;
|
|
15
|
-
ownTechnology;
|
|
16
|
-
ownTags;
|
|
17
|
-
description;
|
|
18
|
-
technology;
|
|
19
|
-
tags;
|
|
20
|
-
};
|
|
21
|
-
var RelationshipArchetype = class {
|
|
22
|
-
constructor(name, definition, parent) {
|
|
23
|
-
this.name = name;
|
|
24
|
-
this.parent = parent;
|
|
25
|
-
this.ownDescription = definition?.description;
|
|
26
|
-
this.ownTechnology = definition?.technology;
|
|
27
|
-
this.ownTags = definition?.tags ?? [];
|
|
28
|
-
this.description = this.ownDescription ?? parent?.description;
|
|
29
|
-
this.technology = this.ownTechnology ?? parent?.technology;
|
|
30
|
-
this.tags = [...parent?.tags ?? [], ...this.ownTags];
|
|
31
|
-
}
|
|
32
|
-
ownDescription;
|
|
33
|
-
ownTechnology;
|
|
34
|
-
ownTags;
|
|
35
|
-
description;
|
|
36
|
-
technology;
|
|
37
|
-
tags;
|
|
38
|
-
};
|
|
39
|
-
function mergeArchetypeWithOverride(archetype, override) {
|
|
40
|
-
return {
|
|
41
|
-
description: override?.description ?? archetype.description,
|
|
42
|
-
technology: override?.technology ?? archetype.technology,
|
|
43
|
-
tags: [...archetype.tags, ...override?.tags ?? []]
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
1
|
// node_modules/.pnpm/change-case@5.4.4/node_modules/change-case/dist/index.js
|
|
48
2
|
var SPLIT_LOWER_UPPER_RE = /([\p{Ll}\d])(\p{Lu})/gu;
|
|
49
3
|
var SPLIT_UPPER_UPPER_RE = /(\p{Lu})([\p{Lu}][\p{Ll}])/gu;
|
|
@@ -130,6 +84,64 @@ function splitPrefixSuffix(input, options = {}) {
|
|
|
130
84
|
];
|
|
131
85
|
}
|
|
132
86
|
|
|
87
|
+
// libs/c4-model/src/archetype.ts
|
|
88
|
+
var ELEMENT_KINDS = {
|
|
89
|
+
person: "person",
|
|
90
|
+
softwareSystem: "softwareSystem",
|
|
91
|
+
container: "container",
|
|
92
|
+
component: "component"
|
|
93
|
+
};
|
|
94
|
+
var ElementArchetype = class {
|
|
95
|
+
constructor(name, elementKind, definition, parent) {
|
|
96
|
+
this.name = name;
|
|
97
|
+
this.elementKind = elementKind;
|
|
98
|
+
this.parent = parent;
|
|
99
|
+
this.ownDescription = definition?.description;
|
|
100
|
+
this.ownTechnology = definition?.technology;
|
|
101
|
+
this.ownTags = definition?.tags ?? [];
|
|
102
|
+
this.description = this.ownDescription ?? parent?.description;
|
|
103
|
+
this.technology = this.ownTechnology ?? parent?.technology;
|
|
104
|
+
this.tags = [...parent?.tags ?? [], ...this.ownTags];
|
|
105
|
+
}
|
|
106
|
+
ownDescription;
|
|
107
|
+
ownTechnology;
|
|
108
|
+
ownTags;
|
|
109
|
+
description;
|
|
110
|
+
technology;
|
|
111
|
+
tags;
|
|
112
|
+
get canonicalName() {
|
|
113
|
+
return camelCase(this.name);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var RelationshipArchetype = class {
|
|
117
|
+
constructor(name, definition, parent) {
|
|
118
|
+
this.name = name;
|
|
119
|
+
this.parent = parent;
|
|
120
|
+
this.ownDescription = definition?.description;
|
|
121
|
+
this.ownTechnology = definition?.technology;
|
|
122
|
+
this.ownTags = definition?.tags ?? [];
|
|
123
|
+
this.description = this.ownDescription ?? parent?.description;
|
|
124
|
+
this.technology = this.ownTechnology ?? parent?.technology;
|
|
125
|
+
this.tags = [...parent?.tags ?? [], ...this.ownTags];
|
|
126
|
+
}
|
|
127
|
+
ownDescription;
|
|
128
|
+
ownTechnology;
|
|
129
|
+
ownTags;
|
|
130
|
+
description;
|
|
131
|
+
technology;
|
|
132
|
+
tags;
|
|
133
|
+
get canonicalName() {
|
|
134
|
+
return camelCase(this.name);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function mergeArchetypeWithOverride(archetype, override) {
|
|
138
|
+
return {
|
|
139
|
+
description: override?.description ?? archetype.description,
|
|
140
|
+
technology: override?.technology ?? archetype.technology,
|
|
141
|
+
tags: [...archetype.tags, ...override?.tags ?? []]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
133
145
|
// libs/c4-model/src/core.ts
|
|
134
146
|
var Element = class {
|
|
135
147
|
constructor(name, defaultTags = [], definition, archetype, overrideDefinition) {
|
|
@@ -169,9 +181,9 @@ var Element = class {
|
|
|
169
181
|
getRelationshipsInHierarchy() {
|
|
170
182
|
return this._relationships.concat(this.getChildElements().flatMap((element) => element.getRelationshipsInHierarchy()));
|
|
171
183
|
}
|
|
172
|
-
getChildElementNames(
|
|
184
|
+
getChildElementNames(path4) {
|
|
173
185
|
const result = Array.from(this.getChildElements()).flatMap((reference) => {
|
|
174
|
-
const currentPath = `${
|
|
186
|
+
const currentPath = `${path4 ? path4 : "" + this.name}.${reference.name}`;
|
|
175
187
|
return [currentPath, ...reference.getChildElementNames(currentPath)];
|
|
176
188
|
});
|
|
177
189
|
return result;
|
|
@@ -227,21 +239,46 @@ var Component = class extends TechnicalElement {
|
|
|
227
239
|
};
|
|
228
240
|
|
|
229
241
|
// libs/c4-model/src/container.ts
|
|
230
|
-
var ContainerGroup = class extends Group {
|
|
231
|
-
constructor(name, container) {
|
|
242
|
+
var ContainerGroup = class _ContainerGroup extends Group {
|
|
243
|
+
constructor(name, container, pathSegments = []) {
|
|
232
244
|
super(name);
|
|
233
245
|
this.name = name;
|
|
234
246
|
this.container = container;
|
|
247
|
+
this.pathSegments = pathSegments;
|
|
235
248
|
}
|
|
236
249
|
_components = /* @__PURE__ */ new Map();
|
|
250
|
+
_groups = /* @__PURE__ */ new Map();
|
|
251
|
+
get canonicalName() {
|
|
252
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
253
|
+
}
|
|
254
|
+
get dslName() {
|
|
255
|
+
return [...this.pathSegments, this.name].join("/");
|
|
256
|
+
}
|
|
237
257
|
component(name, archetypeOrDef, override) {
|
|
238
258
|
const component = this.container.component(name, archetypeOrDef, override);
|
|
239
259
|
this._components.set(name, component);
|
|
240
260
|
return component;
|
|
241
261
|
}
|
|
262
|
+
group(groupName) {
|
|
263
|
+
let group = this._groups.get(groupName);
|
|
264
|
+
if (!group) {
|
|
265
|
+
group = new _ContainerGroup(groupName, this.container, [...this.pathSegments, this.name]);
|
|
266
|
+
this._groups.set(groupName, group);
|
|
267
|
+
}
|
|
268
|
+
return group;
|
|
269
|
+
}
|
|
270
|
+
getGroups() {
|
|
271
|
+
return Array.from(this._groups.values());
|
|
272
|
+
}
|
|
242
273
|
getComponents() {
|
|
243
274
|
return Array.from(this._components.values());
|
|
244
275
|
}
|
|
276
|
+
getAllComponents() {
|
|
277
|
+
return [
|
|
278
|
+
...this._components.values(),
|
|
279
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllComponents())
|
|
280
|
+
];
|
|
281
|
+
}
|
|
245
282
|
};
|
|
246
283
|
var Container = class extends TechnicalElement {
|
|
247
284
|
constructor(name, definition, archetype, overrideDefinition) {
|
|
@@ -278,7 +315,7 @@ var Container = class extends TechnicalElement {
|
|
|
278
315
|
return Array.from(this._groups.values());
|
|
279
316
|
}
|
|
280
317
|
getComponentsNotInGroups() {
|
|
281
|
-
const componentsInGroups = this.getGroups().flatMap((group) => group.
|
|
318
|
+
const componentsInGroups = this.getGroups().flatMap((group) => group.getAllComponents());
|
|
282
319
|
return Array.from(this._components.values()).filter((component) => !componentsInGroups.includes(component));
|
|
283
320
|
}
|
|
284
321
|
getChildElements() {
|
|
@@ -287,21 +324,46 @@ var Container = class extends TechnicalElement {
|
|
|
287
324
|
};
|
|
288
325
|
|
|
289
326
|
// libs/c4-model/src/softwareSystem.ts
|
|
290
|
-
var SoftwareSystemGroup = class extends Group {
|
|
291
|
-
constructor(name, softwareSystem) {
|
|
327
|
+
var SoftwareSystemGroup = class _SoftwareSystemGroup extends Group {
|
|
328
|
+
constructor(name, softwareSystem, pathSegments = []) {
|
|
292
329
|
super(name);
|
|
293
330
|
this.name = name;
|
|
294
331
|
this.softwareSystem = softwareSystem;
|
|
332
|
+
this.pathSegments = pathSegments;
|
|
295
333
|
}
|
|
296
334
|
_containers = /* @__PURE__ */ new Map();
|
|
335
|
+
_groups = /* @__PURE__ */ new Map();
|
|
336
|
+
get canonicalName() {
|
|
337
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
338
|
+
}
|
|
339
|
+
get dslName() {
|
|
340
|
+
return [...this.pathSegments, this.name].join("/");
|
|
341
|
+
}
|
|
297
342
|
container(name, archetypeOrDef, override) {
|
|
298
343
|
const container = this.softwareSystem.container(name, archetypeOrDef, override);
|
|
299
344
|
this._containers.set(name, container);
|
|
300
345
|
return container;
|
|
301
346
|
}
|
|
347
|
+
group(groupName) {
|
|
348
|
+
let group = this._groups.get(groupName);
|
|
349
|
+
if (!group) {
|
|
350
|
+
group = new _SoftwareSystemGroup(groupName, this.softwareSystem, [...this.pathSegments, this.name]);
|
|
351
|
+
this._groups.set(groupName, group);
|
|
352
|
+
}
|
|
353
|
+
return group;
|
|
354
|
+
}
|
|
355
|
+
getGroups() {
|
|
356
|
+
return Array.from(this._groups.values());
|
|
357
|
+
}
|
|
302
358
|
getContainers() {
|
|
303
359
|
return Array.from(this._containers.values());
|
|
304
360
|
}
|
|
361
|
+
getAllContainers() {
|
|
362
|
+
return [
|
|
363
|
+
...this._containers.values(),
|
|
364
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllContainers())
|
|
365
|
+
];
|
|
366
|
+
}
|
|
305
367
|
};
|
|
306
368
|
var SoftwareSystem = class extends Element {
|
|
307
369
|
constructor(name, definition, archetype, overrideDefinition) {
|
|
@@ -341,7 +403,7 @@ var SoftwareSystem = class extends Element {
|
|
|
341
403
|
return Array.from(this._containers.values());
|
|
342
404
|
}
|
|
343
405
|
getContainersNotInGroups() {
|
|
344
|
-
const containersInGroups = Array.from(this._groups.values()).flatMap((group) => group.
|
|
406
|
+
const containersInGroups = Array.from(this._groups.values()).flatMap((group) => group.getAllContainers());
|
|
345
407
|
return Array.from(this._containers.values()).filter((container) => !containersInGroups.includes(container));
|
|
346
408
|
}
|
|
347
409
|
};
|
|
@@ -358,14 +420,22 @@ var Person = class extends Element {
|
|
|
358
420
|
};
|
|
359
421
|
|
|
360
422
|
// libs/c4-model/src/model.ts
|
|
361
|
-
var ModelGroup = class extends Group {
|
|
362
|
-
constructor(name, model) {
|
|
423
|
+
var ModelGroup = class _ModelGroup extends Group {
|
|
424
|
+
constructor(name, model, pathSegments = []) {
|
|
363
425
|
super(name);
|
|
364
426
|
this.name = name;
|
|
365
427
|
this.model = model;
|
|
428
|
+
this.pathSegments = pathSegments;
|
|
366
429
|
}
|
|
367
430
|
softwareSystems = /* @__PURE__ */ new Map();
|
|
368
431
|
people = /* @__PURE__ */ new Map();
|
|
432
|
+
_groups = /* @__PURE__ */ new Map();
|
|
433
|
+
get canonicalName() {
|
|
434
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
435
|
+
}
|
|
436
|
+
get dslName() {
|
|
437
|
+
return [...this.pathSegments, this.name].join("/");
|
|
438
|
+
}
|
|
369
439
|
softwareSystem(name, archetypeOrDef, override) {
|
|
370
440
|
const softwareSystem = this.model.softwareSystem(name, archetypeOrDef, override);
|
|
371
441
|
this.softwareSystems.set(name, softwareSystem);
|
|
@@ -376,12 +446,35 @@ var ModelGroup = class extends Group {
|
|
|
376
446
|
this.people.set(name, person);
|
|
377
447
|
return person;
|
|
378
448
|
}
|
|
449
|
+
group(groupName) {
|
|
450
|
+
let group = this._groups.get(groupName);
|
|
451
|
+
if (!group) {
|
|
452
|
+
group = new _ModelGroup(groupName, this.model, [...this.pathSegments, this.name]);
|
|
453
|
+
this._groups.set(groupName, group);
|
|
454
|
+
}
|
|
455
|
+
return group;
|
|
456
|
+
}
|
|
457
|
+
getGroups() {
|
|
458
|
+
return Array.from(this._groups.values());
|
|
459
|
+
}
|
|
379
460
|
getSoftwareSystems() {
|
|
380
461
|
return Array.from(this.softwareSystems.values());
|
|
381
462
|
}
|
|
382
463
|
getPeople() {
|
|
383
464
|
return Array.from(this.people.values());
|
|
384
465
|
}
|
|
466
|
+
getAllSoftwareSystems() {
|
|
467
|
+
return [
|
|
468
|
+
...this.softwareSystems.values(),
|
|
469
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllSoftwareSystems())
|
|
470
|
+
];
|
|
471
|
+
}
|
|
472
|
+
getAllPeople() {
|
|
473
|
+
return [
|
|
474
|
+
...this.people.values(),
|
|
475
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllPeople())
|
|
476
|
+
];
|
|
477
|
+
}
|
|
385
478
|
};
|
|
386
479
|
var Model = class {
|
|
387
480
|
constructor(name) {
|
|
@@ -406,7 +499,6 @@ var Model = class {
|
|
|
406
499
|
this.softwareSystems.set(name, system);
|
|
407
500
|
return system;
|
|
408
501
|
}
|
|
409
|
-
// TODO:Should be a Group<SoftwareSystem | Person> if that is added back in
|
|
410
502
|
group(groupName) {
|
|
411
503
|
let group = this.groups.get(groupName);
|
|
412
504
|
if (!group) {
|
|
@@ -441,11 +533,11 @@ var Model = class {
|
|
|
441
533
|
return Array.from(this.softwareSystems.values());
|
|
442
534
|
}
|
|
443
535
|
getPeopleNotInGroups() {
|
|
444
|
-
const peopleInGroups = Array.from(this.groups.values()).flatMap((group) => group.
|
|
536
|
+
const peopleInGroups = Array.from(this.groups.values()).flatMap((group) => group.getAllPeople());
|
|
445
537
|
return Array.from(this.people.values()).filter((person) => !peopleInGroups.includes(person));
|
|
446
538
|
}
|
|
447
539
|
getSoftwareSystemsNotInGroups() {
|
|
448
|
-
const systemsInGroups = Array.from(this.groups.values()).flatMap((group) => group.
|
|
540
|
+
const systemsInGroups = Array.from(this.groups.values()).flatMap((group) => group.getAllSoftwareSystems());
|
|
449
541
|
return Array.from(this.softwareSystems.values()).filter((system) => !systemsInGroups.includes(system));
|
|
450
542
|
}
|
|
451
543
|
getGroups() {
|
|
@@ -465,6 +557,9 @@ var View = class {
|
|
|
465
557
|
description;
|
|
466
558
|
title;
|
|
467
559
|
_scopes = [];
|
|
560
|
+
_autoLayout;
|
|
561
|
+
_isDefault = false;
|
|
562
|
+
_properties = /* @__PURE__ */ new Map();
|
|
468
563
|
includeAll() {
|
|
469
564
|
this._scopes.push("include *");
|
|
470
565
|
}
|
|
@@ -483,15 +578,37 @@ var View = class {
|
|
|
483
578
|
excludeExpression(expression) {
|
|
484
579
|
this._scopes.push(`exclude ${expression}`);
|
|
485
580
|
}
|
|
581
|
+
autoLayout(direction, rankSeparation, nodeSeparation) {
|
|
582
|
+
this._autoLayout = { direction, rankSeparation, nodeSeparation };
|
|
583
|
+
}
|
|
584
|
+
setDefault() {
|
|
585
|
+
this._isDefault = true;
|
|
586
|
+
}
|
|
587
|
+
addProperty(name, value) {
|
|
588
|
+
this._properties.set(name, value);
|
|
589
|
+
}
|
|
486
590
|
get scopes() {
|
|
487
591
|
return this._scopes;
|
|
488
592
|
}
|
|
593
|
+
get autoLayoutConfig() {
|
|
594
|
+
return this._autoLayout;
|
|
595
|
+
}
|
|
596
|
+
get isDefault() {
|
|
597
|
+
return this._isDefault;
|
|
598
|
+
}
|
|
599
|
+
get properties() {
|
|
600
|
+
return this._properties;
|
|
601
|
+
}
|
|
489
602
|
};
|
|
490
603
|
var Views = class {
|
|
491
604
|
_systemLandscapeViews = /* @__PURE__ */ new Map();
|
|
492
605
|
_systemContextViews = /* @__PURE__ */ new Map();
|
|
493
606
|
_containerViews = /* @__PURE__ */ new Map();
|
|
494
607
|
_componentViews = /* @__PURE__ */ new Map();
|
|
608
|
+
_elementStyles = [];
|
|
609
|
+
_relationshipStyles = [];
|
|
610
|
+
_themes = [];
|
|
611
|
+
_properties = /* @__PURE__ */ new Map();
|
|
495
612
|
addSystemLandscapeView(key, definition) {
|
|
496
613
|
const view = new View(key, { subject: void 0, description: definition.description, title: definition.title });
|
|
497
614
|
this._systemLandscapeViews.set(key, view);
|
|
@@ -512,6 +629,18 @@ var Views = class {
|
|
|
512
629
|
this._componentViews.set(key, view);
|
|
513
630
|
return view;
|
|
514
631
|
}
|
|
632
|
+
addElementStyle(tag, definition) {
|
|
633
|
+
this._elementStyles.push({ tag, definition });
|
|
634
|
+
}
|
|
635
|
+
addRelationshipStyle(tag, definition) {
|
|
636
|
+
this._relationshipStyles.push({ tag, definition });
|
|
637
|
+
}
|
|
638
|
+
addTheme(url) {
|
|
639
|
+
this._themes.push(url);
|
|
640
|
+
}
|
|
641
|
+
addProperty(name, value) {
|
|
642
|
+
this._properties.set(name, value);
|
|
643
|
+
}
|
|
515
644
|
get systemLandscapeViews() {
|
|
516
645
|
return Array.from(this._systemLandscapeViews.values());
|
|
517
646
|
}
|
|
@@ -524,6 +653,18 @@ var Views = class {
|
|
|
524
653
|
get componentViews() {
|
|
525
654
|
return Array.from(this._componentViews.values());
|
|
526
655
|
}
|
|
656
|
+
get elementStyles() {
|
|
657
|
+
return this._elementStyles;
|
|
658
|
+
}
|
|
659
|
+
get relationshipStyles() {
|
|
660
|
+
return this._relationshipStyles;
|
|
661
|
+
}
|
|
662
|
+
get themes() {
|
|
663
|
+
return this._themes;
|
|
664
|
+
}
|
|
665
|
+
get properties() {
|
|
666
|
+
return this._properties;
|
|
667
|
+
}
|
|
527
668
|
};
|
|
528
669
|
|
|
529
670
|
// libs/c4-model/src/structurizrDslWriter.ts
|
|
@@ -579,7 +720,7 @@ var StructurizrDSLWriter = class {
|
|
|
579
720
|
if (elementArchetypes.length === 0 && relationshipArchetypes.length === 0) return "";
|
|
580
721
|
let dsl = this.writeLine(`archetypes {`, level);
|
|
581
722
|
for (const arch of elementArchetypes) {
|
|
582
|
-
const baseType = arch.parent ? arch.parent.
|
|
723
|
+
const baseType = arch.parent ? arch.parent.canonicalName : arch.elementKind;
|
|
583
724
|
let inner = "";
|
|
584
725
|
if (arch.ownDescription) {
|
|
585
726
|
inner += this.writeLine(`description "${arch.ownDescription}"`, level + 2);
|
|
@@ -591,15 +732,15 @@ var StructurizrDSLWriter = class {
|
|
|
591
732
|
inner += this.writeLine(`tags ${arch.ownTags.map((t) => `"${t}"`).join(" ")}`, level + 2);
|
|
592
733
|
}
|
|
593
734
|
if (inner) {
|
|
594
|
-
dsl += this.writeLine(`${arch.
|
|
735
|
+
dsl += this.writeLine(`${arch.canonicalName} = ${baseType} {`, level + 1);
|
|
595
736
|
dsl += inner;
|
|
596
737
|
dsl += this.writeLine(`}`, level + 1);
|
|
597
738
|
} else {
|
|
598
|
-
dsl += this.writeLine(`${arch.
|
|
739
|
+
dsl += this.writeLine(`${arch.canonicalName} = ${baseType} {}`, level + 1);
|
|
599
740
|
}
|
|
600
741
|
}
|
|
601
742
|
for (const arch of relationshipArchetypes) {
|
|
602
|
-
const arrow = arch.parent ? `--${arch.parent.
|
|
743
|
+
const arrow = arch.parent ? `--${arch.parent.canonicalName}->` : `->`;
|
|
603
744
|
let inner = "";
|
|
604
745
|
if (arch.ownDescription) {
|
|
605
746
|
inner += this.writeLine(`description "${arch.ownDescription}"`, level + 2);
|
|
@@ -611,11 +752,11 @@ var StructurizrDSLWriter = class {
|
|
|
611
752
|
inner += this.writeLine(`tags ${arch.ownTags.map((t) => `"${t}"`).join(" ")}`, level + 2);
|
|
612
753
|
}
|
|
613
754
|
if (inner) {
|
|
614
|
-
dsl += this.writeLine(`${arch.
|
|
755
|
+
dsl += this.writeLine(`${arch.canonicalName} = ${arrow} {`, level + 1);
|
|
615
756
|
dsl += inner;
|
|
616
757
|
dsl += this.writeLine(`}`, level + 1);
|
|
617
758
|
} else {
|
|
618
|
-
dsl += this.writeLine(`${arch.
|
|
759
|
+
dsl += this.writeLine(`${arch.canonicalName} = ${arrow} {}`, level + 1);
|
|
619
760
|
}
|
|
620
761
|
}
|
|
621
762
|
dsl += this.writeLine(`}`, level);
|
|
@@ -623,7 +764,7 @@ var StructurizrDSLWriter = class {
|
|
|
623
764
|
}
|
|
624
765
|
writeElement(elementType, element, level, closeElement = true) {
|
|
625
766
|
let elementDsl = "";
|
|
626
|
-
const type = element.archetype ? element.archetype.
|
|
767
|
+
const type = element.archetype ? element.archetype.canonicalName : elementType;
|
|
627
768
|
elementDsl += this.writeLine(`${element.canonicalName} = ${type} "${element.name}" {`, level);
|
|
628
769
|
if (element.archetype) {
|
|
629
770
|
const ovr = element.overrideDefinition;
|
|
@@ -658,11 +799,17 @@ var StructurizrDSLWriter = class {
|
|
|
658
799
|
}
|
|
659
800
|
writeContainerGroup(group, level) {
|
|
660
801
|
let containerGroupDsl = "";
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
containerGroupDsl += this.
|
|
802
|
+
const hasDirect = group.getComponents().length > 0;
|
|
803
|
+
if (hasDirect) {
|
|
804
|
+
containerGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
805
|
+
group.getComponents().forEach((component) => {
|
|
806
|
+
containerGroupDsl += this.writeComponent(component, level + 1);
|
|
807
|
+
});
|
|
808
|
+
containerGroupDsl += this.writeLine(`}`, level);
|
|
809
|
+
}
|
|
810
|
+
group.getGroups().forEach((nested) => {
|
|
811
|
+
containerGroupDsl += this.writeContainerGroup(nested, level);
|
|
664
812
|
});
|
|
665
|
-
containerGroupDsl += this.writeLine(`}`, level);
|
|
666
813
|
return containerGroupDsl;
|
|
667
814
|
}
|
|
668
815
|
writeContainer(container, level) {
|
|
@@ -682,11 +829,17 @@ var StructurizrDSLWriter = class {
|
|
|
682
829
|
}
|
|
683
830
|
writeSoftwareSystemGroup(group, level) {
|
|
684
831
|
let softwareSystemGroupDsl = "";
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
softwareSystemGroupDsl += this.
|
|
832
|
+
const hasDirect = group.getContainers().length > 0;
|
|
833
|
+
if (hasDirect) {
|
|
834
|
+
softwareSystemGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
835
|
+
group.getContainers().forEach((container) => {
|
|
836
|
+
softwareSystemGroupDsl += this.writeContainer(container, level + 1);
|
|
837
|
+
});
|
|
838
|
+
softwareSystemGroupDsl += this.writeLine(`}`, level);
|
|
839
|
+
}
|
|
840
|
+
group.getGroups().forEach((nested) => {
|
|
841
|
+
softwareSystemGroupDsl += this.writeSoftwareSystemGroup(nested, level);
|
|
688
842
|
});
|
|
689
|
-
softwareSystemGroupDsl += this.writeLine(`}`, level);
|
|
690
843
|
return softwareSystemGroupDsl;
|
|
691
844
|
}
|
|
692
845
|
writeSoftwareSystem(softwareSystem, level) {
|
|
@@ -704,7 +857,7 @@ var StructurizrDSLWriter = class {
|
|
|
704
857
|
writeRelationship(relationship, level) {
|
|
705
858
|
let dsl = "";
|
|
706
859
|
if (relationship.archetype) {
|
|
707
|
-
const arrow = `--${relationship.archetype.
|
|
860
|
+
const arrow = `--${relationship.archetype.canonicalName}->`;
|
|
708
861
|
const ovr = relationship.overrideDefinition;
|
|
709
862
|
const desc = ovr?.description ?? relationship.description ?? "uses";
|
|
710
863
|
dsl += this.writeLine(
|
|
@@ -738,21 +891,51 @@ var StructurizrDSLWriter = class {
|
|
|
738
891
|
});
|
|
739
892
|
return relationshipsDsl;
|
|
740
893
|
}
|
|
894
|
+
hasNestedModelGroups(groups) {
|
|
895
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedModelGroups(g.getGroups()));
|
|
896
|
+
}
|
|
897
|
+
hasNestedSoftwareSystemGroups(groups) {
|
|
898
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedSoftwareSystemGroups(g.getGroups()));
|
|
899
|
+
}
|
|
900
|
+
hasNestedContainerGroups(groups) {
|
|
901
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedContainerGroups(g.getGroups()));
|
|
902
|
+
}
|
|
903
|
+
hasNestedGroups() {
|
|
904
|
+
if (this.hasNestedModelGroups(this.model.getGroups())) return true;
|
|
905
|
+
for (const ss of this.model.getSoftwareSystems()) {
|
|
906
|
+
if (this.hasNestedSoftwareSystemGroups(ss.getGroups())) return true;
|
|
907
|
+
for (const c of ss.getGroups().flatMap((g) => g.getAllContainers())) {
|
|
908
|
+
if (this.hasNestedContainerGroups(c.getGroups())) return true;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
741
913
|
writeModelGroup(group, level) {
|
|
742
914
|
let modelGroupDsl = "";
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
modelGroupDsl += this.
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
915
|
+
const hasDirect = group.getPeople().length > 0 || group.getSoftwareSystems().length > 0;
|
|
916
|
+
if (hasDirect) {
|
|
917
|
+
modelGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
918
|
+
group.getPeople().forEach((person) => {
|
|
919
|
+
modelGroupDsl += this.writeElement("person", person, level + 1);
|
|
920
|
+
});
|
|
921
|
+
group.getSoftwareSystems().forEach((softwareSystem) => {
|
|
922
|
+
modelGroupDsl += this.writeSoftwareSystem(softwareSystem, level + 1);
|
|
923
|
+
});
|
|
924
|
+
modelGroupDsl += this.writeLine(`}`, level);
|
|
925
|
+
}
|
|
926
|
+
group.getGroups().forEach((nested) => {
|
|
927
|
+
modelGroupDsl += this.writeModelGroup(nested, level);
|
|
749
928
|
});
|
|
750
|
-
modelGroupDsl += this.writeLine(`}`, level);
|
|
751
929
|
return modelGroupDsl;
|
|
752
930
|
}
|
|
753
931
|
writeModel(model, level) {
|
|
754
932
|
let modelDsl = "";
|
|
755
933
|
modelDsl += this.writeLine(`model {`, level);
|
|
934
|
+
if (this.hasNestedGroups()) {
|
|
935
|
+
modelDsl += this.writeLine(`properties {`, level + 1);
|
|
936
|
+
modelDsl += this.writeLine(`"structurizr.groupSeparator" "/"`, level + 2);
|
|
937
|
+
modelDsl += this.writeLine(`}`, level + 1);
|
|
938
|
+
}
|
|
756
939
|
modelDsl += this.writeArchetypes(level + 1);
|
|
757
940
|
modelDsl += this.writeLine("// Elements", level + 1);
|
|
758
941
|
model.getPeopleNotInGroups().forEach((person) => {
|
|
@@ -775,12 +958,66 @@ var StructurizrDSLWriter = class {
|
|
|
775
958
|
if (view.title) {
|
|
776
959
|
viewDsl += this.writeLine(`title "${view.title}"`, level + 1);
|
|
777
960
|
}
|
|
961
|
+
if (view.isDefault) {
|
|
962
|
+
viewDsl += this.writeLine("default", level + 1);
|
|
963
|
+
}
|
|
778
964
|
view.scopes.forEach((scope) => {
|
|
779
965
|
viewDsl += this.writeLine(`${scope}`, level + 1);
|
|
780
966
|
});
|
|
967
|
+
if (view.autoLayoutConfig) {
|
|
968
|
+
const { direction, rankSeparation, nodeSeparation } = view.autoLayoutConfig;
|
|
969
|
+
let line = "autoLayout";
|
|
970
|
+
if (direction) line += ` ${direction}`;
|
|
971
|
+
if (rankSeparation !== void 0) line += ` ${rankSeparation}`;
|
|
972
|
+
if (nodeSeparation !== void 0) line += ` ${nodeSeparation}`;
|
|
973
|
+
viewDsl += this.writeLine(line, level + 1);
|
|
974
|
+
}
|
|
975
|
+
if (view.properties.size > 0) {
|
|
976
|
+
viewDsl += this.writeLine("properties {", level + 1);
|
|
977
|
+
for (const [name, value] of view.properties) {
|
|
978
|
+
viewDsl += this.writeLine(`"${name}" "${value}"`, level + 2);
|
|
979
|
+
}
|
|
980
|
+
viewDsl += this.writeLine("}", level + 1);
|
|
981
|
+
}
|
|
781
982
|
viewDsl += this.writeLine(`}`, level);
|
|
782
983
|
return viewDsl;
|
|
783
984
|
}
|
|
985
|
+
writeStyles(views, level) {
|
|
986
|
+
const { elementStyles, relationshipStyles } = views;
|
|
987
|
+
if (elementStyles.length === 0 && relationshipStyles.length === 0) return "";
|
|
988
|
+
let dsl = this.writeLine("styles {", level);
|
|
989
|
+
for (const { tag, definition: d } of elementStyles) {
|
|
990
|
+
dsl += this.writeLine(`element "${tag}" {`, level + 1);
|
|
991
|
+
if (d.shape) dsl += this.writeLine(`shape ${d.shape}`, level + 2);
|
|
992
|
+
if (d.icon) dsl += this.writeLine(`icon "${d.icon}"`, level + 2);
|
|
993
|
+
if (d.width) dsl += this.writeLine(`width ${d.width}`, level + 2);
|
|
994
|
+
if (d.height) dsl += this.writeLine(`height ${d.height}`, level + 2);
|
|
995
|
+
if (d.background) dsl += this.writeLine(`background "${d.background}"`, level + 2);
|
|
996
|
+
if (d.color) dsl += this.writeLine(`color "${d.color}"`, level + 2);
|
|
997
|
+
if (d.stroke) dsl += this.writeLine(`stroke "${d.stroke}"`, level + 2);
|
|
998
|
+
if (d.strokeWidth) dsl += this.writeLine(`strokeWidth ${d.strokeWidth}`, level + 2);
|
|
999
|
+
if (d.fontSize) dsl += this.writeLine(`fontSize ${d.fontSize}`, level + 2);
|
|
1000
|
+
if (d.border) dsl += this.writeLine(`border ${d.border}`, level + 2);
|
|
1001
|
+
if (d.opacity !== void 0) dsl += this.writeLine(`opacity ${d.opacity}`, level + 2);
|
|
1002
|
+
if (d.metadata !== void 0) dsl += this.writeLine(`metadata ${d.metadata}`, level + 2);
|
|
1003
|
+
if (d.description !== void 0) dsl += this.writeLine(`description ${d.description}`, level + 2);
|
|
1004
|
+
dsl += this.writeLine("}", level + 1);
|
|
1005
|
+
}
|
|
1006
|
+
for (const { tag, definition: d } of relationshipStyles) {
|
|
1007
|
+
dsl += this.writeLine(`relationship "${tag}" {`, level + 1);
|
|
1008
|
+
if (d.thickness) dsl += this.writeLine(`thickness ${d.thickness}`, level + 2);
|
|
1009
|
+
if (d.color) dsl += this.writeLine(`color "${d.color}"`, level + 2);
|
|
1010
|
+
if (d.style) dsl += this.writeLine(`style ${d.style}`, level + 2);
|
|
1011
|
+
if (d.routing) dsl += this.writeLine(`routing ${d.routing}`, level + 2);
|
|
1012
|
+
if (d.fontSize) dsl += this.writeLine(`fontSize ${d.fontSize}`, level + 2);
|
|
1013
|
+
if (d.width) dsl += this.writeLine(`width ${d.width}`, level + 2);
|
|
1014
|
+
if (d.position !== void 0) dsl += this.writeLine(`position ${d.position}`, level + 2);
|
|
1015
|
+
if (d.opacity !== void 0) dsl += this.writeLine(`opacity ${d.opacity}`, level + 2);
|
|
1016
|
+
dsl += this.writeLine("}", level + 1);
|
|
1017
|
+
}
|
|
1018
|
+
dsl += this.writeLine("}", level);
|
|
1019
|
+
return dsl;
|
|
1020
|
+
}
|
|
784
1021
|
writeViews(views, level) {
|
|
785
1022
|
let viewDsl = "";
|
|
786
1023
|
viewDsl += this.writeLine(`views {`, level);
|
|
@@ -800,6 +1037,19 @@ var StructurizrDSLWriter = class {
|
|
|
800
1037
|
views.componentViews.forEach((view) => {
|
|
801
1038
|
viewDsl += this.writeView(view, "component", level + 1);
|
|
802
1039
|
});
|
|
1040
|
+
viewDsl += this.writeStyles(views, level + 1);
|
|
1041
|
+
if (views.themes.length === 1) {
|
|
1042
|
+
viewDsl += this.writeLine(`theme ${views.themes[0]}`, level + 1);
|
|
1043
|
+
} else if (views.themes.length > 1) {
|
|
1044
|
+
viewDsl += this.writeLine(`themes ${views.themes.join(" ")}`, level + 1);
|
|
1045
|
+
}
|
|
1046
|
+
if (views.properties.size > 0) {
|
|
1047
|
+
viewDsl += this.writeLine("properties {", level + 1);
|
|
1048
|
+
for (const [name, value] of views.properties) {
|
|
1049
|
+
viewDsl += this.writeLine(`"${name}" "${value}"`, level + 2);
|
|
1050
|
+
}
|
|
1051
|
+
viewDsl += this.writeLine("}", level + 1);
|
|
1052
|
+
}
|
|
803
1053
|
viewDsl += this.writeLine(`}`, level);
|
|
804
1054
|
return viewDsl;
|
|
805
1055
|
}
|
|
@@ -824,8 +1074,8 @@ import { glob } from "glob";
|
|
|
824
1074
|
import { join, dirname } from "path";
|
|
825
1075
|
import { fileURLToPath } from "url";
|
|
826
1076
|
var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
827
|
-
async function
|
|
828
|
-
const { modelName = "model", modules: explicitModules, archetypes = {} } = options;
|
|
1077
|
+
async function buildModel(options = {}) {
|
|
1078
|
+
const { modelName = "model", modules: explicitModules, archetypes = {}, addViews } = options;
|
|
829
1079
|
const model = new Model(modelName);
|
|
830
1080
|
let c4Modules;
|
|
831
1081
|
if (explicitModules) {
|
|
@@ -849,14 +1099,16 @@ async function buildModelWithCatalog(options = {}) {
|
|
|
849
1099
|
rootCatalog[instance.key] = local;
|
|
850
1100
|
registrations.push({ instance, key: instance.key, local });
|
|
851
1101
|
}
|
|
1102
|
+
const dependenciesFor = (key) => Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
|
|
852
1103
|
for (const { instance, key, local } of registrations) {
|
|
853
|
-
|
|
854
|
-
instance.buildRelationships(local, dependencies, archetypes);
|
|
1104
|
+
instance.addRelationships(local, dependenciesFor(key), archetypes);
|
|
855
1105
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1106
|
+
const views = new Views();
|
|
1107
|
+
addViews?.(views, rootCatalog);
|
|
1108
|
+
for (const { instance, key, local } of registrations) {
|
|
1109
|
+
instance.addViews?.(views, local, dependenciesFor(key));
|
|
1110
|
+
}
|
|
1111
|
+
return { model, catalog: rootCatalog, views };
|
|
860
1112
|
}
|
|
861
1113
|
|
|
862
1114
|
// libs/c4-model/src/generateDiagrams.ts
|
|
@@ -865,9 +1117,8 @@ import * as os from "os";
|
|
|
865
1117
|
import * as path from "path";
|
|
866
1118
|
import { GenericContainer, Wait } from "testcontainers";
|
|
867
1119
|
async function generateDiagrams(options) {
|
|
868
|
-
const {
|
|
869
|
-
const { model,
|
|
870
|
-
const views = viewsFactory(catalog);
|
|
1120
|
+
const { outputDir, ...buildOptions } = options;
|
|
1121
|
+
const { model, views } = await buildModel(buildOptions);
|
|
871
1122
|
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
872
1123
|
const tmpDir = await fs.promises.mkdtemp(path.join(fs.realpathSync(os.tmpdir()), "c4-diagrams-"));
|
|
873
1124
|
await fs.promises.writeFile(path.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
@@ -888,10 +1139,65 @@ async function generateDiagrams(options) {
|
|
|
888
1139
|
}
|
|
889
1140
|
return generatedFiles;
|
|
890
1141
|
}
|
|
1142
|
+
|
|
1143
|
+
// libs/c4-model/src/validateModel.ts
|
|
1144
|
+
import * as fs2 from "fs";
|
|
1145
|
+
import * as os2 from "os";
|
|
1146
|
+
import * as path2 from "path";
|
|
1147
|
+
import { GenericContainer as GenericContainer2, Wait as Wait2 } from "testcontainers";
|
|
1148
|
+
async function validateModel(model, views) {
|
|
1149
|
+
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
1150
|
+
const tmpDir = await fs2.promises.mkdtemp(path2.join(fs2.realpathSync(os2.tmpdir()), "c4-validate-"));
|
|
1151
|
+
try {
|
|
1152
|
+
await fs2.promises.writeFile(path2.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
1153
|
+
const logs = [];
|
|
1154
|
+
try {
|
|
1155
|
+
await new GenericContainer2("structurizr/structurizr").withBindMounts([{ source: tmpDir, target: "/workspace", mode: "rw" }]).withCommand(["validate", "-workspace", "/workspace/workspace.dsl"]).withWaitStrategy(Wait2.forOneShotStartup()).withLogConsumer((stream) => stream.on("data", (chunk) => logs.push(chunk.toString()))).start();
|
|
1156
|
+
} catch {
|
|
1157
|
+
throw new Error(`Structurizr validation failed:
|
|
1158
|
+
${logs.join("")}`);
|
|
1159
|
+
}
|
|
1160
|
+
} finally {
|
|
1161
|
+
await fs2.promises.rm(tmpDir, { recursive: true, force: true });
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// libs/c4-model/src/exportWorkspaceJson.ts
|
|
1166
|
+
import * as fs3 from "fs";
|
|
1167
|
+
import * as os3 from "os";
|
|
1168
|
+
import * as path3 from "path";
|
|
1169
|
+
import { GenericContainer as GenericContainer3, Wait as Wait3 } from "testcontainers";
|
|
1170
|
+
async function exportWorkspaceJsonFromDsl(dsl) {
|
|
1171
|
+
const tmpDir = await fs3.promises.mkdtemp(path3.join(fs3.realpathSync(os3.tmpdir()), "c4-export-"));
|
|
1172
|
+
try {
|
|
1173
|
+
await fs3.promises.writeFile(path3.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
1174
|
+
const logs = [];
|
|
1175
|
+
try {
|
|
1176
|
+
await new GenericContainer3("structurizr/structurizr").withBindMounts([{ source: tmpDir, target: "/workspace", mode: "rw" }]).withCommand(["export", "-w", "/workspace/workspace.dsl", "-f", "json", "-o", "/workspace"]).withWaitStrategy(Wait3.forOneShotStartup()).withLogConsumer((stream) => stream.on("data", (chunk) => logs.push(chunk.toString()))).start();
|
|
1177
|
+
} catch {
|
|
1178
|
+
throw new Error(`Structurizr JSON export failed:
|
|
1179
|
+
${logs.join("")}`);
|
|
1180
|
+
}
|
|
1181
|
+
const files = await fs3.promises.readdir(tmpDir);
|
|
1182
|
+
const jsonFile = files.find((f) => f.endsWith(".json"));
|
|
1183
|
+
if (!jsonFile) {
|
|
1184
|
+
throw new Error(`Structurizr JSON export produced no .json file. Files: ${files.join(", ")}`);
|
|
1185
|
+
}
|
|
1186
|
+
const jsonContent = await fs3.promises.readFile(path3.join(tmpDir, jsonFile), "utf8");
|
|
1187
|
+
return JSON.parse(jsonContent);
|
|
1188
|
+
} finally {
|
|
1189
|
+
await fs3.promises.rm(tmpDir, { recursive: true, force: true });
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
async function exportWorkspaceJson(model, views) {
|
|
1193
|
+
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
1194
|
+
return exportWorkspaceJsonFromDsl(dsl);
|
|
1195
|
+
}
|
|
891
1196
|
export {
|
|
892
1197
|
Component,
|
|
893
1198
|
Container,
|
|
894
1199
|
ContainerGroup,
|
|
1200
|
+
ELEMENT_KINDS,
|
|
895
1201
|
ElementArchetype,
|
|
896
1202
|
Model,
|
|
897
1203
|
ModelGroup,
|
|
@@ -903,7 +1209,9 @@ export {
|
|
|
903
1209
|
View,
|
|
904
1210
|
Views,
|
|
905
1211
|
buildModel,
|
|
906
|
-
|
|
1212
|
+
exportWorkspaceJson,
|
|
1213
|
+
exportWorkspaceJsonFromDsl,
|
|
907
1214
|
generateDiagrams,
|
|
908
|
-
mergeArchetypeWithOverride
|
|
1215
|
+
mergeArchetypeWithOverride,
|
|
1216
|
+
validateModel
|
|
909
1217
|
};
|