ArielJS is a jQuery-style, chainable JavaScript SDK for creating and converting Mermaid diagrams.
// Express your diagrams naturally with a chainable API
flowchart.flow('Start').to('Process').to('Decision')
.flow('Decision').to('Yes Path', {}, 'Yes')
.flow('Decision').to('No Path', {}, 'No');
ArielJS supports ALL Mermaid diagram types with an emphasis on fluent, chainable interfaces that make your diagrams easy to read and maintain. It also provides bidirectional conversion and customizable terminology to fit your specific domain language.
- Flowcharts - with simplified flow API for connected nodes
- Sequence Diagrams - for interactions between components
- Class Diagrams - for object-oriented relationships
- Entity Relationship Diagrams - for database modeling
- State Diagrams - for state machines and transitions
- Gantt Charts - for project planning and scheduling
- Pie Charts - for data visualization
- User Journeys - for user experience mapping
- Mindmaps - for organizing related ideas
- Git Graphs - for visualizing git workflows
- ... and more!
npm install ariel-js
-
Clone this repository:
git clone https://github.com/yourusername/ariel-js-project.git
-
Navigate to the project directory:
cd ariel-js-project
-
Install dependencies:
npm install
-
Node.js Test: Run the test script to see ArielJS in action:
npm test
-
All Diagram Types: View examples of all supported diagram types:
node tests/all-diagram-types.js
-
Browser Demo: Open
public/index.html
in a browser to visualize a Mermaid diagram. -
Examples Viewer: Launch the examples viewer to see all diagram types:
cd charts && python3 -m http.server 8000
Then open http://localhost:8000/examples-viewer.html in your browser.
// If installed via npm
import createArielJS from 'ariel-js';
// OR if using local files
// import createArielJS from './src/ariel-js.js';
// Create a specific diagram type
const ariel = createArielJS();
const flowchart = ariel('flowchart', 'TD');
const sequence = ariel('sequence');
const classDiagram = ariel('class');
const erDiagram = ariel('er');
// etc.
const chart = ariel('flowchart', 'LR')
.node('A', 'Start')
.edge('B', 'Next')
.node('B', 'End');
const chart = ariel('flowchart', 'LR')
.flow('A', 'Start', { shape: 'stadium' })
.to('B', 'Process', { shape: 'rect' })
.to('C', 'Decision', { shape: 'diamond' })
// Create branches
.flow('C')
.to('D', 'Yes Path', {}, 'Yes')
.to('F', 'End', { shape: 'stadium' })
.flow('C')
.to('E', 'No Path', {}, 'No')
.to('F');
const sequence = ariel('sequence')
.participant('User', null, { type: 'actor' })
.participant('Browser')
.participant('Server')
.message('User', 'Browser', 'Request Page')
.message('Browser', 'Server', 'API Request')
.message('Server', 'Browser', 'Response', { type: '-->' })
.message('Browser', 'User', 'Display Page', { type: '-->' })
.note('over', ['Browser', 'Server'], 'Critical Exchange');
const classDiagram = ariel('class')
.class('Animal')
.attribute('Animal', 'name', 'String', '+')
.method('Animal', 'makeSound', null, [], '+')
.class('Dog')
.attribute('Dog', 'breed', 'String', '+')
.method('Dog', 'bark', null, [], '+')
.inheritance('Dog', 'Animal');
const erDiagram = ariel('er')
.entity('CUSTOMER')
.attribute('CUSTOMER', 'id', 'string', 'PK')
.attribute('CUSTOMER', 'name', 'string')
.entity('ORDER')
.attribute('ORDER', 'id', 'string', 'PK')
.attribute('ORDER', 'customerId', 'string', 'FK')
.oneToMany('CUSTOMER', 'ORDER', 'places');
const gantt = ariel('gantt')
.setTitle('Project Schedule')
.setDateFormat('YYYY-MM-DD')
.section('Planning')
.task('Requirements', 'req', { start: '2023-01-01', end: '2023-01-05' })
.task('Design', 'design', { start: '2023-01-06', end: '2023-01-15' })
.section('Development')
.task('Implementation', 'impl', { start: '2023-01-16', end: '2023-01-31' });
const builder = createArielJS({
methods: { addStep: 'node', connectTo: 'edge' },
properties: { nodeType: 'shape' }
});
const mermaid = 'graph TD; A-->B;';
console.log(createArielJS().fromMermaid(mermaid));
ArielJS uses a chainable API that makes diagram creation intuitive and readable. The chains follow a consistent pattern, with each method returning this
to allow method chaining. The indentation in your code can visually represent the structure of your diagram, making complex diagrams easier to understand and maintain.
Mermaid code:
flowchart TD
A("Start: Initialization")
B{"Process Data"}
C("Visualize Results")
D("Log Error")
E("End")
A --> B
B -->|Success| C
B -->|Failure| D
C --> E
D --> E
style A fill:#a3d2ca,stroke:#333,stroke-width:2px;
style B fill:#f6c6ea,stroke:#333,stroke-width:2px;
style C fill:#ff97b7,stroke:#333,stroke-width:2px;
style D fill:#ff97b7,stroke:#333,stroke-width:2px;
style E fill:#e2eafc,stroke:#333,stroke-width:2px;
Equivalent ArielJS code:
import createArielJS from 'ariel-js';
// Build the flowchart using the simplified flow API
const ariel = createArielJS();
const chart = ariel('flowchart', 'TD')
.flow('A', 'Start: Initialization', { shape: 'round' })
.to('B', 'Process Data', { shape: 'diamond' })
// Success path
.flow('B')
.to('C', 'Visualize Results', { shape: 'round' }, 'Success')
.to('E', 'End', { shape: 'round' })
// Failure path
.flow('B')
.to('D', 'Log Error', { shape: 'round' }, 'Failure')
.to('E')
// Apply styles
.style('A', {"fill":"#a3d2ca","stroke":"#333","stroke-width":"2px"})
.style('B', {"fill":"#f6c6ea","stroke":"#333","stroke-width":"2px"})
.style('C', {"fill":"#ff97b7","stroke":"#333","stroke-width":"2px"})
.style('D', {"fill":"#ff97b7","stroke":"#333","stroke-width":"2px"})
.style('E', {"fill":"#e2eafc","stroke":"#333","stroke-width":"2px"});
console.log(chart.toMermaid());
The ArielJS library provides a consistent, chainable API for all diagram types. The core verbs follow these patterns:
Verb Pattern | Purpose | Examples |
---|---|---|
add/create | Add elements to diagrams | node() , entity() , participant() |
connect | Create relationships | edge() , to() , message() |
set | Configure diagrams | setDirection() , setTitle() |
annotate | Add documentation | note() , style() |
group | Create containers | subgraph() , section() , loop() |
Here's a comprehensive glossary of methods by diagram type:
toMermaid()
- Converts the diagram to Mermaid syntaxaddLine(line, indent)
- Adds a line to the diagram with specified indentationaddLines(lines, indent)
- Adds multiple lines to the diagram
graph(direction)
- Sets the direction of the flowchart (TB, TD, BT, RL, LR)setDirection(direction)
- Sets the direction of the flowchart (alias)node(id, label, options)
- Creates a node with the specified ID and labeledge(targetId, label, options)
- Creates an edge from the current node to the targetsubgraph(id, label, callback)
- Creates a subgraph/container with nested contentstyle(selector, properties)
- Applies CSS-style properties to a node or edgeclass(className, ...nodeIds)
- Assigns CSS classes to nodesnote(text, target)
- Adds a comment/note to the diagramflow(id, label, options)
- Simplified API: starts a flow from a specific nodeto(id, label, nodeOptions, edgeLabel, edgeOptions)
- Simplified API: adds a connected node
participant(name, alias, options)
- Adds an actor/participant to the diagrammessage(from, to, text, options)
- Creates a message between actorsnote(position, actors, text)
- Adds a note to one or more actorsnoteOver(actors, text)
- Adds a note over actorsnoteLeft(actor, text)
- Adds a note to the left of an actornoteRight(actor, text)
- Adds a note to the right of an actorloop(label, callback)
- Creates a loop sectionalt(label, callback)
- Starts an alternative sectionelse(label, callback)
- Adds an else branch to an alt sectionopt(label, callback)
- Creates an optional sectionpar(label, callback)
- Creates a parallel sectionactivate(actor)
- Activates an actor (showing it's processing)deactivate(actor)
- Deactivates an actordestroy(actor)
- Marks an actor as destroyed
class(name, definition)
- Defines a classattribute(className, attrName, type, visibility)
- Adds an attribute to a classmethod(className, methodName, returnType, params, visibility)
- Adds a method to a classinheritance(child, parent)
- Creates an inheritance relationshipcomposition(container, contained)
- Creates a composition relationshipaggregation(container, contained)
- Creates an aggregation relationshipassociation(from, to)
- Creates an association relationshipdependency(dependent, dependency)
- Creates a dependency relationship
entity(name, attributes)
- Defines an entityattribute(entityName, name, type, key, comment)
- Adds an attribute to an entityoneToOne(entity1, entity2, label)
- Creates a one-to-one relationshiponeToMany(entity1, entity2, label)
- Creates a one-to-many relationshipmanyToMany(entity1, entity2, label)
- Creates a many-to-many relationship
root(text)
- Creates the root node of the mindmapchild(text, shape)
- Adds a child to the current node and moves to itsibling(text, shape)
- Adds a sibling to the current node and moves to itparent(text, shape)
- Moves up to parent level and adds a node
ArielJS provides a powerful adapter system that allows you to customize the API to fit your specific domain language, terminology, and workflow patterns.
The most basic form of adaptation is renaming methods to use domain-specific terminology:
const workflowBuilder = createArielJS({
methods: {
// Map custom method names to standard methods
addStep: 'node', // Use addStep() instead of node()
connectTo: 'edge', // Use connectTo() instead of edge()
startAt: 'flow', // Use startAt() instead of flow()
goTo: 'to' // Use goTo() instead of to()
}
});
// Using domain-specific method names
const workflow = workflowBuilder('flowchart', 'TD')
.addStep('A', 'Start Process', { shape: 'stadium' })
.connectTo('B', 'Process Data')
.startAt('B')
.goTo('C', 'Output', {}, 'Complete');
You can rename property keys to match your domain terminology:
const processBuilder = createArielJS({
properties: {
// Use domain-specific property names
stepType: 'shape', // Use stepType instead of shape
primaryColor: 'fill', // Use primaryColor instead of fill
borderColor: 'stroke', // Use borderColor instead of stroke
connectionType: 'type' // Use connectionType instead of type
}
});
// Using domain-specific property names
const process = processBuilder('flowchart', 'TD')
.node('A', 'Start', {
stepType: 'stadium',
primaryColor: '#bbdefb',
borderColor: '#1976d2'
});
You can rearrange method parameters to create more natural APIs for your domain:
const apiBuilder = createArielJS({
parameters: {
// Swap the id and label parameters for node method
// Original: node(id, label, options)
// New: node(label, id, options)
node: [1, 0, 2],
// Move the label to be the first parameter for edge
// Original: edge(targetId, label, options)
// New: edge(label, targetId, options)
edge: [2, 0, 1]
}
});
// Using reordered parameters for more natural APIs
const api = apiBuilder('flowchart', 'LR')
// Instead of node(id, label, options)
.node('Start Process', 'A', { shape: 'stadium' })
// Instead of edge(targetId, label, options)
.edge('Process', 'B');
You can create completely new methods that implement complex operations:
const pipelineBuilder = createArielJS({
customMethods: {
// Add a specialized method for creating pipeline segments
segment: function(id, name, type, options = {}) {
// Choose shape based on segment type
const shape = type === 'source' ? 'circle' :
type === 'sink' ? 'stadium' : 'rect';
// Create the node with appropriate styling
return this.node(id, name, {
shape,
style: { fill: options.color || '#f5f5f5' }
});
},
// Add a specialized method for data flows
dataFlow: function(fromId, toId, dataLabel) {
return this.node(fromId)
.edge(toId, dataLabel || 'data');
}
}
});
// Using custom domain-specific methods
const pipeline = pipelineBuilder('flowchart', 'LR')
.segment('SRC', 'Data Source', 'source', { color: '#bbdefb' })
.dataFlow('SRC', 'PROC', 'raw data')
.segment('PROC', 'Process', 'processor', { color: '#c8e6c9' })
.dataFlow('PROC', 'SINK', 'processed data')
.segment('SINK', 'Database', 'sink', { color: '#ffccbc' });
Combine all of these capabilities to create complete domain-specific languages:
// Factory function for creating data pipeline diagrams
const createPipeline = () => {
return createArielJS({
// Custom method names for pipeline terminology
methods: {
source: 'node',
processor: 'node',
sink: 'node',
pipe: 'edge'
},
// Custom properties for pipeline components
properties: {
sourceType: 'shape',
processorType: 'shape',
sinkType: 'shape',
dataType: 'label'
},
// Custom methods for pipeline operations
customMethods: {
extract: function(id, source) {
return this.node(id, `Extract from ${source}`, { shape: 'circle' });
},
transform: function(id, operation) {
return this.node(id, `Transform: ${operation}`, { shape: 'rect' });
},
load: function(id, destination) {
return this.node(id, `Load to ${destination}`, { shape: 'stadium' });
}
}
})('flowchart', 'LR'); // Always create a left-to-right flowchart
};
// Using a complete domain-specific adapter
const etlPipeline = createPipeline()
.extract('E1', 'MySQL')
.pipe('T1', 'raw records')
.transform('T1', 'Filter & Clean')
.pipe('T2', 'clean records')
.transform('T2', 'Aggregate')
.pipe('L1', 'summary data')
.load('L1', 'Data Warehouse');
See examples/adapter.js for complete examples of creating and using adapters.
src/ariel-js.js
: The ArielJS librarytests/
: Test scripts and examplestest.js
: Basic test scriptall-diagram-types.js
: Examples of all diagram typesbidirectional-test.js
: Tests for Mermaid conversionflow-api-test.js
: Tests for the simplified flow APImindmap-test.js
: Tests for mindmap chaining
examples/
: Advanced usage examplesadapter.js
: Examples of custom adapters and domain-specific APIs
charts/
: Diagram examples and viewersexamples-viewer.html
: Interactive diagram viewerexamples/
: Example diagrams in Markdown formatexample-converted.js
: Example of converted JavaScript code
LICENSE
: MIT License