UNPKG

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
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