@agilewallaby/c4-model 2.5.0 → 2.7.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilewallaby/c4-model",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,16 +1,18 @@
1
1
  import { Model } from './model';
2
+ import { ElementArchetype, RelationshipArchetype } from './archetype';
2
3
  type Catalog = Record<string, unknown>;
3
4
  type RootCatalog = Record<string, Catalog>;
4
5
  export interface AnyC4Module {
5
6
  readonly key: string;
6
- registerDefinitions(model: Model): Catalog;
7
- buildRelationships(local: Catalog, dependencies: RootCatalog): void;
7
+ registerDefinitions(model: Model, archetypes: Record<string, ElementArchetype | RelationshipArchetype>): Catalog;
8
+ buildRelationships(local: Catalog, dependencies: RootCatalog, archetypes: Record<string, ElementArchetype | RelationshipArchetype>): void;
8
9
  }
9
10
  export interface BuildModelOptions {
10
11
  modelName?: string;
11
12
  modules?: ReadonlyArray<AnyC4Module>;
12
13
  globPath?: string;
13
14
  searchRoot?: string;
15
+ archetypes?: Record<string, ElementArchetype | RelationshipArchetype>;
14
16
  }
15
17
  export declare function buildModelWithCatalog<TRoot>(options?: BuildModelOptions): Promise<{
16
18
  model: Model;
@@ -3,23 +3,23 @@ import { Component, ComponentDefinition } from './component';
3
3
  import { ElementArchetype } from './archetype';
4
4
  export type ContainerDefinition = TechnologyDefinition;
5
5
  interface DefineComponent {
6
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
6
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
7
7
  }
8
- export declare class ContainerGroup extends Group implements DefineComponent {
8
+ export declare class ContainerGroup extends Group<Component> implements DefineComponent {
9
9
  readonly name: string;
10
10
  private readonly container;
11
11
  private _components;
12
12
  constructor(name: string, container: DefineComponent);
13
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
13
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
14
14
  getComponents(): ReadonlyArray<Component>;
15
15
  }
16
- export declare class Container extends TechnicalElement implements DefineComponent {
16
+ export declare class Container extends TechnicalElement<Component> implements DefineComponent {
17
17
  readonly name: string;
18
18
  private _components;
19
19
  private _groups;
20
20
  constructor(name: string, definition?: ContainerDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
21
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
22
- addGroup(groupName: string): ContainerGroup;
21
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
22
+ group(groupName: string): ContainerGroup;
23
23
  getGroups(): ReadonlyArray<ContainerGroup>;
24
24
  getComponentsNotInGroups(): ReadonlyArray<Component>;
25
25
  getChildElements(): ReadonlyArray<Element>;
package/src/core.d.ts CHANGED
@@ -6,7 +6,7 @@ export interface Definition {
6
6
  export interface TechnologyDefinition extends Definition {
7
7
  technology?: string;
8
8
  }
9
- export declare abstract class Element {
9
+ export declare abstract class Element<TChild extends Element = never> {
10
10
  readonly name: string;
11
11
  readonly description?: string;
12
12
  readonly tags: ReadonlyArray<string>;
@@ -17,11 +17,12 @@ export declare abstract class Element {
17
17
  get canonicalName(): string;
18
18
  uses(otherElement: Element, archetypeOrDef?: RelationshipArchetype | TechnologyDefinition, override?: TechnologyDefinition): void;
19
19
  get relationships(): ReadonlyArray<Relationship>;
20
+ with<TChildren extends Record<string, TChild>>(callback: (self: this) => TChildren): this & TChildren;
20
21
  abstract getChildElements(): ReadonlyArray<Element>;
21
22
  getRelationshipsInHierarchy(): ReadonlyArray<Relationship>;
22
23
  getChildElementNames(path?: string): ReadonlyArray<string>;
23
24
  }
24
- export declare abstract class TechnicalElement extends Element {
25
+ export declare abstract class TechnicalElement<TChild extends Element = never> extends Element<TChild> {
25
26
  readonly technology?: string;
26
27
  constructor(name: string, defaultTags?: string[], definition?: TechnologyDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
27
28
  }
@@ -35,7 +36,9 @@ export declare class Relationship {
35
36
  readonly overrideDefinition?: TechnologyDefinition;
36
37
  constructor(source: Element, destination: Element, definition?: TechnologyDefinition, archetype?: RelationshipArchetype, overrideDefinition?: TechnologyDefinition);
37
38
  }
38
- export declare class Group {
39
+ export declare class Group<TChild extends Element | Group = never> {
39
40
  readonly name: string;
40
41
  constructor(name: string);
42
+ get canonicalName(): string;
43
+ with<TChildren extends Record<string, TChild>>(callback: (self: this) => TChildren): this & TChildren;
41
44
  }
package/src/index.cjs CHANGED
@@ -214,6 +214,10 @@ var Element = class {
214
214
  get relationships() {
215
215
  return this._relationships;
216
216
  }
217
+ with(callback) {
218
+ const children = callback(this);
219
+ return Object.assign(this, children);
220
+ }
217
221
  getRelationshipsInHierarchy() {
218
222
  return this._relationships.concat(this.getChildElements().flatMap((element) => element.getRelationshipsInHierarchy()));
219
223
  }
@@ -252,6 +256,13 @@ var Group = class {
252
256
  constructor(name) {
253
257
  this.name = name;
254
258
  }
259
+ get canonicalName() {
260
+ return camelCase(this.name);
261
+ }
262
+ with(callback) {
263
+ const children = callback(this);
264
+ return Object.assign(this, children);
265
+ }
255
266
  // TODO: Implement this in some useful way?
256
267
  // public addToGroup(groupCollection: string, groupMember: T) {}
257
268
  };
@@ -275,8 +286,8 @@ var ContainerGroup = class extends Group {
275
286
  this.container = container;
276
287
  }
277
288
  _components = /* @__PURE__ */ new Map();
278
- defineComponent(name, archetypeOrDef, override) {
279
- const component = this.container.defineComponent(name, archetypeOrDef, override);
289
+ component(name, archetypeOrDef, override) {
290
+ const component = this.container.component(name, archetypeOrDef, override);
280
291
  this._components.set(name, component);
281
292
  return component;
282
293
  }
@@ -291,7 +302,7 @@ var Container = class extends TechnicalElement {
291
302
  }
292
303
  _components = /* @__PURE__ */ new Map();
293
304
  _groups = /* @__PURE__ */ new Map();
294
- defineComponent(name, archetypeOrDef, override) {
305
+ component(name, archetypeOrDef, override) {
295
306
  if (this._components.has(name)) {
296
307
  throw Error(`A Component named '${name}' is defined elsewhere in this Container. A Component can be defined only once.`);
297
308
  }
@@ -307,7 +318,7 @@ var Container = class extends TechnicalElement {
307
318
  this._components.set(name, component);
308
319
  return component;
309
320
  }
310
- addGroup(groupName) {
321
+ group(groupName) {
311
322
  let group = this._groups.get(groupName);
312
323
  if (!group) {
313
324
  group = new ContainerGroup(groupName, this);
@@ -335,8 +346,8 @@ var SoftwareSystemGroup = class extends Group {
335
346
  this.softwareSystem = softwareSystem;
336
347
  }
337
348
  _containers = /* @__PURE__ */ new Map();
338
- defineContainer(name, archetypeOrDef, override) {
339
- const container = this.softwareSystem.defineContainer(name, archetypeOrDef, override);
349
+ container(name, archetypeOrDef, override) {
350
+ const container = this.softwareSystem.container(name, archetypeOrDef, override);
340
351
  this._containers.set(name, container);
341
352
  return container;
342
353
  }
@@ -351,7 +362,7 @@ var SoftwareSystem = class extends Element {
351
362
  }
352
363
  _containers = /* @__PURE__ */ new Map();
353
364
  _groups = /* @__PURE__ */ new Map();
354
- defineContainer(name, archetypeOrDef, override) {
365
+ container(name, archetypeOrDef, override) {
355
366
  if (this._containers.has(name)) {
356
367
  throw Error(`A Container named '${name}' is defined elsewhere in this SoftwareSystem. A Container can be defined only once.`);
357
368
  }
@@ -367,7 +378,7 @@ var SoftwareSystem = class extends Element {
367
378
  this._containers.set(name, container);
368
379
  return container;
369
380
  }
370
- addGroup(groupName) {
381
+ group(groupName) {
371
382
  let group = this._groups.get(groupName);
372
383
  if (!group) {
373
384
  group = new SoftwareSystemGroup(groupName, this);
@@ -407,13 +418,13 @@ var ModelGroup = class extends Group {
407
418
  }
408
419
  softwareSystems = /* @__PURE__ */ new Map();
409
420
  people = /* @__PURE__ */ new Map();
410
- defineSoftwareSystem(name, archetypeOrDef, override) {
411
- const softwareSystem = this.model.defineSoftwareSystem(name, archetypeOrDef, override);
421
+ softwareSystem(name, archetypeOrDef, override) {
422
+ const softwareSystem = this.model.softwareSystem(name, archetypeOrDef, override);
412
423
  this.softwareSystems.set(name, softwareSystem);
413
424
  return softwareSystem;
414
425
  }
415
- definePerson(name, archetypeOrDef, override) {
416
- const person = this.model.definePerson(name, archetypeOrDef, override);
426
+ person(name, archetypeOrDef, override) {
427
+ const person = this.model.person(name, archetypeOrDef, override);
417
428
  this.people.set(name, person);
418
429
  return person;
419
430
  }
@@ -431,7 +442,7 @@ var Model = class {
431
442
  softwareSystems = /* @__PURE__ */ new Map();
432
443
  people = /* @__PURE__ */ new Map();
433
444
  groups = /* @__PURE__ */ new Map();
434
- defineSoftwareSystem(name, archetypeOrDef, override) {
445
+ softwareSystem(name, archetypeOrDef, override) {
435
446
  if (this.softwareSystems.has(name)) {
436
447
  throw Error(`A SoftwareSystem named '${name}' is defined elsewhere in this Model. A SoftwareSystem can be defined only once.`);
437
448
  }
@@ -448,7 +459,7 @@ var Model = class {
448
459
  return system;
449
460
  }
450
461
  // TODO:Should be a Group<SoftwareSystem | Person> if that is added back in
451
- addGroup(groupName) {
462
+ group(groupName) {
452
463
  let group = this.groups.get(groupName);
453
464
  if (!group) {
454
465
  group = new ModelGroup(groupName, this);
@@ -456,7 +467,7 @@ var Model = class {
456
467
  }
457
468
  return group;
458
469
  }
459
- definePerson(name, archetypeOrDef, override) {
470
+ person(name, archetypeOrDef, override) {
460
471
  if (this.people.has(name)) {
461
472
  throw Error(`A Person named '${name}' is defined elsewhere in this Model. A Person can be defined only once.`);
462
473
  }
@@ -472,6 +483,7 @@ var Model = class {
472
483
  this.people.set(name, person);
473
484
  return person;
474
485
  }
486
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
475
487
  validate() {
476
488
  }
477
489
  getPeople() {
@@ -698,7 +710,7 @@ var StructurizrDSLWriter = class {
698
710
  }
699
711
  writeContainerGroup(group, level) {
700
712
  let containerGroupDsl = "";
701
- containerGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
713
+ containerGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
702
714
  group.getComponents().forEach((component) => {
703
715
  containerGroupDsl += this.writeComponent(component, level + 1);
704
716
  });
@@ -722,7 +734,7 @@ var StructurizrDSLWriter = class {
722
734
  }
723
735
  writeSoftwareSystemGroup(group, level) {
724
736
  let softwareSystemGroupDsl = "";
725
- softwareSystemGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
737
+ softwareSystemGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
726
738
  group.getContainers().forEach((container) => {
727
739
  softwareSystemGroupDsl += this.writeContainer(container, level + 1);
728
740
  });
@@ -780,7 +792,7 @@ var StructurizrDSLWriter = class {
780
792
  }
781
793
  writeModelGroup(group, level) {
782
794
  let modelGroupDsl = "";
783
- modelGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
795
+ modelGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
784
796
  group.getPeople().forEach((person) => {
785
797
  modelGroupDsl += this.writeElement("person", person, level + 1);
786
798
  });
@@ -866,7 +878,7 @@ var import_url = require("url");
866
878
  var import_meta = {};
867
879
  var _dirname = typeof __dirname !== "undefined" ? __dirname : (0, import_path.dirname)((0, import_url.fileURLToPath)(import_meta.url));
868
880
  async function buildModelWithCatalog(options = {}) {
869
- const { modelName = "model", modules: explicitModules } = options;
881
+ const { modelName = "model", modules: explicitModules, archetypes = {} } = options;
870
882
  const model = new Model(modelName);
871
883
  let c4Modules;
872
884
  if (explicitModules) {
@@ -886,13 +898,13 @@ async function buildModelWithCatalog(options = {}) {
886
898
  const registrations = [];
887
899
  const rootCatalog = {};
888
900
  for (const instance of c4Modules) {
889
- const local = instance.registerDefinitions(model);
901
+ const local = instance.registerDefinitions(model, archetypes);
890
902
  rootCatalog[instance.key] = local;
891
903
  registrations.push({ instance, key: instance.key, local });
892
904
  }
893
905
  for (const { instance, key, local } of registrations) {
894
906
  const dependencies = Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
895
- instance.buildRelationships(local, dependencies);
907
+ instance.buildRelationships(local, dependencies, archetypes);
896
908
  }
897
909
  return { model, catalog: rootCatalog };
898
910
  }
package/src/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export interface Definition {
7
7
  export interface TechnologyDefinition extends Definition {
8
8
  technology?: string;
9
9
  }
10
- declare abstract class Element$1 {
10
+ declare abstract class Element$1<TChild extends Element$1 = never> {
11
11
  readonly name: string;
12
12
  readonly description?: string;
13
13
  readonly tags: ReadonlyArray<string>;
@@ -18,11 +18,12 @@ declare abstract class Element$1 {
18
18
  get canonicalName(): string;
19
19
  uses(otherElement: Element$1, archetypeOrDef?: RelationshipArchetype | TechnologyDefinition, override?: TechnologyDefinition): void;
20
20
  get relationships(): ReadonlyArray<Relationship>;
21
+ with<TChildren extends Record<string, TChild>>(callback: (self: this) => TChildren): this & TChildren;
21
22
  abstract getChildElements(): ReadonlyArray<Element$1>;
22
23
  getRelationshipsInHierarchy(): ReadonlyArray<Relationship>;
23
24
  getChildElementNames(path?: string): ReadonlyArray<string>;
24
25
  }
25
- declare abstract class TechnicalElement extends Element$1 {
26
+ declare abstract class TechnicalElement<TChild extends Element$1 = never> extends Element$1<TChild> {
26
27
  readonly technology?: string;
27
28
  constructor(name: string, defaultTags?: string[], definition?: TechnologyDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
28
29
  }
@@ -36,9 +37,11 @@ declare class Relationship {
36
37
  readonly overrideDefinition?: TechnologyDefinition;
37
38
  constructor(source: Element$1, destination: Element$1, definition?: TechnologyDefinition, archetype?: RelationshipArchetype, overrideDefinition?: TechnologyDefinition);
38
39
  }
39
- declare class Group {
40
+ declare class Group<TChild extends Element$1 | Group = never> {
40
41
  readonly name: string;
41
42
  constructor(name: string);
43
+ get canonicalName(): string;
44
+ with<TChildren extends Record<string, TChild>>(callback: (self: this) => TChildren): this & TChildren;
42
45
  }
43
46
  export type ElementKind = "person" | "softwareSystem" | "container" | "component";
44
47
  export declare class ElementArchetype {
@@ -77,49 +80,49 @@ export declare class Component extends TechnicalElement {
77
80
  }
78
81
  export type ContainerDefinition = TechnologyDefinition;
79
82
  export interface DefineComponent {
80
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
83
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
81
84
  }
82
- export declare class ContainerGroup extends Group implements DefineComponent {
85
+ export declare class ContainerGroup extends Group<Component> implements DefineComponent {
83
86
  readonly name: string;
84
87
  private readonly container;
85
88
  private _components;
86
89
  constructor(name: string, container: DefineComponent);
87
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
90
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
88
91
  getComponents(): ReadonlyArray<Component>;
89
92
  }
90
- export declare class Container extends TechnicalElement implements DefineComponent {
93
+ export declare class Container extends TechnicalElement<Component> implements DefineComponent {
91
94
  readonly name: string;
92
95
  private _components;
93
96
  private _groups;
94
97
  constructor(name: string, definition?: ContainerDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
95
- defineComponent(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
96
- addGroup(groupName: string): ContainerGroup;
98
+ component(name: string, archetypeOrDef?: ElementArchetype | ComponentDefinition, override?: ComponentDefinition): Component;
99
+ group(groupName: string): ContainerGroup;
97
100
  getGroups(): ReadonlyArray<ContainerGroup>;
98
101
  getComponentsNotInGroups(): ReadonlyArray<Component>;
99
102
  getChildElements(): ReadonlyArray<Element$1>;
100
103
  }
101
104
  export type SoftwareSystemDefinition = Definition;
102
105
  export interface DefineContainer {
103
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
106
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
104
107
  }
105
108
  export interface SoftwareSystemReference {
106
109
  name: string;
107
110
  }
108
- export declare class SoftwareSystemGroup extends Group implements DefineContainer {
111
+ export declare class SoftwareSystemGroup extends Group<Container> implements DefineContainer {
109
112
  readonly name: string;
110
113
  private readonly softwareSystem;
111
114
  private _containers;
112
115
  constructor(name: string, softwareSystem: DefineContainer);
113
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
116
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
114
117
  getContainers(): ReadonlyArray<Container>;
115
118
  }
116
- export declare class SoftwareSystem extends Element$1 implements DefineContainer {
119
+ export declare class SoftwareSystem extends Element$1<Container> implements DefineContainer {
117
120
  readonly name: string;
118
121
  private _containers;
119
122
  private _groups;
120
123
  constructor(name: string, definition?: SoftwareSystemDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
121
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
122
- addGroup(groupName: string): SoftwareSystemGroup;
124
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
125
+ group(groupName: string): SoftwareSystemGroup;
123
126
  getGroups(): ReadonlyArray<SoftwareSystemGroup>;
124
127
  getChildElements(): ReadonlyArray<Element$1>;
125
128
  getContainersNotInGroups(): ReadonlyArray<Container>;
@@ -134,31 +137,31 @@ export type CatalogKeyOf<TRoot, TModule> = {
134
137
  [K in keyof TRoot]: TRoot[K] extends TModule ? K : never;
135
138
  }[keyof TRoot];
136
139
  export type Dependencies<TRoot, TModule> = Omit<TRoot, CatalogKeyOf<TRoot, TModule>>;
137
- export interface C4Module<TRoot, TLocal> {
140
+ export interface C4Module<TRoot, TLocal, TArchetypes = Record<string, ElementArchetype | RelationshipArchetype>> {
138
141
  readonly key: CatalogKeyOf<TRoot, TLocal>;
139
- registerDefinitions(model: Model): TLocal;
140
- buildRelationships(local: TLocal, dependencies: Dependencies<TRoot, TLocal>): void;
142
+ registerDefinitions(model: Model, archetypes: TArchetypes): TLocal;
143
+ buildRelationships(local: TLocal, dependencies: Dependencies<TRoot, TLocal>, archetypes: TArchetypes): void;
141
144
  }
142
145
  export interface DefineSoftwareSystem {
143
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
146
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
144
147
  }
145
148
  export interface DefinePerson {
146
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
149
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
147
150
  }
148
- export declare class ModelGroup extends Group implements DefineSoftwareSystem, DefinePerson {
151
+ export declare class ModelGroup extends Group<Person | SoftwareSystem> implements DefineSoftwareSystem, DefinePerson {
149
152
  readonly name: string;
150
153
  private readonly model;
151
154
  private softwareSystems;
152
155
  private people;
153
156
  constructor(name: string, model: DefineSoftwareSystem & DefinePerson);
154
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
155
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
157
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
158
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
156
159
  getSoftwareSystems(): ReadonlyArray<SoftwareSystem>;
157
160
  getPeople(): ReadonlyArray<Person>;
158
161
  }
159
162
  export interface ModelDefinitions {
160
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
161
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
163
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
164
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
162
165
  }
163
166
  export declare class Model {
164
167
  name: string;
@@ -166,9 +169,9 @@ export declare class Model {
166
169
  private softwareSystems;
167
170
  private people;
168
171
  private groups;
169
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
170
- addGroup(groupName: string): Group & ModelDefinitions;
171
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
172
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
173
+ group(groupName: string): Group & ModelDefinitions;
174
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
172
175
  validate(): void;
173
176
  getPeople(): ReadonlyArray<Person>;
174
177
  getSoftwareSystems(): ReadonlyArray<SoftwareSystem>;
@@ -235,14 +238,15 @@ export type Catalog = Record<string, unknown>;
235
238
  export type RootCatalog = Record<string, Catalog>;
236
239
  export interface AnyC4Module {
237
240
  readonly key: string;
238
- registerDefinitions(model: Model): Catalog;
239
- buildRelationships(local: Catalog, dependencies: RootCatalog): void;
241
+ registerDefinitions(model: Model, archetypes: Record<string, ElementArchetype | RelationshipArchetype>): Catalog;
242
+ buildRelationships(local: Catalog, dependencies: RootCatalog, archetypes: Record<string, ElementArchetype | RelationshipArchetype>): void;
240
243
  }
241
244
  export interface BuildModelOptions {
242
245
  modelName?: string;
243
246
  modules?: ReadonlyArray<AnyC4Module>;
244
247
  globPath?: string;
245
248
  searchRoot?: string;
249
+ archetypes?: Record<string, ElementArchetype | RelationshipArchetype>;
246
250
  }
247
251
  export declare function buildModelWithCatalog<TRoot>(options?: BuildModelOptions): Promise<{
248
252
  model: Model;
package/src/index.js CHANGED
@@ -162,6 +162,10 @@ 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
  }
@@ -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
  };
@@ -223,8 +234,8 @@ var ContainerGroup = class extends Group {
223
234
  this.container = container;
224
235
  }
225
236
  _components = /* @__PURE__ */ new Map();
226
- defineComponent(name, archetypeOrDef, override) {
227
- const component = this.container.defineComponent(name, archetypeOrDef, override);
237
+ component(name, archetypeOrDef, override) {
238
+ const component = this.container.component(name, archetypeOrDef, override);
228
239
  this._components.set(name, component);
229
240
  return component;
230
241
  }
@@ -239,7 +250,7 @@ var Container = class extends TechnicalElement {
239
250
  }
240
251
  _components = /* @__PURE__ */ new Map();
241
252
  _groups = /* @__PURE__ */ new Map();
242
- defineComponent(name, archetypeOrDef, override) {
253
+ component(name, archetypeOrDef, override) {
243
254
  if (this._components.has(name)) {
244
255
  throw Error(`A Component named '${name}' is defined elsewhere in this Container. A Component can be defined only once.`);
245
256
  }
@@ -255,7 +266,7 @@ var Container = class extends TechnicalElement {
255
266
  this._components.set(name, component);
256
267
  return component;
257
268
  }
258
- addGroup(groupName) {
269
+ group(groupName) {
259
270
  let group = this._groups.get(groupName);
260
271
  if (!group) {
261
272
  group = new ContainerGroup(groupName, this);
@@ -283,8 +294,8 @@ var SoftwareSystemGroup = class extends Group {
283
294
  this.softwareSystem = softwareSystem;
284
295
  }
285
296
  _containers = /* @__PURE__ */ new Map();
286
- defineContainer(name, archetypeOrDef, override) {
287
- const container = this.softwareSystem.defineContainer(name, archetypeOrDef, override);
297
+ container(name, archetypeOrDef, override) {
298
+ const container = this.softwareSystem.container(name, archetypeOrDef, override);
288
299
  this._containers.set(name, container);
289
300
  return container;
290
301
  }
@@ -299,7 +310,7 @@ var SoftwareSystem = class extends Element {
299
310
  }
300
311
  _containers = /* @__PURE__ */ new Map();
301
312
  _groups = /* @__PURE__ */ new Map();
302
- defineContainer(name, archetypeOrDef, override) {
313
+ container(name, archetypeOrDef, override) {
303
314
  if (this._containers.has(name)) {
304
315
  throw Error(`A Container named '${name}' is defined elsewhere in this SoftwareSystem. A Container can be defined only once.`);
305
316
  }
@@ -315,7 +326,7 @@ var SoftwareSystem = class extends Element {
315
326
  this._containers.set(name, container);
316
327
  return container;
317
328
  }
318
- addGroup(groupName) {
329
+ group(groupName) {
319
330
  let group = this._groups.get(groupName);
320
331
  if (!group) {
321
332
  group = new SoftwareSystemGroup(groupName, this);
@@ -355,13 +366,13 @@ var ModelGroup = class extends Group {
355
366
  }
356
367
  softwareSystems = /* @__PURE__ */ new Map();
357
368
  people = /* @__PURE__ */ new Map();
358
- defineSoftwareSystem(name, archetypeOrDef, override) {
359
- const softwareSystem = this.model.defineSoftwareSystem(name, archetypeOrDef, override);
369
+ softwareSystem(name, archetypeOrDef, override) {
370
+ const softwareSystem = this.model.softwareSystem(name, archetypeOrDef, override);
360
371
  this.softwareSystems.set(name, softwareSystem);
361
372
  return softwareSystem;
362
373
  }
363
- definePerson(name, archetypeOrDef, override) {
364
- const person = this.model.definePerson(name, archetypeOrDef, override);
374
+ person(name, archetypeOrDef, override) {
375
+ const person = this.model.person(name, archetypeOrDef, override);
365
376
  this.people.set(name, person);
366
377
  return person;
367
378
  }
@@ -379,7 +390,7 @@ var Model = class {
379
390
  softwareSystems = /* @__PURE__ */ new Map();
380
391
  people = /* @__PURE__ */ new Map();
381
392
  groups = /* @__PURE__ */ new Map();
382
- defineSoftwareSystem(name, archetypeOrDef, override) {
393
+ softwareSystem(name, archetypeOrDef, override) {
383
394
  if (this.softwareSystems.has(name)) {
384
395
  throw Error(`A SoftwareSystem named '${name}' is defined elsewhere in this Model. A SoftwareSystem can be defined only once.`);
385
396
  }
@@ -396,7 +407,7 @@ var Model = class {
396
407
  return system;
397
408
  }
398
409
  // TODO:Should be a Group<SoftwareSystem | Person> if that is added back in
399
- addGroup(groupName) {
410
+ group(groupName) {
400
411
  let group = this.groups.get(groupName);
401
412
  if (!group) {
402
413
  group = new ModelGroup(groupName, this);
@@ -404,7 +415,7 @@ var Model = class {
404
415
  }
405
416
  return group;
406
417
  }
407
- definePerson(name, archetypeOrDef, override) {
418
+ person(name, archetypeOrDef, override) {
408
419
  if (this.people.has(name)) {
409
420
  throw Error(`A Person named '${name}' is defined elsewhere in this Model. A Person can be defined only once.`);
410
421
  }
@@ -420,6 +431,7 @@ var Model = class {
420
431
  this.people.set(name, person);
421
432
  return person;
422
433
  }
434
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
423
435
  validate() {
424
436
  }
425
437
  getPeople() {
@@ -646,7 +658,7 @@ var StructurizrDSLWriter = class {
646
658
  }
647
659
  writeContainerGroup(group, level) {
648
660
  let containerGroupDsl = "";
649
- containerGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
661
+ containerGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
650
662
  group.getComponents().forEach((component) => {
651
663
  containerGroupDsl += this.writeComponent(component, level + 1);
652
664
  });
@@ -670,7 +682,7 @@ var StructurizrDSLWriter = class {
670
682
  }
671
683
  writeSoftwareSystemGroup(group, level) {
672
684
  let softwareSystemGroupDsl = "";
673
- softwareSystemGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
685
+ softwareSystemGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
674
686
  group.getContainers().forEach((container) => {
675
687
  softwareSystemGroupDsl += this.writeContainer(container, level + 1);
676
688
  });
@@ -728,7 +740,7 @@ var StructurizrDSLWriter = class {
728
740
  }
729
741
  writeModelGroup(group, level) {
730
742
  let modelGroupDsl = "";
731
- modelGroupDsl += this.writeLine(`${group.name} = group "${group.name}" {`, level);
743
+ modelGroupDsl += this.writeLine(`${group.canonicalName} = group "${group.name}" {`, level);
732
744
  group.getPeople().forEach((person) => {
733
745
  modelGroupDsl += this.writeElement("person", person, level + 1);
734
746
  });
@@ -813,7 +825,7 @@ import { join, dirname } from "path";
813
825
  import { fileURLToPath } from "url";
814
826
  var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
815
827
  async function buildModelWithCatalog(options = {}) {
816
- const { modelName = "model", modules: explicitModules } = options;
828
+ const { modelName = "model", modules: explicitModules, archetypes = {} } = options;
817
829
  const model = new Model(modelName);
818
830
  let c4Modules;
819
831
  if (explicitModules) {
@@ -833,13 +845,13 @@ async function buildModelWithCatalog(options = {}) {
833
845
  const registrations = [];
834
846
  const rootCatalog = {};
835
847
  for (const instance of c4Modules) {
836
- const local = instance.registerDefinitions(model);
848
+ const local = instance.registerDefinitions(model, archetypes);
837
849
  rootCatalog[instance.key] = local;
838
850
  registrations.push({ instance, key: instance.key, local });
839
851
  }
840
852
  for (const { instance, key, local } of registrations) {
841
853
  const dependencies = Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
842
- instance.buildRelationships(local, dependencies);
854
+ instance.buildRelationships(local, dependencies, archetypes);
843
855
  }
844
856
  return { model, catalog: rootCatalog };
845
857
  }
package/src/model.d.ts CHANGED
@@ -1,36 +1,36 @@
1
1
  import { Group } from './core';
2
2
  import { SoftwareSystem, SoftwareSystemDefinition } from './softwareSystem';
3
3
  import { Person, PersonDefinition } from './person';
4
- import { ElementArchetype } from './archetype';
4
+ import { ElementArchetype, RelationshipArchetype } from './archetype';
5
5
  export type CatalogKeyOf<TRoot, TModule> = {
6
6
  [K in keyof TRoot]: TRoot[K] extends TModule ? K : never;
7
7
  }[keyof TRoot];
8
8
  export type Dependencies<TRoot, TModule> = Omit<TRoot, CatalogKeyOf<TRoot, TModule>>;
9
- export interface C4Module<TRoot, TLocal> {
9
+ export interface C4Module<TRoot, TLocal, TArchetypes = Record<string, ElementArchetype | RelationshipArchetype>> {
10
10
  readonly key: CatalogKeyOf<TRoot, TLocal>;
11
- registerDefinitions(model: Model): TLocal;
12
- buildRelationships(local: TLocal, dependencies: Dependencies<TRoot, TLocal>): void;
11
+ registerDefinitions(model: Model, archetypes: TArchetypes): TLocal;
12
+ buildRelationships(local: TLocal, dependencies: Dependencies<TRoot, TLocal>, archetypes: TArchetypes): void;
13
13
  }
14
14
  interface DefineSoftwareSystem {
15
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
15
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
16
16
  }
17
17
  interface DefinePerson {
18
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
18
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
19
19
  }
20
- export declare class ModelGroup extends Group implements DefineSoftwareSystem, DefinePerson {
20
+ export declare class ModelGroup extends Group<Person | SoftwareSystem> implements DefineSoftwareSystem, DefinePerson {
21
21
  readonly name: string;
22
22
  private readonly model;
23
23
  private softwareSystems;
24
24
  private people;
25
25
  constructor(name: string, model: DefineSoftwareSystem & DefinePerson);
26
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
27
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
26
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
27
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
28
28
  getSoftwareSystems(): ReadonlyArray<SoftwareSystem>;
29
29
  getPeople(): ReadonlyArray<Person>;
30
30
  }
31
31
  export interface ModelDefinitions {
32
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
33
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
32
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
33
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
34
34
  }
35
35
  export declare class Model {
36
36
  name: string;
@@ -38,9 +38,9 @@ export declare class Model {
38
38
  private softwareSystems;
39
39
  private people;
40
40
  private groups;
41
- defineSoftwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
42
- addGroup(groupName: string): Group & ModelDefinitions;
43
- definePerson(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
41
+ softwareSystem(name: string, archetypeOrDef?: ElementArchetype | SoftwareSystemDefinition, override?: SoftwareSystemDefinition): SoftwareSystem;
42
+ group(groupName: string): Group & ModelDefinitions;
43
+ person(name: string, archetypeOrDef?: ElementArchetype | PersonDefinition, override?: PersonDefinition): Person;
44
44
  validate(): void;
45
45
  getPeople(): ReadonlyArray<Person>;
46
46
  getSoftwareSystems(): ReadonlyArray<SoftwareSystem>;
@@ -3,26 +3,26 @@ import { Container, ContainerDefinition } from './container';
3
3
  import { ElementArchetype } from './archetype';
4
4
  export type SoftwareSystemDefinition = Definition;
5
5
  interface DefineContainer {
6
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
6
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
7
7
  }
8
8
  export interface SoftwareSystemReference {
9
9
  name: string;
10
10
  }
11
- export declare class SoftwareSystemGroup extends Group implements DefineContainer {
11
+ export declare class SoftwareSystemGroup extends Group<Container> implements DefineContainer {
12
12
  readonly name: string;
13
13
  private readonly softwareSystem;
14
14
  private _containers;
15
15
  constructor(name: string, softwareSystem: DefineContainer);
16
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
16
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
17
17
  getContainers(): ReadonlyArray<Container>;
18
18
  }
19
- export declare class SoftwareSystem extends Element implements DefineContainer {
19
+ export declare class SoftwareSystem extends Element<Container> implements DefineContainer {
20
20
  readonly name: string;
21
21
  private _containers;
22
22
  private _groups;
23
23
  constructor(name: string, definition?: SoftwareSystemDefinition, archetype?: ElementArchetype, overrideDefinition?: TechnologyDefinition);
24
- defineContainer(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
25
- addGroup(groupName: string): SoftwareSystemGroup;
24
+ container(name: string, archetypeOrDef?: ElementArchetype | ContainerDefinition, override?: ContainerDefinition): Container;
25
+ group(groupName: string): SoftwareSystemGroup;
26
26
  getGroups(): ReadonlyArray<SoftwareSystemGroup>;
27
27
  getChildElements(): ReadonlyArray<Element>;
28
28
  getContainersNotInGroups(): ReadonlyArray<Container>;