@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.
- package/CLAUDE.md +45 -0
- package/package.json +7 -3
- package/src/component.d.ts +7 -0
- package/src/{lib/component.js → component.js} +2 -5
- package/src/component.js.map +1 -0
- package/src/{lib/container.d.ts → container.d.ts} +4 -8
- package/src/{lib/container.js → container.js} +6 -12
- package/src/container.js.map +1 -0
- package/src/core.d.ts +36 -0
- package/src/{lib/core.js → core.js} +7 -36
- package/src/core.js.map +1 -0
- package/src/generateDiagrams.d.ts +7 -0
- package/src/generateDiagrams.js +55 -0
- package/src/generateDiagrams.js.map +1 -0
- package/src/index.d.ts +8 -3
- package/src/index.js +8 -3
- package/src/index.js.map +1 -1
- package/src/{lib/model.d.ts → model.d.ts} +23 -9
- package/src/{lib/model.js → model.js} +41 -56
- package/src/model.js.map +1 -0
- package/src/person.d.ts +7 -0
- package/src/person.js +15 -0
- package/src/person.js.map +1 -0
- package/src/{lib/softwareSystem.d.ts → softwareSystem.d.ts} +4 -8
- package/src/{lib/softwareSystem.js → softwareSystem.js} +4 -10
- package/src/softwareSystem.js.map +1 -0
- package/src/{lib/structurizrDslWriter.d.ts → structurizrDslWriter.d.ts} +1 -1
- package/src/{lib/structurizrDslWriter.js → structurizrDslWriter.js} +41 -42
- package/src/structurizrDslWriter.js.map +1 -0
- package/src/{lib/views.js → views.js} +2 -2
- package/src/views.js.map +1 -0
- package/src/lib/component.d.ts +0 -10
- package/src/lib/component.js.map +0 -1
- package/src/lib/container.js.map +0 -1
- package/src/lib/core.d.ts +0 -51
- package/src/lib/core.js.map +0 -1
- package/src/lib/model.js.map +0 -1
- package/src/lib/person.d.ts +0 -11
- package/src/lib/person.js +0 -24
- package/src/lib/person.js.map +0 -1
- package/src/lib/softwareSystem.js.map +0 -1
- package/src/lib/structurizrDslWriter.js.map +0 -1
- package/src/lib/tests/system1/c4.dsl.d.ts +0 -2
- package/src/lib/tests/system1/c4.dsl.js +0 -9
- package/src/lib/tests/system1/c4.dsl.js.map +0 -1
- package/src/lib/tests/system2/c4.dsl.d.ts +0 -2
- package/src/lib/tests/system2/c4.dsl.js +0 -9
- package/src/lib/tests/system2/c4.dsl.js.map +0 -1
- package/src/lib/views.js.map +0 -1
- /package/{dist/libs/c4-model/libs/c4-model/README.md → README.md} +0 -0
- /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
|
|
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.
|
|
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, [
|
|
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,
|
|
2
|
-
import { Component, ComponentDefinition
|
|
3
|
-
export
|
|
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
|
|
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.
|
|
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, [
|
|
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
|
|
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.
|
|
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([
|
|
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
|
|
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([
|
|
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
|
package/src/core.js.map
ADDED
|
@@ -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":"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"}
|
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
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("./
|
|
5
|
-
tslib_1.__exportStar(require("./
|
|
6
|
-
tslib_1.__exportStar(require("./
|
|
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,
|
|
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 {
|
|
3
|
-
import { Person, PersonDefinition
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
121
|
-
return tslib_1.__awaiter(this,
|
|
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:
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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
|