@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 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":"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"}
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":"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"}
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;CACtB;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,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,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;CACZ;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;KAChB,CAAC;IACF,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,WAAW,EAAE,iBAAiB,EAAE,CAAC;CAClC;AAyCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,eAAe,CA+F9F"}
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 mapNodeType(nodeType, name) {
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
- const composedOfSets = [];
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
- composedOfSets.push(children);
63
- boundaries.push({ kind: "region", label, wraps: children });
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
- const components = calm.nodes.map((node) => {
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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"}
@@ -1,6 +1,9 @@
1
+ export interface GroupLayout {
2
+ layers: string[][];
3
+ }
1
4
  export interface LayoutInput {
2
5
  nodeIds: string[];
3
- composedOfSets: string[][];
6
+ composedOfSets: GroupLayout[];
4
7
  deployedInSets: string[][];
5
8
  }
6
9
  export interface NodePosition {
@@ -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,MAAM,EAAE,EAAE,CAAC;IAC3B,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,CAsD3E"}
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"}
@@ -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 toLayout = group.filter((id) => !processedComposed.has(id));
56
- if (toLayout.length === 0)
57
- continue;
58
- const groupLayout = layoutRow(toLayout, EXTERNAL_START_X, nextY, COLS);
59
- groupLayout.forEach((pos, id) => {
60
- positions.set(id, pos);
61
- processedComposed.add(id);
62
- });
63
- const groupRows = Math.ceil(toLayout.length / COLS);
64
- nextY += groupRows * (COMP_H + ROW_GAP) + SECTION_Y_GAP;
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;AAe5B,SAAS,SAAS,CAChB,GAAa,EACb,MAAc,EACd,MAAc,EACd,IAAY;IAEZ,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACpB,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE;YACb,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC;YACpC,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC;YACpC,CAAC,EAAE,MAAM;YACT,CAAC,EAAE,MAAM;SACV,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAE1D,4DAA4D;IAC5D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,0FAA0F;IAC1F,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClG,sGAAsG;IACtG,iGAAiG;IACjG,uEAAuE;IACvE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;IAElD,wBAAwB;IACxB,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACrF,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,cAAc;QAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,YAAY,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;IACzD,IAAI,KAAK,GAAG,gBAAgB,GAAG,cAAc,GAAG,aAAa,CAAC;IAE9D,wFAAwF;IACxF,MAAM,gBAAgB,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAC/C,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,cAAc,GAAG,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAClF,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,cAAc;YAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC/D,KAAK,IAAI,YAAY,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,aAAa,CAAC;IAC7D,CAAC;IAED,4DAA4D;IAC5D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAClE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvE,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE;YAC9B,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACvB,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACpD,KAAK,IAAI,SAAS,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,aAAa,CAAC;IAC1D,CAAC;IAED,yCAAyC;IACzC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,eAAe,GAAG,SAAS,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5E,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,eAAe;YAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,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;AAE/D,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,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,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.2.1",
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.2.1",
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": {