diagrams-js
Version:
A TypeScript port of the diagrams Python library for drawing cloud system architecture diagrams as code
1,589 lines (1,588 loc) • 52 kB
TypeScript
import { dump, load, loadAll } from "js-yaml";
//#region src/providers/resources-list.d.ts
declare namespace resources_list_d_exports {
export { ResourceInfo, allResources, findResource };
}
interface ResourceInfo {
provider: string;
type: string;
resource: string;
}
declare const allResources: ResourceInfo[];
declare function findResource(query: string): ResourceInfo[];
declare namespace yaml_d_exports {
export { dump, load, loadAll };
}
//#endregion
//#region src/Cluster.d.ts
/**
* Represents a cluster (group) of nodes in a diagram.
* Clusters visually group related nodes together with a background and border.
*
* @example
* ```typescript
* const vpc = diagram.cluster("VPC");
*
* const subnet1 = vpc.cluster("Public Subnet");
* subnet1.add(Server("Web Server"));
*
* const subnet2 = vpc.cluster("Private Subnet");
* subnet2.add(Database("DB"));
* ```
*/
interface Cluster {
/** The display label of the cluster */
label: string;
/** Unique identifier for the cluster */
name: string;
/** Nesting depth of the cluster (0 for top-level) */
depth: number;
/** Graphviz attributes for the cluster */
graphAttr: Record<string, string>;
/**
* Cluster attributes that can be modified by hooks.
* This provides direct access to the internal graphAttr store.
* Changes here will be reflected in the rendered output.
*/
clusterAttrs: Record<string, string>;
/** CSS class(es) to add to the rendered SVG element */
className: string | undefined;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs: Record<string, string>;
/** The diagram this cluster belongs to */
diagram: Diagram;
/**
* Internal method to register a node with the cluster
* @param nodeId - Unique identifier for the node
* @param label - Display label for the node
* @param attrs - Graphviz attributes for the node
* @internal
*/
["~node"](nodeId: string, label: string, attrs: Record<string, unknown>): void;
/**
* Add a node to this cluster
* @param node - The node to add
* @returns The added node
*/
add<T extends Node>(node: T): T;
/**
* Add a subgraph (nested cluster)
* @param cluster - The cluster to add as a subgraph
* @internal
*/
subgraph(cluster: Cluster): void;
/**
* Create a nested cluster within this one
* @param label - The label for the nested cluster
* @param options - Optional cluster configuration
* @returns The created nested cluster
*/
cluster(label: string, options?: ClusterOptions): Cluster;
/**
* Get all nodes in this cluster
* @returns Map of node IDs to node data
* @internal
*/
getNodes(): Map<string, {
label: string;
attrs: Record<string, unknown>;
}>;
/**
* Get all subgraphs (nested clusters)
* @returns Array of nested clusters
* @internal
*/
getSubgraphs(): Cluster[];
/**
* Get parent cluster (if any)
* @returns The parent cluster or undefined if top-level
*/
getParent(): Cluster | undefined;
/**
* Get parent diagram
* @returns The diagram this cluster belongs to
*/
getDiagram(): Diagram;
/**
* Get the SVG element for this cluster.
* If no svg argument is provided, queries the current document.
* @param svg - Optional SVG string or Element to query within
* @returns The SVG element, or null if not found
*/
getElement(svg?: string | Element): Element | null;
}
/**
* Create a new cluster
* @param label - The display label for the cluster
* @param direction - Layout direction for the cluster
* @param options - Optional Graphviz attributes or ClusterOptions
* @param diagram - The diagram this cluster belongs to
* @param parent - Optional parent cluster for nesting
* @returns A new Cluster instance
* @example
* ```typescript
* const cluster = diagram.cluster("VPC");
* cluster.add(Server("Web"));
* ```
*/
declare function Cluster(label?: string, direction?: "TB" | "BT" | "LR" | "RL", options?: Record<string, string> | ClusterOptions, diagram?: Diagram, parent?: Cluster): Cluster;
//#endregion
//#region src/Edge.d.ts
/**
* Represents an edge (connection) between nodes in a diagram.
* Edges can be styled with labels, colors, and styles.
*
* @example
* ```typescript
* // Create a labeled edge
* db.to(EdgeLabel("queries"), app);
*
* // Create a colored edge
* db.to(EdgeColor("red"), app);
*
* // Create a styled edge
* db.to(EdgeStyle("dashed"), app);
* ```
*/
interface Edge {
/** The node this edge is connected to */
node: Node | undefined;
/** Whether this is a forward edge (arrow points forward) */
forward: boolean;
/** Whether this is a reverse edge (arrow points back) */
reverse: boolean;
/** Graphviz attributes for this edge (includes computed properties like dir) */
attrs: Record<string, string>;
/**
* Edge attributes that can be modified by hooks.
* This is the internal attribute store that hooks should modify.
* Changes here will be reflected in the attrs getter.
*/
edgeAttrs: Record<string, string>;
/** CSS class(es) to add to the rendered SVG element */
className: string | undefined;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs: Record<string, string>;
/** @internal Source node ID (set during connection) */
["~fromNodeId"]: string;
/** @internal Target node ID (set during connection) */
["~toNodeId"]: string;
/**
* Connect this edge to a node or merge with another edge
* @param target - The target node or edge to merge
* @returns The target node or this edge
*/
to(target: Node | Edge): Node | Edge;
/**
* Connect from a node or merge with another edge
* @param target - The source node or edge to merge
* @returns The source node or this edge
*/
from(target: Node | Edge): Node | Edge;
/**
* Get the SVG element for this edge.
* If no svg argument is provided, queries the current document.
* @param svg - Optional SVG string or Element to query within
* @returns The SVG element, or null if not found
*/
getElement(svg?: string | Element): Element | null;
}
/**
* Create a new edge
* @param options - Edge configuration options
* @returns A new Edge instance
* @example
* ```typescript
* const edge = Edge({ label: "HTTP", color: "blue", style: "dashed" });
* nodeA.to(edge, nodeB);
* ```
*/
declare function Edge(options?: EdgeOptions): Edge;
/**
* Create an edge with a label
* @param label - The text label for the edge
* @returns An Edge with the specified label
* @example
* ```typescript
* db.to(EdgeLabel("queries"), app);
* ```
*/
declare function EdgeLabel(label: string): Edge;
/**
* Create an edge with a color
* @param color - The color for the edge (CSS color or Graphviz color)
* @returns An Edge with the specified color
* @example
* ```typescript
* db.to(EdgeColor("red"), app);
* ```
*/
declare function EdgeColor(color: string): Edge;
/**
* Create an edge with a style
* @param style - The line style (solid, dashed, dotted, etc.)
* @returns An Edge with the specified style
* @example
* ```typescript
* db.to(EdgeStyle("dashed"), app);
* ```
*/
declare function EdgeStyle(style: string): Edge;
declare namespace Edge {
var label: typeof EdgeLabel;
}
declare namespace Edge {
var color: typeof EdgeColor;
}
declare namespace Edge {
var style: typeof EdgeStyle;
}
//#endregion
//#region src/Node.d.ts
/**
* Represents a node in a diagram.
* Nodes are connected using the `to()`, `from()`, and `with()` methods.
*
* @example
* ```typescript
* const db = Database("PostgreSQL");
* const app = AppServer("API");
*
* // Connect db to app (db → app)
* db.to(app);
*
* // Connect with edge styling
* db.to(EdgeColor("red"), app);
*
* // Undirected connection
* db.with(app);
* ```
*/
interface Node {
/** The display label of the node */
label: string;
/** Unique identifier for the node */
nodeId: string;
/** The cluster this node belongs to, if any */
cluster: Cluster | undefined;
/**
* Node attributes that can be modified by hooks.
* This provides direct access to the internal attribute store.
* Changes here will be reflected in the rendered output.
*/
nodeAttrs: Record<string, string | number>;
/** The cloud provider (e.g., "aws", "gcp", "azure") */
provider?: string;
/** The service type (e.g., "compute", "database", "storage") */
type?: string;
/** The specific resource type (e.g., "EC2", "S3", "RDS") */
resource?: string;
/** CSS class(es) to add to the rendered SVG element */
className: string | undefined;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs: Record<string, string>;
/** @internal */
["~id"]: string;
/** @internal */
["~diagram"]: Diagram | null;
/** @internal */
["~cluster"]: Cluster | undefined;
/** @internal */
["~attrs"]: Record<string, string | number>;
/** @internal */
["~iconDataUrl"]: string | null;
/** @internal */
["~type"]?: string;
/** @internal */
["~register"](parent: Diagram | Cluster): void;
/** Metadata attached to this node (e.g., cloud provider specs, pricing) */
metadata: Record<string, any>;
/**
* Connect this node to another node (forward direction)
* Creates an edge from this node to the target
* @param target - The target node or array of nodes
* @returns The target node(s) for chaining
*/
to(target: Node): Node;
to(targets: Node[]): Node[];
/**
* Connect this node to another node with an edge
* @param edge - The edge configuration
* @returns The edge for further configuration
*/
to(edge: Edge): Edge;
/**
* Connect this node to another node with a styled edge
* @param edge - The edge configuration
* @param target - The target node
* @returns The target node for chaining
*/
to(edge: Edge, target: Node): Node;
to(edge: Edge, targets: Node[]): Node[];
/**
* Connect this node from another node (reverse direction)
* Creates an edge pointing back from the target to this node
* @param source - The source node or array of nodes
* @returns This node for chaining
*/
from(source: Node): Node;
from(sources: Node[]): Node;
/**
* Connect from a node with an edge (reverse direction)
* @param edge - The edge configuration
* @param source - The source node
* @returns This node for chaining
*/
from(edge: Edge, source: Node): Node;
from(edge: Edge, sources: Node[]): Node[];
/**
* Create an undirected connection between nodes
* Creates an edge without arrowheads
* @param target - The target node or array of nodes
* @returns The target node(s) for chaining
*/
with(target: Node): Node;
with(targets: Node[]): Node[];
/**
* Create an undirected connection with edge styling
* @param edge - The edge configuration
* @param target - The target node
* @returns The target node for chaining
*/
with(edge: Edge, target: Node): Node;
with(edge: Edge, targets: Node[]): Node[];
/**
* Get the SVG element for this node.
* If no svg argument is provided, queries the current document.
* @param svg - Optional SVG string or Element to query within
* @returns The SVG element, or null if not found
*/
getElement(svg?: string | Element): Element | null;
/**
* Internal method to connect this node to another with an edge
* @param target - The target node
* @param edge - The edge configuration
* @returns The target node
* @internal
*/
["~connect"](target: Node, edge: Edge): Node;
}
/**
* Create a new node
* @param label - The display label for the node
* @param options - Optional configuration for the node
* @returns A new Node instance
* @example
* ```typescript
* const node = Node("My Service", { shape: "box", color: "blue" });
* diagram.add(node);
* ```
*/
declare function Node(label?: string, options?: NodeOptions): Node;
//#endregion
//#region src/plugins/types.d.ts
/**
* Runtime environment support declaration
*/
interface RuntimeSupport {
/** Supports Node.js runtime */
node: boolean;
/** Supports browser runtime */
browser: boolean;
/** Supports Deno runtime */
deno: boolean;
/** Supports Bun runtime */
bun: boolean;
}
/**
* Core plugin interface - all plugins must implement this
* Plugins are created via factory functions to maintain consistency with diagrams-js patterns
*/
interface DiagramsPlugin {
/** Unique plugin name (e.g., "docker-compose", "aws-metadata") */
name: string;
/** Plugin version (semver) */
version: string;
/** Plugin API version for compatibility checking */
apiVersion: "1.0";
/** Runtime environment support */
runtimeSupport: RuntimeSupport;
/** Plugin dependencies - names of other plugins that must be loaded first */
dependencies?: string[];
/** Required configuration keys (if any) */
requiredConfig?: string[];
/** Plugin capabilities */
capabilities: PluginCapability[];
/**
* Initialize the plugin with configuration
* Called after dependencies are resolved
*/
initialize?: (config: unknown, context: PluginContext) => Promise<void>;
/**
* Clean up resources when plugin is unregistered
*/
destroy?: () => Promise<void>;
}
/**
* Plugin capability types
*/
type PluginCapability = ImporterCapability | ExporterCapability | RendererCapability | MetadataCapability | HookCapability;
/**
* Import capability - allows importing from external formats
*/
interface ImporterCapability {
type: "importer";
/** Unique importer name (e.g., "docker-compose", "terraform") */
name: string;
/** File extensions this importer handles (e.g., [".yml", ".yaml"]) */
extensions: string[];
/** MIME types this importer can handle */
mimeTypes?: string[];
/** Check if this importer can handle the given source */
canImport: (source: string | string[], context: ImportContext) => Promise<boolean>;
/** Import source into diagram */
import: (source: string | string[], diagram: Diagram, context: ImportContext) => Promise<void>;
}
/**
* Export capability - allows exporting to external formats
*/
interface ExporterCapability {
type: "exporter";
/** Unique exporter name (e.g., "docker-compose", "terraform") */
name: string;
/** Default file extension (e.g., ".tf", ".yml") */
extension: string;
/** MIME type of exported content */
mimeType: string;
/** Export diagram to the target format */
export: (diagram: Diagram, context: ExportContext) => Promise<string | Uint8Array>;
}
/**
* Renderer capability - custom renderers for different output formats
*/
interface RendererCapability {
type: "renderer";
/** Renderer name */
name: string;
/** Supported output formats */
formats: string[];
/** Render SVG to target format */
render: (svg: string, format: string, context: RenderContext) => Promise<string | Uint8Array>;
}
/**
* Metadata capability - provides cloud provider metadata (pricing, specs, etc.)
*/
interface MetadataCapability {
type: "metadata";
/** Cloud provider name (e.g., "aws", "azure", "gcp") */
provider: string;
/** Node types this provider supports */
nodeTypes: string[];
/** Get metadata for a node type */
getMetadata: (nodeType: string, config: unknown, context: MetadataContext) => Promise<NodeMetadata>;
}
/**
* Hook capability - register lifecycle hooks
*/
interface HookCapability {
type: "hook";
/** Hooks to register */
hooks: Array<{
/** Hook event name */event: HookEvent; /** Handler function */
handler: HookHandler; /** Priority (higher = earlier execution, default: 0) */
priority?: number;
}>;
}
/**
* Plugin factory function type
*/
type CreatePlugin = (config?: unknown) => DiagramsPlugin;
/**
* Plugin context passed to capabilities and hooks
*/
interface PluginContext {
/** The plugin registry */
registry: PluginRegistry;
/** Fetch function for making HTTP requests */
fetch: typeof globalThis.fetch;
/** Get a registered plugin by name */
getPlugin: (name: string) => DiagramsPlugin | undefined;
/** Get an importer by name */
getImporter: (name: string) => ImporterCapability | undefined;
/** Get an exporter by name */
getExporter: (name: string) => ExporterCapability | undefined;
/** Get a renderer by format */
getRenderer: (format: string) => RendererCapability | undefined;
/** Get a metadata provider by name */
getMetadataProvider: (provider: string) => MetadataCapability | undefined;
/** Execute hooks for an event */
executeHooks: <T>(event: HookEvent, data: T) => Promise<T>;
/** Get a list of available resources */
loadResourcesList: () => Promise<typeof resources_list_d_exports | null>;
/** Load Yaml module */
loadYaml: () => Promise<typeof yaml_d_exports | null>;
/**
* Library exports - use these instead of importing diagrams-js to avoid multiple instances.
* This provides access to all diagrams-js exports including Diagram, Node, Edge, Custom, Iconify, etc.
*/
lib: typeof index_d_exports;
}
/**
* Context passed to importers
*/
interface ImportContext extends PluginContext {
/** Format being imported */
format: string;
/** Source content (string or array of strings for grouped/clustered import) */
source: string | string[];
}
/**
* Context passed to exporters
*/
interface ExportContext extends PluginContext {
/** Format being exported */
format: string;
}
/**
* Context passed to renderers
*/
interface RenderContext extends PluginContext {
/** Output format */
format: string;
/** Render options */
options?: Record<string, unknown>;
}
/**
* Context passed to metadata providers
*/
interface MetadataContext extends PluginContext {
/** Node being queried */
node: Node;
/** Current node metadata (if any) */
currentMetadata?: Record<string, unknown>;
}
/**
* Context passed to hook handlers
*/
interface HookContext extends PluginContext {
/** Event being handled */
event: HookEvent;
}
/**
* Hook event types
*/
declare enum HookEvent {
BEFORE_IMPORT = "before:import",
AFTER_IMPORT = "after:import",
BEFORE_EXPORT = "before:export",
AFTER_EXPORT = "after:export",
BEFORE_RENDER = "before:render",
AFTER_RENDER = "after:render",
AFTER_LAYOUT = "after:layout",
BEFORE_SERIALIZE = "before:serialize",
AFTER_DESERIALIZE = "after:deserialize",
NODE_CREATE = "node:create",
EDGE_CREATE = "edge:create",
CLUSTER_CREATE = "cluster:create",
METADATA_ATTACH = "metadata:attach",
METADATA_CALCULATE = "metadata:calculate"
}
/**
* Hook handler function type
*/
type HookHandler<T = unknown> = (data: T, context: HookContext) => Promise<T | void>;
/**
* Node metadata structure
*/
interface NodeMetadata {
/** Cloud provider */
provider?: string;
/** Region */
region?: string;
/** Instance/node type */
instanceType?: string;
/** Specifications */
specifications?: {
cpu?: number | string;
memory?: string;
storage?: string;
[key: string]: unknown;
};
/** Pricing information */
pricing?: {
hourly?: number;
monthly?: number;
onDemand?: number;
reserved?: number;
spot?: number;
[key: string]: unknown;
};
/** Availability zones */
availabilityZones?: string[];
/** Compliance certifications */
compliance?: string[];
/** Additional provider-specific metadata */
[key: string]: unknown;
}
/**
* Plugin registry interface
*/
interface PluginRegistry {
/** Register a plugin */
register: (plugin: DiagramsPlugin) => Promise<void>;
/** Unregister a plugin */
unregister: (name: string) => Promise<void>;
/** Get a plugin by name */
getPlugin: (name: string) => DiagramsPlugin | undefined;
/** Get an importer by name */
getImporter: (name: string) => ImporterCapability | undefined;
/** Get an exporter by name */
getExporter: (name: string) => ExporterCapability | undefined;
/** Get a renderer by format */
getRenderer: (format: string) => RendererCapability | undefined;
/** Get a metadata provider by name */
getMetadataProvider: (provider: string) => MetadataCapability | undefined;
/** Execute hooks for an event */
executeHooks: <T>(event: HookEvent, data: T) => Promise<T>;
/** List all registered plugins */
listPlugins: () => DiagramsPlugin[];
/** List all capabilities by type */
listCapabilities: () => {
importers: string[];
exporters: string[];
renderers: string[];
metadataProviders: string[];
};
loadResourcesList: () => Promise<typeof resources_list_d_exports | null>;
loadYaml: () => Promise<typeof yaml_d_exports | null>;
}
/**
* Error thrown when a plugin fails to load
*/
declare class PluginError extends Error {
pluginName?: string | undefined;
cause?: Error | undefined;
constructor(message: string, pluginName?: string | undefined, cause?: Error | undefined);
}
/**
* Error thrown when dependency resolution fails
*/
declare class DependencyError extends PluginError {
missingDependencies: string[];
circularDependencies?: string[] | undefined;
constructor(pluginName: string, missingDependencies: string[], circularDependencies?: string[] | undefined);
}
/**
* Error thrown when runtime is not supported
*/
declare class RuntimeError extends PluginError {
requiredRuntimes: RuntimeSupport;
currentRuntime: string;
constructor(pluginName: string, requiredRuntimes: RuntimeSupport, currentRuntime: string);
}
//#endregion
//#region src/types.d.ts
/**
* Theme definitions for diagram styling.
* Each theme defines cluster background colors (by depth), border color, and edge color.
*/
declare const THEMES: {
/** Pastel colors - soft blues, greens, and purples */readonly pastel: {
readonly bgcolor: readonly ["#E5F5FD", "#EBF3E7", "#ECE8F6", "#FDF7E3"];
readonly pencolor: "#AEB6BE";
readonly edgecolor: "#7B8894";
}; /** Neutral grayscale theme */
readonly neutral: {
readonly bgcolor: readonly ["#F8F9FA", "#F1F3F5", "#E9ECEF", "#DEE2E6"];
readonly pencolor: "#ADB5BD";
readonly edgecolor: "#495057";
}; /** Blue color palette */
readonly blues: {
readonly bgcolor: readonly ["#E7F5FF", "#D0EBFF", "#A5D8FF", "#74C0FC"];
readonly pencolor: "#339AF0";
readonly edgecolor: "#1971C2";
}; /** Green color palette */
readonly greens: {
readonly bgcolor: readonly ["#EBFBEE", "#D3F9D8", "#B2F2BB", "#8CE99A"];
readonly pencolor: "#40C057";
readonly edgecolor: "#2F9E44";
}; /** Orange/warm color palette */
readonly orange: {
readonly bgcolor: readonly ["#FFF4E6", "#FFE8CC", "#FFD8A8", "#FFC078"];
readonly pencolor: "#FD7E14";
readonly edgecolor: "#E8590C";
};
};
/** Available theme names */
type ThemeName = keyof typeof THEMES;
/** Theme configuration type */
type ThemeConfig = (typeof THEMES)[ThemeName];
/**
* Options for creating a diagram
* @example
* ```typescript
* const options: DiagramOptions = {
* name: "My Architecture",
* direction: "TB",
* theme: "pastel",
* curvestyle: "ortho"
* };
* const diagram = Diagram("", options);
* ```
*/
interface DiagramOptions {
/** The name/title of the diagram (overrides the name parameter) */
name?: string;
/** The filename used when saving (defaults to name converted to snake_case) */
filename?: string;
/** Layout direction: TB (top-bottom), BT (bottom-top), LR (left-right), RL (right-left) */
direction?: "TB" | "BT" | "LR" | "RL";
/** Edge curve style: ortho (orthogonal), curved, spline, or polyline */
curvestyle?: "ortho" | "curved" | "spline" | "polyline";
/** Whether to automatically prefix node labels with their type */
autolabel?: boolean;
/** Whether to create a strict graph (no duplicate edges) */
strict?: boolean;
/** Color theme for the diagram */
theme?: ThemeName;
/** Graph-level Graphviz attributes */
graphAttr?: Record<string, string>;
/** Default node Graphviz attributes */
nodeAttr?: Record<string, string>;
/** Default edge Graphviz attributes */
edgeAttr?: Record<string, string>;
/** Custom plugin registry (creates new one if not provided) */
pluginRegistry?: PluginRegistry;
}
/**
* Options for rendering a diagram
* @example
* ```typescript
* const svg = await diagram.render({ format: "svg" });
* const png = await diagram.render({ format: "png", scale: 2 });
* ```
*/
interface RenderOptions {
/** Output format: svg, png, jpg, dot, or json */
format?: "svg" | "png" | "jpg" | "dot" | "json";
/** Output filename */
filename?: string;
/** Output width in pixels (for PNG/JPG) */
width?: number;
/** Output height in pixels (for PNG/JPG) */
height?: number;
/** Scale factor for output (for PNG/JPG, default: 2) */
scale?: number;
/** Whether to inject icons into SVG output */
injectIcons?: boolean;
/** Whether to embed diagram metadata into SVG output (default: true) */
embedData?: boolean;
/** Whether to return output as data URL */
dataUrl?: boolean;
}
/**
* Options for creating an edge
* @example
* ```typescript
* const edge = Edge({ label: "HTTP", color: "blue", style: "dashed" });
* ```
*/
interface EdgeOptions {
/** The source node (internal use) */
node?: Node;
/** Whether this is a forward edge */
forward?: boolean;
/** Whether this is a reverse edge */
reverse?: boolean;
/** Edge label text */
label?: string;
/** Edge color */
color?: string;
/** Edge style (solid, dashed, dotted, etc.) */
style?: string;
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
/** Additional Graphviz edge attributes */
[key: string]: unknown;
}
/**
* Options for creating a node
* @example
* ```typescript
* const node = Node("My Service", { shape: "box", color: "blue" });
* ```
*/
interface NodeOptions {
/** Custom unique identifier for the node */
nodeId?: string;
/** @internal Node type for autolabel */
["~type"]?: string;
/** @internal Icon data URL */
["~iconDataUrl"]?: string;
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
/** Additional Graphviz node attributes */
[key: string]: unknown;
}
/**
* Options for creating a cluster
* @example
* ```typescript
* const cluster = diagram.cluster("VPC", {
* className: "production",
* dataAttrs: { region: "us-east-1" }
* });
* ```
*/
interface ClusterOptions {
/** Graphviz attributes for the cluster */
graphAttr?: Record<string, string>;
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
}
type Yaml = typeof yaml_d_exports;
//#endregion
//#region src/json.d.ts
/**
* JSON representation of a node in the diagram.
*/
interface DiagramNodeJSON {
/** Unique identifier for the node */
id: string;
/** Display label for the node */
label?: string;
/** Cloud provider identifier (e.g., 'aws', 'gcp', 'azure') */
provider?: string;
/** Service type within the provider (e.g., 'compute', 'storage') */
type?: string;
/** Specific resource type (e.g., 'EC2', 'S3', 'RDS') */
resource?: string;
/** Custom icon URL or data URI */
iconUrl?: string;
/** Additional Graphviz attributes */
attrs?: Record<string, string | number>;
/** Metadata attached to this node (e.g., cloud provider specs, pricing) */
metadata?: Record<string, any>;
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
}
/**
* JSON representation of an edge (connection) between nodes.
*/
interface DiagramEdgeJSON {
/** Source node ID */
from: string;
/** Target node ID */
to: string;
/** Edge direction */
direction?: "forward" | "back" | "both" | "none";
/** Edge label text */
label?: string;
/** Edge color */
color?: string;
/** Edge line style */
style?: string;
/** Additional Graphviz attributes */
attrs?: Record<string, string>;
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
}
/**
* JSON representation of a cluster (group) of nodes.
*/
interface DiagramClusterJSON {
/** Display label for the cluster */
label: string;
/** Array of node IDs that belong to this cluster */
nodes?: string[];
/** Graphviz attributes for this cluster */
graphAttr?: Record<string, string>;
/** Nested clusters */
clusters?: DiagramClusterJSON[];
/** CSS class(es) to add to the rendered SVG element */
className?: string;
/** Custom data attributes to add to the rendered SVG element */
dataAttrs?: Record<string, string>;
}
/**
* A provider module mapping type names to factory functions.
* Can be passed to `fromJSON()` to override or supplement the auto-registered providers.
*
* @example
* ```typescript
* import * as awsCompute from "diagrams-js/aws/compute";
* const diagram = fromJSON(json, { providers: [awsCompute] });
* ```
*/
type ProviderModule = Record<string, (label?: string, options?: Record<string, unknown>) => Node>;
/**
* Options for `fromJSON()`.
*/
interface FromJSONOptions {
/**
* Additional provider modules for resolving node icons from their type.
*
* Provider factories are auto-registered when their modules are imported,
* so in most cases you don't need this option. It's available for cases
* where you want to override or supplement the auto-registered factories.
*
* @example
* ```typescript
* // Usually not needed -- factories auto-register when you import them:
* import { EC2 } from "diagrams-js/aws/compute";
*
* // But you can explicitly pass modules if needed:
* import * as awsCompute from "diagrams-js/aws/compute";
* fromJSON(json, { providers: [awsCompute] });
* ```
*/
providers?: ProviderModule[];
}
/**
* Complete JSON representation of a diagram.
* This is the top-level type for serialization/deserialization.
*/
interface DiagramJSON {
/** JSON Schema reference for validation and IDE support */
$schema?: string;
/** The name/title of the diagram */
name?: string;
/** The filename used when saving */
filename?: string;
/** Layout direction */
direction?: "TB" | "BT" | "LR" | "RL";
/** Edge curve style */
curvestyle?: "ortho" | "curved" | "spline" | "polyline";
/** Whether to auto-prefix labels with type */
autolabel?: boolean;
/** Whether to create a strict graph */
strict?: boolean;
/** Color theme */
theme?: "pastel" | "neutral" | "blues" | "greens" | "orange";
/** Graph-level Graphviz attributes */
graphAttr?: Record<string, string>;
/** Default node Graphviz attributes */
nodeAttr?: Record<string, string>;
/** Default edge Graphviz attributes */
edgeAttr?: Record<string, string>;
/** All nodes in the diagram */
nodes: DiagramNodeJSON[];
/** All edges between nodes */
edges?: DiagramEdgeJSON[];
/** Clusters (groups) of nodes */
clusters?: DiagramClusterJSON[];
}
/**
* Create a Diagram from a JSON representation.
* This is the inverse of `diagram.toJSON()`.
*
* @param input - The JSON object or string representing a diagram
* @returns A fully constructed Diagram with all nodes, edges, and clusters
*
* @example
* ```typescript
* import { Diagram } from "diagrams-js";
*
* const json = {
* name: "My Architecture",
* direction: "LR",
* nodes: [
* { id: "web", label: "Web Server", provider: "aws", type: "compute", resource: "EC2" },
* { id: "db", label: "Database", provider: "aws", type: "database", resource: "RDS" }
* ],
* edges: [
* { from: "web", to: "db", label: "SQL" }
* ]
* };
*
* const diagram = await Diagram.fromJSON(json);
* const svg = await diagram.render(); // icons resolved automatically
* ```
*/
declare function fromJSON(input: DiagramJSON | string, opts?: FromJSONOptions): Promise<Diagram>;
//#endregion
//#region src/diff.d.ts
/**
* Type of change detected during diff computation.
*/
type ChangeKind = "added" | "removed" | "modified" | "unchanged";
/**
* Diff result for a single node.
*/
interface NodeDiff {
/** The type of change */
kind: ChangeKind;
/** The node before changes (for removed, modified) */
before?: DiagramNodeJSON;
/** The node after changes (for added, modified) */
after?: DiagramNodeJSON;
/** Array of field paths that changed (for modified) */
changes?: string[];
}
/**
* Diff result for a single edge.
*/
interface EdgeDiff {
/** The type of change */
kind: ChangeKind;
/** The edge before changes */
before?: DiagramEdgeJSON;
/** The edge after changes */
after?: DiagramEdgeJSON;
/** Array of field paths that changed */
changes?: string[];
}
/**
* Diff result for a cluster (recursive).
*/
interface ClusterDiff {
/** The type of change */
kind: ChangeKind;
/** Cluster label */
label: string;
/** The cluster before changes */
before?: DiagramClusterJSON;
/** The cluster after changes */
after?: DiagramClusterJSON;
/** Array of field paths that changed */
changes?: string[];
/** Nested cluster diffs */
clusters?: ClusterDiff[];
/** Node IDs in this cluster and their diff status */
nodes?: Map<string, NodeDiff>;
}
/**
* Summary of changes in the diff.
*/
interface DiffSummary {
/** Number of added nodes/edges/clusters */
added: number;
/** Number of removed nodes/edges/clusters */
removed: number;
/** Number of modified nodes/edges/clusters */
modified: number;
/** Number of unchanged nodes/edges/clusters */
unchanged: number;
}
/**
* Metadata-level changes (diagram options, not individual elements).
*/
interface DiffMeta {
/** Diagram name change */
name?: {
before?: string;
after?: string;
};
/** Theme change */
theme?: {
before?: string;
after?: string;
};
/** Direction change */
direction?: {
before?: string;
after?: string;
};
/** Curve style change */
curvestyle?: {
before?: string;
after?: string;
};
/** Graph attributes change */
graphAttr?: {
before?: Record<string, string>;
after?: Record<string, string>;
};
/** Node attributes change */
nodeAttr?: {
before?: Record<string, string>;
after?: Record<string, string>;
};
/** Edge attributes change */
edgeAttr?: {
before?: Record<string, string>;
after?: Record<string, string>;
};
}
/**
* Complete diff result for a diagram comparison.
*/
interface DiagramDiffResult {
/** Node diffs by node ID */
nodes: Map<string, NodeDiff>;
/** Edge diffs by composite key "from->to[label]" */
edges: Map<string, EdgeDiff>;
/** Cluster diffs */
clusters: ClusterDiff[];
/** Summary counts */
summary: DiffSummary;
/** Metadata-level changes */
meta: DiffMeta;
}
/**
* Options for computing a diff.
*/
interface DiffOptions {
/** Fields to ignore during comparison */
ignore?: {
/** Ignore position/layout changes (default: true) */position?: boolean; /** Ignore metadata changes entirely, or specific metadata keys */
metadata?: boolean | string[]; /** Ignore specific Graphviz attributes */
attrs?: string[]; /** Ignore node ID changes - treat same-fingerprint nodes as unchanged (default: false) */
nodeId?: boolean;
};
/** Custom node matching function (overrides default ID + fingerprint matching) */
matchNodes?: (a: DiagramNodeJSON, b: DiagramNodeJSON) => boolean;
}
/**
* Options for rendering a diff.
*/
interface RenderDiffOptions {
/** Output format: svg (combined) or html (self-contained page) */
format?: "svg" | "html";
/** Layout mode: side-by-side (default) or stacked */
layout?: "side-by-side" | "stacked";
/** Color theme: light (default) or dark */
theme?: "light" | "dark";
/** How to display unchanged elements: "show" | "dim" | "hide" (default: "show") */
showUnchanged?: "show" | "dim" | "hide";
/** Show legend in HTML output (default: true) */
showLegend?: boolean;
/** Show summary header in HTML output (default: true) */
showSummary?: boolean;
/** Enable hover tooltips in HTML output (default: true) */
hoverDetails?: boolean;
}
/**
* Compute the diff between two diagram versions.
*
* @param before - The original diagram (JSON or Diagram object)
* @param after - The updated diagram (JSON or Diagram object)
* @param opts - Options for diff computation
* @returns Complete diff result with nodes, edges, clusters, and summary
*
* @example
* ```typescript
* const diff = computeDiff(diagramV1.toJSON(), diagramV2.toJSON());
* console.log(diff.summary); // { added: 2, removed: 1, modified: 3, ... }
* ```
*/
declare function computeDiff(before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: DiffOptions): DiagramDiffResult;
/**
* Render a visual diff between two diagram versions.
*
* @param diff - The computed diff result from `computeDiff()`
* @param before - The original diagram (JSON or Diagram object)
* @param after - The updated diagram (JSON or Diagram object)
* @param opts - Options for rendering the diff
* @returns Promise resolving to SVG or HTML string
*
* @example
* ```typescript
* const diff = computeDiff(beforeJson, afterJson);
* const html = await renderDiff(diff, beforeJson, afterJson, { format: "html" });
* await fs.writeFile("diff.html", html);
* ```
*/
declare function renderDiff(diff: DiagramDiffResult, before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: RenderDiffOptions): Promise<string>;
//#endregion
//#region src/icons.d.ts
/**
* Maps a node to its icon information
*/
interface NodeIconMap {
/** The node that has an icon */
node: Node;
/** Key to identify the icon in IconData */
icon: string;
/** Optional path to the icon file */
iconPath?: string;
}
/**
* Map of icon keys to data URIs
*/
interface IconData {
[key: string]: string;
}
//#endregion
//#region src/Diagram.d.ts
/**
* Represents a diagram that contains nodes, edges, and clusters.
* Diagrams are rendered using Graphviz to produce SVG, PNG, JPG, or DOT output.
*
* @example
* ```typescript
* const diagram = Diagram("My Architecture", {
* direction: "TB",
* theme: "pastel"
* });
*
* const db = diagram.add(Database("PostgreSQL"));
* const app = diagram.add(AppServer("API"));
* db.to(app);
*
* const svg = await diagram.render();
* ```
*/
interface Diagram {
/** The name/title of the diagram */
name: string;
/** The filename used when saving the diagram */
filename: string;
/** Layout direction: TB (top-bottom), BT (bottom-top), LR (left-right), RL (right-left) */
direction: "TB" | "BT" | "LR" | "RL";
/** Edge curve style: ortho (orthogonal), curved, spline, or polyline */
curveStyle: "ortho" | "curved" | "spline" | "polyline";
/** Whether to automatically prefix node labels with their type */
autolabel: boolean;
/** Whether to create a strict graph (no duplicate edges) */
strict: boolean;
/** The color theme name */
theme: ThemeName;
/** The theme configuration */
themeConfig: ThemeConfig;
/** Graph-level attributes for Graphviz */
graphAttr: Record<string, string>;
/** Default node attributes for Graphviz */
nodeAttr: Record<string, string>;
/** Default edge attributes for Graphviz */
edgeAttr: Record<string, string>;
/** @internal Track if user explicitly set icon-related properties in nodeAttr */
["~userNodeAttr"]?: {
shape?: string;
height?: string;
width?: string;
fixedsize?: string;
margin?: string;
labelloc?: string;
imagescale?: string;
};
/**
* Add a node to this diagram
* @param node - The node to add
* @returns The added node
*/
add<T extends Node>(node: T): T;
/**
* Create a cluster (group) of nodes
* @param label - The label for the cluster
* @param options - Optional cluster configuration
* @returns The cluster object
*/
cluster(label: string, options?: ClusterOptions): Cluster;
/**
* Render the diagram to SVG or other formats
* @param options - Rendering options
* @returns The rendered output
*/
render(options?: RenderOptions): Promise<string | Uint8Array>;
/**
* Render with icon data (for external icon injection)
* @param iconData - Map of icon keys to data URIs
* @param nodeMap - Node-to-icon mappings
* @returns The rendered SVG string
* @internal
*/
renderWithIcons(iconData?: IconData, nodeMap?: NodeIconMap[]): Promise<string>;
/**
* Serialize the diagram to JSON
* @returns JSON representation of the diagram
*/
toJSON(): DiagramJSON;
/**
* Save the diagram to a file
* @param filepath - The file path to save to (optional)
* @param options - Rendering options
* @returns Promise that resolves when saved
*/
save(filepath?: string, options?: RenderOptions): Promise<void>;
/**
* Convert the diagram to DOT format string
* @returns DOT format string
*/
toString(): string;
/**
* Import diagram from external format
* @param source - Source content to import (string or array of strings for grouped/clustered import)
* @param format - Format to import from (e.g., "docker-compose", "terraform")
* @returns Promise that resolves when import is complete
*/
import(source: string | string[], format: string): Promise<void>;
/**
* Register plugins with the diagram
* @param plugins - Array of plugin factory functions
* @returns Promise that resolves when all plugins are registered and initialized
* @example
* ```typescript
* const diagram = Diagram("My Architecture");
* await diagram.registerPlugins([dockerComposePlugin, loggingPlugin]);
* diagram.add(EC2("Web Server"));
* ```
*/
registerPlugins(plugins?: DiagramsPlugin[]): Promise<void>;
/**
* Export diagram to external format
* @param format - Format to export to (e.g., "docker-compose", "terraform")
* @returns Promise resolving to exported content
*/
export(format: string): Promise<string | Uint8Array>;
/**
* Attach metadata from a provider to nodes
* @param provider - Provider name (e.g., "aws", "azure", "gcp")
* @param nodeType - Optional node type filter (e.g., "EC2")
* @returns Promise that resolves when metadata is attached
*/
attachMetadata(provider: string, nodeType?: string): Promise<void>;
/**
* Get the plugin registry for this diagram
* @returns The plugin registry
*/
registry: PluginRegistry;
/**
* Register a node with an icon for automatic icon injection
* @param node - The node to register
* @param iconKey - Key to identify the icon in iconData
* @param iconPath - Optional path to the icon file
* @internal
*/
["~registerIcon"](node: Node, iconKey: string, iconPath?: string): void;
/**
* Track a node object for serialization
* @param node - The node object to track
* @internal
*/
["~trackNode"](node: Node): void;
/**
* Load icon data for injection
* @param iconData - Map of icon keys to data URIs
* @internal
*/
["~setIconData"](iconData: IconData): void;
/**
* Get the node icon map
* @returns Array of node-to-icon mappings
* @internal
*/
["~getNodeIconMap"](): NodeIconMap[];
/**
* Get the icon data
* @returns Map of icon keys to data URIs
* @internal
*/
["~getIconData"](): IconData;
/**
* Track a node that has an icon (for automatic icon injection)
* @param node - The node with an icon
* @param iconDataUrl - The data URL of the icon
* @internal
*/
["~trackNodeWithIcon"](node: Node, iconDataUrl: string): void;
/**
* Track a pending icon load promise
* @param promise - Promise that resolves when icon is loaded
* @internal
*/
["~trackPendingIconLoad"](promise: Promise<void>): void;
/**
* Internal method to register a node with the diagram
* @param nodeId - Unique identifier for the node
* @param label - Display label for the node
* @param attrs - Graphviz attributes for the node
* @internal
*/
["~node"](nodeId: string, label: string, attrs: Record<string, unknown>): void;
/**
* Internal method to connect two nodes with an edge
* @param from - Source node
* @param to - Target node
* @param edge - Edge object
* @internal
*/
["~connect"](from: Node, to: Node, edge: Edge): void;
/**
* Internal method to add a subgraph/cluster
* @param cluster - The cluster to add
* @internal
*/
["~subgraph"](cluster: Cluster): void;
}
/**
* Create a new diagram
* @param name - The name/title of the diagram (optional, can also be set in options)
* @param options - Configuration options for the diagram
* @returns A new Diagram instance
* @example
* ```typescript
* const diagram = Diagram("My System", {
* direction: "LR",
* theme: "pastel",
* curvestyle: "ortho"
* });
* ```
*/
declare function Diagram(name?: string, options?: DiagramOptions): Diagram;
declare namespace Diagram {
var fromJSON: typeof fromJSON;
}
declare namespace Diagram {
var fromSVG: (svg: string) => Promise<Diagram>;
}
declare namespace Diagram {
var diff: (before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: DiffOptions) => Promise<DiagramDiffResult>;
}
declare namespace Diagram {
var renderDiff: (before: DiagramJSON | Diagram, after: DiagramJSON | Diagram, opts?: RenderDiffOptions) => Promise<string>;
}
//#endregion
//#region src/Custom.d.ts
/**
* Custom node with an external icon
* Allows using icons from URLs or local file paths
*
* @example
* ```typescript
* // With URL (browser)
* const custom = Custom("My Service", "https://example.com/icon.png");
*
* // With local path (Node.js with file system access)
* const local = Custom("Local Service", "./icons/my-icon.png");
*
* // In a diagram
* const diagram = Diagram("Custom Nodes");
* const node = diagram.add(Custom("Custom", "https://example.com/icon.png"));
* ```
*/
interface Custom extends Node {
/** @internal */
["~iconUrl"]: string;
/**
* Get the icon URL/path for this node
* @returns The icon URL or file path
* @internal
*/
["~getIconUrl"](): string;
/**
* Load the icon and return as data URL
* @returns Promise resolving to the icon data URL, or null if loading failed
*/
loadIcon(): Promise<string | null>;
}
/**
* Create a custom node with an external icon
* @param label - The display label for the node
* @param iconUrl - URL or file path to the icon image (supports PNG, JPG, SVG)
* @param options - Optional configuration for the node
* @returns A new Custom node instance
* @example
* ```typescript
* // Using a remote URL
* const node = Custom("My Service", "https://example.com/icon.png");
* diagram.add(node);
*
* // Using a local file (Node.js)
* const local = Custom("Local Service", "./assets/icon.svg");
* diagram.add(local);
*
* // With custom options
* const styled = Custom("Service", "icon.png", {
* shape: "box",
* width: "1.2",
* height: "1.2"
* });
* ```
*/
declare function Custom(label: string, iconUrl: string, options?: {
/** Custom node ID */nodeId?: string; /** Graphviz shape attribute */
shape?: string; /** Graphviz height attribute */
height?: string; /** Graphviz width attribute */
width?: string; /** Graphviz fixedsize attribute */
fixedsize?: string; /** Graphviz margin attribute */
margin?: string; /** Graphviz labelloc attribute */
labelloc?: string; /** Graphviz imagescale attribute */
imagescale?: string;
}): Custom;
/**
* Create a custom node with an Iconify icon
* Uses the Iconify API (https://iconify.design/) to fetch icons
*
* @param label - The display label for the node
* @param iconName - Icon name in "prefix:name" format (e.g., "mdi:home", "logos:aws")
* @returns A new Custom node instance with the Iconify icon
*
* @example
* ```typescript
* // Material Design icon
* const home = Iconify("Home", "mdi:home");
*
* // Technology logos
* const aws = Iconify("AWS", "logos:aws");
* const docker = Iconify("Docker", "logos:docker");
*
* // In a diagram
* const diagram = Diagram("Architecture");
* diagram.add(Iconify("Web Server", "mdi:server"));
* ```
*
* @see https://iconify.design/ - Browse icons at https://icon-sets.iconify.design/
*
* The implementation is simple:
* ```typescript
* const Iconify = (name, image) => Custom(name, `https://api.iconify.design/${image}.svg`)
* ```
*/
declare function Iconify(label: string, iconName: string): Custom;
//#endregion
//#region src/plugins/registry.d.ts
/**
* Create a plugin registry
*
* @example
* ```typescript
* const registry = createPluginRegistry();
* await registry.register(createDockerComposePlugin);
* await registry.register(createAWSMetadataPlugin, { region: 'us-west-2' });
* ```
*/
declare function createPluginRegistry(): PluginRegistry;
//#endregion
//#region src/plugins/built-in/json.d.ts
/**
* Create the built-in JSON plugin
*
* This plugin is automatically registered with every diagram and provides
* native JSON serialization/deserialization capabilities.
*
* @example
* ```typescript
* const diagram = Diagram('Test');
* // JSON import/export is available by default
* const json = diagram.toJSON();
* ```
*/
declare function createJSONPlugin(): DiagramsPlugin;
/**
* Default JSON plugin instance
* Exported for convenience
*/
declare const jsonPlugin: DiagramsPlugin;
//#endregion
//#region src/plugins/built-in/svg.d.ts
/**
* Create the built-in SVG plugin
*
* This plugin is automatically registered with every diagram and provides
* SVG export/import with embedded metadata capabilities.
*/
declare function createSVGPlugin(): DiagramsPlugin;
/**
* Default SVG plugin instance
* Exported fo