Skip to main content

ODS Doc

A TypeScript library for generating comprehensive Markdown documentation from Open Domain Specification (ODS) workspaces. This package automatically creates structured documentation with embedded diagrams, relationship tables, and navigation for domain-driven design projects.

👀 Check out the ODS Example Workspace documentation and hosted Docsify site: https://eshop.open-ds.io https://github.com/Open-Domain-Specification/open-domain-specification/tree/main/models/petstore

Features​

  • Hierarchical Documentation: Generate complete documentation trees from workspace to aggregate level
  • Embedded Visualizations: Automatically include context maps, consumable maps, relation maps and flow maps as SVG diagrams
  • Relationship Tables: Context relationships (declared and implied), consumptions, entity relations with cardinality
  • Tactical Detail: Attributes, commands, events, invariants and what they constrain, policies
  • Glossary: A per-context glossary on each context page and a workspace-wide glossary page
  • Teams and Diagnostics: Who owns each context, and the result of workspace.validate() on the workspace page
  • Navigation Structure: Create sidebar navigation with proper hierarchy and cross-linking
  • A Complete Static Site: An index.html docsify shell alongside the Markdown, so the folder renders on any static host
  • Breadcrumb Navigation: Optional breadcrumb trails for easy navigation
  • Multiple Component Types: Support for workspaces, domains, subdomains, bounded contexts, services, and aggregates

Installation​

npm install @open-domain-specification/doc

Usage​

At its core the @open-domain-specification/doc package provides a single function toDoc that converts the workspace to a Dictionary of Markdown files.

The function accepts an ODSWorkspace instance and returns a dictionary where keys are file paths and values are Markdown content.

See the Example Workspace for a complete example of how to use the toDoc function and generate documentation.

import { Workspace } from "@open-domain-specification/core";
import { toDoc } from "@open-domain-specification/doc";
import { describe, expect, it } from "vitest";

const ws = new Workspace("eCommerce", {
description: "DDD workspace for an eCommerce platform example",
version: "0.1.0",
homepage: "https://example.com",
primaryColor: "#0ea5e9",
logoUrl: "https://example.com/logo.svg",
});

const wsMd = `

# eCommerce
DDD workspace for an eCommerce platform example

![contextmap](./contextmap.svg)

[Glossary](./glossary.md)

## Domains
> No domains.

## Diagnostics
> No diagnostics.

## Health
### Refactor
> Nothing is marked for refactoring.

### Tolerated
> No compromises recorded.

### No comments
> Every relationship carries at least one comment.


## Teams
> No teams.

## Context Relationships


## Consumptions


`;

const glossaryMd = `

# eCommerce Glossary

> No glossary terms in any bounded context.
`;

const indexHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>eCommerce</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
if (!location.hash) location.hash = "#/e_commerce/index.md";
window.$docsify = {
name: "eCommerce",
loadSidebar: true,
alias: { "/.*/_sidebar.md": "/_sidebar.md" },
relativePath: true,
subMaxLevel: 2
};
</script>
<script src="https://cdn.jsdelivr.net/npm/docsify@4"></script>
</body>
</html>
`;

const contextMap = `\
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="data:text/css,.graph%20text%20%7B%0A%09font-family%3A%20sans-serif%3B%0A%09stroke%3A%20white%3B%0A%09paint-order%3A%20stroke%3B%0A%09stroke-width%3A%203%3B%0A%09stroke-linecap%3A%20square%3B%0A%7D%0A%0A.namespace%20polygon%20%7B%0A%09fill-opacity%3A%200.2%3B%0A%09stroke%3A%20none%3B%0A%7D%0A" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 13.1.2 (0)
-->
<!-- Pages: 1 -->
<svg width="8pt" height="8pt"
viewBox="0.00 0.00 8.00 8.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 4)">
<polygon fill="white" stroke="none" points="-4,4 -4,-4 4,-4 4,4 -4,4"/>
</g>
</svg>
`;

describe("Generate example documentation", () => {
it("should generate docs", async () => {
expect(await toDoc(ws)).toEqual({
"_sidebar.md":
"* [eCommerce](/e_commerce/index.md)\n\t* [Glossary](/e_commerce/glossary.md)",
"e_commerce/contextmap.svg": contextMap,
"e_commerce/glossary.md": glossaryMd,
"e_commerce/index.md": wsMd,
"index.html": indexHtml,
});
});
});

The generated documentation includes a sidebar navigation structure that reflects the hierarchy of the ODS workspace. Each component type (workspace, domain, subdomain, bounded context, service, aggregate) has its own section in the sidebar. A bounded context is listed under every subdomain it serves, and contexts that serve no subdomain are listed directly under the workspace. The glossary page sits under the workspace.

This is crafted for ease of use with Docsify or similar documentation generators that support hierarchical navigation, however you can also create your own custom navigation structure based on the generated Markdown files.

The Docsify Shell​

Alongside the Markdown, toDoc writes an index.html: a docsify shell that loads docsify from a CDN, names the site after the workspace, points a bare / at the workspace page, and resolves each page's diagrams beside it. The folder is therefore a complete static site — drop it on any host, no docsify serve required.

A Playwright spec in the pages package (packages/pages/e2e/docsify.spec.ts) serves the generated petstore folder from a plain static server and walks every page in the sidebar, failing the build on a missing heading, a console error, or any request that 404s.