@agilewallaby/c4-model 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CLAUDE.md +45 -0
  2. package/package.json +7 -3
  3. package/src/component.d.ts +7 -0
  4. package/src/{lib/component.js → component.js} +2 -5
  5. package/src/component.js.map +1 -0
  6. package/src/{lib/container.d.ts → container.d.ts} +4 -8
  7. package/src/{lib/container.js → container.js} +6 -12
  8. package/src/container.js.map +1 -0
  9. package/src/core.d.ts +36 -0
  10. package/src/{lib/core.js → core.js} +7 -36
  11. package/src/core.js.map +1 -0
  12. package/src/generateDiagrams.d.ts +7 -0
  13. package/src/generateDiagrams.js +55 -0
  14. package/src/generateDiagrams.js.map +1 -0
  15. package/src/index.d.ts +8 -3
  16. package/src/index.js +8 -3
  17. package/src/index.js.map +1 -1
  18. package/src/{lib/model.d.ts → model.d.ts} +23 -9
  19. package/src/{lib/model.js → model.js} +41 -56
  20. package/src/model.js.map +1 -0
  21. package/src/person.d.ts +7 -0
  22. package/src/person.js +15 -0
  23. package/src/person.js.map +1 -0
  24. package/src/{lib/softwareSystem.d.ts → softwareSystem.d.ts} +4 -8
  25. package/src/{lib/softwareSystem.js → softwareSystem.js} +4 -10
  26. package/src/softwareSystem.js.map +1 -0
  27. package/src/{lib/structurizrDslWriter.d.ts → structurizrDslWriter.d.ts} +1 -1
  28. package/src/{lib/structurizrDslWriter.js → structurizrDslWriter.js} +41 -42
  29. package/src/structurizrDslWriter.js.map +1 -0
  30. package/src/{lib/views.js → views.js} +2 -2
  31. package/src/views.js.map +1 -0
  32. package/src/lib/component.d.ts +0 -10
  33. package/src/lib/component.js.map +0 -1
  34. package/src/lib/container.js.map +0 -1
  35. package/src/lib/core.d.ts +0 -51
  36. package/src/lib/core.js.map +0 -1
  37. package/src/lib/model.js.map +0 -1
  38. package/src/lib/person.d.ts +0 -11
  39. package/src/lib/person.js +0 -24
  40. package/src/lib/person.js.map +0 -1
  41. package/src/lib/softwareSystem.js.map +0 -1
  42. package/src/lib/structurizrDslWriter.js.map +0 -1
  43. package/src/lib/tests/system1/c4.dsl.d.ts +0 -2
  44. package/src/lib/tests/system1/c4.dsl.js +0 -9
  45. package/src/lib/tests/system1/c4.dsl.js.map +0 -1
  46. package/src/lib/tests/system2/c4.dsl.d.ts +0 -2
  47. package/src/lib/tests/system2/c4.dsl.js +0 -9
  48. package/src/lib/tests/system2/c4.dsl.js.map +0 -1
  49. package/src/lib/views.js.map +0 -1
  50. /package/{dist/libs/c4-model/libs/c4-model/README.md → README.md} +0 -0
  51. /package/src/{lib/views.d.ts → views.d.ts} +0 -0
package/CLAUDE.md ADDED
@@ -0,0 +1,45 @@
1
+ # c4-model
2
+
3
+ ## About
4
+
5
+ TypeScript library for defining C4 architecture models and generating Structurizr DSL.
6
+
7
+ ## Structurizr DSL Reference
8
+
9
+ Structurizr DSL docs are available locally at `docs/structurizr/` (run
10
+ `pnpm fetch-structurizr-docs` to populate). When working on `structurizrDslWriter.ts`,
11
+ read the relevant files from that directory. If not present locally, source is:
12
+ https://github.com/structurizr/structurizr.github.io/tree/main/dsl
13
+
14
+ ## Running tasks
15
+
16
+ ```sh
17
+ pnpm exec nx run c4-model:test
18
+ pnpm exec nx run c4-model:build
19
+ pnpm exec nx run c4-model:lint
20
+ ```
21
+
22
+ ## Architecture
23
+
24
+ - `core.ts` — Base classes: `Element`, `TechnicalElement`, `Relationship`, `Reference`, `Group`
25
+ - `model.ts` — `Model` class, `C4Module` interface, `buildModel()` two-phase loader
26
+ - `person.ts` / `softwareSystem.ts` / `container.ts` / `component.ts` — C4 element types
27
+ - `views.ts` — View definitions (system landscape, context, container, component)
28
+ - `structurizrDslWriter.ts` — Generates Structurizr DSL from a Model + Views
29
+
30
+ ## C4Module pattern
31
+
32
+ Modules are defined in `c4.dsl.ts` files discovered by `buildModel()` via glob. Each exports a `c4Module`:
33
+
34
+ ```ts
35
+ export const c4Module: C4Module<RootCatalog, LocalCatalog> = {
36
+ key: 'myModule',
37
+ registerDefinitions(model) { /* define elements, return catalog */ },
38
+ buildRelationships(local, dependencies) { /* wire up cross-module relationships */ },
39
+ }
40
+ ```
41
+
42
+ - **Phase 1**: All modules register definitions; results stored in a root catalog keyed by module key
43
+ - **Phase 2**: Each module receives its own catalog and all other modules' catalogs to build relationships
44
+ - `CatalogKeyOf` and `Dependencies` utility types ensure type-safe keys and dependency access
45
+ - See `libs/c4-model-examples` for integration tests using `buildModel()`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilewallaby/c4-model",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -9,9 +9,13 @@
9
9
  "url": "https://github.com/AgileWallaby/c4.git"
10
10
  },
11
11
  "dependencies": {
12
+ "change-case": "^5.4.4",
13
+ "glob": "^10.3.10",
14
+ "testcontainers": "^10.28.0",
12
15
  "tslib": "^2.3.0"
13
16
  },
14
17
  "type": "commonjs",
15
18
  "main": "./src/index.js",
16
- "typings": "./src/index.d.ts"
17
- }
19
+ "typings": "./src/index.d.ts",
20
+ "types": "./src/index.d.ts"
21
+ }
@@ -0,0 +1,7 @@
1
+ import { Element, TechnicalElement, TechnologyDefinition } from './core';
2
+ export type ComponentDefinition = TechnologyDefinition;
3
+ export declare class Component extends TechnicalElement {
4
+ readonly name: string;
5
+ constructor(name: string, definition?: ComponentDefinition);
6
+ getChildElements(): ReadonlyArray<Element>;
7
+ }
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReferencedComponent = exports.Component = void 0;
3
+ exports.Component = void 0;
4
4
  const core_1 = require("./core");
5
5
  class Component extends core_1.TechnicalElement {
6
6
  constructor(name, definition) {
7
- super(name, ["Component"], definition);
7
+ super(name, ['Component'], definition);
8
8
  this.name = name;
9
9
  }
10
10
  getChildElements() {
@@ -12,7 +12,4 @@ class Component extends core_1.TechnicalElement {
12
12
  }
13
13
  }
14
14
  exports.Component = Component;
15
- class ReferencedComponent extends core_1.Reference {
16
- }
17
- exports.ReferencedComponent = ReferencedComponent;
18
15
  //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/component.ts"],"names":[],"mappings":";;;AAAA,iCAAwE;AAIxE,MAAa,SAAU,SAAQ,uBAAgB;IAC3C,YAC6B,IAAY,EACrC,UAAgC;QAEhC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAA;QAHb,SAAI,GAAJ,IAAI,CAAQ;IAIzC,CAAC;IAEM,gBAAgB;QACnB,OAAO,EAAE,CAAA;IACb,CAAC;CACJ;AAXD,8BAWC"}
@@ -1,11 +1,10 @@
1
- import { Element, Group, Reference, TechnicalElement, TechnologyDefinition } from "./core";
2
- import { Component, ComponentDefinition, ReferencedComponent } from "./component";
3
- export interface ContainerDefinition extends TechnologyDefinition {
4
- }
1
+ import { Element, Group, TechnicalElement, TechnologyDefinition } from './core';
2
+ import { Component, ComponentDefinition } from './component';
3
+ export type ContainerDefinition = TechnologyDefinition;
5
4
  interface DefineComponent {
6
5
  defineComponent(name: string, definition?: ComponentDefinition): Component;
7
6
  }
8
- export declare class ContainerGroup extends Group<Container> implements DefineComponent {
7
+ export declare class ContainerGroup extends Group implements DefineComponent {
9
8
  readonly name: string;
10
9
  private readonly container;
11
10
  private _components;
@@ -24,7 +23,4 @@ export declare class Container extends TechnicalElement implements DefineCompone
24
23
  getComponentsNotInGroups(): ReadonlyArray<Component>;
25
24
  getChildElements(): ReadonlyArray<Element>;
26
25
  }
27
- export declare class ReferencedContainer extends Reference<Component> {
28
- referenceComponent(name: string): ReferencedComponent;
29
- }
30
26
  export {};
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReferencedContainer = exports.Container = exports.ContainerGroup = void 0;
3
+ exports.Container = exports.ContainerGroup = void 0;
4
4
  const core_1 = require("./core");
5
5
  const component_1 = require("./component");
6
+ // TODO: This will be a Group<Container> if that is added back in
6
7
  class ContainerGroup extends core_1.Group {
7
8
  constructor(name, container) {
8
9
  super(name);
@@ -22,14 +23,14 @@ class ContainerGroup extends core_1.Group {
22
23
  exports.ContainerGroup = ContainerGroup;
23
24
  class Container extends core_1.TechnicalElement {
24
25
  constructor(name, definition) {
25
- super(name, ["Container"], definition);
26
+ super(name, ['Container'], definition);
26
27
  this.name = name;
27
28
  this._components = new Map();
28
29
  this._groups = new Map();
29
30
  }
30
31
  defineComponent(name, definition) {
31
32
  if (this._components.has(name)) {
32
- throw Error(`A Component named '${name}' is defined elsewhere in this Container. A Component can be defined only once, but can be referenced multiple times.`);
33
+ throw Error(`A Component named '${name}' is defined elsewhere in this Container. A Component can be defined only once.`);
33
34
  }
34
35
  const component = new component_1.Component(name, definition);
35
36
  this._components.set(name, component);
@@ -47,19 +48,12 @@ class Container extends core_1.TechnicalElement {
47
48
  return Array.from(this._groups.values());
48
49
  }
49
50
  getComponentsNotInGroups() {
50
- const componentsInGroups = this.getGroups().flatMap(group => group.getComponents());
51
- return Array.from(this._components.values()).filter(component => !componentsInGroups.includes(component));
51
+ const componentsInGroups = this.getGroups().flatMap((group) => group.getComponents());
52
+ return Array.from(this._components.values()).filter((component) => !componentsInGroups.includes(component));
52
53
  }
53
54
  getChildElements() {
54
55
  return Array.from(this._components.values());
55
56
  }
56
57
  }
57
58
  exports.Container = Container;
58
- class ReferencedContainer extends core_1.Reference {
59
- referenceComponent(name) {
60
- const componentReference = this.referenceChild(name, (name) => new component_1.ReferencedComponent(name));
61
- return componentReference;
62
- }
63
- }
64
- exports.ReferencedContainer = ReferencedContainer;
65
59
  //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/container.ts"],"names":[],"mappings":";;;AAAA,iCAA+E;AAC/E,2CAA4D;AAQ5D,iEAAiE;AACjE,MAAa,cAAe,SAAQ,YAAK;IAGrC,YAC6B,IAAY,EACpB,SAA0B;QAE3C,KAAK,CAAC,IAAI,CAAC,CAAA;QAHc,SAAI,GAAJ,IAAI,CAAQ;QACpB,cAAS,GAAT,SAAS,CAAiB;QAJvC,gBAAW,GAAG,IAAI,GAAG,EAAqB,CAAA;IAOlD,CAAC;IAEM,eAAe,CAAC,IAAY,EAAE,UAAgC;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAClE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACrC,OAAO,SAAS,CAAA;IACpB,CAAC;IAEM,aAAa;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAA;IAChD,CAAC;CACJ;AAnBD,wCAmBC;AAED,MAAa,SAAU,SAAQ,uBAAgB;IAI3C,YAC6B,IAAY,EACrC,UAAgC;QAEhC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAA;QAHb,SAAI,GAAJ,IAAI,CAAQ;QAJjC,gBAAW,GAAG,IAAI,GAAG,EAAqB,CAAA;QAC1C,YAAO,GAAG,IAAI,GAAG,EAA0B,CAAA;IAOnD,CAAC;IAEM,eAAe,CAAC,IAAY,EAAE,UAAgC;QACjE,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,CAAC,sBAAsB,IAAI,iFAAiF,CAAC,CAAA;QAC5H,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAEjD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAErC,OAAO,SAAS,CAAA;IACpB,CAAC;IAEM,QAAQ,CAAC,SAAiB;QAC7B,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,KAAK,GAAG,IAAI,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;YAC3C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QACtC,CAAC;QACD,OAAO,KAAK,CAAA;IAChB,CAAC;IAEM,SAAS;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC5C,CAAC;IAEM,wBAAwB;QAC3B,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAA;QACrF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA;IAC/G,CAAC;IAEM,gBAAgB;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAA;IAChD,CAAC;CACJ;AA5CD,8BA4CC"}
package/src/core.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ export interface Definition {
2
+ description?: string;
3
+ tags?: string[];
4
+ }
5
+ export interface TechnologyDefinition extends Definition {
6
+ technology?: string;
7
+ }
8
+ export declare abstract class Element {
9
+ readonly name: string;
10
+ readonly description?: string;
11
+ readonly tags: ReadonlyArray<string>;
12
+ private _relationships;
13
+ constructor(name: string, defaultTags?: string[], definition?: Definition);
14
+ get canonicalName(): string;
15
+ uses(otherElement: Element, definition?: TechnologyDefinition): void;
16
+ get relationships(): ReadonlyArray<Relationship>;
17
+ abstract getChildElements(): ReadonlyArray<Element>;
18
+ getRelationshipsInHierarchy(): ReadonlyArray<Relationship>;
19
+ getChildElementNames(path?: string): ReadonlyArray<string>;
20
+ }
21
+ export declare abstract class TechnicalElement extends Element {
22
+ readonly technology?: string;
23
+ constructor(name: string, defaultTags?: string[], definition?: TechnologyDefinition);
24
+ }
25
+ export declare class Relationship {
26
+ readonly source: Element;
27
+ readonly destination: Element;
28
+ readonly description?: string;
29
+ readonly tags: ReadonlyArray<string>;
30
+ readonly technology?: string;
31
+ constructor(source: Element, destination: Element, definition?: TechnologyDefinition);
32
+ }
33
+ export declare class Group {
34
+ readonly name: string;
35
+ constructor(name: string);
36
+ }
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Group = exports.Reference = exports.Relationship = exports.TechnicalElement = exports.Element = void 0;
3
+ exports.Group = exports.Relationship = exports.TechnicalElement = exports.Element = void 0;
4
+ const change_case_1 = require("change-case");
4
5
  class Element {
5
6
  constructor(name, defaultTags = [], definition) {
6
7
  var _a;
7
8
  this.name = name;
8
9
  this._relationships = [];
9
10
  this.description = definition === null || definition === void 0 ? void 0 : definition.description;
10
- this.tags = ((_a = definition === null || definition === void 0 ? void 0 : definition.tags) !== null && _a !== void 0 ? _a : []).concat(["Element"]).concat(defaultTags);
11
+ this.tags = ((_a = definition === null || definition === void 0 ? void 0 : definition.tags) !== null && _a !== void 0 ? _a : []).concat(['Element']).concat(defaultTags);
11
12
  }
12
13
  get canonicalName() {
13
- return this.name.toLowerCase();
14
+ return (0, change_case_1.camelCase)(this.name);
14
15
  }
15
16
  uses(otherElement, definition) {
16
17
  const relationship = new Relationship(this, otherElement, definition);
@@ -20,10 +21,10 @@ class Element {
20
21
  return this._relationships;
21
22
  }
22
23
  getRelationshipsInHierarchy() {
23
- return this._relationships.concat(this.getChildElements().flatMap(element => element.getRelationshipsInHierarchy()));
24
+ return this._relationships.concat(this.getChildElements().flatMap((element) => element.getRelationshipsInHierarchy()));
24
25
  }
25
26
  getChildElementNames(path) {
26
- const result = Array.from(this.getChildElements()).flatMap(reference => {
27
+ const result = Array.from(this.getChildElements()).flatMap((reference) => {
27
28
  const currentPath = `${path ? path : '' + this.name}.${reference.name}`;
28
29
  return [currentPath, ...reference.getChildElementNames(currentPath)];
29
30
  });
@@ -45,44 +46,14 @@ class Relationship {
45
46
  this.destination = destination;
46
47
  this.description = definition === null || definition === void 0 ? void 0 : definition.description;
47
48
  this.technology = definition === null || definition === void 0 ? void 0 : definition.technology;
48
- this.tags = ((_a = definition === null || definition === void 0 ? void 0 : definition.tags) !== null && _a !== void 0 ? _a : []).concat(["Relationship"]);
49
+ this.tags = ((_a = definition === null || definition === void 0 ? void 0 : definition.tags) !== null && _a !== void 0 ? _a : []).concat(['Relationship']);
49
50
  }
50
51
  }
51
52
  exports.Relationship = Relationship;
52
- class Reference {
53
- constructor(name) {
54
- this.name = name;
55
- this._references = new Map();
56
- }
57
- get canonicalName() {
58
- return this.name.toLowerCase();
59
- }
60
- referenceChild(name, createChild) {
61
- let reference = this._references.get(name);
62
- if (!reference) {
63
- reference = createChild(name);
64
- this._references.set(name, reference);
65
- }
66
- return reference;
67
- }
68
- get references() {
69
- return Array.from(this._references.values());
70
- }
71
- getChildElementNames(path) {
72
- const result = Array.from(this._references.values()).flatMap(reference => {
73
- const currentPath = `${path ? path : '' + this.name}.${reference.name}`;
74
- return [currentPath, ...reference.getChildElementNames(currentPath)];
75
- });
76
- return result;
77
- }
78
- }
79
- exports.Reference = Reference;
80
53
  class Group {
81
54
  constructor(name) {
82
55
  this.name = name;
83
56
  }
84
- addToGroup(groupCollection, groupMember) {
85
- }
86
57
  }
87
58
  exports.Group = Group;
88
59
  //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/core.ts"],"names":[],"mappings":";;;AAAA,6CAAuC;AAWvC,MAAsB,OAAO;IAMzB,YACoB,IAAY,EAC5B,cAAwB,EAAE,EAC1B,UAAuB;;QAFP,SAAI,GAAJ,IAAI,CAAQ;QAHxB,mBAAc,GAAmB,EAAE,CAAA;QAOvC,IAAI,CAAC,WAAW,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,WAAW,CAAA;QAC1C,IAAI,CAAC,IAAI,GAAG,CAAC,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,IAAI,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAChF,CAAC;IAED,IAAW,aAAa;QACpB,OAAO,IAAA,uBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAEM,IAAI,CAAC,YAAqB,EAAE,UAAiC;QAChE,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,CAAC,CAAA;QACrE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC1C,CAAC;IAED,IAAW,aAAa;QACpB,OAAO,IAAI,CAAC,cAAc,CAAA;IAC9B,CAAC;IAIM,2BAA2B;QAC9B,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAAC,CAAA;IAC1H,CAAC;IAEM,oBAAoB,CAAC,IAAa;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YACrE,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,CAAA;YACvE,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAA;QACxE,CAAC,CAAC,CAAA;QACF,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ;AAzCD,0BAyCC;AAED,MAAsB,gBAAiB,SAAQ,OAAO;IAGlD,YAAY,IAAY,EAAE,cAAwB,EAAE,EAAE,UAAiC;QACnF,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,UAAU,CAAA;IAC5C,CAAC;CACJ;AAPD,4CAOC;AAED,MAAa,YAAY;IAKrB,YACoB,MAAe,EACf,WAAoB,EACpC,UAAiC;;QAFjB,WAAM,GAAN,MAAM,CAAS;QACf,gBAAW,GAAX,WAAW,CAAS;QAGpC,IAAI,CAAC,WAAW,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,WAAW,CAAA;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,UAAU,CAAA;QACxC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,IAAI,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;IACjE,CAAC;CACJ;AAdD,oCAcC;AAED,MAAa,KAAK;IACd,YAAmC,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;CAItD;AALD,sBAKC"}
@@ -0,0 +1,7 @@
1
+ import { BuildModelOptions } from './model';
2
+ import { Views } from './views';
3
+ export interface GenerateDiagramsOptions<TRoot> extends BuildModelOptions {
4
+ views: (catalog: TRoot) => Views;
5
+ outputDir: string;
6
+ }
7
+ export declare function generateDiagrams<TRoot>(options: GenerateDiagramsOptions<TRoot>): Promise<string[]>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDiagrams = generateDiagrams;
4
+ const tslib_1 = require("tslib");
5
+ const fs = require("fs");
6
+ const os = require("os");
7
+ const path = require("path");
8
+ const testcontainers_1 = require("testcontainers");
9
+ const model_1 = require("./model");
10
+ const structurizrDslWriter_1 = require("./structurizrDslWriter");
11
+ function generateDiagrams(options) {
12
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
13
+ const { views: viewsFactory, outputDir } = options, buildOptions = tslib_1.__rest(options
14
+ // a) Build model + catalog
15
+ , ["views", "outputDir"]);
16
+ // a) Build model + catalog
17
+ const { model, catalog } = yield (0, model_1.buildModelWithCatalog)(buildOptions);
18
+ // b) Build views from catalog via callback
19
+ const views = viewsFactory(catalog);
20
+ // c) Generate DSL string
21
+ const dsl = new structurizrDslWriter_1.StructurizrDSLWriter(model, views).write();
22
+ // d) Write DSL to a temp directory (resolve symlinks so Docker bind mounts work on macOS)
23
+ const tmpDir = yield fs.promises.mkdtemp(path.join(fs.realpathSync(os.tmpdir()), 'c4-diagrams-'));
24
+ yield fs.promises.writeFile(path.join(tmpDir, 'workspace.dsl'), dsl, 'utf8');
25
+ // e) Run Structurizr CLI container to export .mmd files
26
+ yield new testcontainers_1.GenericContainer('structurizr/structurizr')
27
+ .withBindMounts([{ source: tmpDir, target: '/workspace', mode: 'rw' }])
28
+ .withCommand(['export', '-w', '/workspace/workspace.dsl', '-f', 'mermaid', '-o', '/workspace'])
29
+ .withWaitStrategy(testcontainers_1.Wait.forOneShotStartup())
30
+ .start();
31
+ // f) Copy .mmd files to outputDir
32
+ yield fs.promises.mkdir(outputDir, { recursive: true });
33
+ const tmpFiles = yield fs.promises.readdir(tmpDir);
34
+ const mmdFiles = tmpFiles.filter((f) => f.endsWith('.mmd'));
35
+ for (const file of mmdFiles) {
36
+ yield fs.promises.copyFile(path.join(tmpDir, file), path.join(outputDir, file));
37
+ }
38
+ const generatedFiles = mmdFiles.map((f) => path.join(outputDir, f));
39
+ // g) For each .mmd file, render to .png via minlag/mermaid-cli container
40
+ for (const file of mmdFiles) {
41
+ const baseName = path.basename(file, '.mmd');
42
+ const pngFile = `${baseName}.png`;
43
+ yield new testcontainers_1.GenericContainer('minlag/mermaid-cli')
44
+ .withBindMounts([{ source: tmpDir, target: '/data', mode: 'rw' }])
45
+ .withCommand(['-i', `/data/${file}`, '-o', `/data/${pngFile}`])
46
+ .withWaitStrategy(testcontainers_1.Wait.forOneShotStartup())
47
+ .start();
48
+ yield fs.promises.copyFile(path.join(tmpDir, pngFile), path.join(outputDir, pngFile));
49
+ generatedFiles.push(path.join(outputDir, pngFile));
50
+ }
51
+ // h) Return all generated file paths
52
+ return generatedFiles;
53
+ });
54
+ }
55
+ //# sourceMappingURL=generateDiagrams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateDiagrams.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/generateDiagrams.ts"],"names":[],"mappings":";;AAeA,4CAkDC;;AAjED,yBAAwB;AACxB,yBAAwB;AACxB,6BAA4B;AAE5B,mDAAuD;AAEvD,mCAAkE;AAClE,iEAA6D;AAQ7D,SAAsB,gBAAgB,CAAQ,OAAuC;;QACjF,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,KAAsB,OAAO,EAAxB,YAAY,kBAAK,OAAO;QAEnE,2BAA2B;UAFrB,sBAAmD,CAAU,CAAA;QAEnE,2BAA2B;QAC3B,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,IAAA,6BAAqB,EAAQ,YAAY,CAAC,CAAA;QAE3E,2CAA2C;QAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAEnC,yBAAyB;QACzB,MAAM,GAAG,GAAG,IAAI,2CAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAA;QAE1D,0FAA0F;QAC1F,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC,CAAA;QACjG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QAE5E,wDAAwD;QACxD,MAAM,IAAI,iCAAgB,CAAC,yBAAyB,CAAC;aAChD,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;aACtE,WAAW,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;aAC9F,gBAAgB,CAAC,qBAAI,CAAC,iBAAiB,EAAE,CAAC;aAC1C,KAAK,EAAE,CAAA;QAEZ,kCAAkC;QAClC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvD,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAE3D,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAA;QACnF,CAAC;QAED,MAAM,cAAc,GAAa,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAA;QAE7E,yEAAyE;QACzE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAC5C,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAA;YACjC,MAAM,IAAI,iCAAgB,CAAC,oBAAoB,CAAC;iBAC3C,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACjE,WAAW,CAAC,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;iBAC9D,gBAAgB,CAAC,qBAAI,CAAC,iBAAiB,EAAE,CAAC;iBAC1C,KAAK,EAAE,CAAA;YAEZ,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;YACrF,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACtD,CAAC;QAED,qCAAqC;QACrC,OAAO,cAAc,CAAA;IACzB,CAAC;CAAA"}
package/src/index.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- export * from './lib/model';
2
- export * from './lib/views';
3
- export * from './lib/structurizrDslWriter';
1
+ export * from './model';
2
+ export * from './person';
3
+ export * from './softwareSystem';
4
+ export * from './container';
5
+ export * from './component';
6
+ export * from './views';
7
+ export * from './structurizrDslWriter';
8
+ export * from './generateDiagrams';
package/src/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./lib/model"), exports);
5
- tslib_1.__exportStar(require("./lib/views"), exports);
6
- tslib_1.__exportStar(require("./lib/structurizrDslWriter"), exports);
4
+ tslib_1.__exportStar(require("./model"), exports);
5
+ tslib_1.__exportStar(require("./person"), exports);
6
+ tslib_1.__exportStar(require("./softwareSystem"), exports);
7
+ tslib_1.__exportStar(require("./container"), exports);
8
+ tslib_1.__exportStar(require("./component"), exports);
9
+ tslib_1.__exportStar(require("./views"), exports);
10
+ tslib_1.__exportStar(require("./structurizrDslWriter"), exports);
11
+ tslib_1.__exportStar(require("./generateDiagrams"), exports);
7
12
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/index.ts"],"names":[],"mappings":";;;AAAA,sDAA2B;AAC3B,sDAA2B;AAC3B,qEAA0C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/c4-model/src/index.ts"],"names":[],"mappings":";;;AAAA,kDAAuB;AACvB,mDAAwB;AACxB,2DAAgC;AAChC,sDAA2B;AAC3B,sDAA2B;AAC3B,kDAAuB;AACvB,iEAAsC;AACtC,6DAAkC"}
@@ -1,13 +1,22 @@
1
1
  import { Group } from './core';
2
- import { ReferencedSoftwareSystem, SoftwareSystem, SoftwareSystemDefinition } from './softwareSystem';
3
- import { Person, PersonDefinition, ReferencedPerson } from './person';
2
+ import { SoftwareSystem, SoftwareSystemDefinition } from './softwareSystem';
3
+ import { Person, PersonDefinition } from './person';
4
+ export type CatalogKeyOf<TRoot, TModule> = {
5
+ [K in keyof TRoot]: TRoot[K] extends TModule ? K : never;
6
+ }[keyof TRoot];
7
+ export type Dependencies<TRoot, TModule> = Omit<TRoot, CatalogKeyOf<TRoot, TModule>>;
8
+ export interface C4Module<TRoot, TLocal> {
9
+ readonly key: CatalogKeyOf<TRoot, TLocal>;
10
+ registerDefinitions(model: Model): TLocal;
11
+ buildRelationships(local: TLocal, dependencies: Dependencies<TRoot, TLocal>): void;
12
+ }
4
13
  interface DefineSoftwareSystem {
5
14
  defineSoftwareSystem(name: string, definition?: SoftwareSystemDefinition): SoftwareSystem;
6
15
  }
7
16
  interface DefinePerson {
8
17
  definePerson(name: string, definition?: PersonDefinition): Person;
9
18
  }
10
- export declare class ModelGroup extends Group<SoftwareSystem | Person> implements DefineSoftwareSystem, DefinePerson {
19
+ export declare class ModelGroup extends Group implements DefineSoftwareSystem, DefinePerson {
11
20
  readonly name: string;
12
21
  private readonly model;
13
22
  private softwareSystems;
@@ -26,15 +35,11 @@ export declare class Model {
26
35
  name: string;
27
36
  constructor(name: string);
28
37
  private softwareSystems;
29
- private referencedSoftwareSystems;
30
38
  private people;
31
- private referencedPeople;
32
39
  private groups;
33
40
  defineSoftwareSystem(name: string, definition?: SoftwareSystemDefinition): SoftwareSystem;
34
- addGroup(groupName: string): Group<SoftwareSystem | Person> & ModelDefinitions;
35
- referenceSoftwareSystem(name: string): ReferencedSoftwareSystem;
41
+ addGroup(groupName: string): Group & ModelDefinitions;
36
42
  definePerson(name: string, definition?: PersonDefinition): Person;
37
- referencePerson(name: string): ReferencedPerson;
38
43
  validate(): void;
39
44
  getPeople(): ReadonlyArray<Person>;
40
45
  getSoftwareSystems(): ReadonlyArray<SoftwareSystem>;
@@ -42,5 +47,14 @@ export declare class Model {
42
47
  getSoftwareSystemsNotInGroups(): ReadonlyArray<SoftwareSystem>;
43
48
  getGroups(): ReadonlyArray<ModelGroup>;
44
49
  }
45
- export declare function buildModel(modelName: string, globPath?: string): Promise<Model>;
50
+ export interface BuildModelOptions {
51
+ modelName?: string;
52
+ globPath?: string;
53
+ searchRoot?: string;
54
+ }
55
+ export declare function buildModelWithCatalog<TRoot>(options?: BuildModelOptions): Promise<{
56
+ model: Model;
57
+ catalog: TRoot;
58
+ }>;
59
+ export declare function buildModel(options?: BuildModelOptions): Promise<Model>;
46
60
  export {};
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildModel = exports.Model = exports.ModelGroup = void 0;
3
+ exports.Model = exports.ModelGroup = void 0;
4
+ exports.buildModelWithCatalog = buildModelWithCatalog;
5
+ exports.buildModel = buildModel;
4
6
  const tslib_1 = require("tslib");
5
7
  const glob_1 = require("glob");
6
8
  const path_1 = require("path");
7
9
  const core_1 = require("./core");
8
10
  const softwareSystem_1 = require("./softwareSystem");
9
11
  const person_1 = require("./person");
12
+ // TODO: This will be a Group of type <SoftwareSystem | Person> if that is added back in
10
13
  class ModelGroup extends core_1.Group {
11
14
  constructor(name, model) {
12
15
  super(name);
@@ -37,19 +40,18 @@ class Model {
37
40
  constructor(name) {
38
41
  this.name = name;
39
42
  this.softwareSystems = new Map();
40
- this.referencedSoftwareSystems = new Map();
41
43
  this.people = new Map();
42
- this.referencedPeople = new Map();
43
44
  this.groups = new Map();
44
45
  }
45
46
  defineSoftwareSystem(name, definition) {
46
47
  if (this.softwareSystems.has(name)) {
47
- throw Error(`A SoftwareSystem named '${name}' is defined elsewhere in this Model. A SoftwareSystem can be defined only once, but can be referenced multiple times.`);
48
+ throw Error(`A SoftwareSystem named '${name}' is defined elsewhere in this Model. A SoftwareSystem can be defined only once.`);
48
49
  }
49
50
  const system = new softwareSystem_1.SoftwareSystem(name, definition);
50
51
  this.softwareSystems.set(name, system);
51
52
  return system;
52
53
  }
54
+ // TODO:Should be a Group<SoftwareSystem | Person> if that is added back in
53
55
  addGroup(groupName) {
54
56
  let group = this.groups.get(groupName);
55
57
  if (!group) {
@@ -58,46 +60,15 @@ class Model {
58
60
  }
59
61
  return group;
60
62
  }
61
- referenceSoftwareSystem(name) {
62
- let system = this.referencedSoftwareSystems.get(name);
63
- if (!system) {
64
- system = new softwareSystem_1.ReferencedSoftwareSystem(name);
65
- this.referencedSoftwareSystems.set(name, system);
66
- }
67
- return system;
68
- }
69
63
  definePerson(name, definition) {
70
64
  if (this.people.has(name)) {
71
- throw Error(`A Person named '${name}' is defined elsewhere in this Model. A Person can be defined only once, but can be referenced multiple times.`);
65
+ throw Error(`A Person named '${name}' is defined elsewhere in this Model. A Person can be defined only once.`);
72
66
  }
73
67
  const person = new person_1.Person(name, definition);
74
68
  this.people.set(name, person);
75
69
  return person;
76
70
  }
77
- referencePerson(name) {
78
- let person = this.referencedPeople.get(name);
79
- if (!person) {
80
- person = new person_1.ReferencedPerson(name);
81
- this.referencedPeople.set(name, person);
82
- }
83
- return person;
84
- }
85
- validate() {
86
- const undefinedSoftwareSystems = Array.from(this.referencedSoftwareSystems.keys()).filter(name => !this.softwareSystems.has(name));
87
- if (undefinedSoftwareSystems.length > 0) {
88
- throw Error(`SoftwareSystems named '${undefinedSoftwareSystems.join("', '")}' are referenced but not defined.`);
89
- }
90
- const undefinedPeople = Array.from(this.referencedPeople.keys()).filter(name => !this.people.has(name));
91
- if (undefinedPeople.length > 0) {
92
- throw Error(`People named '${undefinedPeople.join("', '")}' are referenced but not defined.`);
93
- }
94
- const definedElements = Array.from(this.softwareSystems.values()).flatMap(system => system.getChildElementNames());
95
- const referencedElements = Array.from(this.referencedSoftwareSystems.values()).flatMap(system => system.getChildElementNames());
96
- const undefinedElements = referencedElements.filter(name => !definedElements.includes(name));
97
- if (undefinedElements.length > 0) {
98
- throw Error(`Elements named '${undefinedElements.join("', '")}' are referenced but not defined.`);
99
- }
100
- }
71
+ validate() { }
101
72
  getPeople() {
102
73
  return Array.from(this.people.values());
103
74
  }
@@ -105,39 +76,53 @@ class Model {
105
76
  return Array.from(this.softwareSystems.values());
106
77
  }
107
78
  getPeopleNotInGroups() {
108
- const peopleInGroups = Array.from(this.groups.values()).flatMap(group => group.getPeople());
109
- return Array.from(this.people.values()).filter(person => !peopleInGroups.includes(person));
79
+ const peopleInGroups = Array.from(this.groups.values()).flatMap((group) => group.getPeople());
80
+ return Array.from(this.people.values()).filter((person) => !peopleInGroups.includes(person));
110
81
  }
111
82
  getSoftwareSystemsNotInGroups() {
112
- const systemsInGroups = Array.from(this.groups.values()).flatMap(group => group.getSoftwareSystems());
113
- return Array.from(this.softwareSystems.values()).filter(system => !systemsInGroups.includes(system));
83
+ const systemsInGroups = Array.from(this.groups.values()).flatMap((group) => group.getSoftwareSystems());
84
+ return Array.from(this.softwareSystems.values()).filter((system) => !systemsInGroups.includes(system));
114
85
  }
115
86
  getGroups() {
116
87
  return Array.from(this.groups.values());
117
88
  }
118
89
  }
119
90
  exports.Model = Model;
120
- function buildModel(modelName, globPath = 'c4.dsl.ts') {
121
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
91
+ function buildModelWithCatalog() {
92
+ return tslib_1.__awaiter(this, arguments, void 0, function* (options = {}) {
93
+ const { modelName = 'model', globPath = 'c4.dsl.ts', searchRoot = __dirname } = options;
122
94
  const model = new Model(modelName);
123
- const result = yield (0, glob_1.glob)(`**/${globPath}`, { cwd: __dirname });
95
+ const result = yield (0, glob_1.glob)(`**/${globPath}`, { cwd: searchRoot });
124
96
  if (result.length === 0) {
125
97
  throw new Error(`No ${globPath} files found`);
126
98
  }
127
- for (const file of result) {
128
- const moduleFile = (0, path_1.join)(__dirname, file);
129
- console.log(`Accumulating model from ${moduleFile}`);
130
- const module = yield Promise.resolve(`${moduleFile}`).then(s => require(s));
131
- if (typeof module.buildModel === 'function') {
132
- module.buildModel(model);
133
- }
134
- else {
135
- console.log(`${file} does not contain the method 'buildModel'`);
99
+ const modules = yield Promise.all(result.map((file) => Promise.resolve(`${(0, path_1.join)(searchRoot, file)}`).then(s => require(s))));
100
+ const registrations = [];
101
+ const rootCatalog = {};
102
+ // Phase 1: each module registers its own definitions; results are nested under the module's key
103
+ for (const module of modules) {
104
+ if (!module.c4Module) {
105
+ continue;
136
106
  }
107
+ const instance = module.c4Module;
108
+ const local = instance.registerDefinitions(model);
109
+ rootCatalog[instance.key] = local;
110
+ registrations.push({ instance, key: instance.key, local });
111
+ }
112
+ if (registrations.length === 0) {
113
+ throw new Error(`No c4Module exports found in any ${globPath} files`);
137
114
  }
138
- model.validate();
139
- return model;
115
+ // Phase 2: each module receives its own slice (local) and every other module's slice (dependencies) to build relationships
116
+ for (const { instance, key, local } of registrations) {
117
+ const dependencies = Object.fromEntries(Object.entries(rootCatalog).filter(([k]) => k !== key));
118
+ instance.buildRelationships(local, dependencies);
119
+ }
120
+ return { model, catalog: rootCatalog };
121
+ });
122
+ }
123
+ function buildModel() {
124
+ return tslib_1.__awaiter(this, arguments, void 0, function* (options = {}) {
125
+ return (yield buildModelWithCatalog(options)).model;
140
126
  });
141
127
  }
142
- exports.buildModel = buildModel;
143
128
  //# sourceMappingURL=model.js.map