@agilewallaby/c4-model 2.6.0 → 2.8.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/buildModel.d.ts +7 -4
- package/src/container.d.ts +11 -4
- package/src/core.d.ts +6 -3
- package/src/exportWorkspaceJson.d.ts +4 -0
- package/src/generateDiagrams.d.ts +1 -3
- package/src/index.cjs +355 -46
- package/src/index.d.ts +151 -55
- package/src/index.js +351 -44
- package/src/model.d.ts +14 -4
- package/src/softwareSystem.d.ts +11 -4
- 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
|
@@ -162,12 +162,16 @@ var Element = class {
|
|
|
162
162
|
get relationships() {
|
|
163
163
|
return this._relationships;
|
|
164
164
|
}
|
|
165
|
+
with(callback) {
|
|
166
|
+
const children = callback(this);
|
|
167
|
+
return Object.assign(this, children);
|
|
168
|
+
}
|
|
165
169
|
getRelationshipsInHierarchy() {
|
|
166
170
|
return this._relationships.concat(this.getChildElements().flatMap((element) => element.getRelationshipsInHierarchy()));
|
|
167
171
|
}
|
|
168
|
-
getChildElementNames(
|
|
172
|
+
getChildElementNames(path4) {
|
|
169
173
|
const result = Array.from(this.getChildElements()).flatMap((reference) => {
|
|
170
|
-
const currentPath = `${
|
|
174
|
+
const currentPath = `${path4 ? path4 : "" + this.name}.${reference.name}`;
|
|
171
175
|
return [currentPath, ...reference.getChildElementNames(currentPath)];
|
|
172
176
|
});
|
|
173
177
|
return result;
|
|
@@ -200,6 +204,13 @@ var Group = class {
|
|
|
200
204
|
constructor(name) {
|
|
201
205
|
this.name = name;
|
|
202
206
|
}
|
|
207
|
+
get canonicalName() {
|
|
208
|
+
return camelCase(this.name);
|
|
209
|
+
}
|
|
210
|
+
with(callback) {
|
|
211
|
+
const children = callback(this);
|
|
212
|
+
return Object.assign(this, children);
|
|
213
|
+
}
|
|
203
214
|
// TODO: Implement this in some useful way?
|
|
204
215
|
// public addToGroup(groupCollection: string, groupMember: T) {}
|
|
205
216
|
};
|
|
@@ -216,21 +227,46 @@ var Component = class extends TechnicalElement {
|
|
|
216
227
|
};
|
|
217
228
|
|
|
218
229
|
// libs/c4-model/src/container.ts
|
|
219
|
-
var ContainerGroup = class extends Group {
|
|
220
|
-
constructor(name, container) {
|
|
230
|
+
var ContainerGroup = class _ContainerGroup extends Group {
|
|
231
|
+
constructor(name, container, pathSegments = []) {
|
|
221
232
|
super(name);
|
|
222
233
|
this.name = name;
|
|
223
234
|
this.container = container;
|
|
235
|
+
this.pathSegments = pathSegments;
|
|
224
236
|
}
|
|
225
237
|
_components = /* @__PURE__ */ new Map();
|
|
238
|
+
_groups = /* @__PURE__ */ new Map();
|
|
239
|
+
get canonicalName() {
|
|
240
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
241
|
+
}
|
|
242
|
+
get dslName() {
|
|
243
|
+
return [...this.pathSegments, this.name].join("/");
|
|
244
|
+
}
|
|
226
245
|
component(name, archetypeOrDef, override) {
|
|
227
246
|
const component = this.container.component(name, archetypeOrDef, override);
|
|
228
247
|
this._components.set(name, component);
|
|
229
248
|
return component;
|
|
230
249
|
}
|
|
250
|
+
group(groupName) {
|
|
251
|
+
let group = this._groups.get(groupName);
|
|
252
|
+
if (!group) {
|
|
253
|
+
group = new _ContainerGroup(groupName, this.container, [...this.pathSegments, this.name]);
|
|
254
|
+
this._groups.set(groupName, group);
|
|
255
|
+
}
|
|
256
|
+
return group;
|
|
257
|
+
}
|
|
258
|
+
getGroups() {
|
|
259
|
+
return Array.from(this._groups.values());
|
|
260
|
+
}
|
|
231
261
|
getComponents() {
|
|
232
262
|
return Array.from(this._components.values());
|
|
233
263
|
}
|
|
264
|
+
getAllComponents() {
|
|
265
|
+
return [
|
|
266
|
+
...this._components.values(),
|
|
267
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllComponents())
|
|
268
|
+
];
|
|
269
|
+
}
|
|
234
270
|
};
|
|
235
271
|
var Container = class extends TechnicalElement {
|
|
236
272
|
constructor(name, definition, archetype, overrideDefinition) {
|
|
@@ -255,7 +291,7 @@ var Container = class extends TechnicalElement {
|
|
|
255
291
|
this._components.set(name, component);
|
|
256
292
|
return component;
|
|
257
293
|
}
|
|
258
|
-
|
|
294
|
+
group(groupName) {
|
|
259
295
|
let group = this._groups.get(groupName);
|
|
260
296
|
if (!group) {
|
|
261
297
|
group = new ContainerGroup(groupName, this);
|
|
@@ -267,7 +303,7 @@ var Container = class extends TechnicalElement {
|
|
|
267
303
|
return Array.from(this._groups.values());
|
|
268
304
|
}
|
|
269
305
|
getComponentsNotInGroups() {
|
|
270
|
-
const componentsInGroups = this.getGroups().flatMap((group) => group.
|
|
306
|
+
const componentsInGroups = this.getGroups().flatMap((group) => group.getAllComponents());
|
|
271
307
|
return Array.from(this._components.values()).filter((component) => !componentsInGroups.includes(component));
|
|
272
308
|
}
|
|
273
309
|
getChildElements() {
|
|
@@ -276,21 +312,46 @@ var Container = class extends TechnicalElement {
|
|
|
276
312
|
};
|
|
277
313
|
|
|
278
314
|
// libs/c4-model/src/softwareSystem.ts
|
|
279
|
-
var SoftwareSystemGroup = class extends Group {
|
|
280
|
-
constructor(name, softwareSystem) {
|
|
315
|
+
var SoftwareSystemGroup = class _SoftwareSystemGroup extends Group {
|
|
316
|
+
constructor(name, softwareSystem, pathSegments = []) {
|
|
281
317
|
super(name);
|
|
282
318
|
this.name = name;
|
|
283
319
|
this.softwareSystem = softwareSystem;
|
|
320
|
+
this.pathSegments = pathSegments;
|
|
284
321
|
}
|
|
285
322
|
_containers = /* @__PURE__ */ new Map();
|
|
323
|
+
_groups = /* @__PURE__ */ new Map();
|
|
324
|
+
get canonicalName() {
|
|
325
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
326
|
+
}
|
|
327
|
+
get dslName() {
|
|
328
|
+
return [...this.pathSegments, this.name].join("/");
|
|
329
|
+
}
|
|
286
330
|
container(name, archetypeOrDef, override) {
|
|
287
331
|
const container = this.softwareSystem.container(name, archetypeOrDef, override);
|
|
288
332
|
this._containers.set(name, container);
|
|
289
333
|
return container;
|
|
290
334
|
}
|
|
335
|
+
group(groupName) {
|
|
336
|
+
let group = this._groups.get(groupName);
|
|
337
|
+
if (!group) {
|
|
338
|
+
group = new _SoftwareSystemGroup(groupName, this.softwareSystem, [...this.pathSegments, this.name]);
|
|
339
|
+
this._groups.set(groupName, group);
|
|
340
|
+
}
|
|
341
|
+
return group;
|
|
342
|
+
}
|
|
343
|
+
getGroups() {
|
|
344
|
+
return Array.from(this._groups.values());
|
|
345
|
+
}
|
|
291
346
|
getContainers() {
|
|
292
347
|
return Array.from(this._containers.values());
|
|
293
348
|
}
|
|
349
|
+
getAllContainers() {
|
|
350
|
+
return [
|
|
351
|
+
...this._containers.values(),
|
|
352
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllContainers())
|
|
353
|
+
];
|
|
354
|
+
}
|
|
294
355
|
};
|
|
295
356
|
var SoftwareSystem = class extends Element {
|
|
296
357
|
constructor(name, definition, archetype, overrideDefinition) {
|
|
@@ -315,7 +376,7 @@ var SoftwareSystem = class extends Element {
|
|
|
315
376
|
this._containers.set(name, container);
|
|
316
377
|
return container;
|
|
317
378
|
}
|
|
318
|
-
|
|
379
|
+
group(groupName) {
|
|
319
380
|
let group = this._groups.get(groupName);
|
|
320
381
|
if (!group) {
|
|
321
382
|
group = new SoftwareSystemGroup(groupName, this);
|
|
@@ -330,7 +391,7 @@ var SoftwareSystem = class extends Element {
|
|
|
330
391
|
return Array.from(this._containers.values());
|
|
331
392
|
}
|
|
332
393
|
getContainersNotInGroups() {
|
|
333
|
-
const containersInGroups = Array.from(this._groups.values()).flatMap((group) => group.
|
|
394
|
+
const containersInGroups = Array.from(this._groups.values()).flatMap((group) => group.getAllContainers());
|
|
334
395
|
return Array.from(this._containers.values()).filter((container) => !containersInGroups.includes(container));
|
|
335
396
|
}
|
|
336
397
|
};
|
|
@@ -347,14 +408,22 @@ var Person = class extends Element {
|
|
|
347
408
|
};
|
|
348
409
|
|
|
349
410
|
// libs/c4-model/src/model.ts
|
|
350
|
-
var ModelGroup = class extends Group {
|
|
351
|
-
constructor(name, model) {
|
|
411
|
+
var ModelGroup = class _ModelGroup extends Group {
|
|
412
|
+
constructor(name, model, pathSegments = []) {
|
|
352
413
|
super(name);
|
|
353
414
|
this.name = name;
|
|
354
415
|
this.model = model;
|
|
416
|
+
this.pathSegments = pathSegments;
|
|
355
417
|
}
|
|
356
418
|
softwareSystems = /* @__PURE__ */ new Map();
|
|
357
419
|
people = /* @__PURE__ */ new Map();
|
|
420
|
+
_groups = /* @__PURE__ */ new Map();
|
|
421
|
+
get canonicalName() {
|
|
422
|
+
return camelCase([...this.pathSegments, this.name].join(" "));
|
|
423
|
+
}
|
|
424
|
+
get dslName() {
|
|
425
|
+
return [...this.pathSegments, this.name].join("/");
|
|
426
|
+
}
|
|
358
427
|
softwareSystem(name, archetypeOrDef, override) {
|
|
359
428
|
const softwareSystem = this.model.softwareSystem(name, archetypeOrDef, override);
|
|
360
429
|
this.softwareSystems.set(name, softwareSystem);
|
|
@@ -365,12 +434,35 @@ var ModelGroup = class extends Group {
|
|
|
365
434
|
this.people.set(name, person);
|
|
366
435
|
return person;
|
|
367
436
|
}
|
|
437
|
+
group(groupName) {
|
|
438
|
+
let group = this._groups.get(groupName);
|
|
439
|
+
if (!group) {
|
|
440
|
+
group = new _ModelGroup(groupName, this.model, [...this.pathSegments, this.name]);
|
|
441
|
+
this._groups.set(groupName, group);
|
|
442
|
+
}
|
|
443
|
+
return group;
|
|
444
|
+
}
|
|
445
|
+
getGroups() {
|
|
446
|
+
return Array.from(this._groups.values());
|
|
447
|
+
}
|
|
368
448
|
getSoftwareSystems() {
|
|
369
449
|
return Array.from(this.softwareSystems.values());
|
|
370
450
|
}
|
|
371
451
|
getPeople() {
|
|
372
452
|
return Array.from(this.people.values());
|
|
373
453
|
}
|
|
454
|
+
getAllSoftwareSystems() {
|
|
455
|
+
return [
|
|
456
|
+
...this.softwareSystems.values(),
|
|
457
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllSoftwareSystems())
|
|
458
|
+
];
|
|
459
|
+
}
|
|
460
|
+
getAllPeople() {
|
|
461
|
+
return [
|
|
462
|
+
...this.people.values(),
|
|
463
|
+
...Array.from(this._groups.values()).flatMap((g) => g.getAllPeople())
|
|
464
|
+
];
|
|
465
|
+
}
|
|
374
466
|
};
|
|
375
467
|
var Model = class {
|
|
376
468
|
constructor(name) {
|
|
@@ -395,8 +487,7 @@ var Model = class {
|
|
|
395
487
|
this.softwareSystems.set(name, system);
|
|
396
488
|
return system;
|
|
397
489
|
}
|
|
398
|
-
|
|
399
|
-
addGroup(groupName) {
|
|
490
|
+
group(groupName) {
|
|
400
491
|
let group = this.groups.get(groupName);
|
|
401
492
|
if (!group) {
|
|
402
493
|
group = new ModelGroup(groupName, this);
|
|
@@ -420,6 +511,7 @@ var Model = class {
|
|
|
420
511
|
this.people.set(name, person);
|
|
421
512
|
return person;
|
|
422
513
|
}
|
|
514
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
423
515
|
validate() {
|
|
424
516
|
}
|
|
425
517
|
getPeople() {
|
|
@@ -429,11 +521,11 @@ var Model = class {
|
|
|
429
521
|
return Array.from(this.softwareSystems.values());
|
|
430
522
|
}
|
|
431
523
|
getPeopleNotInGroups() {
|
|
432
|
-
const peopleInGroups = Array.from(this.groups.values()).flatMap((group) => group.
|
|
524
|
+
const peopleInGroups = Array.from(this.groups.values()).flatMap((group) => group.getAllPeople());
|
|
433
525
|
return Array.from(this.people.values()).filter((person) => !peopleInGroups.includes(person));
|
|
434
526
|
}
|
|
435
527
|
getSoftwareSystemsNotInGroups() {
|
|
436
|
-
const systemsInGroups = Array.from(this.groups.values()).flatMap((group) => group.
|
|
528
|
+
const systemsInGroups = Array.from(this.groups.values()).flatMap((group) => group.getAllSoftwareSystems());
|
|
437
529
|
return Array.from(this.softwareSystems.values()).filter((system) => !systemsInGroups.includes(system));
|
|
438
530
|
}
|
|
439
531
|
getGroups() {
|
|
@@ -453,6 +545,9 @@ var View = class {
|
|
|
453
545
|
description;
|
|
454
546
|
title;
|
|
455
547
|
_scopes = [];
|
|
548
|
+
_autoLayout;
|
|
549
|
+
_isDefault = false;
|
|
550
|
+
_properties = /* @__PURE__ */ new Map();
|
|
456
551
|
includeAll() {
|
|
457
552
|
this._scopes.push("include *");
|
|
458
553
|
}
|
|
@@ -471,15 +566,37 @@ var View = class {
|
|
|
471
566
|
excludeExpression(expression) {
|
|
472
567
|
this._scopes.push(`exclude ${expression}`);
|
|
473
568
|
}
|
|
569
|
+
autoLayout(direction, rankSeparation, nodeSeparation) {
|
|
570
|
+
this._autoLayout = { direction, rankSeparation, nodeSeparation };
|
|
571
|
+
}
|
|
572
|
+
setDefault() {
|
|
573
|
+
this._isDefault = true;
|
|
574
|
+
}
|
|
575
|
+
addProperty(name, value) {
|
|
576
|
+
this._properties.set(name, value);
|
|
577
|
+
}
|
|
474
578
|
get scopes() {
|
|
475
579
|
return this._scopes;
|
|
476
580
|
}
|
|
581
|
+
get autoLayoutConfig() {
|
|
582
|
+
return this._autoLayout;
|
|
583
|
+
}
|
|
584
|
+
get isDefault() {
|
|
585
|
+
return this._isDefault;
|
|
586
|
+
}
|
|
587
|
+
get properties() {
|
|
588
|
+
return this._properties;
|
|
589
|
+
}
|
|
477
590
|
};
|
|
478
591
|
var Views = class {
|
|
479
592
|
_systemLandscapeViews = /* @__PURE__ */ new Map();
|
|
480
593
|
_systemContextViews = /* @__PURE__ */ new Map();
|
|
481
594
|
_containerViews = /* @__PURE__ */ new Map();
|
|
482
595
|
_componentViews = /* @__PURE__ */ new Map();
|
|
596
|
+
_elementStyles = [];
|
|
597
|
+
_relationshipStyles = [];
|
|
598
|
+
_themes = [];
|
|
599
|
+
_properties = /* @__PURE__ */ new Map();
|
|
483
600
|
addSystemLandscapeView(key, definition) {
|
|
484
601
|
const view = new View(key, { subject: void 0, description: definition.description, title: definition.title });
|
|
485
602
|
this._systemLandscapeViews.set(key, view);
|
|
@@ -500,6 +617,18 @@ var Views = class {
|
|
|
500
617
|
this._componentViews.set(key, view);
|
|
501
618
|
return view;
|
|
502
619
|
}
|
|
620
|
+
addElementStyle(tag, definition) {
|
|
621
|
+
this._elementStyles.push({ tag, definition });
|
|
622
|
+
}
|
|
623
|
+
addRelationshipStyle(tag, definition) {
|
|
624
|
+
this._relationshipStyles.push({ tag, definition });
|
|
625
|
+
}
|
|
626
|
+
addTheme(url) {
|
|
627
|
+
this._themes.push(url);
|
|
628
|
+
}
|
|
629
|
+
addProperty(name, value) {
|
|
630
|
+
this._properties.set(name, value);
|
|
631
|
+
}
|
|
503
632
|
get systemLandscapeViews() {
|
|
504
633
|
return Array.from(this._systemLandscapeViews.values());
|
|
505
634
|
}
|
|
@@ -512,6 +641,18 @@ var Views = class {
|
|
|
512
641
|
get componentViews() {
|
|
513
642
|
return Array.from(this._componentViews.values());
|
|
514
643
|
}
|
|
644
|
+
get elementStyles() {
|
|
645
|
+
return this._elementStyles;
|
|
646
|
+
}
|
|
647
|
+
get relationshipStyles() {
|
|
648
|
+
return this._relationshipStyles;
|
|
649
|
+
}
|
|
650
|
+
get themes() {
|
|
651
|
+
return this._themes;
|
|
652
|
+
}
|
|
653
|
+
get properties() {
|
|
654
|
+
return this._properties;
|
|
655
|
+
}
|
|
515
656
|
};
|
|
516
657
|
|
|
517
658
|
// libs/c4-model/src/structurizrDslWriter.ts
|
|
@@ -646,11 +787,17 @@ var StructurizrDSLWriter = class {
|
|
|
646
787
|
}
|
|
647
788
|
writeContainerGroup(group, level) {
|
|
648
789
|
let containerGroupDsl = "";
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
containerGroupDsl += this.
|
|
790
|
+
const hasDirect = group.getComponents().length > 0;
|
|
791
|
+
if (hasDirect) {
|
|
792
|
+
containerGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
793
|
+
group.getComponents().forEach((component) => {
|
|
794
|
+
containerGroupDsl += this.writeComponent(component, level + 1);
|
|
795
|
+
});
|
|
796
|
+
containerGroupDsl += this.writeLine(`}`, level);
|
|
797
|
+
}
|
|
798
|
+
group.getGroups().forEach((nested) => {
|
|
799
|
+
containerGroupDsl += this.writeContainerGroup(nested, level);
|
|
652
800
|
});
|
|
653
|
-
containerGroupDsl += this.writeLine(`}`, level);
|
|
654
801
|
return containerGroupDsl;
|
|
655
802
|
}
|
|
656
803
|
writeContainer(container, level) {
|
|
@@ -670,11 +817,17 @@ var StructurizrDSLWriter = class {
|
|
|
670
817
|
}
|
|
671
818
|
writeSoftwareSystemGroup(group, level) {
|
|
672
819
|
let softwareSystemGroupDsl = "";
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
softwareSystemGroupDsl += this.
|
|
820
|
+
const hasDirect = group.getContainers().length > 0;
|
|
821
|
+
if (hasDirect) {
|
|
822
|
+
softwareSystemGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
823
|
+
group.getContainers().forEach((container) => {
|
|
824
|
+
softwareSystemGroupDsl += this.writeContainer(container, level + 1);
|
|
825
|
+
});
|
|
826
|
+
softwareSystemGroupDsl += this.writeLine(`}`, level);
|
|
827
|
+
}
|
|
828
|
+
group.getGroups().forEach((nested) => {
|
|
829
|
+
softwareSystemGroupDsl += this.writeSoftwareSystemGroup(nested, level);
|
|
676
830
|
});
|
|
677
|
-
softwareSystemGroupDsl += this.writeLine(`}`, level);
|
|
678
831
|
return softwareSystemGroupDsl;
|
|
679
832
|
}
|
|
680
833
|
writeSoftwareSystem(softwareSystem, level) {
|
|
@@ -726,21 +879,51 @@ var StructurizrDSLWriter = class {
|
|
|
726
879
|
});
|
|
727
880
|
return relationshipsDsl;
|
|
728
881
|
}
|
|
882
|
+
hasNestedModelGroups(groups) {
|
|
883
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedModelGroups(g.getGroups()));
|
|
884
|
+
}
|
|
885
|
+
hasNestedSoftwareSystemGroups(groups) {
|
|
886
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedSoftwareSystemGroups(g.getGroups()));
|
|
887
|
+
}
|
|
888
|
+
hasNestedContainerGroups(groups) {
|
|
889
|
+
return groups.some((g) => g.getGroups().length > 0 || this.hasNestedContainerGroups(g.getGroups()));
|
|
890
|
+
}
|
|
891
|
+
hasNestedGroups() {
|
|
892
|
+
if (this.hasNestedModelGroups(this.model.getGroups())) return true;
|
|
893
|
+
for (const ss of this.model.getSoftwareSystems()) {
|
|
894
|
+
if (this.hasNestedSoftwareSystemGroups(ss.getGroups())) return true;
|
|
895
|
+
for (const c of ss.getGroups().flatMap((g) => g.getAllContainers())) {
|
|
896
|
+
if (this.hasNestedContainerGroups(c.getGroups())) return true;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
729
901
|
writeModelGroup(group, level) {
|
|
730
902
|
let modelGroupDsl = "";
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
modelGroupDsl += this.
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
903
|
+
const hasDirect = group.getPeople().length > 0 || group.getSoftwareSystems().length > 0;
|
|
904
|
+
if (hasDirect) {
|
|
905
|
+
modelGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.dslName}" {`, level);
|
|
906
|
+
group.getPeople().forEach((person) => {
|
|
907
|
+
modelGroupDsl += this.writeElement("person", person, level + 1);
|
|
908
|
+
});
|
|
909
|
+
group.getSoftwareSystems().forEach((softwareSystem) => {
|
|
910
|
+
modelGroupDsl += this.writeSoftwareSystem(softwareSystem, level + 1);
|
|
911
|
+
});
|
|
912
|
+
modelGroupDsl += this.writeLine(`}`, level);
|
|
913
|
+
}
|
|
914
|
+
group.getGroups().forEach((nested) => {
|
|
915
|
+
modelGroupDsl += this.writeModelGroup(nested, level);
|
|
737
916
|
});
|
|
738
|
-
modelGroupDsl += this.writeLine(`}`, level);
|
|
739
917
|
return modelGroupDsl;
|
|
740
918
|
}
|
|
741
919
|
writeModel(model, level) {
|
|
742
920
|
let modelDsl = "";
|
|
743
921
|
modelDsl += this.writeLine(`model {`, level);
|
|
922
|
+
if (this.hasNestedGroups()) {
|
|
923
|
+
modelDsl += this.writeLine(`properties {`, level + 1);
|
|
924
|
+
modelDsl += this.writeLine(`"structurizr.groupSeparator" "/"`, level + 2);
|
|
925
|
+
modelDsl += this.writeLine(`}`, level + 1);
|
|
926
|
+
}
|
|
744
927
|
modelDsl += this.writeArchetypes(level + 1);
|
|
745
928
|
modelDsl += this.writeLine("// Elements", level + 1);
|
|
746
929
|
model.getPeopleNotInGroups().forEach((person) => {
|
|
@@ -763,12 +946,66 @@ var StructurizrDSLWriter = class {
|
|
|
763
946
|
if (view.title) {
|
|
764
947
|
viewDsl += this.writeLine(`title "${view.title}"`, level + 1);
|
|
765
948
|
}
|
|
949
|
+
if (view.isDefault) {
|
|
950
|
+
viewDsl += this.writeLine("default", level + 1);
|
|
951
|
+
}
|
|
766
952
|
view.scopes.forEach((scope) => {
|
|
767
953
|
viewDsl += this.writeLine(`${scope}`, level + 1);
|
|
768
954
|
});
|
|
955
|
+
if (view.autoLayoutConfig) {
|
|
956
|
+
const { direction, rankSeparation, nodeSeparation } = view.autoLayoutConfig;
|
|
957
|
+
let line = "autoLayout";
|
|
958
|
+
if (direction) line += ` ${direction}`;
|
|
959
|
+
if (rankSeparation !== void 0) line += ` ${rankSeparation}`;
|
|
960
|
+
if (nodeSeparation !== void 0) line += ` ${nodeSeparation}`;
|
|
961
|
+
viewDsl += this.writeLine(line, level + 1);
|
|
962
|
+
}
|
|
963
|
+
if (view.properties.size > 0) {
|
|
964
|
+
viewDsl += this.writeLine("properties {", level + 1);
|
|
965
|
+
for (const [name, value] of view.properties) {
|
|
966
|
+
viewDsl += this.writeLine(`"${name}" "${value}"`, level + 2);
|
|
967
|
+
}
|
|
968
|
+
viewDsl += this.writeLine("}", level + 1);
|
|
969
|
+
}
|
|
769
970
|
viewDsl += this.writeLine(`}`, level);
|
|
770
971
|
return viewDsl;
|
|
771
972
|
}
|
|
973
|
+
writeStyles(views, level) {
|
|
974
|
+
const { elementStyles, relationshipStyles } = views;
|
|
975
|
+
if (elementStyles.length === 0 && relationshipStyles.length === 0) return "";
|
|
976
|
+
let dsl = this.writeLine("styles {", level);
|
|
977
|
+
for (const { tag, definition: d } of elementStyles) {
|
|
978
|
+
dsl += this.writeLine(`element "${tag}" {`, level + 1);
|
|
979
|
+
if (d.shape) dsl += this.writeLine(`shape ${d.shape}`, level + 2);
|
|
980
|
+
if (d.icon) dsl += this.writeLine(`icon "${d.icon}"`, level + 2);
|
|
981
|
+
if (d.width) dsl += this.writeLine(`width ${d.width}`, level + 2);
|
|
982
|
+
if (d.height) dsl += this.writeLine(`height ${d.height}`, level + 2);
|
|
983
|
+
if (d.background) dsl += this.writeLine(`background "${d.background}"`, level + 2);
|
|
984
|
+
if (d.color) dsl += this.writeLine(`color "${d.color}"`, level + 2);
|
|
985
|
+
if (d.stroke) dsl += this.writeLine(`stroke "${d.stroke}"`, level + 2);
|
|
986
|
+
if (d.strokeWidth) dsl += this.writeLine(`strokeWidth ${d.strokeWidth}`, level + 2);
|
|
987
|
+
if (d.fontSize) dsl += this.writeLine(`fontSize ${d.fontSize}`, level + 2);
|
|
988
|
+
if (d.border) dsl += this.writeLine(`border ${d.border}`, level + 2);
|
|
989
|
+
if (d.opacity !== void 0) dsl += this.writeLine(`opacity ${d.opacity}`, level + 2);
|
|
990
|
+
if (d.metadata !== void 0) dsl += this.writeLine(`metadata ${d.metadata}`, level + 2);
|
|
991
|
+
if (d.description !== void 0) dsl += this.writeLine(`description ${d.description}`, level + 2);
|
|
992
|
+
dsl += this.writeLine("}", level + 1);
|
|
993
|
+
}
|
|
994
|
+
for (const { tag, definition: d } of relationshipStyles) {
|
|
995
|
+
dsl += this.writeLine(`relationship "${tag}" {`, level + 1);
|
|
996
|
+
if (d.thickness) dsl += this.writeLine(`thickness ${d.thickness}`, level + 2);
|
|
997
|
+
if (d.color) dsl += this.writeLine(`color "${d.color}"`, level + 2);
|
|
998
|
+
if (d.style) dsl += this.writeLine(`style ${d.style}`, level + 2);
|
|
999
|
+
if (d.routing) dsl += this.writeLine(`routing ${d.routing}`, level + 2);
|
|
1000
|
+
if (d.fontSize) dsl += this.writeLine(`fontSize ${d.fontSize}`, level + 2);
|
|
1001
|
+
if (d.width) dsl += this.writeLine(`width ${d.width}`, level + 2);
|
|
1002
|
+
if (d.position !== void 0) dsl += this.writeLine(`position ${d.position}`, level + 2);
|
|
1003
|
+
if (d.opacity !== void 0) dsl += this.writeLine(`opacity ${d.opacity}`, level + 2);
|
|
1004
|
+
dsl += this.writeLine("}", level + 1);
|
|
1005
|
+
}
|
|
1006
|
+
dsl += this.writeLine("}", level);
|
|
1007
|
+
return dsl;
|
|
1008
|
+
}
|
|
772
1009
|
writeViews(views, level) {
|
|
773
1010
|
let viewDsl = "";
|
|
774
1011
|
viewDsl += this.writeLine(`views {`, level);
|
|
@@ -788,6 +1025,19 @@ var StructurizrDSLWriter = class {
|
|
|
788
1025
|
views.componentViews.forEach((view) => {
|
|
789
1026
|
viewDsl += this.writeView(view, "component", level + 1);
|
|
790
1027
|
});
|
|
1028
|
+
viewDsl += this.writeStyles(views, level + 1);
|
|
1029
|
+
if (views.themes.length === 1) {
|
|
1030
|
+
viewDsl += this.writeLine(`theme ${views.themes[0]}`, level + 1);
|
|
1031
|
+
} else if (views.themes.length > 1) {
|
|
1032
|
+
viewDsl += this.writeLine(`themes ${views.themes.join(" ")}`, level + 1);
|
|
1033
|
+
}
|
|
1034
|
+
if (views.properties.size > 0) {
|
|
1035
|
+
viewDsl += this.writeLine("properties {", level + 1);
|
|
1036
|
+
for (const [name, value] of views.properties) {
|
|
1037
|
+
viewDsl += this.writeLine(`"${name}" "${value}"`, level + 2);
|
|
1038
|
+
}
|
|
1039
|
+
viewDsl += this.writeLine("}", level + 1);
|
|
1040
|
+
}
|
|
791
1041
|
viewDsl += this.writeLine(`}`, level);
|
|
792
1042
|
return viewDsl;
|
|
793
1043
|
}
|
|
@@ -812,8 +1062,8 @@ import { glob } from "glob";
|
|
|
812
1062
|
import { join, dirname } from "path";
|
|
813
1063
|
import { fileURLToPath } from "url";
|
|
814
1064
|
var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
815
|
-
async function
|
|
816
|
-
const { modelName = "model", modules: explicitModules, archetypes = {} } = options;
|
|
1065
|
+
async function buildModel(options = {}) {
|
|
1066
|
+
const { modelName = "model", modules: explicitModules, archetypes = {}, addViews } = options;
|
|
817
1067
|
const model = new Model(modelName);
|
|
818
1068
|
let c4Modules;
|
|
819
1069
|
if (explicitModules) {
|
|
@@ -837,14 +1087,16 @@ async function buildModelWithCatalog(options = {}) {
|
|
|
837
1087
|
rootCatalog[instance.key] = local;
|
|
838
1088
|
registrations.push({ instance, key: instance.key, local });
|
|
839
1089
|
}
|
|
1090
|
+
const dependenciesFor = (key) => Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
|
|
840
1091
|
for (const { instance, key, local } of registrations) {
|
|
841
|
-
|
|
842
|
-
instance.buildRelationships(local, dependencies, archetypes);
|
|
1092
|
+
instance.addRelationships(local, dependenciesFor(key), archetypes);
|
|
843
1093
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1094
|
+
const views = new Views();
|
|
1095
|
+
addViews?.(views, rootCatalog);
|
|
1096
|
+
for (const { instance, key, local } of registrations) {
|
|
1097
|
+
instance.addViews?.(views, local, dependenciesFor(key));
|
|
1098
|
+
}
|
|
1099
|
+
return { model, catalog: rootCatalog, views };
|
|
848
1100
|
}
|
|
849
1101
|
|
|
850
1102
|
// libs/c4-model/src/generateDiagrams.ts
|
|
@@ -853,9 +1105,8 @@ import * as os from "os";
|
|
|
853
1105
|
import * as path from "path";
|
|
854
1106
|
import { GenericContainer, Wait } from "testcontainers";
|
|
855
1107
|
async function generateDiagrams(options) {
|
|
856
|
-
const {
|
|
857
|
-
const { model,
|
|
858
|
-
const views = viewsFactory(catalog);
|
|
1108
|
+
const { outputDir, ...buildOptions } = options;
|
|
1109
|
+
const { model, views } = await buildModel(buildOptions);
|
|
859
1110
|
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
860
1111
|
const tmpDir = await fs.promises.mkdtemp(path.join(fs.realpathSync(os.tmpdir()), "c4-diagrams-"));
|
|
861
1112
|
await fs.promises.writeFile(path.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
@@ -876,6 +1127,60 @@ async function generateDiagrams(options) {
|
|
|
876
1127
|
}
|
|
877
1128
|
return generatedFiles;
|
|
878
1129
|
}
|
|
1130
|
+
|
|
1131
|
+
// libs/c4-model/src/validateModel.ts
|
|
1132
|
+
import * as fs2 from "fs";
|
|
1133
|
+
import * as os2 from "os";
|
|
1134
|
+
import * as path2 from "path";
|
|
1135
|
+
import { GenericContainer as GenericContainer2, Wait as Wait2 } from "testcontainers";
|
|
1136
|
+
async function validateModel(model, views) {
|
|
1137
|
+
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
1138
|
+
const tmpDir = await fs2.promises.mkdtemp(path2.join(fs2.realpathSync(os2.tmpdir()), "c4-validate-"));
|
|
1139
|
+
try {
|
|
1140
|
+
await fs2.promises.writeFile(path2.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
1141
|
+
const logs = [];
|
|
1142
|
+
try {
|
|
1143
|
+
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();
|
|
1144
|
+
} catch {
|
|
1145
|
+
throw new Error(`Structurizr validation failed:
|
|
1146
|
+
${logs.join("")}`);
|
|
1147
|
+
}
|
|
1148
|
+
} finally {
|
|
1149
|
+
await fs2.promises.rm(tmpDir, { recursive: true, force: true });
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// libs/c4-model/src/exportWorkspaceJson.ts
|
|
1154
|
+
import * as fs3 from "fs";
|
|
1155
|
+
import * as os3 from "os";
|
|
1156
|
+
import * as path3 from "path";
|
|
1157
|
+
import { GenericContainer as GenericContainer3, Wait as Wait3 } from "testcontainers";
|
|
1158
|
+
async function exportWorkspaceJsonFromDsl(dsl) {
|
|
1159
|
+
const tmpDir = await fs3.promises.mkdtemp(path3.join(fs3.realpathSync(os3.tmpdir()), "c4-export-"));
|
|
1160
|
+
try {
|
|
1161
|
+
await fs3.promises.writeFile(path3.join(tmpDir, "workspace.dsl"), dsl, "utf8");
|
|
1162
|
+
const logs = [];
|
|
1163
|
+
try {
|
|
1164
|
+
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();
|
|
1165
|
+
} catch {
|
|
1166
|
+
throw new Error(`Structurizr JSON export failed:
|
|
1167
|
+
${logs.join("")}`);
|
|
1168
|
+
}
|
|
1169
|
+
const files = await fs3.promises.readdir(tmpDir);
|
|
1170
|
+
const jsonFile = files.find((f) => f.endsWith(".json"));
|
|
1171
|
+
if (!jsonFile) {
|
|
1172
|
+
throw new Error(`Structurizr JSON export produced no .json file. Files: ${files.join(", ")}`);
|
|
1173
|
+
}
|
|
1174
|
+
const jsonContent = await fs3.promises.readFile(path3.join(tmpDir, jsonFile), "utf8");
|
|
1175
|
+
return JSON.parse(jsonContent);
|
|
1176
|
+
} finally {
|
|
1177
|
+
await fs3.promises.rm(tmpDir, { recursive: true, force: true });
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
async function exportWorkspaceJson(model, views) {
|
|
1181
|
+
const dsl = new StructurizrDSLWriter(model, views).write();
|
|
1182
|
+
return exportWorkspaceJsonFromDsl(dsl);
|
|
1183
|
+
}
|
|
879
1184
|
export {
|
|
880
1185
|
Component,
|
|
881
1186
|
Container,
|
|
@@ -891,7 +1196,9 @@ export {
|
|
|
891
1196
|
View,
|
|
892
1197
|
Views,
|
|
893
1198
|
buildModel,
|
|
894
|
-
|
|
1199
|
+
exportWorkspaceJson,
|
|
1200
|
+
exportWorkspaceJsonFromDsl,
|
|
895
1201
|
generateDiagrams,
|
|
896
|
-
mergeArchetypeWithOverride
|
|
1202
|
+
mergeArchetypeWithOverride,
|
|
1203
|
+
validateModel
|
|
897
1204
|
};
|