coreuml-core
v1.0.1
Published
Framework-agnostic UML diagram engine for parsing, layout, and serialization
Maintainers
Readme
CoreUML
A framework-agnostic UML diagram engine for parsing, layout, and serialization. CoreUML provides a simple DSL for creating UML class diagrams with automatic layout, manual positioning, and SVG export capabilities.
Features
Core Functionality
- 📝 Simple DSL: Intuitive syntax for defining UML class diagrams
- 🎨 Multiple Diagram Types: Classes, interfaces, enumerations, and packages
- 🔗 Rich Relationships: Association, inheritance, composition, aggregation, dependency, realization
- 🎯 Association Classes: Full support for UML association classes (many-to-many patterns)
- 📐 Dynamic Sizing: Content-aware width and height for all UML elements
- 🗺️ Automatic Layout: Hierarchical layout using Dagre algorithm
- 📍 Manual Positioning: Fine-grained control with
@positionannotations - 🎨 Customization: Colors, stereotypes, and custom styling
- 💾 Import/Export: JSON serialization and SVG generation
- 🔄 Round-trip: Parse → serialize → parse with full fidelity
- ✅ Type-Safe: Written in TypeScript with complete type definitions
- 🧪 Well-Tested: 87% test coverage with 164+ tests
Advanced Features
- Generic Types: Support for type parameters (
class Box<T>) - Abstract Classes: Abstract classes and methods with italic rendering
- Static Members: Static attributes and methods with underline styling
- Visibility Modifiers: Public (+), private (-), protected (#), package (~)
- Multiplicity: Relationship cardinality (1, 0.., 1..)
- Label Positioning: Start, middle, or end label placement
- Connection Points: Custom attachment points (top, bottom, left, right)
- Bidirectional Relationships: Double-headed arrows
- Notes: Attached or standalone documentation notes
- Packages: Logical grouping of classes
Installation
npm install CoreUML-coreQuick Start
import { createDiagramEngine, exportToSVG, layoutDiagram } from 'CoreUML-core';
const engine = createDiagramEngine();
// Define your UML diagram
const diagram = engine.parse(`
class User {
+ id: number
+ name: string
+ email: string
+ login(): void
}
class Order {
+ id: number
+ total: number
+ items: OrderItem[]
}
User "1" --> "0..*" Order : "places"
`);
// Auto-layout
const layout = layoutDiagram(diagram);
// Export to SVG
const svg = exportToSVG(diagram, layout, {
autoSize: true,
padding: 40
});
console.log(svg); // SVG markup ready for useSyntax Guide
Classes
// Basic class
class User {
+ name: string
+ email: string
+ login(): void
}
// Abstract class
abstract class Entity {
+ id: number
+ abstract validate(): boolean
}
// Class with generics
class Repository<T> {
+ items: T[]
+ add(item: T): void
}
// Static members
class Config {
+ static instance: Config
+ static getInstance(): Config
}
// Default values
class Counter {
+ count: number = 0
}Interfaces
interface Drawable {
+ draw(): void
+ clear(): void
}
// Interface with generics
interface Repository<T> {
+ find(id: number): T
+ save(entity: T): void
}Enumerations
enum Status { PENDING, ACTIVE, COMPLETED, CANCELLED }
enum Color { RED, GREEN, BLUE }Relationships
// Association (simple arrow)
User --> Order
// Association with multiplicity
Customer "1" --> "0..*" Order
// Association with label
User --> Order : "places"
// Inheritance (empty triangle)
User <|-- Entity
// Composition (filled diamond)
House -|> Room
// Aggregation (empty diamond)
Team o-- Player
// Dependency (dashed arrow)
Service ..> Logger
// Realization (dashed arrow with triangle)
Circle ..|> Drawable
// Bidirectional
A <--> BAssociation Classes
Association classes represent relationships that have their own attributes:
class Student {
+ studentId: number
+ name: string
}
class Course {
+ courseId: number
+ title: string
}
class Enrollment {
+ grade: float
+ enrollmentDate: Date
+ status: string
}
// Many-to-many association
Student "0..*" -- "0..*" Course : "enrolls in"
// Link the association class
@associationClass Enrollment student-courseAnnotations
// Position (manual layout)
@position User (100, 200)
// Stereotype
@stereotype UserService "service"
// Color
@color Important red
@color package-domain "#e3f2fd"
// Relationship color
@color user-order blue
// Label position
User --> Order @middle : "places"
// Connection points
User[right] --> Order[left]Packages
package domain {
class User {
+ name: string
}
class Order {
+ id: number
}
}
@position package-domain (50, 50)
@color package-domain lightblueNotes
// Attached note
note for User "This represents a user in the system"
// Standalone note
note at (200, 300) "Important: Always validate input"API Reference
createDiagramEngine()
Creates a new diagram engine instance.
const engine = createDiagramEngine();parse(code: string): Diagram
Parses UML code and returns a diagram object.
const diagram = engine.parse(`
class User {
+ name: string
}
`);serialize(diagram: Diagram): string
Serializes a diagram back to UML code.
const code = engine.serialize(diagram);layoutDiagram(diagram: Diagram, options?: LayoutOptions): LayoutResult
Computes automatic layout for a diagram.
const layout = layoutDiagram(diagram, {
direction: 'TB', // TB, LR, BT, RL
nodeSep: 80, // Horizontal spacing
rankSep: 100 // Vertical spacing
});applyLayout(diagram: Diagram, layout: LayoutResult): Diagram
Applies computed layout to a diagram.
const positionedDiagram = applyLayout(diagram, layout);exportToSVG(diagram: Diagram, layout: LayoutResult, options?: SVGOptions): string
Exports diagram to SVG.
const svg = exportToSVG(diagram, layout, {
autoSize: true, // Auto-calculate viewBox
padding: 40, // Padding around diagram
nodeWidth: 200, // Default node width (overridden by dynamic sizing)
nodeHeight: 150 // Default node height (overridden by dynamic sizing)
});exportDiagram(diagram: Diagram, metadata?: Metadata): string
Exports diagram to JSON.
const json = exportDiagram(diagram, {
author: 'John Doe',
description: 'E-commerce domain model'
});importDiagram(json: string): Diagram
Imports diagram from JSON.
const diagram = importDiagram(json);Dynamic Sizing
CoreUML automatically calculates optimal dimensions for all UML elements based on their content:
Width Calculation
- Minimum: 120px
- Maximum: 400px
- Algorithm: Text width estimation based on character count and font size
- Factors: Class name, attributes, methods, stereotypes, type parameters
Height Calculation
- Dynamic: Based on number of attributes and methods
- Components:
- Header: 30px (40px with stereotype)
- Attributes: 16px per line + 8px padding
- Methods: 16px per line + 8px padding
- Separators: 4px between sections
Example:
// This class will have optimal width based on longest text
class VeryLongClassNameWithManyAttributes {
+ veryLongAttributeName: VeryLongTypeName
+ anotherLongAttribute: AnotherType
+ methodWithLongName(param1: Type, param2: Type): ReturnType
}Examples
Basic E-commerce Domain
const diagram = engine.parse(`
abstract class Entity {
+ id: number
+ createdAt: Date
+ abstract validate(): boolean
}
class Customer {
+ name: string
+ email: string
+ register(): void
}
class Order {
+ orderNumber: string
+ total: number
+ status: OrderStatus
+ submit(): void
}
class Product {
+ sku: string
+ name: string
+ price: number
}
enum OrderStatus { PENDING, CONFIRMED, SHIPPED, DELIVERED }
Customer <|-- Entity
Order <|-- Entity
Product <|-- Entity
Customer "1" --> "0..*" Order : "places"
Order "1" --> "1..*" Product : "contains"
@position Entity (300, 50)
@position Customer (100, 200)
@position Order (300, 200)
@position Product (500, 200)
@position OrderStatus (500, 350)
`);Layered Architecture
const diagram = engine.parse(`
package presentation {
class UserController {
+ getUser(id: number): User
+ createUser(data: UserDTO): User
}
}
package domain {
class User {
+ id: number
+ name: string
+ email: string
+ validate(): boolean
}
interface IUserRepository {
+ find(id: number): User
+ save(user: User): void
}
}
package infrastructure {
class UserRepository {
+ find(id: number): User
+ save(user: User): void
}
}
UserController --> User
UserController --> IUserRepository
UserRepository ..|> IUserRepository
@position package-presentation (50, 50)
@position package-domain (50, 200)
@position package-infrastructure (50, 400)
`);Association Class Pattern
const diagram = engine.parse(`
class Employee {
+ employeeId: number
+ name: string
+ department: string
}
class Project {
+ projectId: number
+ name: string
+ budget: number
}
class Assignment {
+ role: string
+ hoursPerWeek: number
+ startDate: Date
+ endDate: Date
+ updateHours(hours: number): void
}
Employee "0..*" -- "0..*" Project : "assigned to"
@associationClass Assignment employee-project
@position Employee (100, 200)
@position Project (500, 200)
@position Assignment (300, 50)
`);Testing
Run the test suite:
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageTest Coverage
Overall: 87.27% lines, 86.64% statements, 74.74% branches
Parser: 97.66% statements
Validation: 98.30% statements
Layout: 90.00% statements
SVG Rendering: 78.93% statements
Serialization: 76.92% statementsFramework Integration
CoreUML is framework-agnostic and works with any JavaScript/TypeScript framework:
React
import { useEffect, useState } from 'react';
import { createDiagramEngine, exportToSVG, layoutDiagram } from 'CoreUML-core';
function DiagramViewer({ code }) {
const [svg, setSvg] = useState('');
useEffect(() => {
const engine = createDiagramEngine();
const diagram = engine.parse(code);
const layout = layoutDiagram(diagram);
const svgOutput = exportToSVG(diagram, layout, { autoSize: true });
setSvg(svgOutput);
}, [code]);
return <div dangerouslySetInnerHTML={{ __html: svg }} />;
}Vue
<template>
<div v-html="svg"></div>
</template>
<script>
import { createDiagramEngine, exportToSVG, layoutDiagram } from 'CoreUML-core';
export default {
props: ['code'],
data() {
return { svg: '' };
},
watch: {
code: {
immediate: true,
handler(newCode) {
const engine = createDiagramEngine();
const diagram = engine.parse(newCode);
const layout = layoutDiagram(diagram);
this.svg = exportToSVG(diagram, layout, { autoSize: true });
}
}
}
};
</script>Node.js (Server-side)
import { createDiagramEngine, exportToSVG, layoutDiagram } from 'CoreUML-core';
import { writeFileSync } from 'fs';
const engine = createDiagramEngine();
const diagram = engine.parse(code);
const layout = layoutDiagram(diagram);
const svg = exportToSVG(diagram, layout, { autoSize: true });
writeFileSync('output.svg', svg);UML Compliance
CoreUML implements a significant subset of UML 2.5 class diagram specification:
Supported (~70%)
- ✅ Classes with attributes and methods
- ✅ Interfaces
- ✅ Enumerations
- ✅ Abstract classes and methods
- ✅ Visibility modifiers
- ✅ Static members
- ✅ Generic types
- ✅ Association relationships
- ✅ Association classes
- ✅ Inheritance
- ✅ Composition
- ✅ Aggregation
- ✅ Dependency
- ✅ Realization
- ✅ Multiplicity
- ✅ Stereotypes
- ✅ Notes
- ✅ Packages
Planned
- ⏳ Qualified associations
- ⏳ N-ary associations
- ⏳ Constraints (OCL)
- ⏳ Templates
- ⏳ Nested classes
- ⏳ Signals
- ⏳ Data types
Performance
CoreUML is designed for performance:
- Parsing: ~1ms for typical diagrams (10-20 classes)
- Layout: ~50ms for complex diagrams (50+ classes)
- SVG Generation: ~10ms
- Memory: Minimal overhead with immutable data structures
Limitations
- Max Input Size: 5MB (configurable via parser)
- Recommended: < 100 classes per diagram for optimal performance
Architecture
CoreUML-core/
├── src/
│ ├── engine/ # Core parsing and validation
│ │ ├── parser.ts
│ │ ├── validation.ts
│ │ └── DiagramEngine.ts
│ ├── layout/ # Automatic layout using Dagre
│ │ └── layoutEngine.ts
│ ├── io/ # Import/export functionality
│ │ ├── svg.ts
│ │ └── serialization.ts
│ ├── types/ # TypeScript type definitions
│ │ └── diagram.ts
│ └── index.ts # Public API
├── tests/ # Comprehensive test suite
├── examples/ # Example diagrams
└── dist/ # Compiled outputContributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development Setup
# Clone repository
git clone https://github.com/fabiooraziomirto/CoreUML.git
cd CoreUML
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverageGuidelines
- Code Style: Follow existing TypeScript conventions
- Tests: Add tests for new features (maintain 80%+ coverage)
- Documentation: Update README and JSDoc comments
- Commits: Use conventional commit messages
License & Usage
Apache License 2.0 - see LICENSE file for details.
Note: This software may be used freely for any purpose. However, publications, articles, or papers describing or analyzing this architecture require prior written permission from the author.
Acknowledgments
- Layout engine powered by Dagre
- Inspired by PlantUML and Mermaid
- Built with TypeScript and tested with Jest
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ by FoM Dev
