@agilewallaby/c4-model 2.1.0 → 2.3.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 +6 -5
- package/src/archetype.d.ts +30 -0
- package/src/buildModel.d.ts +20 -0
- package/src/component.d.ts +2 -1
- package/src/container.d.ts +5 -4
- package/src/core.d.ts +9 -4
- package/src/generateDiagrams.d.ts +1 -1
- package/src/index.cjs +952 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +396 -85
- package/src/model.d.ts +9 -18
- package/src/person.d.ts +3 -2
- package/src/softwareSystem.d.ts +6 -5
- package/src/structurizrDslWriter.d.ts +3 -0
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './archetype';
|
|
1
2
|
export * from './model';
|
|
2
3
|
export * from './person';
|
|
3
4
|
export * from './softwareSystem';
|
|
@@ -5,4 +6,5 @@ export * from './container';
|
|
|
5
6
|
export * from './component';
|
|
6
7
|
export * from './views';
|
|
7
8
|
export * from './structurizrDslWriter';
|
|
9
|
+
export * from './buildModel';
|
|
8
10
|
export * from './generateDiagrams';
|
package/src/index.js
CHANGED
|
@@ -1,24 +1,162 @@
|
|
|
1
|
-
// libs/c4-model/src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
// node_modules/.pnpm/change-case@5.4.4/node_modules/change-case/dist/index.js
|
|
48
|
+
var SPLIT_LOWER_UPPER_RE = /([\p{Ll}\d])(\p{Lu})/gu;
|
|
49
|
+
var SPLIT_UPPER_UPPER_RE = /(\p{Lu})([\p{Lu}][\p{Ll}])/gu;
|
|
50
|
+
var SPLIT_SEPARATE_NUMBER_RE = /(\d)\p{Ll}|(\p{L})\d/u;
|
|
51
|
+
var DEFAULT_STRIP_REGEXP = /[^\p{L}\d]+/giu;
|
|
52
|
+
var SPLIT_REPLACE_VALUE = "$1\0$2";
|
|
53
|
+
var DEFAULT_PREFIX_SUFFIX_CHARACTERS = "";
|
|
54
|
+
function split(value) {
|
|
55
|
+
let result = value.trim();
|
|
56
|
+
result = result.replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE).replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE);
|
|
57
|
+
result = result.replace(DEFAULT_STRIP_REGEXP, "\0");
|
|
58
|
+
let start = 0;
|
|
59
|
+
let end = result.length;
|
|
60
|
+
while (result.charAt(start) === "\0")
|
|
61
|
+
start++;
|
|
62
|
+
if (start === end)
|
|
63
|
+
return [];
|
|
64
|
+
while (result.charAt(end - 1) === "\0")
|
|
65
|
+
end--;
|
|
66
|
+
return result.slice(start, end).split(/\0/g);
|
|
67
|
+
}
|
|
68
|
+
function splitSeparateNumbers(value) {
|
|
69
|
+
const words = split(value);
|
|
70
|
+
for (let i = 0; i < words.length; i++) {
|
|
71
|
+
const word = words[i];
|
|
72
|
+
const match = SPLIT_SEPARATE_NUMBER_RE.exec(word);
|
|
73
|
+
if (match) {
|
|
74
|
+
const offset = match.index + (match[1] ?? match[2]).length;
|
|
75
|
+
words.splice(i, 1, word.slice(0, offset), word.slice(offset));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return words;
|
|
79
|
+
}
|
|
80
|
+
function camelCase(input, options) {
|
|
81
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
82
|
+
const lower = lowerFactory(options?.locale);
|
|
83
|
+
const upper = upperFactory(options?.locale);
|
|
84
|
+
const transform = options?.mergeAmbiguousCharacters ? capitalCaseTransformFactory(lower, upper) : pascalCaseTransformFactory(lower, upper);
|
|
85
|
+
return prefix + words.map((word, index) => {
|
|
86
|
+
if (index === 0)
|
|
87
|
+
return lower(word);
|
|
88
|
+
return transform(word, index);
|
|
89
|
+
}).join(options?.delimiter ?? "") + suffix;
|
|
90
|
+
}
|
|
91
|
+
function lowerFactory(locale) {
|
|
92
|
+
return locale === false ? (input) => input.toLowerCase() : (input) => input.toLocaleLowerCase(locale);
|
|
93
|
+
}
|
|
94
|
+
function upperFactory(locale) {
|
|
95
|
+
return locale === false ? (input) => input.toUpperCase() : (input) => input.toLocaleUpperCase(locale);
|
|
96
|
+
}
|
|
97
|
+
function capitalCaseTransformFactory(lower, upper) {
|
|
98
|
+
return (word) => `${upper(word[0])}${lower(word.slice(1))}`;
|
|
99
|
+
}
|
|
100
|
+
function pascalCaseTransformFactory(lower, upper) {
|
|
101
|
+
return (word, index) => {
|
|
102
|
+
const char0 = word[0];
|
|
103
|
+
const initial = index > 0 && char0 >= "0" && char0 <= "9" ? "_" + char0 : upper(char0);
|
|
104
|
+
return initial + lower(word.slice(1));
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function splitPrefixSuffix(input, options = {}) {
|
|
108
|
+
const splitFn = options.split ?? (options.separateNumbers ? splitSeparateNumbers : split);
|
|
109
|
+
const prefixCharacters = options.prefixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
|
|
110
|
+
const suffixCharacters = options.suffixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
|
|
111
|
+
let prefixIndex = 0;
|
|
112
|
+
let suffixIndex = input.length;
|
|
113
|
+
while (prefixIndex < input.length) {
|
|
114
|
+
const char = input.charAt(prefixIndex);
|
|
115
|
+
if (!prefixCharacters.includes(char))
|
|
116
|
+
break;
|
|
117
|
+
prefixIndex++;
|
|
118
|
+
}
|
|
119
|
+
while (suffixIndex > prefixIndex) {
|
|
120
|
+
const index = suffixIndex - 1;
|
|
121
|
+
const char = input.charAt(index);
|
|
122
|
+
if (!suffixCharacters.includes(char))
|
|
123
|
+
break;
|
|
124
|
+
suffixIndex = index;
|
|
125
|
+
}
|
|
126
|
+
return [
|
|
127
|
+
input.slice(0, prefixIndex),
|
|
128
|
+
splitFn(input.slice(prefixIndex, suffixIndex)),
|
|
129
|
+
input.slice(suffixIndex)
|
|
130
|
+
];
|
|
131
|
+
}
|
|
5
132
|
|
|
6
133
|
// libs/c4-model/src/core.ts
|
|
7
|
-
import { camelCase } from "change-case";
|
|
8
134
|
var Element = class {
|
|
9
|
-
constructor(name, defaultTags = [], definition) {
|
|
135
|
+
constructor(name, defaultTags = [], definition, archetype, overrideDefinition) {
|
|
10
136
|
this.name = name;
|
|
11
137
|
this.description = definition?.description;
|
|
12
138
|
this.tags = (definition?.tags ?? []).concat(["Element"]).concat(defaultTags);
|
|
139
|
+
this.archetype = archetype;
|
|
140
|
+
this.overrideDefinition = overrideDefinition;
|
|
13
141
|
}
|
|
14
142
|
description;
|
|
15
143
|
tags;
|
|
144
|
+
archetype;
|
|
145
|
+
overrideDefinition;
|
|
16
146
|
_relationships = [];
|
|
17
147
|
get canonicalName() {
|
|
18
148
|
return camelCase(this.name);
|
|
19
149
|
}
|
|
20
|
-
uses(otherElement,
|
|
21
|
-
|
|
150
|
+
uses(otherElement, archetypeOrDef, override) {
|
|
151
|
+
let definition;
|
|
152
|
+
let archetype;
|
|
153
|
+
if (archetypeOrDef instanceof RelationshipArchetype) {
|
|
154
|
+
archetype = archetypeOrDef;
|
|
155
|
+
definition = mergeArchetypeWithOverride(archetypeOrDef, override);
|
|
156
|
+
} else {
|
|
157
|
+
definition = archetypeOrDef;
|
|
158
|
+
}
|
|
159
|
+
const relationship = new Relationship(this, otherElement, definition, archetype, override);
|
|
22
160
|
this._relationships.push(relationship);
|
|
23
161
|
}
|
|
24
162
|
get relationships() {
|
|
@@ -37,22 +175,26 @@ var Element = class {
|
|
|
37
175
|
};
|
|
38
176
|
var TechnicalElement = class extends Element {
|
|
39
177
|
technology;
|
|
40
|
-
constructor(name, defaultTags = [], definition) {
|
|
41
|
-
super(name, defaultTags, definition);
|
|
178
|
+
constructor(name, defaultTags = [], definition, archetype, overrideDefinition) {
|
|
179
|
+
super(name, defaultTags, definition, archetype, overrideDefinition);
|
|
42
180
|
this.technology = definition?.technology;
|
|
43
181
|
}
|
|
44
182
|
};
|
|
45
183
|
var Relationship = class {
|
|
46
|
-
constructor(source, destination, definition) {
|
|
184
|
+
constructor(source, destination, definition, archetype, overrideDefinition) {
|
|
47
185
|
this.source = source;
|
|
48
186
|
this.destination = destination;
|
|
49
187
|
this.description = definition?.description;
|
|
50
188
|
this.technology = definition?.technology;
|
|
51
189
|
this.tags = (definition?.tags ?? []).concat(["Relationship"]);
|
|
190
|
+
this.archetype = archetype;
|
|
191
|
+
this.overrideDefinition = overrideDefinition;
|
|
52
192
|
}
|
|
53
193
|
description;
|
|
54
194
|
tags;
|
|
55
195
|
technology;
|
|
196
|
+
archetype;
|
|
197
|
+
overrideDefinition;
|
|
56
198
|
};
|
|
57
199
|
var Group = class {
|
|
58
200
|
constructor(name) {
|
|
@@ -64,8 +206,8 @@ var Group = class {
|
|
|
64
206
|
|
|
65
207
|
// libs/c4-model/src/component.ts
|
|
66
208
|
var Component = class extends TechnicalElement {
|
|
67
|
-
constructor(name, definition) {
|
|
68
|
-
super(name, ["Component"], definition);
|
|
209
|
+
constructor(name, definition, archetype, overrideDefinition) {
|
|
210
|
+
super(name, ["Component"], definition, archetype, overrideDefinition);
|
|
69
211
|
this.name = name;
|
|
70
212
|
}
|
|
71
213
|
getChildElements() {
|
|
@@ -81,8 +223,8 @@ var ContainerGroup = class extends Group {
|
|
|
81
223
|
this.container = container;
|
|
82
224
|
}
|
|
83
225
|
_components = /* @__PURE__ */ new Map();
|
|
84
|
-
defineComponent(name,
|
|
85
|
-
const component = this.container.defineComponent(name,
|
|
226
|
+
defineComponent(name, archetypeOrDef, override) {
|
|
227
|
+
const component = this.container.defineComponent(name, archetypeOrDef, override);
|
|
86
228
|
this._components.set(name, component);
|
|
87
229
|
return component;
|
|
88
230
|
}
|
|
@@ -91,17 +233,25 @@ var ContainerGroup = class extends Group {
|
|
|
91
233
|
}
|
|
92
234
|
};
|
|
93
235
|
var Container = class extends TechnicalElement {
|
|
94
|
-
constructor(name, definition) {
|
|
95
|
-
super(name, ["Container"], definition);
|
|
236
|
+
constructor(name, definition, archetype, overrideDefinition) {
|
|
237
|
+
super(name, ["Container"], definition, archetype, overrideDefinition);
|
|
96
238
|
this.name = name;
|
|
97
239
|
}
|
|
98
240
|
_components = /* @__PURE__ */ new Map();
|
|
99
241
|
_groups = /* @__PURE__ */ new Map();
|
|
100
|
-
defineComponent(name,
|
|
242
|
+
defineComponent(name, archetypeOrDef, override) {
|
|
101
243
|
if (this._components.has(name)) {
|
|
102
244
|
throw Error(`A Component named '${name}' is defined elsewhere in this Container. A Component can be defined only once.`);
|
|
103
245
|
}
|
|
104
|
-
|
|
246
|
+
let definition;
|
|
247
|
+
let archetype;
|
|
248
|
+
if (archetypeOrDef instanceof ElementArchetype) {
|
|
249
|
+
archetype = archetypeOrDef;
|
|
250
|
+
definition = mergeArchetypeWithOverride(archetypeOrDef, override);
|
|
251
|
+
} else {
|
|
252
|
+
definition = archetypeOrDef;
|
|
253
|
+
}
|
|
254
|
+
const component = new Component(name, definition, archetype, override);
|
|
105
255
|
this._components.set(name, component);
|
|
106
256
|
return component;
|
|
107
257
|
}
|
|
@@ -133,8 +283,8 @@ var SoftwareSystemGroup = class extends Group {
|
|
|
133
283
|
this.softwareSystem = softwareSystem;
|
|
134
284
|
}
|
|
135
285
|
_containers = /* @__PURE__ */ new Map();
|
|
136
|
-
defineContainer(name,
|
|
137
|
-
const container = this.softwareSystem.defineContainer(name,
|
|
286
|
+
defineContainer(name, archetypeOrDef, override) {
|
|
287
|
+
const container = this.softwareSystem.defineContainer(name, archetypeOrDef, override);
|
|
138
288
|
this._containers.set(name, container);
|
|
139
289
|
return container;
|
|
140
290
|
}
|
|
@@ -143,17 +293,25 @@ var SoftwareSystemGroup = class extends Group {
|
|
|
143
293
|
}
|
|
144
294
|
};
|
|
145
295
|
var SoftwareSystem = class extends Element {
|
|
146
|
-
constructor(name, definition) {
|
|
147
|
-
super(name, ["Software System"], definition);
|
|
296
|
+
constructor(name, definition, archetype, overrideDefinition) {
|
|
297
|
+
super(name, ["Software System"], definition, archetype, overrideDefinition);
|
|
148
298
|
this.name = name;
|
|
149
299
|
}
|
|
150
300
|
_containers = /* @__PURE__ */ new Map();
|
|
151
301
|
_groups = /* @__PURE__ */ new Map();
|
|
152
|
-
defineContainer(name,
|
|
302
|
+
defineContainer(name, archetypeOrDef, override) {
|
|
153
303
|
if (this._containers.has(name)) {
|
|
154
304
|
throw Error(`A Container named '${name}' is defined elsewhere in this SoftwareSystem. A Container can be defined only once.`);
|
|
155
305
|
}
|
|
156
|
-
|
|
306
|
+
let definition;
|
|
307
|
+
let archetype;
|
|
308
|
+
if (archetypeOrDef instanceof ElementArchetype) {
|
|
309
|
+
archetype = archetypeOrDef;
|
|
310
|
+
definition = mergeArchetypeWithOverride(archetypeOrDef, override);
|
|
311
|
+
} else {
|
|
312
|
+
definition = archetypeOrDef;
|
|
313
|
+
}
|
|
314
|
+
const container = new Container(name, definition, archetype, override);
|
|
157
315
|
this._containers.set(name, container);
|
|
158
316
|
return container;
|
|
159
317
|
}
|
|
@@ -179,8 +337,8 @@ var SoftwareSystem = class extends Element {
|
|
|
179
337
|
|
|
180
338
|
// libs/c4-model/src/person.ts
|
|
181
339
|
var Person = class extends Element {
|
|
182
|
-
constructor(name, definition) {
|
|
183
|
-
super(name, ["Person"], definition);
|
|
340
|
+
constructor(name, definition, archetype, overrideDefinition) {
|
|
341
|
+
super(name, ["Person"], definition, archetype, overrideDefinition);
|
|
184
342
|
this.name = name;
|
|
185
343
|
}
|
|
186
344
|
getChildElements() {
|
|
@@ -189,7 +347,6 @@ var Person = class extends Element {
|
|
|
189
347
|
};
|
|
190
348
|
|
|
191
349
|
// libs/c4-model/src/model.ts
|
|
192
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
193
350
|
var ModelGroup = class extends Group {
|
|
194
351
|
constructor(name, model) {
|
|
195
352
|
super(name);
|
|
@@ -198,13 +355,13 @@ var ModelGroup = class extends Group {
|
|
|
198
355
|
}
|
|
199
356
|
softwareSystems = /* @__PURE__ */ new Map();
|
|
200
357
|
people = /* @__PURE__ */ new Map();
|
|
201
|
-
defineSoftwareSystem(name,
|
|
202
|
-
const softwareSystem = this.model.defineSoftwareSystem(name,
|
|
358
|
+
defineSoftwareSystem(name, archetypeOrDef, override) {
|
|
359
|
+
const softwareSystem = this.model.defineSoftwareSystem(name, archetypeOrDef, override);
|
|
203
360
|
this.softwareSystems.set(name, softwareSystem);
|
|
204
361
|
return softwareSystem;
|
|
205
362
|
}
|
|
206
|
-
definePerson(name,
|
|
207
|
-
const person = this.model.definePerson(name,
|
|
363
|
+
definePerson(name, archetypeOrDef, override) {
|
|
364
|
+
const person = this.model.definePerson(name, archetypeOrDef, override);
|
|
208
365
|
this.people.set(name, person);
|
|
209
366
|
return person;
|
|
210
367
|
}
|
|
@@ -222,11 +379,19 @@ var Model = class {
|
|
|
222
379
|
softwareSystems = /* @__PURE__ */ new Map();
|
|
223
380
|
people = /* @__PURE__ */ new Map();
|
|
224
381
|
groups = /* @__PURE__ */ new Map();
|
|
225
|
-
defineSoftwareSystem(name,
|
|
382
|
+
defineSoftwareSystem(name, archetypeOrDef, override) {
|
|
226
383
|
if (this.softwareSystems.has(name)) {
|
|
227
384
|
throw Error(`A SoftwareSystem named '${name}' is defined elsewhere in this Model. A SoftwareSystem can be defined only once.`);
|
|
228
385
|
}
|
|
229
|
-
|
|
386
|
+
let definition;
|
|
387
|
+
let archetype;
|
|
388
|
+
if (archetypeOrDef instanceof ElementArchetype) {
|
|
389
|
+
archetype = archetypeOrDef;
|
|
390
|
+
definition = mergeArchetypeWithOverride(archetypeOrDef, override);
|
|
391
|
+
} else {
|
|
392
|
+
definition = archetypeOrDef;
|
|
393
|
+
}
|
|
394
|
+
const system = new SoftwareSystem(name, definition, archetype, override);
|
|
230
395
|
this.softwareSystems.set(name, system);
|
|
231
396
|
return system;
|
|
232
397
|
}
|
|
@@ -239,11 +404,19 @@ var Model = class {
|
|
|
239
404
|
}
|
|
240
405
|
return group;
|
|
241
406
|
}
|
|
242
|
-
definePerson(name,
|
|
407
|
+
definePerson(name, archetypeOrDef, override) {
|
|
243
408
|
if (this.people.has(name)) {
|
|
244
409
|
throw Error(`A Person named '${name}' is defined elsewhere in this Model. A Person can be defined only once.`);
|
|
245
410
|
}
|
|
246
|
-
|
|
411
|
+
let definition;
|
|
412
|
+
let archetype;
|
|
413
|
+
if (archetypeOrDef instanceof ElementArchetype) {
|
|
414
|
+
archetype = archetypeOrDef;
|
|
415
|
+
definition = mergeArchetypeWithOverride(archetypeOrDef, override);
|
|
416
|
+
} else {
|
|
417
|
+
definition = archetypeOrDef;
|
|
418
|
+
}
|
|
419
|
+
const person = new Person(name, definition, archetype, override);
|
|
247
420
|
this.people.set(name, person);
|
|
248
421
|
return person;
|
|
249
422
|
}
|
|
@@ -267,37 +440,6 @@ var Model = class {
|
|
|
267
440
|
return Array.from(this.groups.values());
|
|
268
441
|
}
|
|
269
442
|
};
|
|
270
|
-
async function buildModelWithCatalog(options = {}) {
|
|
271
|
-
const { modelName = "model", globPath = "c4.dsl.ts", searchRoot = __dirname } = options;
|
|
272
|
-
const model = new Model(modelName);
|
|
273
|
-
const result = await glob(`**/${globPath}`, { cwd: searchRoot });
|
|
274
|
-
if (result.length === 0) {
|
|
275
|
-
throw new Error(`No ${globPath} files found`);
|
|
276
|
-
}
|
|
277
|
-
const modules = await Promise.all(result.map((file) => import(join(searchRoot, file))));
|
|
278
|
-
const registrations = [];
|
|
279
|
-
const rootCatalog = {};
|
|
280
|
-
for (const module of modules) {
|
|
281
|
-
if (!module.c4Module) {
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const instance = module.c4Module;
|
|
285
|
-
const local = instance.registerDefinitions(model);
|
|
286
|
-
rootCatalog[instance.key] = local;
|
|
287
|
-
registrations.push({ instance, key: instance.key, local });
|
|
288
|
-
}
|
|
289
|
-
if (registrations.length === 0) {
|
|
290
|
-
throw new Error(`No c4Module exports found in any ${globPath} files`);
|
|
291
|
-
}
|
|
292
|
-
for (const { instance, key, local } of registrations) {
|
|
293
|
-
const dependencies = Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
|
|
294
|
-
instance.buildRelationships(local, dependencies);
|
|
295
|
-
}
|
|
296
|
-
return { model, catalog: rootCatalog };
|
|
297
|
-
}
|
|
298
|
-
async function buildModel(options = {}) {
|
|
299
|
-
return (await buildModelWithCatalog(options)).model;
|
|
300
|
-
}
|
|
301
443
|
|
|
302
444
|
// libs/c4-model/src/views.ts
|
|
303
445
|
var View = class {
|
|
@@ -379,13 +521,115 @@ var StructurizrDSLWriter = class {
|
|
|
379
521
|
this.model = model;
|
|
380
522
|
this.views = views;
|
|
381
523
|
}
|
|
524
|
+
collectArchetypes() {
|
|
525
|
+
const elementSet = /* @__PURE__ */ new Set();
|
|
526
|
+
const relationshipSet = /* @__PURE__ */ new Set();
|
|
527
|
+
const collectFromElement = (element) => {
|
|
528
|
+
if (element.archetype) {
|
|
529
|
+
let arch = element.archetype;
|
|
530
|
+
while (arch) {
|
|
531
|
+
elementSet.add(arch);
|
|
532
|
+
arch = arch.parent;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
element.relationships.forEach((rel) => {
|
|
536
|
+
if (rel.archetype) {
|
|
537
|
+
let arch = rel.archetype;
|
|
538
|
+
while (arch) {
|
|
539
|
+
relationshipSet.add(arch);
|
|
540
|
+
arch = arch.parent;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
element.getChildElements().forEach(collectFromElement);
|
|
545
|
+
};
|
|
546
|
+
const allElements = [...this.model.getPeople(), ...this.model.getSoftwareSystems()];
|
|
547
|
+
allElements.forEach(collectFromElement);
|
|
548
|
+
const sortArchetypes = (set) => {
|
|
549
|
+
const sorted = [];
|
|
550
|
+
const visited = /* @__PURE__ */ new Set();
|
|
551
|
+
const visit = (arch) => {
|
|
552
|
+
if (visited.has(arch)) return;
|
|
553
|
+
if (arch.parent && set.has(arch.parent)) visit(arch.parent);
|
|
554
|
+
visited.add(arch);
|
|
555
|
+
sorted.push(arch);
|
|
556
|
+
};
|
|
557
|
+
set.forEach(visit);
|
|
558
|
+
return sorted;
|
|
559
|
+
};
|
|
560
|
+
return {
|
|
561
|
+
elementArchetypes: sortArchetypes(elementSet),
|
|
562
|
+
relationshipArchetypes: sortArchetypes(relationshipSet)
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
writeArchetypes(level) {
|
|
566
|
+
const { elementArchetypes, relationshipArchetypes } = this.collectArchetypes();
|
|
567
|
+
if (elementArchetypes.length === 0 && relationshipArchetypes.length === 0) return "";
|
|
568
|
+
let dsl = this.writeLine(`archetypes {`, level);
|
|
569
|
+
for (const arch of elementArchetypes) {
|
|
570
|
+
const baseType = arch.parent ? arch.parent.name : arch.elementKind;
|
|
571
|
+
let inner = "";
|
|
572
|
+
if (arch.ownDescription) {
|
|
573
|
+
inner += this.writeLine(`description "${arch.ownDescription}"`, level + 2);
|
|
574
|
+
}
|
|
575
|
+
if (arch.ownTechnology) {
|
|
576
|
+
inner += this.writeLine(`technology "${arch.ownTechnology}"`, level + 2);
|
|
577
|
+
}
|
|
578
|
+
if (arch.ownTags.length > 0) {
|
|
579
|
+
inner += this.writeLine(`tags ${arch.ownTags.map((t) => `"${t}"`).join(" ")}`, level + 2);
|
|
580
|
+
}
|
|
581
|
+
if (inner) {
|
|
582
|
+
dsl += this.writeLine(`${arch.name} = ${baseType} {`, level + 1);
|
|
583
|
+
dsl += inner;
|
|
584
|
+
dsl += this.writeLine(`}`, level + 1);
|
|
585
|
+
} else {
|
|
586
|
+
dsl += this.writeLine(`${arch.name} = ${baseType} {}`, level + 1);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
for (const arch of relationshipArchetypes) {
|
|
590
|
+
const arrow = arch.parent ? `--${arch.parent.name}->` : `->`;
|
|
591
|
+
let inner = "";
|
|
592
|
+
if (arch.ownDescription) {
|
|
593
|
+
inner += this.writeLine(`description "${arch.ownDescription}"`, level + 2);
|
|
594
|
+
}
|
|
595
|
+
if (arch.ownTechnology) {
|
|
596
|
+
inner += this.writeLine(`technology "${arch.ownTechnology}"`, level + 2);
|
|
597
|
+
}
|
|
598
|
+
if (arch.ownTags.length > 0) {
|
|
599
|
+
inner += this.writeLine(`tags ${arch.ownTags.map((t) => `"${t}"`).join(" ")}`, level + 2);
|
|
600
|
+
}
|
|
601
|
+
if (inner) {
|
|
602
|
+
dsl += this.writeLine(`${arch.name} = ${arrow} {`, level + 1);
|
|
603
|
+
dsl += inner;
|
|
604
|
+
dsl += this.writeLine(`}`, level + 1);
|
|
605
|
+
} else {
|
|
606
|
+
dsl += this.writeLine(`${arch.name} = ${arrow} {}`, level + 1);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
dsl += this.writeLine(`}`, level);
|
|
610
|
+
return dsl;
|
|
611
|
+
}
|
|
382
612
|
writeElement(elementType, element, level, closeElement = true) {
|
|
383
613
|
let elementDsl = "";
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
614
|
+
const type = element.archetype ? element.archetype.name : elementType;
|
|
615
|
+
elementDsl += this.writeLine(`${element.canonicalName} = ${type} "${element.name}" {`, level);
|
|
616
|
+
if (element.archetype) {
|
|
617
|
+
const ovr = element.overrideDefinition;
|
|
618
|
+
if (ovr?.description) {
|
|
619
|
+
elementDsl += this.writeLine(`description "${ovr.description}"`, level + 1);
|
|
620
|
+
}
|
|
621
|
+
if (ovr?.tags && ovr.tags.length > 0) {
|
|
622
|
+
elementDsl += this.writeLine(`tags ${ovr.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
623
|
+
}
|
|
624
|
+
if (ovr && "technology" in ovr && ovr.technology) {
|
|
625
|
+
elementDsl += this.writeLine(`technology "${ovr.technology}"`, level + 1);
|
|
626
|
+
}
|
|
627
|
+
} else {
|
|
628
|
+
if (element.description) {
|
|
629
|
+
elementDsl += this.writeLine(`description "${element.description}"`, level + 1);
|
|
630
|
+
}
|
|
631
|
+
elementDsl += this.writeLine(`tags ${element.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
387
632
|
}
|
|
388
|
-
elementDsl += this.writeLine(`tags ${element.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
389
633
|
if (closeElement) {
|
|
390
634
|
elementDsl += this.writeLine(`}`, level);
|
|
391
635
|
}
|
|
@@ -394,7 +638,9 @@ var StructurizrDSLWriter = class {
|
|
|
394
638
|
writeComponent(component, level) {
|
|
395
639
|
let componentDsl = "";
|
|
396
640
|
componentDsl += this.writeElement("component", component, level, false);
|
|
397
|
-
|
|
641
|
+
if (!component.archetype && component.technology) {
|
|
642
|
+
componentDsl += this.writeLine(`technology "${component.technology}"`, level + 1);
|
|
643
|
+
}
|
|
398
644
|
componentDsl += this.writeLine(`}`, level);
|
|
399
645
|
return componentDsl;
|
|
400
646
|
}
|
|
@@ -410,7 +656,9 @@ var StructurizrDSLWriter = class {
|
|
|
410
656
|
writeContainer(container, level) {
|
|
411
657
|
let containerDsl = "";
|
|
412
658
|
containerDsl += this.writeElement("container", container, level, false);
|
|
413
|
-
|
|
659
|
+
if (!container.archetype && container.technology) {
|
|
660
|
+
containerDsl += this.writeLine(`technology "${container.technology}"`, level + 1);
|
|
661
|
+
}
|
|
414
662
|
container.getComponentsNotInGroups().forEach((component) => {
|
|
415
663
|
containerDsl += this.writeComponent(component, level + 1);
|
|
416
664
|
});
|
|
@@ -441,17 +689,39 @@ var StructurizrDSLWriter = class {
|
|
|
441
689
|
softwareSystemDsl += this.writeLine(`}`, level);
|
|
442
690
|
return softwareSystemDsl;
|
|
443
691
|
}
|
|
692
|
+
writeRelationship(relationship, level) {
|
|
693
|
+
let dsl = "";
|
|
694
|
+
if (relationship.archetype) {
|
|
695
|
+
const arrow = `--${relationship.archetype.name}->`;
|
|
696
|
+
const ovr = relationship.overrideDefinition;
|
|
697
|
+
const desc = ovr?.description ?? relationship.description ?? "uses";
|
|
698
|
+
dsl += this.writeLine(
|
|
699
|
+
`${relationship.source.canonicalName} ${arrow} ${relationship.destination.canonicalName} "${desc}" {`,
|
|
700
|
+
level
|
|
701
|
+
);
|
|
702
|
+
if (ovr?.technology) {
|
|
703
|
+
dsl += this.writeLine(`technology "${ovr.technology}"`, level + 1);
|
|
704
|
+
}
|
|
705
|
+
if (ovr?.tags && ovr.tags.length > 0) {
|
|
706
|
+
dsl += this.writeLine(`tags ${ovr.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
707
|
+
}
|
|
708
|
+
dsl += this.writeLine(`}`, level);
|
|
709
|
+
} else {
|
|
710
|
+
const tech = relationship.technology ? ` "${relationship.technology}"` : "";
|
|
711
|
+
dsl += this.writeLine(
|
|
712
|
+
`${relationship.source.canonicalName} -> ${relationship.destination.canonicalName} "${relationship.description ?? "uses"}"${tech} {`,
|
|
713
|
+
level
|
|
714
|
+
);
|
|
715
|
+
dsl += this.writeLine(`tags ${relationship.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
716
|
+
dsl += this.writeLine(`}`, level);
|
|
717
|
+
}
|
|
718
|
+
return dsl;
|
|
719
|
+
}
|
|
444
720
|
writeRelationships(elements, level) {
|
|
445
721
|
let relationshipsDsl = "";
|
|
446
722
|
elements.forEach((element) => {
|
|
447
723
|
element.getRelationshipsInHierarchy().forEach((relationship) => {
|
|
448
|
-
|
|
449
|
-
relationshipsDsl += this.writeLine(
|
|
450
|
-
`${relationship.source.canonicalName} -> ${relationship.destination.canonicalName} "${relationship.description ?? "uses"}"${tech} {`,
|
|
451
|
-
level
|
|
452
|
-
);
|
|
453
|
-
relationshipsDsl += this.writeLine(`tags ${relationship.tags.map((tag) => `"${tag}"`).join(" ")}`, level + 1);
|
|
454
|
-
relationshipsDsl += this.writeLine(`}`, level);
|
|
724
|
+
relationshipsDsl += this.writeRelationship(relationship, level);
|
|
455
725
|
});
|
|
456
726
|
});
|
|
457
727
|
return relationshipsDsl;
|
|
@@ -471,6 +741,7 @@ var StructurizrDSLWriter = class {
|
|
|
471
741
|
writeModel(model, level) {
|
|
472
742
|
let modelDsl = "";
|
|
473
743
|
modelDsl += this.writeLine(`model {`, level);
|
|
744
|
+
modelDsl += this.writeArchetypes(level + 1);
|
|
474
745
|
modelDsl += this.writeLine("// Elements", level + 1);
|
|
475
746
|
model.getPeopleNotInGroups().forEach((person) => {
|
|
476
747
|
modelDsl += this.writeElement("person", person, level + 1);
|
|
@@ -487,10 +758,7 @@ var StructurizrDSLWriter = class {
|
|
|
487
758
|
return modelDsl;
|
|
488
759
|
}
|
|
489
760
|
writeView(view, viewType, level) {
|
|
490
|
-
let viewDsl = this.writeLine(
|
|
491
|
-
`${viewType}${view.subject ? ' "' + view.subject.canonicalName + '"' : ""} "${view.key}" {`,
|
|
492
|
-
level
|
|
493
|
-
);
|
|
761
|
+
let viewDsl = this.writeLine(`${viewType}${view.subject ? ' "' + view.subject.canonicalName + '"' : ""} "${view.key}" {`, level);
|
|
494
762
|
viewDsl += this.writeLine(`description "${view.description}"`, level + 1);
|
|
495
763
|
if (view.title) {
|
|
496
764
|
viewDsl += this.writeLine(`title "${view.title}"`, level + 1);
|
|
@@ -540,6 +808,46 @@ var StructurizrDSLWriter = class {
|
|
|
540
808
|
}
|
|
541
809
|
};
|
|
542
810
|
|
|
811
|
+
// libs/c4-model/src/buildModel.ts
|
|
812
|
+
import { glob } from "glob";
|
|
813
|
+
import { join, dirname } from "path";
|
|
814
|
+
import { fileURLToPath } from "url";
|
|
815
|
+
var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
816
|
+
async function buildModelWithCatalog(options = {}) {
|
|
817
|
+
const { modelName = "model", modules: explicitModules } = options;
|
|
818
|
+
const model = new Model(modelName);
|
|
819
|
+
let c4Modules;
|
|
820
|
+
if (explicitModules) {
|
|
821
|
+
c4Modules = [...explicitModules];
|
|
822
|
+
} else {
|
|
823
|
+
const { globPath = "c4.dsl.ts", searchRoot = _dirname } = options;
|
|
824
|
+
const result = await glob(`**/${globPath}`, { cwd: searchRoot });
|
|
825
|
+
if (result.length === 0) {
|
|
826
|
+
throw new Error(`No ${globPath} files found`);
|
|
827
|
+
}
|
|
828
|
+
const imported = await Promise.all(result.map((file) => import(join(searchRoot, file))));
|
|
829
|
+
c4Modules = imported.filter((m) => m.c4Module).map((m) => m.c4Module);
|
|
830
|
+
}
|
|
831
|
+
if (c4Modules.length === 0) {
|
|
832
|
+
throw new Error("No c4Module instances found");
|
|
833
|
+
}
|
|
834
|
+
const registrations = [];
|
|
835
|
+
const rootCatalog = {};
|
|
836
|
+
for (const instance of c4Modules) {
|
|
837
|
+
const local = instance.registerDefinitions(model);
|
|
838
|
+
rootCatalog[instance.key] = local;
|
|
839
|
+
registrations.push({ instance, key: instance.key, local });
|
|
840
|
+
}
|
|
841
|
+
for (const { instance, key, local } of registrations) {
|
|
842
|
+
const dependencies = Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
|
|
843
|
+
instance.buildRelationships(local, dependencies);
|
|
844
|
+
}
|
|
845
|
+
return { model, catalog: rootCatalog };
|
|
846
|
+
}
|
|
847
|
+
async function buildModel(options = {}) {
|
|
848
|
+
return (await buildModelWithCatalog(options)).model;
|
|
849
|
+
}
|
|
850
|
+
|
|
543
851
|
// libs/c4-model/src/generateDiagrams.ts
|
|
544
852
|
import * as fs from "fs";
|
|
545
853
|
import * as os from "os";
|
|
@@ -573,9 +881,11 @@ export {
|
|
|
573
881
|
Component,
|
|
574
882
|
Container,
|
|
575
883
|
ContainerGroup,
|
|
884
|
+
ElementArchetype,
|
|
576
885
|
Model,
|
|
577
886
|
ModelGroup,
|
|
578
887
|
Person,
|
|
888
|
+
RelationshipArchetype,
|
|
579
889
|
SoftwareSystem,
|
|
580
890
|
SoftwareSystemGroup,
|
|
581
891
|
StructurizrDSLWriter,
|
|
@@ -583,5 +893,6 @@ export {
|
|
|
583
893
|
Views,
|
|
584
894
|
buildModel,
|
|
585
895
|
buildModelWithCatalog,
|
|
586
|
-
generateDiagrams
|
|
896
|
+
generateDiagrams,
|
|
897
|
+
mergeArchetypeWithOverride
|
|
587
898
|
};
|