@alistigo/calm-to-archify 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/cli/commands/build.js +6 -6
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/transform.js +5 -5
- package/dist/cli/commands/transform.js.map +1 -1
- package/dist/cli/commands/watch.d.ts +9 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/commands/watch.js +52 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/lib/calm-to-archify.d.ts +10 -0
- package/dist/cli/lib/calm-to-archify.d.ts.map +1 -1
- package/dist/cli/lib/calm-to-archify.js +194 -7
- package/dist/cli/lib/calm-to-archify.js.map +1 -1
- package/dist/cli/lib/layout.d.ts +4 -1
- package/dist/cli/lib/layout.d.ts.map +1 -1
- package/dist/cli/lib/layout.js +14 -12
- package/dist/cli/lib/layout.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/package.json +7 -1
- package/dist/schemas/index.d.ts +66 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +60 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/x-archify-metadata.schema.json +61 -0
- package/docs/archify-diagram-types.md +83 -0
- package/docs/x-archify-metadata.md +137 -0
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -66,6 +66,34 @@ calm-to-archify transform path/to/my.arch.json --output path/to/output.archify.j
|
|
|
66
66
|
|
|
67
67
|
Accepts CALM architecture instances — files that contain `nodes` and `relationships` at the top level. Pattern files (`.pattern.json`) are JSON Schema documents and are not supported.
|
|
68
68
|
|
|
69
|
+
## Customising node-type colors and legend labels
|
|
70
|
+
|
|
71
|
+
If your CALM documents use custom node-types (from a CALM extension), add an `x-archify` entry to the document's `metadata` array to control how each type is rendered:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"metadata": [
|
|
76
|
+
{
|
|
77
|
+
"x-archify": {
|
|
78
|
+
"node-types": {
|
|
79
|
+
"module": { "component-type": "backend", "legend-label": "Module" },
|
|
80
|
+
"plugin": { "component-type": "external", "legend-label": "Plugin" },
|
|
81
|
+
"skill": { "component-type": "cloud", "legend-label": "Skill" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See [docs/x-archify-metadata.md](docs/x-archify-metadata.md) for the full reference — available component types, legend label overrides, node `sublabel` and `tag` mapping, fallback behaviour, and the exported TypeScript types and JSON Schema.
|
|
90
|
+
|
|
91
|
+
## Diagram types and 1→N output
|
|
92
|
+
|
|
93
|
+
archify supports 5 diagram types: `architecture`, `workflow`, `sequence`, `dataflow`, and `lifecycle`. `calm-to-archify` currently produces only `architecture` diagrams (1→1 mapping). Support for deriving additional diagram types (flows, lifecycles) from the same CALM file — producing multiple HTML outputs — is planned.
|
|
94
|
+
|
|
95
|
+
See [docs/archify-diagram-types.md](docs/archify-diagram-types.md) for the full reference: all supported types, the planned 1→N output naming convention, and click panel customisation via `sources`.
|
|
96
|
+
|
|
69
97
|
## About CALM
|
|
70
98
|
|
|
71
99
|
[CALM (Common Architecture Language Model)](https://calm.finos.org/) is an open standard from [FINOS](https://www.finos.org/) for describing software architectures as machine-readable JSON. It lets you capture nodes (services, datastores, people) and the relationships between them in a way that can be validated, queried, and visualised automatically.
|
|
@@ -12,23 +12,23 @@ function resolveArchifyRenderBin() {
|
|
|
12
12
|
export class BuildCommand extends Command {
|
|
13
13
|
static paths = [Command.Default, ["build"]];
|
|
14
14
|
static usage = Command.Usage({
|
|
15
|
-
description: "Run the full CALM → archify HTML pipeline for one or more .arch.json files",
|
|
15
|
+
description: "Run the full CALM → archify HTML pipeline for one or more .arch.calm.json files",
|
|
16
16
|
details: `
|
|
17
|
-
Reads each CALM .arch.json file, transforms it to archify JSON-IR, then
|
|
17
|
+
Reads each CALM .arch.calm.json file, transforms it to archify JSON-IR, then
|
|
18
18
|
renders a standalone interactive HTML file using the archify renderer.
|
|
19
19
|
|
|
20
20
|
By default each output is written next to its source file.
|
|
21
21
|
Use --output-dir to redirect all outputs to a specific directory.
|
|
22
22
|
|
|
23
23
|
Pattern files (.pattern.json) are JSON Schema documents and are not
|
|
24
|
-
supported — only CALM architecture instances (.arch.json) are accepted.
|
|
24
|
+
supported — only CALM architecture instances (.arch.calm.json) are accepted.
|
|
25
25
|
`,
|
|
26
26
|
examples: [
|
|
27
|
-
["Process all architecture files", "calm-to-archify build systems/*.arch.json"],
|
|
28
|
-
["Process a single file", "calm-to-archify build path/to/my.arch.json"],
|
|
27
|
+
["Process all architecture files", "calm-to-archify build systems/*.arch.calm.json"],
|
|
28
|
+
["Process a single file", "calm-to-archify build path/to/my.arch.calm.json"],
|
|
29
29
|
[
|
|
30
30
|
"Output to a specific directory",
|
|
31
|
-
"calm-to-archify build systems/*.arch.json --output-dir .archify-out",
|
|
31
|
+
"calm-to-archify build systems/*.arch.calm.json --output-dir .archify-out",
|
|
32
32
|
],
|
|
33
33
|
],
|
|
34
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAqB,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,SAAS,uBAAuB;IAC9B,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,OAAO,YAAa,SAAQ,OAAO;IACvC,MAAM,CAAU,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAErD,MAAM,CAAU,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACpC,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,21 +7,21 @@ export class TransformCommand extends Command {
|
|
|
7
7
|
static usage = Command.Usage({
|
|
8
8
|
description: "Transform a CALM architecture JSON file into archify diagram JSON",
|
|
9
9
|
details: `
|
|
10
|
-
Reads a CALM .arch.json file and produces an archify JSON-IR file
|
|
10
|
+
Reads a CALM .arch.calm.json file and produces an archify JSON-IR file
|
|
11
11
|
that can be rendered to interactive HTML using archify-render or
|
|
12
12
|
'archify render architecture'.
|
|
13
13
|
|
|
14
14
|
Pattern files (.pattern.json) are JSON Schema documents and are not
|
|
15
|
-
supported — only CALM architecture instances (.arch.json) are accepted.
|
|
15
|
+
supported — only CALM architecture instances (.arch.calm.json) are accepted.
|
|
16
16
|
`,
|
|
17
17
|
examples: [
|
|
18
18
|
[
|
|
19
|
-
"Transform typical-alistigo-artifact.arch.json",
|
|
20
|
-
"calm-to-archify systems/typical-alistigo-artifact.arch.json --output .archify-out/typical-alistigo-artifact.archify.json",
|
|
19
|
+
"Transform typical-alistigo-artifact.arch.calm.json",
|
|
20
|
+
"calm-to-archify systems/typical-alistigo-artifact.arch.calm.json --output .archify-out/typical-alistigo-artifact.archify.json",
|
|
21
21
|
],
|
|
22
22
|
[
|
|
23
23
|
"Transform with explicit output path",
|
|
24
|
-
"calm-to-archify path/to/my.arch.json --output path/to/output.archify.json",
|
|
24
|
+
"calm-to-archify path/to/my.arch.calm.json --output path/to/output.archify.json",
|
|
25
25
|
],
|
|
26
26
|
],
|
|
27
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/cli/commands/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAqB,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,MAAM,OAAO,gBAAiB,SAAQ,OAAO;IAC3C,MAAM,CAAU,KAAK,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAExC,MAAM,CAAU,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACpC,WAAW,EAAE,mEAAmE;QAChF,OAAO,EAAE;;;;;;;KAOR;QACD,QAAQ,EAAE;YACR;gBACE,+
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/cli/commands/transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "clipanion";
|
|
2
|
+
export declare class WatchCommand extends Command {
|
|
3
|
+
static paths: string[][];
|
|
4
|
+
static usage: import("clipanion").Usage;
|
|
5
|
+
inputFiles: string[];
|
|
6
|
+
outputDir: string | undefined;
|
|
7
|
+
execute(): Promise<number>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/watch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAE5C,qBAAa,YAAa,SAAQ,OAAO;IACvC,OAAgB,KAAK,aAAe;IAEpC,OAAgB,KAAK,4BAUlB;IAEH,UAAU,WAA+C;IAEzD,SAAS,qBAGN;IAEG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CA6BjC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync, watch } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Command, Option } from "clipanion";
|
|
4
|
+
export class WatchCommand extends Command {
|
|
5
|
+
static paths = [["watch"]];
|
|
6
|
+
static usage = Command.Usage({
|
|
7
|
+
description: "Watch .arch.calm.json files and rebuild on change.",
|
|
8
|
+
details: `
|
|
9
|
+
Runs an initial build of all specified files, then watches their parent
|
|
10
|
+
directories for changes. Any .arch.calm.json file that is modified triggers
|
|
11
|
+
a single-file rebuild via the build command.
|
|
12
|
+
|
|
13
|
+
Intended for development — keeps running until interrupted (Ctrl+C).
|
|
14
|
+
`,
|
|
15
|
+
examples: [["Watch all architecture files", "calm-to-archify watch systems/*.arch.calm.json"]],
|
|
16
|
+
});
|
|
17
|
+
inputFiles = Option.Rest({ required: 1, name: "files" });
|
|
18
|
+
outputDir = Option.String("--output-dir,-o", {
|
|
19
|
+
description: "Output directory (default: same directory as each input file)",
|
|
20
|
+
required: false,
|
|
21
|
+
});
|
|
22
|
+
async execute() {
|
|
23
|
+
// Initial build
|
|
24
|
+
const buildArgs = ["build", ...this.inputFiles];
|
|
25
|
+
if (this.outputDir)
|
|
26
|
+
buildArgs.push("--output-dir", this.outputDir);
|
|
27
|
+
const initialResult = await this.cli.run(buildArgs);
|
|
28
|
+
if (initialResult !== 0) {
|
|
29
|
+
this.context.stderr.write("Initial build failed — watching anyway.\n");
|
|
30
|
+
}
|
|
31
|
+
this.context.stdout.write("Watching for changes… (Ctrl+C to stop)\n");
|
|
32
|
+
// Unique parent directories of all input files
|
|
33
|
+
const dirs = new Set(this.inputFiles.map((f) => path.dirname(path.resolve(f))));
|
|
34
|
+
for (const dir of dirs) {
|
|
35
|
+
watch(dir, (_, filename) => {
|
|
36
|
+
if (!filename?.endsWith(".arch.calm.json"))
|
|
37
|
+
return;
|
|
38
|
+
const filePath = path.join(dir, filename);
|
|
39
|
+
if (!existsSync(filePath))
|
|
40
|
+
return;
|
|
41
|
+
this.context.stdout.write(`[watch] ${filename} changed, rebuilding…\n`);
|
|
42
|
+
const args = ["build", filePath];
|
|
43
|
+
if (this.outputDir)
|
|
44
|
+
args.push("--output-dir", this.outputDir);
|
|
45
|
+
void this.cli.run(args);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
await new Promise(() => { }); // keep alive until Ctrl+C
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/cli/commands/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,OAAO,YAAa,SAAQ,OAAO;IACvC,MAAM,CAAU,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpC,MAAM,CAAU,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACpC,WAAW,EAAE,oDAAoD;QACjE,OAAO,EAAE;;;;;;KAMR;QACD,QAAQ,EAAE,CAAC,CAAC,8BAA8B,EAAE,gDAAgD,CAAC,CAAC;KAC/F,CAAC,CAAC;IAEH,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAEzD,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE;QAC3C,WAAW,EAAE,+DAA+D;QAC5E,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,KAAK,CAAC,OAAO;QACX,gBAAgB;QAChB,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,SAAS;YAAE,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACnE,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAEtE,+CAA+C;QAC/C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE;gBACzB,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC;oBAAE,OAAO;gBACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,OAAO;gBAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,QAAQ,yBAAyB,CAAC,CAAC;gBACxE,MAAM,IAAI,GAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAC3C,IAAI,IAAI,CAAC,SAAS;oBAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,0BAA0B;QAC7D,OAAO,CAAC,CAAC;IACX,CAAC"}
|
|
@@ -3,6 +3,7 @@ export interface CalmNode {
|
|
|
3
3
|
"node-type": string;
|
|
4
4
|
name: string;
|
|
5
5
|
description?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
6
7
|
}
|
|
7
8
|
export interface CalmRelationship {
|
|
8
9
|
"unique-id": string;
|
|
@@ -37,6 +38,7 @@ export interface CalmDocument {
|
|
|
37
38
|
"unique-id": string;
|
|
38
39
|
name: string;
|
|
39
40
|
description?: string;
|
|
41
|
+
metadata?: Array<Record<string, unknown>>;
|
|
40
42
|
nodes: CalmNode[];
|
|
41
43
|
relationships: CalmRelationship[];
|
|
42
44
|
}
|
|
@@ -44,6 +46,8 @@ export interface ArchifyComponent {
|
|
|
44
46
|
id: string;
|
|
45
47
|
type: string;
|
|
46
48
|
label: string;
|
|
49
|
+
sublabel?: string;
|
|
50
|
+
tag?: string;
|
|
47
51
|
pos: [number, number];
|
|
48
52
|
size: [number, number];
|
|
49
53
|
}
|
|
@@ -56,6 +60,7 @@ export interface ArchifyConnection {
|
|
|
56
60
|
id: string;
|
|
57
61
|
from: string;
|
|
58
62
|
to: string;
|
|
63
|
+
via?: [number, number][];
|
|
59
64
|
}
|
|
60
65
|
export interface ArchifyDocument {
|
|
61
66
|
schema_version: 1;
|
|
@@ -64,6 +69,11 @@ export interface ArchifyDocument {
|
|
|
64
69
|
title: string;
|
|
65
70
|
subtitle?: string;
|
|
66
71
|
output: string;
|
|
72
|
+
legend?: {
|
|
73
|
+
entries: Record<string, {
|
|
74
|
+
label: string;
|
|
75
|
+
}>;
|
|
76
|
+
};
|
|
67
77
|
};
|
|
68
78
|
components: ArchifyComponent[];
|
|
69
79
|
boundaries: ArchifyBoundary[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calm-to-archify.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/calm-to-archify.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"calm-to-archify.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/calm-to-archify.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,EACf;QAAE,aAAa,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,GACzD;QAAE,aAAa,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,GACzD;QAAE,QAAQ,EAAE;YAAE,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,WAAW,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,GACzE;QAAE,SAAS,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,CAAC,CAAC;IAClB,YAAY,EAAE,cAAc,CAAC;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;gBAAE,KAAK,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC;KACzD,CAAC;IACF,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,WAAW,EAAE,iBAAiB,EAAE,CAAC;CAClC;AAmKD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,eAAe,CA+L9F"}
|
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { computeLayout } from "./layout.js";
|
|
3
3
|
// fallow-ignore-next-line complexity
|
|
4
|
-
function
|
|
4
|
+
function extractArchifyNodeTypes(calm) {
|
|
5
|
+
const map = new Map();
|
|
6
|
+
if (!calm.metadata)
|
|
7
|
+
return map;
|
|
8
|
+
for (const entry of calm.metadata) {
|
|
9
|
+
const archify = entry["x-archify"];
|
|
10
|
+
if (!archify || typeof archify !== "object")
|
|
11
|
+
continue;
|
|
12
|
+
const nodeTypes = archify["node-types"];
|
|
13
|
+
if (!nodeTypes || typeof nodeTypes !== "object")
|
|
14
|
+
continue;
|
|
15
|
+
for (const [type, hint] of Object.entries(nodeTypes)) {
|
|
16
|
+
if (hint && typeof hint === "object")
|
|
17
|
+
map.set(type, hint);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
// fallow-ignore-next-line complexity
|
|
23
|
+
function mapNodeType(nodeType, name, hintMap) {
|
|
24
|
+
const hint = hintMap.get(nodeType);
|
|
25
|
+
if (hint)
|
|
26
|
+
return hint["component-type"];
|
|
5
27
|
const lower = name.toLowerCase();
|
|
6
28
|
switch (nodeType) {
|
|
7
29
|
case "actor":
|
|
@@ -36,10 +58,114 @@ function firstSentence(text) {
|
|
|
36
58
|
return text.length <= maxLen ? text : `${text.slice(0, maxLen - 1)}…`;
|
|
37
59
|
return text.slice(0, dot + 1);
|
|
38
60
|
}
|
|
61
|
+
// Node types whose nodes are pure visual grouping containers — rendered only as boundary
|
|
62
|
+
// regions, not as individual component boxes. Add new group node-types here as needed.
|
|
63
|
+
const GROUP_NODE_TYPES = new Set(["group"]);
|
|
64
|
+
// Kahn's topological layering: nodes whose predecessors are all in earlier layers
|
|
65
|
+
// share a row. Respects the original declaration order within each layer for stability.
|
|
66
|
+
// fallow-ignore-next-line complexity
|
|
67
|
+
function topoLayers(nodes, edges) {
|
|
68
|
+
const inDegree = new Map(nodes.map((n) => [n, 0]));
|
|
69
|
+
const adj = new Map(nodes.map((n) => [n, []]));
|
|
70
|
+
for (const { source, destination } of edges) {
|
|
71
|
+
inDegree.set(destination, (inDegree.get(destination) ?? 0) + 1);
|
|
72
|
+
adj.get(source).push(destination);
|
|
73
|
+
}
|
|
74
|
+
const layers = [];
|
|
75
|
+
let current = nodes.filter((n) => (inDegree.get(n) ?? 0) === 0);
|
|
76
|
+
while (current.length > 0) {
|
|
77
|
+
layers.push(current);
|
|
78
|
+
const next = [];
|
|
79
|
+
for (const node of current) {
|
|
80
|
+
for (const neighbor of adj.get(node) ?? []) {
|
|
81
|
+
const d = (inDegree.get(neighbor) ?? 1) - 1;
|
|
82
|
+
inDegree.set(neighbor, d);
|
|
83
|
+
if (d === 0)
|
|
84
|
+
next.push(neighbor);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
current = next;
|
|
88
|
+
}
|
|
89
|
+
return layers;
|
|
90
|
+
}
|
|
91
|
+
// fallow-ignore-next-line complexity
|
|
92
|
+
function computeGroupLayers(members, allConnections) {
|
|
93
|
+
const memberSet = new Set(members);
|
|
94
|
+
const internalEdges = allConnections.filter((c) => memberSet.has(c.source) && memberSet.has(c.destination));
|
|
95
|
+
// Entry nodes: group members that receive a connection from outside the group
|
|
96
|
+
const entryNodes = new Set(allConnections
|
|
97
|
+
.filter((c) => !memberSet.has(c.source) && memberSet.has(c.destination))
|
|
98
|
+
.map((c) => c.destination));
|
|
99
|
+
// Reversed adjacency: dest → [nodes that depend on dest]
|
|
100
|
+
const reversedAdj = new Map(members.map((m) => [m, []]));
|
|
101
|
+
for (const { source, destination } of internalEdges) {
|
|
102
|
+
reversedAdj.get(destination).push(source);
|
|
103
|
+
}
|
|
104
|
+
// BFS from entry nodes using reversed edges (places nodes with many dependents near the top)
|
|
105
|
+
const layerOf = new Map();
|
|
106
|
+
if (entryNodes.size > 0) {
|
|
107
|
+
const queue = [...entryNodes].map((n) => [n, 0]);
|
|
108
|
+
for (const [n, l] of queue)
|
|
109
|
+
layerOf.set(n, l);
|
|
110
|
+
while (queue.length > 0) {
|
|
111
|
+
const [id, layer] = queue.shift();
|
|
112
|
+
for (const neighbor of reversedAdj.get(id) ?? []) {
|
|
113
|
+
if (!layerOf.has(neighbor)) {
|
|
114
|
+
layerOf.set(neighbor, layer + 1);
|
|
115
|
+
queue.push([neighbor, layer + 1]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Topological sub-layers for nodes unreached by the reversed BFS
|
|
121
|
+
const unreached = members.filter((m) => !layerOf.has(m));
|
|
122
|
+
if (unreached.length > 0) {
|
|
123
|
+
const unreachedSet = new Set(unreached);
|
|
124
|
+
const subEdges = internalEdges.filter((e) => unreachedSet.has(e.source) && unreachedSet.has(e.destination));
|
|
125
|
+
const subLayers = topoLayers(unreached, subEdges);
|
|
126
|
+
const baseLayer = layerOf.size > 0 ? Math.max(...layerOf.values()) + 1 : 0;
|
|
127
|
+
for (let i = 0; i < subLayers.length; i++) {
|
|
128
|
+
for (const node of subLayers[i] ?? [])
|
|
129
|
+
layerOf.set(node, baseLayer + i);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const rows = new Map();
|
|
133
|
+
for (const [node, layer] of layerOf) {
|
|
134
|
+
if (!rows.has(layer))
|
|
135
|
+
rows.set(layer, []);
|
|
136
|
+
rows.get(layer).push(node);
|
|
137
|
+
}
|
|
138
|
+
if (rows.size === 0)
|
|
139
|
+
return [members];
|
|
140
|
+
const maxIdx = Math.max(...rows.keys());
|
|
141
|
+
return Array.from({ length: maxIdx + 1 }, (_, i) => rows.get(i) ?? []);
|
|
142
|
+
}
|
|
39
143
|
// fallow-ignore-next-line complexity
|
|
40
144
|
export function transformCalmToArchify(calm, outputPath) {
|
|
145
|
+
const hintMap = extractArchifyNodeTypes(calm);
|
|
146
|
+
const groupNodeIds = new Set(calm.nodes.filter((n) => GROUP_NODE_TYPES.has(n["node-type"])).map((n) => n["unique-id"]));
|
|
41
147
|
const nodeIds = calm.nodes.map((n) => n["unique-id"]);
|
|
42
|
-
|
|
148
|
+
// Pre-collect all connects edges for topology-aware group layer computation
|
|
149
|
+
const allConnections = calm.relationships.flatMap((rel) => {
|
|
150
|
+
const rt = rel["relationship-type"];
|
|
151
|
+
if ("connects" in rt) {
|
|
152
|
+
return [{ source: rt.connects.source.node, destination: rt.connects.destination.node }];
|
|
153
|
+
}
|
|
154
|
+
return [];
|
|
155
|
+
});
|
|
156
|
+
// Pre-pass: record direct component members of each group node for boundary expansion
|
|
157
|
+
const groupComponents = new Map();
|
|
158
|
+
for (const rel of calm.relationships) {
|
|
159
|
+
const rt = rel["relationship-type"];
|
|
160
|
+
if ("composed-of" in rt) {
|
|
161
|
+
const { container, nodes: children } = rt["composed-of"];
|
|
162
|
+
if (groupNodeIds.has(container)) {
|
|
163
|
+
groupComponents.set(container, children.filter((id) => !groupNodeIds.has(id)));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const expandGroups = (ids) => ids.flatMap((id) => (groupNodeIds.has(id) ? (groupComponents.get(id) ?? []) : [id]));
|
|
168
|
+
const composedGroups = [];
|
|
43
169
|
const deployedInSets = [];
|
|
44
170
|
const boundaries = [];
|
|
45
171
|
const connections = [];
|
|
@@ -59,8 +185,11 @@ export function transformCalmToArchify(calm, outputPath) {
|
|
|
59
185
|
const { container, nodes: children } = rt["composed-of"];
|
|
60
186
|
const containerNode = calm.nodes.find((n) => n["unique-id"] === container);
|
|
61
187
|
const label = containerNode?.name ?? container;
|
|
62
|
-
|
|
63
|
-
|
|
188
|
+
const componentChildren = expandGroups(children);
|
|
189
|
+
const directChildren = children.filter((id) => !groupNodeIds.has(id));
|
|
190
|
+
const layers = computeGroupLayers(directChildren, allConnections);
|
|
191
|
+
composedGroups.push({ layout: { layers }, expandedCount: componentChildren.length });
|
|
192
|
+
boundaries.push({ kind: "region", label, wraps: componentChildren });
|
|
64
193
|
continue;
|
|
65
194
|
}
|
|
66
195
|
if ("deployed-in" in rt) {
|
|
@@ -91,23 +220,80 @@ export function transformCalmToArchify(calm, outputPath) {
|
|
|
91
220
|
}
|
|
92
221
|
}
|
|
93
222
|
}
|
|
223
|
+
// Largest (outermost) groups first — use expanded count so nesting order is correct
|
|
224
|
+
// even when a nested group has more direct children than its parent.
|
|
225
|
+
composedGroups.sort((a, b) => b.expandedCount - a.expandedCount);
|
|
226
|
+
const composedOfSets = composedGroups.map((g) => g.layout);
|
|
94
227
|
const layoutInput = {
|
|
95
|
-
nodeIds,
|
|
228
|
+
nodeIds: nodeIds.filter((id) => !groupNodeIds.has(id)),
|
|
96
229
|
composedOfSets,
|
|
97
230
|
deployedInSets,
|
|
98
231
|
};
|
|
99
232
|
const positions = computeLayout(layoutInput);
|
|
100
|
-
|
|
233
|
+
// For cross-column connections spanning 3+ rows the auto-router creates an S-shaped path
|
|
234
|
+
// that cuts through intermediate nodes. Route these via the right outer margin instead,
|
|
235
|
+
// approaching the destination through the row gap above/below it to avoid same-row siblings.
|
|
236
|
+
const VIA_X = 590; // outside the 2-column grid (rightmost component edge = 310+240 = 550)
|
|
237
|
+
const COMP_H = 55;
|
|
238
|
+
const ROW_GAP = 40;
|
|
239
|
+
const ROW_HEIGHT = COMP_H + ROW_GAP;
|
|
240
|
+
const COL_BOUNDARY = 290; // midpoint between col0 right-edge(270) and col1 left-edge(310)
|
|
241
|
+
for (const conn of connections) {
|
|
242
|
+
const src = positions.get(conn.from);
|
|
243
|
+
const dst = positions.get(conn.to);
|
|
244
|
+
if (!src || !dst)
|
|
245
|
+
continue;
|
|
246
|
+
const srcCol = src.x > COL_BOUNDARY ? 1 : 0;
|
|
247
|
+
const dstCol = dst.x > COL_BOUNDARY ? 1 : 0;
|
|
248
|
+
// Only col1→col0 connections need the right-margin detour; col0→col1 routes cleanly
|
|
249
|
+
// through the inter-column gap at x≈290 and adding via there would cross same-row col1 nodes.
|
|
250
|
+
if (srcCol !== 1 || dstCol !== 0)
|
|
251
|
+
continue;
|
|
252
|
+
const srcCenterY = src.y + src.h / 2;
|
|
253
|
+
const dstCenterY = dst.y + dst.h / 2;
|
|
254
|
+
if (Math.abs(srcCenterY - dstCenterY) > 3 * ROW_HEIGHT) {
|
|
255
|
+
const dstCenterX = dst.x + dst.w / 2;
|
|
256
|
+
// Approach the destination through the row gap to avoid its same-row sibling in the other column
|
|
257
|
+
const gapY = dstCenterY > srcCenterY
|
|
258
|
+
? dst.y - ROW_GAP / 2 // dest below: enter gap above dest row
|
|
259
|
+
: dst.y + dst.h + ROW_GAP / 2; // dest above: enter gap below dest row
|
|
260
|
+
conn.via = [
|
|
261
|
+
[VIA_X, srcCenterY],
|
|
262
|
+
[VIA_X, gapY],
|
|
263
|
+
[dstCenterX, gapY],
|
|
264
|
+
];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const components = calm.nodes
|
|
268
|
+
.filter((node) => !groupNodeIds.has(node["unique-id"]))
|
|
269
|
+
// fallow-ignore-next-line complexity
|
|
270
|
+
.map((node) => {
|
|
101
271
|
const pos = positions.get(node["unique-id"]) ?? { x: 0, y: 0, w: 140, h: 55 };
|
|
272
|
+
const hint = hintMap.get(node["node-type"]);
|
|
273
|
+
const sublabel = hint?.["sublabel"] && typeof node[hint["sublabel"]] === "string"
|
|
274
|
+
? node[hint["sublabel"]]
|
|
275
|
+
: undefined;
|
|
276
|
+
const tag = hint?.["tag"] && typeof node[hint["tag"]] === "string"
|
|
277
|
+
? node[hint["tag"]]
|
|
278
|
+
: undefined;
|
|
102
279
|
return {
|
|
103
280
|
id: node["unique-id"],
|
|
104
|
-
type: mapNodeType(node["node-type"], node.name),
|
|
281
|
+
type: mapNodeType(node["node-type"], node.name, hintMap),
|
|
105
282
|
label: node.name,
|
|
283
|
+
...(sublabel && { sublabel }),
|
|
284
|
+
...(tag && { tag }),
|
|
106
285
|
pos: [pos.x, pos.y],
|
|
107
286
|
size: [pos.w, pos.h],
|
|
108
287
|
};
|
|
109
288
|
});
|
|
110
289
|
const subtitle = calm.description ? firstSentence(calm.description) : undefined;
|
|
290
|
+
const legendOverrides = {};
|
|
291
|
+
for (const node of calm.nodes.filter((n) => !groupNodeIds.has(n["unique-id"]))) {
|
|
292
|
+
const hint = hintMap.get(node["node-type"]);
|
|
293
|
+
if (hint?.["legend-label"]) {
|
|
294
|
+
legendOverrides[hint["component-type"]] = { label: hint["legend-label"] };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
111
297
|
return {
|
|
112
298
|
schema_version: 1,
|
|
113
299
|
diagram_type: "architecture",
|
|
@@ -115,6 +301,7 @@ export function transformCalmToArchify(calm, outputPath) {
|
|
|
115
301
|
title: calm.name,
|
|
116
302
|
...(subtitle && { subtitle }),
|
|
117
303
|
output: path.isAbsolute(outputPath) ? outputPath : outputPath,
|
|
304
|
+
...(Object.keys(legendOverrides).length > 0 && { legend: { entries: legendOverrides } }),
|
|
118
305
|
},
|
|
119
306
|
components,
|
|
120
307
|
boundaries,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calm-to-archify.js","sourceRoot":"","sources":["../../../src/cli/lib/calm-to-archify.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"calm-to-archify.js","sourceRoot":"","sources":["../../../src/cli/lib/calm-to-archify.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/lib/layout.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/layout.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/layout.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAuBD,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAwD3E"}
|
package/dist/cli/lib/layout.js
CHANGED
|
@@ -24,7 +24,7 @@ function layoutRow(ids, startX, startY, cols) {
|
|
|
24
24
|
export function computeLayout(input) {
|
|
25
25
|
const { nodeIds, composedOfSets, deployedInSets } = input;
|
|
26
26
|
// Nodes that appear in composed-of children (deepest level)
|
|
27
|
-
const composedChildren = new Set(composedOfSets.flat());
|
|
27
|
+
const composedChildren = new Set(composedOfSets.flatMap((g) => g.layers.flat()));
|
|
28
28
|
// Nodes that appear in deployed-in children (middle level, not already composed children)
|
|
29
29
|
const deployedChildren = new Set(deployedInSets.flat().filter((id) => !composedChildren.has(id)));
|
|
30
30
|
// All nodes that are container targets (the "container" node itself, i.e. the node that wraps others)
|
|
@@ -49,19 +49,21 @@ export function computeLayout(input) {
|
|
|
49
49
|
const deployedRows = Math.ceil(deployedOnlyList.length / COLS);
|
|
50
50
|
nextY += deployedRows * (COMP_H + ROW_GAP) + SECTION_Y_GAP;
|
|
51
51
|
}
|
|
52
|
-
// Row 2+: composed children, laid out per composed-of group
|
|
52
|
+
// Row 2+: composed children, laid out per composed-of group, layer by layer
|
|
53
53
|
const processedComposed = new Set();
|
|
54
54
|
for (const group of composedOfSets) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
for (const layer of group.layers) {
|
|
56
|
+
const toLayout = layer.filter((id) => !processedComposed.has(id));
|
|
57
|
+
if (toLayout.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
const layerLayout = layoutRow(toLayout, EXTERNAL_START_X, nextY, COLS);
|
|
60
|
+
layerLayout.forEach((pos, id) => {
|
|
61
|
+
positions.set(id, pos);
|
|
62
|
+
processedComposed.add(id);
|
|
63
|
+
});
|
|
64
|
+
nextY += Math.ceil(toLayout.length / COLS) * (COMP_H + ROW_GAP);
|
|
65
|
+
}
|
|
66
|
+
nextY += SECTION_Y_GAP;
|
|
65
67
|
}
|
|
66
68
|
// Any remaining nodes not yet positioned
|
|
67
69
|
const remaining = nodeIds.filter((id) => !positions.has(id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/cli/lib/layout.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,GAAG,CAAC;AACnB,MAAM,MAAM,GAAG,EAAE,CAAC;AAClB,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,IAAI,GAAG,CAAC,CAAC;AACf,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,gBAAgB,GAAG,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/cli/lib/layout.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Cli } from "clipanion";
|
|
3
3
|
import { BuildCommand } from "./cli/commands/build.js";
|
|
4
4
|
import { TransformCommand } from "./cli/commands/transform.js";
|
|
5
|
+
import { WatchCommand } from "./cli/commands/watch.js";
|
|
5
6
|
const cli = new Cli({
|
|
6
7
|
binaryLabel: "calm-to-archify",
|
|
7
8
|
binaryName: "calm-to-archify",
|
|
@@ -9,5 +10,6 @@ const cli = new Cli({
|
|
|
9
10
|
});
|
|
10
11
|
cli.register(BuildCommand);
|
|
11
12
|
cli.register(TransformCommand);
|
|
13
|
+
cli.register(WatchCommand);
|
|
12
14
|
cli.runExit(process.argv.slice(2));
|
|
13
15
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;IAClB,WAAW,EAAE,iBAAiB;IAC9B,UAAU,EAAE,iBAAiB;IAC7B,aAAa,EAAE,OAAO;CACvB,CAAC,CAAC;AAEH,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC3B,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAC/B,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC3B,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alistigo/calm-to-archify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mikael Labrut",
|
|
@@ -17,8 +17,14 @@
|
|
|
17
17
|
"bin": {
|
|
18
18
|
"calm-to-archify": "./dist/cli.js"
|
|
19
19
|
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./dist/cli.js",
|
|
22
|
+
"./schemas": "./dist/schemas/index.js",
|
|
23
|
+
"./schemas/x-archify-metadata.schema.json": "./dist/schemas/x-archify-metadata.schema.json"
|
|
24
|
+
},
|
|
20
25
|
"files": [
|
|
21
26
|
"dist",
|
|
27
|
+
"docs",
|
|
22
28
|
"README.md"
|
|
23
29
|
],
|
|
24
30
|
"publishConfig": {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type ComponentType = "frontend" | "backend" | "database" | "cloud" | "security" | "messagebus" | "external";
|
|
2
|
+
export interface NodeTypeHint {
|
|
3
|
+
"component-type": ComponentType;
|
|
4
|
+
"legend-label"?: string;
|
|
5
|
+
sublabel?: string;
|
|
6
|
+
tag?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface XArchifyMetadata {
|
|
9
|
+
"x-archify": {
|
|
10
|
+
"node-types": Record<string, NodeTypeHint>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare const xArchifyMetadataSchema: {
|
|
14
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
15
|
+
readonly $id: "https://alistigo.com/schemas/calm-to-archify/x-archify-metadata/1.0.0/schema.json";
|
|
16
|
+
readonly title: "x-archify CALM metadata entry";
|
|
17
|
+
readonly description: "Vendor-prefixed metadata entry added to a CALM architecture document's `metadata` array. Maps custom CALM node-types to archify rendering hints (component type and optional legend label).";
|
|
18
|
+
readonly type: "object";
|
|
19
|
+
readonly properties: {
|
|
20
|
+
readonly "x-archify": {
|
|
21
|
+
readonly type: "object";
|
|
22
|
+
readonly description: "Archify rendering hints for custom CALM node-types.";
|
|
23
|
+
readonly properties: {
|
|
24
|
+
readonly "node-types": {
|
|
25
|
+
readonly type: "object";
|
|
26
|
+
readonly description: "A map from CALM node-type identifiers to archify rendering hints. Each key is a node-type string (e.g. 'module', 'plugin'); the value controls how nodes of that type are visualised.";
|
|
27
|
+
readonly additionalProperties: {
|
|
28
|
+
readonly $ref: "#/$defs/NodeTypeHint";
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
readonly required: readonly ["node-types"];
|
|
33
|
+
readonly additionalProperties: false;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly required: readonly ["x-archify"];
|
|
37
|
+
readonly $defs: {
|
|
38
|
+
readonly NodeTypeHint: {
|
|
39
|
+
readonly type: "object";
|
|
40
|
+
readonly title: "Node-type hint";
|
|
41
|
+
readonly description: "Archify rendering hint for a single CALM node-type.";
|
|
42
|
+
readonly properties: {
|
|
43
|
+
readonly "component-type": {
|
|
44
|
+
readonly type: "string";
|
|
45
|
+
readonly enum: ComponentType[];
|
|
46
|
+
readonly description: "The archify component type that controls the icon and color of nodes of this type in the rendered diagram.";
|
|
47
|
+
};
|
|
48
|
+
readonly "legend-label": {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
readonly description: "Human-readable label shown for this component-type in the diagram legend. Overrides the archify default label (e.g. 'Backend' can be overridden to 'Module').";
|
|
51
|
+
};
|
|
52
|
+
readonly sublabel: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly description: "Name of a CALM node property whose value will be shown as a secondary line below the node label in the diagram (e.g. 'core-npm-package'). Only rendered if the node has that property and its value is a string.";
|
|
55
|
+
};
|
|
56
|
+
readonly tag: {
|
|
57
|
+
readonly type: "string";
|
|
58
|
+
readonly description: "Name of a CALM node property whose value will be shown as a tag badge on the node (e.g. 'ddd-layer'). Only rendered if the node has that property and its value is a string.";
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
readonly required: readonly ["component-type"];
|
|
62
|
+
readonly additionalProperties: false;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,YAAY,GACZ,UAAU,CAAC;AAEf,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,aAAa,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE;QACX,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;KAC5C,CAAC;CACH;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAwCpB,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;CAwBpB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const xArchifyMetadataSchema = {
|
|
2
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
$id: "https://alistigo.com/schemas/calm-to-archify/x-archify-metadata/1.0.0/schema.json",
|
|
4
|
+
title: "x-archify CALM metadata entry",
|
|
5
|
+
description: "Vendor-prefixed metadata entry added to a CALM architecture document's `metadata` array. Maps custom CALM node-types to archify rendering hints (component type and optional legend label).",
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
"x-archify": {
|
|
9
|
+
type: "object",
|
|
10
|
+
description: "Archify rendering hints for custom CALM node-types.",
|
|
11
|
+
properties: {
|
|
12
|
+
"node-types": {
|
|
13
|
+
type: "object",
|
|
14
|
+
description: "A map from CALM node-type identifiers to archify rendering hints. Each key is a node-type string (e.g. 'module', 'plugin'); the value controls how nodes of that type are visualised.",
|
|
15
|
+
additionalProperties: { $ref: "#/$defs/NodeTypeHint" },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
required: ["node-types"],
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["x-archify"],
|
|
23
|
+
$defs: {
|
|
24
|
+
NodeTypeHint: {
|
|
25
|
+
type: "object",
|
|
26
|
+
title: "Node-type hint",
|
|
27
|
+
description: "Archify rendering hint for a single CALM node-type.",
|
|
28
|
+
properties: {
|
|
29
|
+
"component-type": {
|
|
30
|
+
type: "string",
|
|
31
|
+
enum: [
|
|
32
|
+
"frontend",
|
|
33
|
+
"backend",
|
|
34
|
+
"database",
|
|
35
|
+
"cloud",
|
|
36
|
+
"security",
|
|
37
|
+
"messagebus",
|
|
38
|
+
"external",
|
|
39
|
+
],
|
|
40
|
+
description: "The archify component type that controls the icon and color of nodes of this type in the rendered diagram.",
|
|
41
|
+
},
|
|
42
|
+
"legend-label": {
|
|
43
|
+
type: "string",
|
|
44
|
+
description: "Human-readable label shown for this component-type in the diagram legend. Overrides the archify default label (e.g. 'Backend' can be overridden to 'Module').",
|
|
45
|
+
},
|
|
46
|
+
sublabel: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "Name of a CALM node property whose value will be shown as a secondary line below the node label in the diagram (e.g. 'core-npm-package'). Only rendered if the node has that property and its value is a string.",
|
|
49
|
+
},
|
|
50
|
+
tag: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Name of a CALM node property whose value will be shown as a tag badge on the node (e.g. 'ddd-layer'). Only rendered if the node has that property and its value is a string.",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
required: ["component-type"],
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,8CAA8C;IACvD,GAAG,EAAE,mFAAmF;IACxF,KAAK,EAAE,+BAA+B;IACtC,WAAW,EACT,6LAA6L;IAC/L,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,qDAAqD;YAClE,UAAU,EAAE;gBACV,YAAY,EAAE;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,uLAAuL;oBACzL,oBAAoB,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE;iBACvD;aACF;YACD,QAAQ,EAAE,CAAC,YAAY,CAAC;YACxB,oBAAoB,EAAE,KAAK;SAC5B;KACF;IACD,QAAQ,EAAE,CAAC,WAAW,CAAC;IACvB,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,gBAAgB;YACvB,WAAW,EAAE,qDAAqD;YAClE,UAAU,EAAE;gBACV,gBAAgB,EAAE;oBAChB,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE;wBACJ,UAAU;wBACV,SAAS;wBACT,UAAU;wBACV,OAAO;wBACP,UAAU;wBACV,YAAY;wBACZ,UAAU;qBACQ;oBACpB,WAAW,EACT,4GAA4G;iBAC/G;gBACD,cAAc,EAAE;oBACd,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,+JAA+J;iBAClK;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,kNAAkN;iBACrN;gBACD,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,8KAA8K;iBACjL;aACF;YACD,QAAQ,EAAE,CAAC,gBAAgB,CAAC;YAC5B,oBAAoB,EAAE,KAAK;SAC5B;KACF;CACO,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://alistigo.com/schemas/calm-to-archify/x-archify-metadata/1.0.0/schema.json",
|
|
4
|
+
"title": "x-archify CALM metadata entry",
|
|
5
|
+
"description": "Vendor-prefixed metadata entry added to a CALM architecture document's `metadata` array. Maps custom CALM node-types to archify rendering hints (component type and optional legend label).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"x-archify": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"description": "Archify rendering hints for custom CALM node-types.",
|
|
11
|
+
"properties": {
|
|
12
|
+
"node-types": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"description": "A map from CALM node-type identifiers to archify rendering hints. Each key is a node-type string (e.g. 'module', 'plugin'); the value controls how nodes of that type are visualised.",
|
|
15
|
+
"additionalProperties": {
|
|
16
|
+
"$ref": "#/$defs/NodeTypeHint"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"required": ["node-types"],
|
|
21
|
+
"additionalProperties": false
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["x-archify"],
|
|
25
|
+
"$defs": {
|
|
26
|
+
"NodeTypeHint": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"title": "Node-type hint",
|
|
29
|
+
"description": "Archify rendering hint for a single CALM node-type.",
|
|
30
|
+
"properties": {
|
|
31
|
+
"component-type": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"enum": [
|
|
34
|
+
"frontend",
|
|
35
|
+
"backend",
|
|
36
|
+
"database",
|
|
37
|
+
"cloud",
|
|
38
|
+
"security",
|
|
39
|
+
"messagebus",
|
|
40
|
+
"external"
|
|
41
|
+
],
|
|
42
|
+
"description": "The archify component type that controls the icon and color of nodes of this type in the rendered diagram."
|
|
43
|
+
},
|
|
44
|
+
"legend-label": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Human-readable label shown for this component-type in the diagram legend. Overrides the archify default label (e.g. 'Backend' can be overridden to 'Module')."
|
|
47
|
+
},
|
|
48
|
+
"sublabel": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"description": "Name of a CALM node property whose value will be shown as a secondary line below the node label in the diagram (e.g. 'core-npm-package'). Only rendered if the node has that property and its value is a string."
|
|
51
|
+
},
|
|
52
|
+
"tag": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"description": "Name of a CALM node property whose value will be shown as a tag badge on the node (e.g. 'ddd-layer'). Only rendered if the node has that property and its value is a string."
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"required": ["component-type"],
|
|
58
|
+
"additionalProperties": false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# archify diagram types and CALM mapping
|
|
2
|
+
|
|
3
|
+
## archify diagram types
|
|
4
|
+
|
|
5
|
+
archify supports 5 diagram types. Each produces a standalone interactive HTML file:
|
|
6
|
+
|
|
7
|
+
| `diagram_type` | Purpose | CALM mapping status |
|
|
8
|
+
|----------------|---------|---------------------|
|
|
9
|
+
| `architecture` | Component/service landscape — boxes, regions, connections | **Implemented** |
|
|
10
|
+
| `workflow` | Swimlane process flows — lanes, nodes, edges with roles | Planned |
|
|
11
|
+
| `sequence` | Message interactions between participants | Planned |
|
|
12
|
+
| `dataflow` | Multi-stage data pipeline / processing flows | Planned |
|
|
13
|
+
| `lifecycle` | State machine — states, transitions, lanes | Planned |
|
|
14
|
+
|
|
15
|
+
## Current behaviour: 1→1 (one CALM file → one HTML)
|
|
16
|
+
|
|
17
|
+
`calm-to-archify` currently performs a 1→1 transformation: one `.arch.calm.json` input produces one `.archify.json` intermediate and one `.archify.html` output, always as an `architecture` diagram.
|
|
18
|
+
|
|
19
|
+
The mapping extracts:
|
|
20
|
+
- **Components** from CALM `nodes` (excluding `group` node-types, which become boundaries)
|
|
21
|
+
- **Boundaries** from `composed-of` and `deployed-in` relationships
|
|
22
|
+
- **Connections** from `connects` and `interacts` relationships
|
|
23
|
+
|
|
24
|
+
## Roadmap: 1→N (one CALM file → multiple HTML files)
|
|
25
|
+
|
|
26
|
+
A CALM document can contain multiple kinds of diagrams worth visualising from the same source:
|
|
27
|
+
|
|
28
|
+
- The top-level nodes and relationships → `architecture` diagram
|
|
29
|
+
- Named CALM flows (e.g. a set of `connects` relationships tagged as a specific use-case flow) → `workflow` or `sequence` diagram
|
|
30
|
+
- A state machine modelled in CALM → `lifecycle` diagram
|
|
31
|
+
|
|
32
|
+
When 1→N is implemented, each output will use a distinct file name derived from the CALM document's `unique-id` and the diagram type:
|
|
33
|
+
|
|
34
|
+
| Input | Output |
|
|
35
|
+
|-------|--------|
|
|
36
|
+
| `my-system.arch.calm.json` | `my-system.architecture.archify.html` |
|
|
37
|
+
| `my-system.arch.calm.json` | `my-system.checkout-flow.workflow.archify.html` |
|
|
38
|
+
| `my-system.arch.calm.json` | `my-system.order-lifecycle.lifecycle.archify.html` |
|
|
39
|
+
|
|
40
|
+
Currently only the architecture output is produced; the naming convention will be stabilised before 1→N is implemented.
|
|
41
|
+
|
|
42
|
+
## Declaring additional diagram targets in CALM metadata
|
|
43
|
+
|
|
44
|
+
The planned mechanism uses `x-archify` metadata entries with a `diagrams` array alongside `node-types`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"metadata": [
|
|
49
|
+
{
|
|
50
|
+
"x-archify": {
|
|
51
|
+
"node-types": { ... },
|
|
52
|
+
"diagrams": [
|
|
53
|
+
{
|
|
54
|
+
"type": "workflow",
|
|
55
|
+
"title": "Checkout flow",
|
|
56
|
+
"output-suffix": "checkout-flow",
|
|
57
|
+
"filter": { "relationship-tag": "checkout-flow" }
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This API is **not yet implemented** — it documents the intended design so CALM authors can plan ahead.
|
|
67
|
+
|
|
68
|
+
## Click panel customisation (sources)
|
|
69
|
+
|
|
70
|
+
When a user clicks a component in the rendered HTML, archify shows a detail panel. You can populate it with up to three source references per component via the `sources` field in the archify JSON:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"id": "domain",
|
|
75
|
+
"label": "Domain",
|
|
76
|
+
"sources": [
|
|
77
|
+
{ "path": "packages/my-artifact-domain/src/index.ts", "label": "Source" },
|
|
78
|
+
{ "path": "packages/my-artifact-domain/README.md", "label": "Docs" }
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Automatic `sources` population from CALM node data is not yet implemented in the CLI. It can be added via a future `x-archify` metadata extension once the mapping strategy is clear.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# `x-archify` CALM metadata
|
|
2
|
+
|
|
3
|
+
`x-archify` is a vendor-prefixed extension entry placed in the `metadata` array of a CALM architecture document. It maps custom CALM node-types to archify rendering hints, giving you control over the icon color and legend label for each node-type in the generated diagram — without modifying the CLI.
|
|
4
|
+
|
|
5
|
+
## Why this exists
|
|
6
|
+
|
|
7
|
+
CALM's built-in node-types (`service`, `database`, `actor`, …) map naturally to archify component types. But if your CALM extension defines custom node-types (e.g. `module`, `plugin`, `skill`) the CLI has no way to know how to render them. Rather than hardcoding project-specific mappings in the CLI, each CALM document carries its own rendering hints directly.
|
|
8
|
+
|
|
9
|
+
## Structure
|
|
10
|
+
|
|
11
|
+
Add an entry to your document's `metadata` array:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"metadata": [
|
|
16
|
+
{
|
|
17
|
+
"x-archify": {
|
|
18
|
+
"node-types": {
|
|
19
|
+
"<node-type-id>": {
|
|
20
|
+
"component-type": "<archify-type>",
|
|
21
|
+
"legend-label": "<optional label>"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `node-types`
|
|
31
|
+
|
|
32
|
+
A map from your custom CALM node-type identifiers to rendering hints. Standard CALM built-in types (`service`, `database`, `actor`, `system`, `data-asset`) do not need entries here — they have default mappings in the CLI. Only add entries for your extension node-types.
|
|
33
|
+
|
|
34
|
+
### `component-type` (required)
|
|
35
|
+
|
|
36
|
+
Controls the icon and color used in the rendered diagram. Must be one of the seven archify component types:
|
|
37
|
+
|
|
38
|
+
| Value | Default legend label | Typical use |
|
|
39
|
+
|-------|---------------------|-------------|
|
|
40
|
+
| `backend` | Backend | Services, modules, application logic |
|
|
41
|
+
| `frontend` | Frontend | Web UIs, presentation layers |
|
|
42
|
+
| `database` | Database | Databases, data stores |
|
|
43
|
+
| `cloud` | Cloud | Cloud services, SaaS, CDN, AI tooling |
|
|
44
|
+
| `external` | External | Actors, plugins, external systems |
|
|
45
|
+
| `security` | Security | Auth, encryption, secrets management |
|
|
46
|
+
| `messagebus` | Message bus | Event buses, queues, brokers |
|
|
47
|
+
|
|
48
|
+
### `legend-label` (optional)
|
|
49
|
+
|
|
50
|
+
Overrides the default legend label for a given `component-type`. Useful when you want the legend to use your domain vocabulary ("Module", "Plugin", "Skill") rather than the archify default ("Backend", "External", "Cloud").
|
|
51
|
+
|
|
52
|
+
If multiple node-types map to the same `component-type`, the last `legend-label` wins. Leave it empty if the default label is acceptable.
|
|
53
|
+
|
|
54
|
+
### `sublabel` (optional)
|
|
55
|
+
|
|
56
|
+
The name of a CALM node property whose value will be displayed as a secondary line of text directly below the node label inside the diagram box.
|
|
57
|
+
|
|
58
|
+
Use this to surface a key node attribute without opening the detail panel — for example the npm package name, the DDD layer, or a version string.
|
|
59
|
+
|
|
60
|
+
The value is looked up on each individual node at transform time. If the node doesn't have that property, no sublabel is rendered for it.
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
"module": { "component-type": "backend", "legend-label": "Module", "sublabel": "core-npm-package" }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
With this hint, a `module` node that has `"core-npm-package": "@alistigo/core-document"` will render with `@alistigo/core-document` shown below its label in the diagram.
|
|
67
|
+
|
|
68
|
+
### `tag` (optional)
|
|
69
|
+
|
|
70
|
+
The name of a CALM node property whose value will be displayed as a badge/tag on the node (typically in a corner or below the sublabel, depending on the archify renderer).
|
|
71
|
+
|
|
72
|
+
Use this for categorical metadata — for example the DDD layer (`Domain`, `Application`, `Infrastructure`).
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
"module": { "component-type": "backend", "legend-label": "Module", "tag": "ddd-layer" }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Example
|
|
79
|
+
|
|
80
|
+
This is the mapping used by alistigo artifact diagrams. Each module shows its `core-npm-package` as a sublabel and `ddd-layer` as a tag badge:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"metadata": [
|
|
85
|
+
{ "x-alistigo-extension": "extensions/alistigo-node-types.calm-extension.json" },
|
|
86
|
+
{
|
|
87
|
+
"x-archify": {
|
|
88
|
+
"node-types": {
|
|
89
|
+
"module": { "component-type": "backend", "legend-label": "Module", "sublabel": "core-npm-package", "tag": "ddd-layer" },
|
|
90
|
+
"system": { "component-type": "frontend", "legend-label": "System", "sublabel": "core-npm-package", "tag": "ddd-layer" },
|
|
91
|
+
"plugin": { "component-type": "external", "legend-label": "Plugin", "sublabel": "core-npm-package" },
|
|
92
|
+
"skill": { "component-type": "cloud", "legend-label": "Skill" }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## JSON Schema
|
|
101
|
+
|
|
102
|
+
The schema for this metadata entry is bundled in the package:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
node_modules/@alistigo/calm-to-archify/dist/schemas/x-archify-metadata.schema.json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
You can reference it in a CALM document for VS Code auto-complete and validation (if your editor supports `$schema` on individual property values via a JSON Schema store or workspace settings). It is also importable from TypeScript:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { xArchifyMetadataSchema } from "@alistigo/calm-to-archify/schemas";
|
|
112
|
+
import type { XArchifyMetadata, NodeTypeHint, ComponentType } from "@alistigo/calm-to-archify/schemas";
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The exported types:
|
|
116
|
+
|
|
117
|
+
| Export | Description |
|
|
118
|
+
|--------|-------------|
|
|
119
|
+
| `ComponentType` | Union of all valid archify component type strings |
|
|
120
|
+
| `NodeTypeHint` | Shape of a single node-type hint object |
|
|
121
|
+
| `XArchifyMetadata` | Shape of the full `{ "x-archify": { ... } }` entry |
|
|
122
|
+
| `xArchifyMetadataSchema` | JSON Schema as a typed `const` object (for validation at runtime) |
|
|
123
|
+
|
|
124
|
+
## Fallback behaviour
|
|
125
|
+
|
|
126
|
+
If a node-type has no entry in `x-archify`, the CLI falls back to its built-in switch:
|
|
127
|
+
|
|
128
|
+
| node-type | fallback component-type |
|
|
129
|
+
|-----------|------------------------|
|
|
130
|
+
| `actor` | `external` |
|
|
131
|
+
| `database` | `database` |
|
|
132
|
+
| `data-asset` | `external` |
|
|
133
|
+
| `system` | `backend` |
|
|
134
|
+
| `service` | `backend` (or `cloud`, `messagebus`, `frontend` based on name heuristics) |
|
|
135
|
+
| anything else | `backend` |
|
|
136
|
+
|
|
137
|
+
The `x-archify` hints always take priority over the fallback.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alistigo/calm-to-archify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mikael Labrut",
|
|
@@ -17,8 +17,14 @@
|
|
|
17
17
|
"bin": {
|
|
18
18
|
"calm-to-archify": "./dist/cli.js"
|
|
19
19
|
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./dist/cli.js",
|
|
22
|
+
"./schemas": "./dist/schemas/index.js",
|
|
23
|
+
"./schemas/x-archify-metadata.schema.json": "./dist/schemas/x-archify-metadata.schema.json"
|
|
24
|
+
},
|
|
20
25
|
"files": [
|
|
21
26
|
"dist",
|
|
27
|
+
"docs",
|
|
22
28
|
"README.md"
|
|
23
29
|
],
|
|
24
30
|
"publishConfig": {
|