diagrams-js 0.3.1 → 0.5.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
@@ -18,6 +18,7 @@
18
18
  - **2000+ Node Classes**: Comprehensive coverage of cloud services and infrastructure components
19
19
  - **Cross-Platform**: Works in browsers, Node.js, Deno and Bun
20
20
  - **Multiple Output Formats**: SVG, PNG, JPG, and DOT
21
+ - **Visual Diff**: Compare diagram versions side-by-side with color-coded changes (added, removed, modified, renamed)
21
22
  - **Type-Safe**: Full TypeScript support with comprehensive type definitions
22
23
  - **WebAssembly Powered**: Uses a WebAssembly build of [Graphviz](https://graphviz.org) ([viz](https://github.com/mdaines/viz-js)) for fast, client-side rendering
23
24
  - **Custom Nodes**: Support for external icons and images
@@ -68,6 +69,34 @@ api.to([db, storage]);
68
69
  const svg = await diagram.render();
69
70
  ```
70
71
 
72
+ ### Visual Diff
73
+
74
+ Compare two versions of a diagram to see what changed:
75
+
76
+ ```typescript
77
+ import { Diagram } from "diagrams-js";
78
+ import { writeFileSync } from "fs";
79
+
80
+ // Load two versions (e.g., from git or saved JSON)
81
+ const before = JSON.parse(await fs.readFile("arch-v1.json", "utf8"));
82
+ const after = JSON.parse(await fs.readFile("arch-v2.json", "utf8"));
83
+
84
+ // Generate visual diff as self-contained HTML
85
+ const html = await Diagram.renderDiff(before, after, {
86
+ format: "html",
87
+ theme: "light",
88
+ showUnchanged: "show", // "show" (default), "dim", or "hide"
89
+ });
90
+
91
+ await fs.writeFile("diff.html", html);
92
+ ```
93
+
94
+ The diff shows:
95
+
96
+ - 🟢 **Green**: Added elements
97
+ - 🔴 **Red**: Removed elements
98
+ - 🟠 **Amber**: Modified elements (including label changes)
99
+
71
100
  ### Browser
72
101
 
73
102
  ```html
package/dist/index.d.ts CHANGED
@@ -210,6 +210,8 @@ interface RenderOptions {
210
210
  scale?: number;
211
211
  /** Whether to inject icons into SVG output */
212
212
  injectIcons?: boolean;
213
+ /** Whether to embed diagram metadata into SVG output (default: true) */
214
+ embedData?: boolean;
213
215
  /** Whether to return output as data URL */
214
216
  dataUrl?: boolean;
215
217
  }
@@ -794,9 +796,9 @@ interface DiagramNodeJSON {
794
796
  /** Cloud provider identifier (e.g., 'aws', 'gcp', 'azure') */
795
797
  provider?: string;
796
798
  /** Service type within the provider (e.g., 'compute', 'storage') */
797
- service?: string;
798
- /** Specific resource type (e.g., 'EC2', 'S3', 'RDS') */
799
799
  type?: string;
800
+ /** Specific resource type (e.g., 'EC2', 'S3', 'RDS') */
801
+ resource?: string;
800
802
  /** Custom icon URL or data URI */
801
803
  iconUrl?: string;
802
804
  /** Additional Graphviz attributes */
@@ -919,8 +921,8 @@ interface DiagramJSON {
919
921
  * name: "My Architecture",
920
922
  * direction: "LR",
921
923
  * nodes: [
922
- * { id: "web", label: "Web Server", provider: "aws", service: "compute", type: "EC2" },
923
- * { id: "db", label: "Database", provider: "aws", service: "database", type: "RDS" }
924
+ * { id: "web", label: "Web Server", provider: "aws", type: "compute", resource: "EC2" },
925
+ * { id: "db", label: "Database", provider: "aws", type: "database", resource: "RDS" }
924
926
  * ],
925
927
  * edges: [
926
928
  * { from: "web", to: "db", label: "SQL" }
@@ -933,6 +935,190 @@ interface DiagramJSON {
933
935
  */
934
936
  declare function fromJSON(input: DiagramJSON | string, opts?: FromJSONOptions): Promise<Diagram>;
935
937
  //#endregion
938
+ //#region src/diff.d.ts
939
+ /**
940
+ * Type of change detected during diff computation.
941
+ */
942
+ type ChangeKind = "added" | "removed" | "modified" | "unchanged";
943
+ /**
944
+ * Diff result for a single node.
945
+ */
946
+ interface NodeDiff {
947
+ /** The type of change */
948
+ kind: ChangeKind;
949
+ /** The node before changes (for removed, modified) */
950
+ before?: DiagramNodeJSON;
951
+ /** The node after changes (for added, modified) */
952
+ after?: DiagramNodeJSON;
953
+ /** Array of field paths that changed (for modified) */
954
+ changes?: string[];
955
+ }
956
+ /**
957
+ * Diff result for a single edge.
958
+ */
959
+ interface EdgeDiff {
960
+ /** The type of change */
961
+ kind: ChangeKind;
962
+ /** The edge before changes */
963
+ before?: DiagramEdgeJSON;
964
+ /** The edge after changes */
965
+ after?: DiagramEdgeJSON;
966
+ /** Array of field paths that changed */
967
+ changes?: string[];
968
+ }
969
+ /**
970
+ * Diff result for a cluster (recursive).
971
+ */
972
+ interface ClusterDiff {
973
+ /** The type of change */
974
+ kind: ChangeKind;
975
+ /** Cluster label */
976
+ label: string;
977
+ /** The cluster before changes */
978
+ before?: DiagramClusterJSON;
979
+ /** The cluster after changes */
980
+ after?: DiagramClusterJSON;
981
+ /** Array of field paths that changed */
982
+ changes?: string[];
983
+ /** Nested cluster diffs */
984
+ clusters?: ClusterDiff[];
985
+ /** Node IDs in this cluster and their diff status */
986
+ nodes?: Map<string, NodeDiff>;
987
+ }
988
+ /**
989
+ * Summary of changes in the diff.
990
+ */
991
+ interface DiffSummary {
992
+ /** Number of added nodes/edges/clusters */
993
+ added: number;
994
+ /** Number of removed nodes/edges/clusters */
995
+ removed: number;
996
+ /** Number of modified nodes/edges/clusters */
997
+ modified: number;
998
+ /** Number of unchanged nodes/edges/clusters */
999
+ unchanged: number;
1000
+ }
1001
+ /**
1002
+ * Metadata-level changes (diagram options, not individual elements).
1003
+ */
1004
+ interface DiffMeta {
1005
+ /** Diagram name change */
1006
+ name?: {
1007
+ before?: string;
1008
+ after?: string;
1009
+ };
1010
+ /** Theme change */
1011
+ theme?: {
1012
+ before?: string;
1013
+ after?: string;
1014
+ };
1015
+ /** Direction change */
1016
+ direction?: {
1017
+ before?: string;
1018
+ after?: string;
1019
+ };
1020
+ /** Curve style change */
1021
+ curvestyle?: {
1022
+ before?: string;
1023
+ after?: string;
1024
+ };
1025
+ /** Graph attributes change */
1026
+ graphAttr?: {
1027
+ before?: Record<string, string>;
1028
+ after?: Record<string, string>;
1029
+ };
1030
+ /** Node attributes change */
1031
+ nodeAttr?: {
1032
+ before?: Record<string, string>;
1033
+ after?: Record<string, string>;
1034
+ };
1035
+ /** Edge attributes change */
1036
+ edgeAttr?: {
1037
+ before?: Record<string, string>;
1038
+ after?: Record<string, string>;
1039
+ };
1040
+ }
1041
+ /**
1042
+ * Complete diff result for a diagram comparison.
1043
+ */
1044
+ interface DiagramDiffResult {
1045
+ /** Node diffs by node ID */
1046
+ nodes: Map<string, NodeDiff>;
1047
+ /** Edge diffs by composite key "from->to[label]" */
1048
+ edges: Map<string, EdgeDiff>;
1049
+ /** Cluster diffs */
1050
+ clusters: ClusterDiff[];
1051
+ /** Summary counts */
1052
+ summary: DiffSummary;
1053
+ /** Metadata-level changes */
1054
+ meta: DiffMeta;
1055
+ }
1056
+ /**
1057
+ * Options for computing a diff.
1058
+ */
1059
+ interface DiffOptions {
1060
+ /** Fields to ignore during comparison */
1061
+ ignore?: {
1062
+ /** Ignore position/layout changes (default: true) */position?: boolean; /** Ignore metadata changes entirely, or specific metadata keys */
1063
+ metadata?: boolean | string[]; /** Ignore specific Graphviz attributes */
1064
+ attrs?: string[]; /** Ignore node ID changes - treat same-fingerprint nodes as unchanged (default: false) */
1065
+ nodeId?: boolean;
1066
+ };
1067
+ /** Custom node matching function (overrides default ID + fingerprint matching) */
1068
+ matchNodes?: (a: DiagramNodeJSON, b: DiagramNodeJSON) => boolean;
1069
+ }
1070
+ /**
1071
+ * Options for rendering a diff.
1072
+ */
1073
+ interface RenderDiffOptions {
1074
+ /** Output format: svg (combined) or html (self-contained page) */
1075
+ format?: "svg" | "html";
1076
+ /** Layout mode: side-by-side (default) or stacked */
1077
+ layout?: "side-by-side" | "stacked";
1078
+ /** Color theme: light (default) or dark */
1079
+ theme?: "light" | "dark";
1080
+ /** How to display unchanged elements: "show" | "dim" | "hide" (default: "show") */
1081
+ showUnchanged?: "show" | "dim" | "hide";
1082
+ /** Show legend in HTML output (default: true) */
1083
+ showLegend?: boolean;
1084
+ /** Show summary header in HTML output (default: true) */
1085
+ showSummary?: boolean;
1086
+ /** Enable hover tooltips in HTML output (default: true) */
1087
+ hoverDetails?: boolean;
1088
+ }
1089
+ /**
1090
+ * Compute the diff between two diagram versions.
1091
+ *
1092
+ * @param before - The original diagram (JSON or Diagram object)
1093
+ * @param after - The updated diagram (JSON or Diagram object)
1094
+ * @param opts - Options for diff computation
1095
+ * @returns Complete diff result with nodes, edges, clusters, and summary
1096
+ *
1097
+ * @example
1098
+ * ```typescript
1099
+ * const diff = computeDiff(diagramV1.toJSON(), diagramV2.toJSON());
1100
+ * console.log(diff.summary); // { added: 2, removed: 1, modified: 3, ... }
1101
+ * ```
1102
+ */
1103
+ declare function computeDiff(before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: DiffOptions): DiagramDiffResult;
1104
+ /**
1105
+ * Render a visual diff between two diagram versions.
1106
+ *
1107
+ * @param diff - The computed diff result from `computeDiff()`
1108
+ * @param before - The original diagram (JSON or Diagram object)
1109
+ * @param after - The updated diagram (JSON or Diagram object)
1110
+ * @param opts - Options for rendering the diff
1111
+ * @returns Promise resolving to SVG or HTML string
1112
+ *
1113
+ * @example
1114
+ * ```typescript
1115
+ * const diff = computeDiff(beforeJson, afterJson);
1116
+ * const html = await renderDiff(diff, beforeJson, afterJson, { format: "html" });
1117
+ * await fs.writeFile("diff.html", html);
1118
+ * ```
1119
+ */
1120
+ declare function renderDiff(diff: DiagramDiffResult, before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: RenderDiffOptions): Promise<string>;
1121
+ //#endregion
936
1122
  //#region src/icons.d.ts
937
1123
  /**
938
1124
  * Maps a node to its icon information
@@ -1170,6 +1356,15 @@ declare function Diagram(name?: string, options?: DiagramOptions): Diagram;
1170
1356
  declare namespace Diagram {
1171
1357
  var fromJSON: typeof fromJSON;
1172
1358
  }
1359
+ declare namespace Diagram {
1360
+ var fromSVG: (svg: string) => Promise<Diagram>;
1361
+ }
1362
+ declare namespace Diagram {
1363
+ var diff: (before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: DiffOptions) => Promise<DiagramDiffResult>;
1364
+ }
1365
+ declare namespace Diagram {
1366
+ var renderDiff: (before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: RenderDiffOptions) => Promise<string>;
1367
+ }
1173
1368
  //#endregion
1174
1369
  //#region src/Custom.d.ts
1175
1370
  /**
@@ -1302,8 +1497,22 @@ declare function createJSONPlugin(): DiagramsPlugin;
1302
1497
  * Exported for convenience
1303
1498
  */
1304
1499
  declare const jsonPlugin: DiagramsPlugin;
1500
+ //#endregion
1501
+ //#region src/plugins/built-in/svg.d.ts
1502
+ /**
1503
+ * Create the built-in SVG plugin
1504
+ *
1505
+ * This plugin is automatically registered with every diagram and provides
1506
+ * SVG export/import with embedded metadata capabilities.
1507
+ */
1508
+ declare function createSVGPlugin(): DiagramsPlugin;
1509
+ /**
1510
+ * Default SVG plugin instance
1511
+ * Exported for convenience
1512
+ */
1513
+ declare const svgPlugin: DiagramsPlugin;
1305
1514
  declare namespace index_d_exports {
1306
- export { Cluster, CreatePlugin, Custom, DependencyError, Diagram, DiagramClusterJSON, DiagramEdgeJSON, DiagramJSON, DiagramNodeJSON, DiagramOptions, DiagramsPlugin, Edge, EdgeOptions, ExportContext, ExporterCapability, FromJSONOptions, HookCapability, HookContext, HookEvent, HookHandler, Iconify, ImportContext, ImporterCapability, MetadataCapability, MetadataContext, Node, NodeMetadata, NodeOptions, PluginCapability, PluginContext, PluginError, PluginRegistry, ProviderModule, RenderContext, RendererCapability, RuntimeError, RuntimeSupport, ThemeConfig, ThemeName, Yaml, createJSONPlugin, createPluginRegistry, jsonPlugin };
1515
+ export { ChangeKind, Cluster, ClusterDiff, CreatePlugin, Custom, DependencyError, Diagram, DiagramClusterJSON, DiagramDiffResult, DiagramEdgeJSON, DiagramJSON, DiagramNodeJSON, DiagramOptions, DiagramsPlugin, DiffMeta, DiffOptions, DiffSummary, Edge, EdgeDiff, EdgeOptions, ExportContext, ExporterCapability, FromJSONOptions, HookCapability, HookContext, HookEvent, HookHandler, Iconify, ImportContext, ImporterCapability, MetadataCapability, MetadataContext, Node, NodeDiff, NodeMetadata, NodeOptions, PluginCapability, PluginContext, PluginError, PluginRegistry, ProviderModule, RenderContext, RenderDiffOptions, RendererCapability, RuntimeError, RuntimeSupport, ThemeConfig, ThemeName, Yaml, computeDiff, createJSONPlugin, createPluginRegistry, createSVGPlugin, jsonPlugin, renderDiff, svgPlugin };
1307
1516
  }
1308
1517
  //#endregion
1309
- export { Cluster, type CreatePlugin, Custom, DependencyError, Diagram, type DiagramClusterJSON, type DiagramEdgeJSON, type DiagramJSON, type DiagramNodeJSON, type DiagramOptions, type DiagramsPlugin, Edge, type EdgeOptions, type ExportContext, type ExporterCapability, type FromJSONOptions, type HookCapability, type HookContext, HookEvent, type HookHandler, Iconify, type ImportContext, type ImporterCapability, type MetadataCapability, type MetadataContext, type Node, type NodeMetadata, type NodeOptions, type PluginCapability, type PluginContext, PluginError, type PluginRegistry, type ProviderModule, type RenderContext, type RendererCapability, RuntimeError, type RuntimeSupport, type ThemeConfig, type ThemeName, type Yaml, createJSONPlugin, createPluginRegistry, jsonPlugin };
1518
+ export { type ChangeKind, Cluster, type ClusterDiff, type CreatePlugin, Custom, DependencyError, Diagram, type DiagramClusterJSON, type DiagramDiffResult, type DiagramEdgeJSON, type DiagramJSON, type DiagramNodeJSON, type DiagramOptions, type DiagramsPlugin, type DiffMeta, type DiffOptions, type DiffSummary, Edge, type EdgeDiff, type EdgeOptions, type ExportContext, type ExporterCapability, type FromJSONOptions, type HookCapability, type HookContext, HookEvent, type HookHandler, Iconify, type ImportContext, type ImporterCapability, type MetadataCapability, type MetadataContext, type Node, type NodeDiff, type NodeMetadata, type NodeOptions, type PluginCapability, type PluginContext, PluginError, type PluginRegistry, type ProviderModule, type RenderContext, type RenderDiffOptions, type RendererCapability, RuntimeError, type RuntimeSupport, type ThemeConfig, type ThemeName, type Yaml, computeDiff, createJSONPlugin, createPluginRegistry, createSVGPlugin, jsonPlugin, renderDiff, svgPlugin };