A modern, web-based tool for designing and visualizing Entity–Relationship (ER) diagrams using extended academic Chen notation. ChenForge combines a domain-specific language (DSL) with a powerful compiler pipeline to transform high-level entity definitions into publication-ready ER diagrams.
Live Demo: https://danielsamo.github.io/ChenForge/
- 🎯 Chen Notation: Native support for extended academic Chen notation with proper visual representation
- ✍️ Intuitive DSL: Domain-specific language for defining entities, relationships, and attributes
- 🔴 Real-time Validation: Immediate error feedback integrated into the editor with precise diagnostics
- 🎨 Interactive Diagrams: SVG-based rendering with D3 for smooth visualization and interaction
- 🏗️ Modular Architecture: Clean separation between parsing, compilation, and rendering layers
- 🔄 Recursive Relationships: Support for reflexive relationships with automatic layout handling
- 📊 Rich Attribute Types: Primary keys, unique keys, optional, derived, simple, composite, and multivalued attributes
- 🎭 Relationship Types: Strong (ST), Existence-dependent (EX), and Identifying (ID) relationships
- Node.js >= 22.12.0
- npm
npm install
npm run devThe application will be available at http://localhost:4321
npm run buildOutput will be in the dist/ directory.
ChenForge uses a clean, declarative DSL for defining ER models.
Entities are the primary objects in your data model:
entity User ST
entity Product ST
entity Role WK
ST: Strong entity (independent, has a primary key)WK: Weak entity (dependent on another entity for identification)
Relationships define connections between entities with cardinality constraints:
relationship User (1,n) Product (1,n) Purchases ST
relationship User (1,1) Role (0,n) HasRole EX
relationship Product (0,n) Product (1,1) Component ID
Format: relationship Entity1 (min1,max1) Entity2 (min2,max2) RelationshipName Type
Relationship Types:
ST: Strong relationship (between strong entities)EX: Existence-dependent weak relationship (identifies weak entity by participation)ID: Identifying weak relationship (primary key includes relationship)
Cardinality:
(0,1): Zero or one(1,1): Exactly one (total participation)(1,n)or(1,m): One or more(0,n)or(0,m): Zero or more(n,m): Many-to-many
Attributes describe properties of entities or relationships:
attribute User username, email PK
attribute Product name, price SP
attribute Product description OP
attribute Product manufacturedDate DR
attribute Product tags MV (0,n)
attribute User firstName, lastName1, lastName2 CP fullName
attribute Profile profilePicture, bio SP
Attribute Types:
PK: Primary key (unique, required)UK: Unique keySP: Simple attributeOP: Optional attributeDR: Derived attribute (computed)CP: Composite attribute (with sub-attributes)MV: Multivalued attribute (with cardinality)
Composite Attributes:
attribute User street, city, zipcode CP address
Multivalued Attributes:
attribute User phoneNumbers MV (1,n)
ChenForge is built on a 7-layer modular architecture with clear separation of concerns:
┌─────────────────────────────────────────────┐
│ Web UI (Astro + Svelte) │ Interactive interface
├─────────────────────────────────────────────┤
│ Editor Integration (CodeMirror 6) │ Real-time editing with syntax highlighting
├─────────────────────────────────────────────┤
│ DSL Layer (Lezer Parser) │ Grammar parsing & tokenization
├─────────────────────────────────────────────┤
│ Semantic Analysis & Validation │ Type checking, scope resolution
├─────────────────────────────────────────────┤
│ IR / Intermediate Representation │ Normalized graph model
├─────────────────────────────────────────────┤
│ Diagram Generation (Graphviz) │ DOT format compilation
├─────────────────────────────────────────────┤
│ SVG Rendering (D3) │ Final visualization
└─────────────────────────────────────────────┘
- File:
dsl.grammar(Lezer grammar specification) - Parser: Generated by
@lezer/generator - Purpose: Defines the syntax of ChenForge's domain-specific language
- Output: AST (Abstract Syntax Tree)
extract.ts: Traverses Lezer AST and extracts semantic nodescardinality.ts: Parses and validates cardinality specificationsast-builder.ts: Constructs the AST from extracted nodesvalidators.ts: Validates uniqueness, references, and semantic constraints- Key Logic:
- Scope resolution (entity references in relationships/attributes)
- Cardinality parsing and validation
- Duplicate detection
types.ts: TypeScript definitions for all schema elementsindex.ts: Schema specification defining node types and field mappingscardinality.ts: Cardinality formatting and display logicutils.ts: Helper functions for scope resolution
- AST Interface: Final parsed output with entities, relationships, attributes
- ParseError: Structured error reporting
- Type Definitions: EntityKind, AttributeKind, RelationshipKind, etc.
compile.ts: Orchestrates the entire pipeline (parse → transform → render)transform.ts: Converts AST to GraphModel with:- Deduplication of entities, attributes, relationships
- Weak entity identification
- Attribute propagation for identifying relationships
graph.ts: Intermediate graph representation ready for visualization
dot.ts: Main renderer; orchestrates Graphviz DOT generationrelationships.ts: Renders relationship nodes with cardinality labels- Handles recursive relationships via dummy nodes
- Formats cardinality arrows based on participation type
attributes.ts: Renders attributes with proper styling- PK/UK with special visual representation
- Optional attributes with dashed lines
- Derived attributes with specific formatting
dot-utils.ts: Graphviz DOT utility functions (node ID generation, label formatting)
- Editor Integration: CodeMirror 6 with real-time linting
- Diagram Display: D3-graphviz for SVG rendering
- Syntax Highlighting: Language definition with semantic tokens
- Autocompletion: Context-aware suggestions based on DSL position
User Code (DSL)
↓
[Grammar] (dsl.grammar) → Lezer Parser → Raw AST
↓
[Extraction] (extract.ts) → Extract nodes with positions
↓
[Validation] (validators.ts) → Semantic validation → ParseError[]
↓
[AST Building] (ast-builder.ts) → Final AST
↓
[Transformation] (transform.ts) → Deduplication, resolution → GraphModel
↓
[DOT Generation] (dot.ts) → Graphviz specification
↓
[D3 Graphviz] → SVG rendering
↓
Visual Diagram + Error Diagnostics (in editor)
ChenForge provides precise, actionable error messages integrated into the editor:
relationship User Role (1,n) HasRole ❌ Error: Entity 'User' requires cardinality
relationship User (1,1) Role HasRole ❌ Error: Duplicate relationship name 'HasRole'
attribute Unknown name PK ❌ Error: Unknown entity 'Unknown' referenced
Error Categories:
- Syntax Errors: Invalid tokens or grammar (detected by Lezer)
- Semantic Errors: Type mismatches, invalid relationships
- Scope Errors: References to undefined entities or relationships
- Uniqueness Errors: Duplicate names within a scope
All errors report precise source locations for accurate inline feedback.
ChenForge uses the standard Chen cardinality notation:
- Minimum: Specifies minimum participation (0 = optional, 1+ = required)
- Maximum: Specifies maximum participation (1 = functional, n/m = many)
Examples:
relationship User (1,n) Order (1,1) Places ST
relationship Department (1,n) Employee (0,n) Works ST
Weak entities are identified through their participation in identifying relationships:
entity Student ST
entity Enrollment WK
relationship Student (1,n) Enrollment (1,1) Enrols ID
The ID relationship type indicates that Enrollment is identified by its participation in Enrols. The identifying relationship's cardinality is shown with a double line in visual notation.
| Layer | Technology | Purpose |
|---|---|---|
| Frontend Framework | Astro 6 + Svelte 5 | Static generation + interactive components |
| Parser | Lezer | LR parser generator for domain language |
| Editor | CodeMirror 6 | Real-time editing with diagnostics |
| Compiler | TypeScript | Type-safe compilation pipeline |
| Visualization | D3-Graphviz | SVG rendering of Graphviz output |
| Graph Layout | Graphviz | DOT format for automatic node positioning |
| Styling | Tailwind CSS | Utility-first CSS framework |
- Incremental Parsing: DSL parser operates on the full source incrementally
- Real-time Diagnostics: Validation runs on every keystroke via CodeMirror linter
- DOT Caching: Graphviz output cached until AST changes
- Deduplication: Transform layer normalizes duplicate declarations automatically
Contributions are welcome. Please ensure:
- Changes maintain the 7-layer architecture
- New validations integrate into the validators module
- Grammar changes are regenerated with
npm run build:dsl - TypeScript types are properly defined