{"id":42831218,"url":"https://github.com/probelabs/maid","last_synced_at":"2026-01-30T11:29:06.881Z","repository":{"id":317178477,"uuid":"1066221595","full_name":"probelabs/maid","owner":"probelabs","description":"A lightweight Mermaid diagram linter which helps humans and AI with perfect diagrams","archived":false,"fork":false,"pushed_at":"2026-01-29T06:24:43.000Z","size":3302,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-29T22:10:36.844Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://probelabs.com/maid","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/probelabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-29T07:36:29.000Z","updated_at":"2026-01-29T21:42:44.000Z","dependencies_parsed_at":"2025-10-30T11:14:52.500Z","dependency_job_id":"ef1f1f8f-a6e0-4c4d-9626-da025e7220e3","html_url":"https://github.com/probelabs/maid","commit_stats":null,"previous_names":["probelabs/mermaid-lint","probelabs/maid"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/probelabs/maid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/probelabs%2Fmaid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/probelabs%2Fmaid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/probelabs%2Fmaid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/probelabs%2Fmaid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/probelabs","download_url":"https://codeload.github.com/probelabs/maid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/probelabs%2Fmaid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28911821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T08:15:08.179Z","status":"ssl_error","status_checked_at":"2026-01-30T08:14:31.507Z","response_time":66,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-30T11:29:06.363Z","updated_at":"2026-01-30T11:29:06.872Z","avatar_url":"https://github.com/probelabs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Maid Illustration](./maid_info_illustration_white.png)\n\n# Maid\n\nFast, accurate Mermaid diagram validator with clear, actionable diagnostics. Built for the AI age where Mermaid has become essential—but validation shouldn't require a browser.\n\n## Why Maid?\n\n- **Built for AI**: Designed for AI agents and LLMs that generate Mermaid diagrams\n- **Render Guarantee**: When Maid says it's valid, your diagram will render\n- **Lightning Fast**: Validates in milliseconds without launching a browser\n- **Human-Friendly**: Clear error messages with line numbers, carets, and actionable hints\n- **Lightweight**: ~5MB vs. mermaid-cli's 1.7GB (Puppeteer + Chrome)\n- **Auto-Fix**: Automatically corrects common AI-generated mistakes\n\n## Quick Start\n\n```bash\n# One‑off (npx)\nnpx -y @probelabs/maid diagram.mmd\n\n# Or install locally (dev dependency)\nnpm install -D @probelabs/maid\nnpx maid diagram.mmd   # uses local bin from @probelabs/maid\n\n# From stdin\ncat diagram.mmd | npx -y @probelabs/maid -\n\n# Markdown with multiple diagrams\nnpx -y @probelabs/maid README.md\n\n# Lint an entire docs directory (recursively)\nnpx -y @probelabs/maid docs/\n```\n\n### SDK Quick Example\n\nUse Maid programmatically (ESM). See docs/SDK.md for more.\n\n```js\nimport { validate, fixText } from '@probelabs/maid';\n\nconst src = 'flowchart TD\\nA-\u003eB';\nconst { errors } = validate(src);\nif (errors.length) {\n  const { fixed } = fixText(src, { level: 'safe' });\n  console.log(fixed);\n}\n```\n\nExit codes\n- 0: no errors (including when no Mermaid diagrams are found)\n- 1: at least one error (warnings do not fail)\n\n## MCP Server for AI Assistants\n\nMaid includes a Model Context Protocol (MCP) server that allows AI assistants like Claude Code to validate and fix Mermaid diagrams directly in conversations.\n\n### Quick Setup for Claude Code\n\nAdd Maid MCP server using the CLI:\n\n```bash\nclaude mcp add -- npx -y @probelabs/maid mcp\n```\n\nOr configure manually in `~/.claude.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"maid\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@probelabs/maid\", \"mcp\"]\n    }\n  }\n}\n```\n\nAfter configuration, restart Claude Code. The assistant will now be able to validate and fix Mermaid diagrams when you ask.\n\n### MCP Tool: `validate_mermaid`\n\n**Inputs:**\n- `text` (string, required): Mermaid diagram text or Markdown content with ```mermaid blocks\n- `autofix` (boolean, optional): Set to `true` to automatically fix syntax errors\n\n**Returns (JSON):**\n- `valid` (boolean): Whether the diagram is valid\n- `diagramType` (string): Detected diagram type (flowchart, pie, sequence, unknown)\n- `errorCount`, `warningCount` (number): Count of errors and warnings\n- `errors` (array): Detailed error objects with line, column, message, code, hint\n- `fixed` (string): Corrected diagram text (only when autofix=true)\n\n### Example Usage in Conversations\n\nOnce configured, you can ask Claude Code:\n- \"Check this Mermaid diagram for errors\"\n- \"Validate the Mermaid diagrams in my README.md\"\n- \"Fix the syntax errors in this flowchart\"\n\nThe assistant will use the MCP server to validate or fix diagrams and show you the results.\n\n## Using as an SDK\n\nMaid can be used programmatically (ESM, CommonJS, and TypeScript). The public API lives at the package root export. See docs/SDK.md for complete examples.\n\nFor detailed examples (ESM, CommonJS, TypeScript) and API surface, see docs/SDK.md.\n\n### Browser Usage with Mermaid.js-Compatible API\n\nMaid provides a **drop-in replacement** for Mermaid.js that works in the browser with no external dependencies. Perfect for validating and rendering diagrams client-side without Puppeteer or Chrome.\n\n**Quick Start (via CDN):**\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eMaid Browser Example\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cdiv id=\"diagram\"\u003e\u003c/div\u003e\n\n    \u003cscript type=\"module\"\u003e\n        // Import from ProLabs CDN\n        import { createMermaidAPI } from 'https://probelabs.com/maid/maid.bundle.js';\n\n        // Create a Mermaid.js-compatible API\n        const maid = createMermaidAPI();\n\n        const diagramText = `\n            flowchart TD\n                A[Start] --\u003e B{Decision}\n                B --\u003e|Yes| C[Process]\n                B --\u003e|No| D[End]\n        `;\n\n        // Use exactly like Mermaid.js\n        const { svg } = await maid.render('diagram-id', diagramText);\n        document.getElementById('diagram').innerHTML = svg;\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n**Features:**\n- ✅ **Same API as Mermaid.js** - Drop-in replacement for `mermaid.render()`\n- ✅ **No dependencies** - Works completely offline (~350KB bundle)\n- ✅ **Built-in validation** - Auto-fixes common errors before rendering\n- ✅ **Experimental renderer** - Supports flowchart and pie diagrams\n\n**Toggle Between Renderers:**\n\n```html\n\u003cscript type=\"module\"\u003e\n    import { createMermaidAPI } from 'https://probelabs.com/maid/maid.bundle.js';\n    import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';\n\n    const maidRenderer = createMermaidAPI();\n    mermaid.initialize({ startOnLoad: false });\n\n    // Choose renderer based on user preference\n    const useMaid = true; // or read from checkbox\n    const renderer = useMaid ? maidRenderer : mermaid;\n\n    // Both use the same API!\n    const { svg } = await renderer.render('id', diagramText);\n\u003c/script\u003e\n```\n\n**Interactive Demo:** Try it live at [https://probelabs.com/maid/demo.html](https://probelabs.com/maid/demo.html)\n\n**API Reference:**\n- `createMermaidAPI()` - Creates Mermaid.js-compatible instance\n- `maid.render(id, text, options?)` - Async render (returns `{ svg }`)\n- `maid.renderSync(id, text, options?)` - Sync render (returns `{ svg }`)\n- `maid.initialize(config?)` - No-op for compatibility\n\n**Supported Diagram Types (Browser Rendering):**\n- ✅ Flowcharts (`flowchart`, `graph`)\n- ✅ Pie charts (`pie`)\n- 🚧 Other types fall back to validation only\n\n**Bundle Sizes:**\n- Maid browser bundle: ~350KB minified\n- Mermaid.js: ~400KB (CDN) or 1.7GB (mermaid-cli + Puppeteer)\n\n### Rendering Diagrams (Experimental)\n\n```bash\n# Render to SVG (default)\nnpx -y @probelabs/maid render diagram.mmd\n\n# Render to PNG\nnpx -y @probelabs/maid render diagram.mmd output.png\n\n# Render from stdin\ncat diagram.mmd | npx -y @probelabs/maid render - output.svg\n\n# Force output format\nnpx -y @probelabs/maid render diagram.mmd -f png\n```\n\nNotes\n- The renderer is **experimental** and primarily for parser validation\n- Currently supports **flowchart, pie, and sequence** diagrams\n- PNG output requires `rsvg-convert` or `ImageMagick` installed\n- See \"Development \u003e Experimental Renderer\" for technical details\n\n#### Renderer Parity / Visual Comparison\n\nTo compare our renderer vs Mermaid CLI across fixtures, see AGENTS.md for the step‑by‑step parity workflow. Quick start:\n\n```\nnpm run build\nnpm run compare:renderers:sequence   # or :flowchart / :pie\n```\nOutputs (Mermaid+Maid SVG/PNG and diffs) go to `.tmp-compare-all/`.\n\n### Development\n\n#### Parsing Parity Quick Loop\n- Compare against Mermaid CLI for one type: `node scripts/compare-linters.js flowchart`\n- Run error-code tests for all: `npm run test:errors:all`\n- Regenerate previews (all types): `npm run generate:previews`\n- CI parity bundle locally: `npm run ci:test` and `npm run ci:previews`\n\n### Autofix in a nutshell\n\n```bash\n# Safe fixes only (mechanical)\nnpx -y @probelabs/maid --fix docs/\n\n# Safe + heuristic fixes (more aggressive)\nnpx -y @probelabs/maid --fix=all docs/\n\n# Preview the fixed content without writing (single file or stdin)\nnpx -y @probelabs/maid --fix --dry-run --print-fixed diagram.mmd\n```\n\nNotes\n- Safe fixes are idempotent and conservative (arrows, inner quotes to `\u0026quot;`, missing `:`, missing `end`, etc.).\n- `--fix=all` additionally enables conservative heuristics (e.g., wrap unquoted labels, close unclosed quotes/brackets).\n- In directory mode, Maid prints \"All diagrams valid after fixes. Modified X file(s).\" when it succeeds post-fix.\n- See \"Autofix\" below for details and examples.\n\n### Directory Scans: Include/Exclude and .gitignore\n\n- Include globs: `--include` or `-I` (repeatable or comma‑separated)\n- Exclude globs: `--exclude` or `-E` (repeatable or comma‑separated)\n- Respect `.gitignore` by default; disable with `--no-gitignore`\n\nExamples\n\n```bash\n# Respect .gitignore (default)\nnpx -y @probelabs/maid docs/\n\n# Only files under docs/content\nnpx -y @probelabs/maid docs/ -I \"docs/content/**/*.md,docs/content/**/*.mmd\"\n\n# Exclude legacy and drafts\nnpx -y @probelabs/maid docs/ -E \"docs/legacy/**\" -E \"**/*.draft.md\"\n\n# Do not respect .gitignore\nnpx -y @probelabs/maid docs/ --no-gitignore\n\n# JSON report for CI\nnpx -y @probelabs/maid --format json -I \"**/*.mdx\" -E \"**/node_modules/**\" docs/\n```\n\n## Why Maid Exists\n\nMermaid has become an essential part of modern engineering culture. It's in our documentation, our AI workflows, and our development processes. Every major LLM knows Mermaid syntax because they've been trained on millions of diagrams. But there's a challenge.\n\n### The AI Challenge\n\nWhen AI generates complex Mermaid diagrams, the success rate is surprisingly low. The syntax is too free-form, making it easy for AI to generate invalid diagrams that look correct but won't render. You can see this yourself in Mermaid's own live editor—even simple mistakes lead to cryptic errors.\n\n### The Validation Gap\n\n**You can't know if a Mermaid diagram will render without actually rendering it.** This architectural constraint exists because:\n\n1. **Tightly Coupled Architecture**: Mermaid's parser (based on Jison, a JavaScript port of the 1990s Bison parser) tightly couples parsing with rendering. Validation requires rendering.\n\n2. **mermaid-cli's Approach**: The official CLI tool bundles Puppeteer and Chrome—a 1.7GB dependency—to validate by actually rendering your diagram.\n\n3. **Cryptic Error Messages**: When validation fails, you get messages like:\n   ```\n   Expecting 'SEMI', 'NEWLINE', 'EOF', 'AMP', 'START_LINK', 'LINK', 'LINK_ID', got 'MINUS'\n   ```\n   These token-based errors are difficult for both humans and AI to understand.\n\n### The Maid Solution\n\nMaid fills this gap with a modern, lightweight validator. We built a parser from scratch that:\n\n- **Decouples validation from rendering** - No browser needed\n- **Provides semantic error messages** - AI and humans can understand and fix issues\n- **Guarantees rendering** - When Maid says it's valid, it will render\n- **Auto-fixes common mistakes** - Especially those AI agents frequently make\n- **Stays lightweight** - 5MB, not 1.7GB\n\nThis isn't about competing with Mermaid—it's about making Mermaid more accessible and reliable for everyone, especially in the AI age.\n\n## Supported Diagrams (today)\n\n- Flowchart (`flowchart`, `graph`)\n- Sequence (`sequenceDiagram`)\n- Pie (`pie`)\n- Class (`classDiagram`)\n- State (`stateDiagram`, `stateDiagram-v2`)\n\nNote: Other Mermaid diagram types (e.g., `gantt`, `journey`, `erDiagram`, etc.) are treated as valid (pass‑through). We’ll add native validation over time.\n\n## What It Catches\n\n### ❌ Common Errors\n- Invalid arrow syntax (`-\u003e` instead of `--\u003e`)\n- Unclosed brackets and mismatched node shapes\n- Invalid directions (must be TD, TB, BT, RL, LR)\n- Missing diagram type declaration\n- Malformed class and subgraph syntax\n\n### ⚠️ Best Practice Warnings\n- Link text without proper pipe delimiters\n- Empty diagrams\n- Problematic HTML entities\n\n## Testing \u0026 Validation\n\nCommands\n- Run baseline tests: `npm test`\n- Error‑code assertions (all types): `npm run test:errors:all`\n- Autofix smoke tests: `node scripts/test-fixes.js`\n  - CI runs these automatically on every PR/commit.\n- Markdown extraction and offsets: `npm run test:markdown`\n- Directory scan behavior: `npm run test:dir`\n- Compare with mermaid‑cli (non‑blocking): `node scripts/compare-linters.js flowchart|pie|sequence`\n\nCurrent coverage\n- Flowchart: 20 valid • 18 invalid\n- Pie: 4 valid • 8 invalid\n- Sequence: 13 valid • 20 invalid\n\n## Roadmap \u0026 Support\n\nAs of 2025‑09‑30. Mermaid statuses summarized from the docs.\n\n| Diagram | Mermaid status | Maid support | Notes |\n| --- | --- | --- | --- |\n| Flowchart | Stable | Yes | TD/TB/BT/RL/LR; subgraphs; strict mode optional |\n| Sequence | Stable | Yes | Blocks (alt/opt/par/critical/etc.), autonumber, notes |\n| Pie | Stable | Yes | Titles, showData, label/number rules |\n| Class | Stable | Yes | Class/members/relations; stereotypes; alias |\n| State | Stable | Yes | Transitions, start `[*]`, state blocks, notes |\n| ER | Experimental | Pass-through | |\n| Gantt | Stable | Pass-through | |\n| User Journey | Stable | Pass-through | |\n| GitGraph | Stable | Planned | |\n| Mindmap | Stable (icons experimental) | Planned | |\n| Timeline | Stable (icons experimental) | Planned | |\n| Quadrant Chart | Stable | Planned | |\n| XY Chart | Stable | Planned | |\n| Requirement | Stable | Planned | |\n| C4 | Experimental | Planned | |\n| Sankey | Experimental | Planned | |\n| Block Diagram | New/experimental | Planned | |\n| Treemap | Beta/New | Planned | |\n\nSupport\n\n| Channel | Use for |\n| --- | --- |\n| GitHub Issues | Bugs, feature requests, questions |\n| Pull Requests | Improvements to validators, diagnostics, docs |\n\n## Testing / CI\n\n- Baseline tests (flowchart): a fast harness that runs Maid over curated valid/invalid fixtures and expects 100% pass/fail parity with our intended behavior. In CI this step is labeled “Run linter tests (flowchart baseline)”.\n  - Command: `npm test` (runs `scripts/test-chevrotain.js`).\n\n- Error-code assertions (all types): verifies that each invalid fixture surfaces the expected stable error codes across flowchart, pie, and sequence.\n  - Command: `npm run test:errors:all`.\n\n- Compare with mermaid-cli: runs mermaid-cli on all fixtures and checks overall VALID/INVALID parity with Maid. This intentionally prints differences but does not fail the job.\n  - Commands: `node scripts/compare-linters.js flowchart|pie|sequence`.\n\n- Markdown extraction and offsets: validates multi-diagram Markdown parsing and line-number accuracy.\n  - Command: `npm run test:markdown`.\n\n- Directory scan: validates recursive scanning, include/exclude, .gitignore handling, and exit codes.\n  - Command: `npm run test:dir`.\n\n## Releasing\n\nWe publish to npm when a Git tag is pushed that matches the package version.\n\nRules\n- Tags must be in the form `vX.Y.Z`.\n- The tag must match `package.json`'s `version`. CI will fail if they differ.\n\nSteps\n1. Bump the version in `package.json` and commit.\n   - Or use npm to bump and create a tag in one step: `npm version patch|minor|major`.\n2. Push the tag: `git push --follow-tags`.\n3. GitHub Actions (Release workflow) will build, run quick tests, and publish to npm.\n\nNotes\n- The package includes only the compiled `out/` folder, README, and LICENSE.\n- Node.js \u003e= 18 is required (see `engines`).\n- Requires a repository secret `NPM_TOKEN` with publish access to the npm package.\n\nThese layers give confidence in correctness (baseline), diagnostic quality (error codes), and compatibility with the reference renderer (mermaid-cli comparison).\n\n## Error Codes\n\nDiagnostics include stable error codes and hints for quick fixes. See the full list in docs/errors.md.\n\n### Autofix Support\n\n- Use `--fix` for safe, mechanical fixes and `--fix=all` to include conservative heuristics.\n- A complete matrix of error codes and autofix behavior is in docs/errors.md (section “Autofix Support Matrix”).\n\n## Autofix\n\nMaid can optionally fix many common issues for you. There are two levels:\n\n- Safe (`--fix`): mechanical, low‑risk changes, idempotent.\n- All (`--fix=all`): includes Safe and adds heuristic fixes that require mild inference.\n\nWhat gets fixed (highlights)\n- Flowchart (Safe):\n  - `-\u003e` → `--\u003e`\n  - Inner quotes → `\u0026quot;` inside quoted labels\n  - `direction` keyword inside subgraphs (replace unknown kw)\n  - Mismatched closer for shapes (e.g., `A(text]` → `A(text)`)\n- Flowchart (Safe):\n  - Wrap unquoted labels when a `\"` appears inside (and normalize inner quotes)\n  - Insert a best‑guess missing closing bracket\n  - Add default direction ` TD` after `flowchart`/`graph` header\n  - Insert ` --\u003e ` when two nodes are placed on one line without an arrow\n- Sequence (Safe):\n  - Add `: ` in messages and notes\n  - Replace `else` with `option` inside `critical`\n  - Insert a new `end` for unclosed blocks (keeps indentation)\n  - Move extraneous tokens after `autonumber` to the next line\n  - Fix inner quotes in participant/actor names by using `\u0026quot;` (e.g., `participant \"Logger \\\"debug\\\"\"` → `participant \"Logger \u0026quot;debug\u0026quot;\"`)\n- Sequence (All):\n  - Normalize malformed `autonumber` to `autonumber`\n  - Close unclosed quotes at end of line\n- Pie (Safe):\n  - Insert missing ` : ` between label and number\n  - Wrap unquoted labels and normalize inner quotes to `\u0026quot;`\n- Pie (All):\n  - Close unclosed quotes (before colon if present, else end of line)\n - Flowchart (Safe):\n   - Remove empty shapes A[\"\"] / A[\" \"] / A[] → A\n\nBefore/After examples\n\nFlowchart (Safe — arrow and quotes)\n```mermaid\n%% before\nflowchart TD\n  A -\u003e B\n  C[\"He said \\\"Hi\\\"\"]\n```\nbecomes\n```mermaid\nflowchart TD\n  A --\u003e B\n  C[\"He said \u0026quot;Hi\u0026quot;\"]\n```\n\nFlowchart (All — wrap unquoted label containing quotes)\n```mermaid\n%% before\nflowchart TD\n  A[Calls logger.debug(\"msg\", data)]\n```\nbecomes\n```mermaid\nflowchart TD\n  A[\"Calls logger.debug(\u0026quot;msg\u0026quot;, data)\"]\n```\n\nSequence (Safe — message colon and missing end)\n```mermaid\n%% before\nsequenceDiagram\n  par Work\n    A-\u003eB hi\n```\nbecomes\n```mermaid\nsequenceDiagram\n  par Work\n    A-\u003eB : hi\n  end\n```\n\nPie (Safe — missing colon and unquoted label)\n```text\npie\n  Dogs 10\n```\nbecomes\n```text\npie\n  \"Dogs\"  : 10\n```\n\nTips\n- Run with a clean working tree so you can review diffs easily.\n- Use `--dry-run --print-fixed` to preview changes for a single file or stdin.\n- After `--fix`, run without `--fix` to confirm exit code 0.\n- Full code → fix mapping is in docs/errors.md (Autofix Support Matrix).\n\n### CLI Output Formats\n\n- Text (default): caret-underlined snippet style with codes, hints, and precise spans.\n- JSON: machine-readable report for editors/CI.\n\n```bash\n# Text (default)\nnpx -y @probelabs/maid diagram.mmd\n\n# JSON\nnpx -y @probelabs/maid --format json diagram.mmd\n```\n\n### Strict Mode\n\nEnable strict mode to require quoted labels inside shapes (e.g., `[ ... ]`, `{ ... }`, `( ... )`).\n\n```bash\nnpx -y @probelabs/maid --strict diagram.mmd\n```\n\nIn strict mode, unquoted labels are flagged with FL-STRICT-LABEL-QUOTES-REQUIRED. Use double quotes and \u0026quot; for inner quotes.\n\n## Scanning Markdown and Directories\n\nMaid validates:\n- Standalone Mermaid files (`.mmd`, `.mermaid`).\n- Markdown files with one or more Mermaid code fences (```mermaid, ```mmd, or ~~~mermaid).\n- Entire directories (recursively), finding Markdown/Mermaid files and validating all embedded diagrams.\n\nBehavior\n- Keeps precise line/column positions relative to the original Markdown file by offsetting diagnostics from each fenced block.\n- “No Mermaid diagrams found” is considered success (exit code 0). Text mode prints a short note; JSON includes `diagramCount: 0`.\n- Exit code is 1 only when errors are present. Warnings do not fail.\n\n### CLI Options\n\n- `--format`, `-f` text|json\n  - text: human-readable snippets with carets (default)\n  - json: machine-readable output for CI/editors\n- `--strict`, `-s`\n  - Require quoted labels inside shapes; emits `FL-STRICT-LABEL-QUOTES-REQUIRED` when violated.\n- Autofix flags:\n  - `--fix` Apply safe auto-fixes (e.g., replace `-\u003e` with `--\u003e`, normalize inner quotes to `\u0026quot;`, add missing `: ` in sequence message and notes, replace `else` with `option` in `critical`, insert missing `end` for blocks, fix `direction` keyword in subgraphs).\n  - `--fix=all` Apply safe + heuristic fixes (e.g., wrap unquoted labels with quotes where it’s unambiguous, close unclosed quotes/brackets in limited contexts). Heuristics are conservative but may be opinionated.\n  - `--dry-run`, `-n` Don’t write files; useful with single files.\n  - `--print-fixed` When combined with `--fix*` on a single file or `-`, print the fixed content to stdout instead of a diagnostic report.\n- Directory scan flags:\n  - `--include`, `-I` Glob(s) to include (repeatable or comma‑separated)\n  - `--exclude`, `-E` Glob(s) to exclude (repeatable or comma‑separated)\n  - `--no-gitignore` Do not respect `.gitignore` (default is to respect it)\n\nExamples\n\n```bash\n# Validate Markdown containing multiple diagrams\nnpx -y @probelabs/maid README.md\n\n# Lint all docs, respecting .gitignore\nnpx -y @probelabs/maid docs/\n\n# Only Markdown/Mermaid under docs/content\nnpx -y @probelabs/maid docs/ -I \"docs/content/**/*.md,docs/content/**/*.mmd\"\n\n# Exclude legacy docs and any *.draft.md files\nnpx -y @probelabs/maid docs/ -E \"docs/legacy/**\" -E \"**/*.draft.md\"\n\n# Disable .gitignore filtering\nnpx -y @probelabs/maid docs/ --no-gitignore\n\n# JSON report for CI\nnpx -y @probelabs/maid --format json docs/\n```\n\n### JSON Output\n\nSingle file (diagram or Markdown):\n\n```json\n{\n  \"file\": \"README.md\",\n  \"valid\": false,\n  \"errorCount\": 1,\n  \"warningCount\": 0,\n  \"diagramCount\": 1,\n  \"errors\": [\n    { \"line\": 12, \"column\": 3, \"severity\": \"error\", \"code\": \"SE-AND-OUTSIDE-PAR\", \"message\": \"…\" }\n  ],\n  \"warnings\": []\n}\n```\n\nDirectory scan:\n\n```json\n{\n  \"valid\": false,\n  \"errorCount\": 2,\n  \"warningCount\": 1,\n  \"diagramCount\": 5,\n  \"files\": [\n    { \"file\": \"docs/good.md\", \"valid\": true,  \"errorCount\": 0, \"warningCount\": 0, \"errors\": [], \"warnings\": [] },\n    { \"file\": \"docs/bad.md\",  \"valid\": false, \"errorCount\": 2, \"warningCount\": 1, \"errors\": [ … ], \"warnings\": [ … ] }\n  ]\n}\n```\n\n## CI/CD Integration\n\n### SDK Details\n\nLooking for programmatic usage? The full SDK guide (examples, exports, and tips) is in docs/SDK.md. The top of this README includes a short SDK Quick Example for convenience.\n\n### GitHub Actions\n\nValidate entire docs directory on every push/PR (Node 22.x):\n\n```yaml\nname: Lint Mermaid Diagrams\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-node@v4\n        with:\n          node-version: '22.x'\n          cache: 'npm'\n      - name: Lint docs/\n        run: npx -y @probelabs/maid docs/\n```\n\nOnly lint files changed in a pull request:\n\n```yaml\nname: Lint Changed Mermaid Files\non:\n  pull_request:\n    branches: [ main ]\n\njobs:\n  lint-changed:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-node@v4\n        with:\n          node-version: '22.x'\n          cache: 'npm'\n      - name: Get changed Mermaid/Markdown files\n        id: changed\n        run: |\n          set -e\n          base=\"${{ github.event.pull_request.base.sha }}\"\n          head=\"${{ github.sha }}\"\n          files=$(git diff --name-only --diff-filter=ACMR \"$base\"...\"$head\" -- \\\n            \"**/*.md\" \"**/*.markdown\" \"**/*.mdx\" \"**/*.mmd\" \"**/*.mermaid\")\n          if [ -z \"$files\" ]; then\n            echo \"files=\" \u003e\u003e \"$GITHUB_OUTPUT\"\n          else\n            # Space-separated list suitable for shell for-loop\n            echo \"files=$files\" \u003e\u003e \"$GITHUB_OUTPUT\"\n          fi\n      - name: Lint changed files\n        if: steps.changed.outputs.files != ''\n        run: |\n          # Install locally for faster repeated invocations\n          npm i -D @probelabs/maid\n          failed=0\n          for f in ${{ steps.changed.outputs.files }}; do\n            echo \"Linting $f\"\n            npx maid \"$f\" || failed=1\n          done\n          if [ \"$failed\" -ne 0 ]; then\n            echo \"Linting failed for one or more files\" \u003e\u00262\n            exit 1\n          fi\n      - name: No Mermaid files changed\n        if: steps.changed.outputs.files == ''\n        run: echo \"No changed Mermaid/Markdown files. Skipping.\"\n```\n\n### Pre-commit Hook\n\nLint only staged files, including Markdown files that contain Mermaid fences (```mermaid or ~~~mermaid):\n\n```bash\n#!/bin/sh\n# .git/hooks/pre-commit\nset -e\n\n# Collect staged files (added/copied/modified/renamed)\nSTAGED=$(git diff --cached --name-only -z --diff-filter=ACMR)\n[ -z \"$STAGED\" ] \u0026\u0026 exit 0\n\n# Build lint list: .mmd/.mermaid, and Markdown files that contain Mermaid fences\nLINT_LIST=\"\"\nwhile IFS= read -r -d '' f; do\n  case \"$f\" in\n    *.mmd|*.mermaid)\n      LINT_LIST=\"$LINT_LIST\\n$f\" ;;\n    *.md|*.markdown|*.mdx)\n      if grep -Eq '^( {0,3})(```|~~~)[[:space:]]*(mermaid|mmd)([[:space:]]|$)' \"$f\"; then\n        LINT_LIST=\"$LINT_LIST\\n$f\"\n      fi\n      ;;\n  esac\ndone \u003c\u003cEOF\n$STAGED\nEOF\n\nTMP=$(mktemp)\nprintf \"%s\\n\" \"$LINT_LIST\" | sed '/^$/d' \u003e \"$TMP\"\n[ ! -s \"$TMP\" ] \u0026\u0026 { rm -f \"$TMP\"; exit 0; }\n\nFAILED=0\nwhile IFS= read -r FILE; do\n  [ -z \"$FILE\" ] \u0026\u0026 continue\n  echo \"maid: $FILE\"\n  npx -y @probelabs/maid \"$FILE\" || FAILED=1\ndone \u003c \"$TMP\"\nrm -f \"$TMP\"\n\nexit $FAILED\n```\n\n## Architecture\n\nBuilt from scratch with modern tooling for reliability and performance:\n\n- **[Chevrotain](https://chevrotain.io/)** - Modern, fast parser framework (not 1990s Bison/Jison)\n  - Allows semantic validation without rendering\n  - Provides exact error locations and recovery\n  - Enables intelligent auto-fix suggestions\n- **TypeScript** - Type-safe implementation with great IDE support\n- **Decoupled Design** - Validation logic completely separate from rendering\n- **Automated Testing** - GitHub Actions CI on every commit\n- **Render Guarantee** - Our test suite validates against actual Mermaid rendering\n\n### Project Structure\n```\n├── src/\n│   ├── core/\n│   │   ├── router.ts         # Detects diagram type and routes\n│   │   └── types.ts          # Shared types\n│   ├── diagrams/\n│   │   ├── flowchart/        # Flowchart lexer/parser/validation\n│   │   ├── sequence/         # Sequence lexer/parser/validation\n│   │   └── pie/              # Pie lexer/parser/validation\n│   └── cli.ts                # CLI implementation\n├── test-fixtures/\n│   ├── flowchart/\n│   │   ├── valid/\n│   │   └── invalid/\n│   └── pie/\n│       └── valid/\n└── scripts/\n    ├── test-chevrotain.js    # Test runner\n    ├── test-linter.js        # Alternate test runner\n    └── compare-linters.js    # mermaid-cli comparison\n```\n\n## Development\n\n### Build from Source\n\n```bash\n# Clone repository\ngit clone https://github.com/probelabs/maid.git\ncd maid\n\n# Install dependencies\nnpm install\n\n# Build\nnpm run build\n\n# Run tests\nnpm test\n```\n\n### Experimental Renderer\n\nMaid includes an experimental lightweight renderer for flowchart and pie diagrams. This renderer serves as a visual validation tool for our parser implementation.\n\n**Purpose:**\n- Validate parser correctness by visually rendering diagrams\n- Identify parsing issues that are difficult to detect through other testing methods\n- Provide a lightweight alternative for basic diagram rendering (294KB vs Mermaid.js's 2.6MB)\n\n**Status:**\n- ⚠️ **Experimental** - Not intended for production use\n- Currently supports flowchart and pie diagrams\n- Primary goal is parser validation, not feature parity with Mermaid.js\n\n**Building the Browser Bundle:**\n```bash\nnpm run build:browser\n# Generates site/maid/maid.bundle.js (294KB, 87KB gzipped)\n```\n\n**Architecture:**\n- Chevrotain parser for CST generation\n- Dagre.js for automatic graph layout\n- Custom SVG generation for shapes and edges\n- **Pluggable design** - Swap layout engines and output renderers\n\n**Pluggability:**\n\nThe renderer uses a clean interface-based architecture that allows you to:\n- Use alternative layout engines (e.g., Graphviz DOT, D3 force-directed)\n- Generate different output formats (e.g., SVG, Canvas, DOT)\n\nExample - Using a custom DOT renderer:\n```typescript\nimport { renderMermaid, DotRenderer } from '@probelabs/maid';\n\nconst result = renderMermaid(diagramText, {\n  renderer: new DotRenderer()\n});\n// result.svg now contains Graphviz DOT format\n```\n\nExample - Custom layout engine:\n```typescript\nimport { renderMermaid, ILayoutEngine } from '@probelabs/maid';\n\nclass MyLayoutEngine implements ILayoutEngine {\n  layout(graph: Graph): Layout {\n    // Your custom layout algorithm\n    return { nodes, edges, width, height };\n  }\n}\n\nconst result = renderMermaid(diagramText, {\n  layoutEngine: new MyLayoutEngine()\n});\n```\n\n**Core Interfaces:**\n- `ILayoutEngine` - Calculates node/edge positions from graph model\n- `IRenderer` - Generates output (SVG, DOT, etc.) from positioned layout\n\n**Implementations:**\n- `DagreLayoutEngine` - Hierarchical layout using Dagre (default)\n- `SVGRenderer` - SVG output with Mermaid-like styling (default)\n- `DotRenderer` - Graphviz DOT format (example implementation)\n\nSee `src/renderer/interfaces.ts` for interface definitions.\n\n### Extending the Linter\n\n1. Add a new module: `src/diagrams/\u003ctype\u003e/{lexer.ts,parser.ts,validate.ts}`\n2. Register in `src/core/router.ts` via header detection\n3. Add fixtures under `test-fixtures/\u003ctype\u003e/{valid,invalid}`\n4. Build and verify: `npm run build \u0026\u0026 node scripts/compare-linters.js \u003ctype\u003e`\n5. Regenerate previews: `node scripts/generate-preview.js \u003ctype\u003e`\n\n## Releasing\n\nWe publish to npm when a Git tag is pushed that matches the package version.\n\nRules\n- Tags must be in the form `vX.Y.Z` and match `package.json`’s `version`.\n\nSteps\n1. Bump version and tag: `npm version patch|minor|major`\n2. Push with tags: `git push --follow-tags`\n3. Release workflow builds, runs quick tests, and publishes to npm\n\nNotes\n- Package includes only compiled `out/`, README, and LICENSE\n- Requires repository secret `NPM_TOKEN` (publish access)\n\n## Edge Cases Covered\n\n- Flowchart:\n  - Escaped quotes in labels (rejected)\n  - Double quotes inside single-quoted labels (rejected, mermaid-compat)\n  - Mismatched quotes inside labels (accepted, mermaid-compat)\n  - Link text outside pipes triggers warnings\n- Pie:\n  - Labels must be quoted (single or double quotes)\n  - Colon and numeric value are required for each slice\n  - `title` without colon is accepted (e.g., `title \"Pets\"`); `title:` is rejected by current mermaid-cli\n  - Current mermaid-cli may emit an error SVG instead of failing the process; our preview scripts detect this and surface the error text\n\n## Contributing\n\nWe welcome contributions! Please ensure:\n\n1. All tests pass: `npm test`\n2. 100% mermaid-cli compatibility: `npm run test:compare`\n3. Update test fixtures if needed\n4. Regenerate previews: `npm run generate:previews`\n\n## License\n\nISC\n\n---\n\nBuilt with ❤️ for developers who care about documentation quality.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprobelabs%2Fmaid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprobelabs%2Fmaid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprobelabs%2Fmaid/lists"}