Skip to content

Commit fe4cb74

Browse files
committed
feat(export): add Mermaid exporter for processes and stateflows
1 parent 71fff6b commit fe4cb74

File tree

11 files changed

+557
-1
lines changed

11 files changed

+557
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on Keep a Changelog, and this project follows Semantic Versi
99
- Added `orgscript format <file> --check` for canonical formatting checks without rewriting files.
1010
- Added `npm run format:check:all` and integrated formatting checks into CI.
1111
- Added `orgscript check <file>` as the combined quality command for validation, linting, and formatting checks.
12+
- Added `orgscript export mermaid <file>` for first-pass Mermaid exports of processes and stateflows.
1213

1314
## [0.3.0] - 2026-03-29
1415

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ See the full example in [`examples/craft-business-lead-to-order.orgs`](examples/
147147
- AST-backed linting: `orgscript lint <file>`
148148
- Combined quality checks: `orgscript check <file>`
149149
- Canonical JSON export: `orgscript export json <file>`
150+
- Mermaid export for `process` and `stateflow`: `orgscript export mermaid <file>`
150151
- Machine-readable diagnostics: `orgscript validate <file> --json`, `orgscript lint <file> --json`
151152
- Golden snapshot tests for AST, canonical model, and formatter output
152153
- Stable lint severities: `error`, `warning`, `info`
@@ -163,6 +164,7 @@ node ./bin/orgscript.js format ./examples/craft-business-lead-to-order.orgs --ch
163164
node ./bin/orgscript.js lint ./tests/lint/process-missing-trigger.orgs
164165
node ./bin/orgscript.js lint ./tests/lint/process-missing-trigger.orgs --json
165166
node ./bin/orgscript.js export json ./examples/craft-business-lead-to-order.orgs
167+
node ./bin/orgscript.js export mermaid ./examples/craft-business-lead-to-order.orgs
166168
```
167169

168170
Exit codes are CI-friendly:
@@ -199,17 +201,21 @@ orgscript format file.orgs --check
199201
orgscript lint file.orgs
200202
orgscript lint file.orgs --json
201203
orgscript export json file.orgs
204+
orgscript export mermaid file.orgs
202205
orgscript check file.orgs
203206
```
204207

205208
`orgscript check` runs `validate`, `lint`, and `format --check` in that order and fails on validation errors, lint errors, or formatting drift. Warnings and info findings alone do not fail the command.
206209

210+
`orgscript export mermaid` currently supports `process` and `stateflow` blocks and emits a Markdown document with Mermaid code blocks for direct use in GitHub or docs.
211+
207212
See [`docs/cli-v0.1-plan.md`](docs/cli-v0.1-plan.md) for the implementation plan.
208213

209214
## Testing
210215

211216
```text
212217
npm test
218+
npm run export:mermaid
213219
npm run format:check:all
214220
npm run validate:all
215221
npm run lint:all

docs/cli-v0.1-plan.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Implemented:
1515
- `format --check`
1616
- `lint`
1717
- `export json`
18+
- `export mermaid`
1819
- `validate --json`
1920
- `lint --json`
2021
- `check`
@@ -45,6 +46,20 @@ Output:
4546

4647
Exports the parsed document into the canonical JSON model.
4748

49+
### `orgscript export mermaid <file>`
50+
51+
Exports supported blocks as a Markdown document with Mermaid code blocks.
52+
53+
Current scope:
54+
55+
- `process` -> `flowchart TD`
56+
- `stateflow` -> `stateDiagram-v2`
57+
58+
Current limitations:
59+
60+
- unsupported block types are skipped and called out in the export
61+
- files without any supported blocks fail with a clear error
62+
4863
### `orgscript format <file>`
4964

5065
Normalizes:

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"validate:all": "node ./scripts/validate-all.js",
1717
"lint:all": "node ./scripts/lint-all.js",
1818
"export:json": "node ./bin/orgscript.js export json ./examples/craft-business-lead-to-order.orgs",
19+
"export:mermaid": "node ./bin/orgscript.js export mermaid ./examples/craft-business-lead-to-order.orgs",
1920
"golden:generate": "node ./scripts/generate-golden.js",
2021
"test": "node ./tests/run.js"
2122
},

scripts/generate-golden.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const path = require("path");
55
const { formatDocument } = require("../src/formatter");
66
const { buildModel } = require("../src/validate");
77
const { toCanonicalModel } = require("../src/export-json");
8+
const { toMermaidMarkdown } = require("../src/export-mermaid");
89

910
const repoRoot = path.resolve(__dirname, "..");
1011
const examplesDir = path.join(repoRoot, "examples");
@@ -30,6 +31,8 @@ for (const file of files) {
3031
const astOutputPath = path.join(goldenDir, `${baseName}.ast.json`);
3132
const modelOutputPath = path.join(goldenDir, `${baseName}.model.json`);
3233
const formattedOutputPath = path.join(goldenDir, `${baseName}.formatted.orgs`);
34+
const mermaidOutputPath = path.join(goldenDir, `${baseName}.mermaid.md`);
35+
const canonicalModel = toCanonicalModel(result.ast);
3336

3437
fs.writeFileSync(
3538
astOutputPath,
@@ -38,11 +41,19 @@ for (const file of files) {
3841
);
3942
fs.writeFileSync(
4043
modelOutputPath,
41-
`${JSON.stringify(toCanonicalModel(result.ast), null, 2)}\n`,
44+
`${JSON.stringify(canonicalModel, null, 2)}\n`,
4245
"utf8"
4346
);
4447
fs.writeFileSync(formattedOutputPath, formatDocument(result.ast), "utf8");
4548

49+
try {
50+
fs.writeFileSync(mermaidOutputPath, toMermaidMarkdown(canonicalModel), "utf8");
51+
} catch (error) {
52+
if (fs.existsSync(mermaidOutputPath)) {
53+
fs.unlinkSync(mermaidOutputPath);
54+
}
55+
}
56+
4657
console.log(`Wrote golden files for ${file}`);
4758
}
4859

src/cli.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
createValidateReport,
77
} = require("./diagnostics");
88
const { toCanonicalModel } = require("./export-json");
9+
const { toMermaidMarkdown } = require("./export-mermaid");
910
const { formatDocument } = require("./formatter");
1011
const { lintDocument, renderLintReport, summarizeFindings } = require("./linter");
1112
const { buildModel, validateFile } = require("./validate");
@@ -19,6 +20,7 @@ Usage:
1920
orgscript format <file> [--check]
2021
orgscript lint <file> [--json]
2122
orgscript export json <file>
23+
orgscript export mermaid <file>
2224
`);
2325
}
2426

@@ -78,6 +80,29 @@ function run(args) {
7880
process.exit(0);
7981
}
8082

83+
if (command === "export" && maybeSubcommand === "mermaid") {
84+
const absolutePath = resolveFile("export", maybeFile);
85+
const result = buildModel(absolutePath);
86+
87+
if (!result.ok) {
88+
printIssues(`Cannot export invalid OrgScript: ${absolutePath}`, [
89+
...result.syntaxIssues,
90+
...result.semanticIssues,
91+
]);
92+
process.exit(1);
93+
}
94+
95+
try {
96+
const canonical = toCanonicalModel(result.ast);
97+
const mermaid = toMermaidMarkdown(canonical);
98+
process.stdout.write(mermaid);
99+
process.exit(0);
100+
} catch (error) {
101+
console.error(`Cannot export Mermaid from ${absolutePath}: ${error.message}`);
102+
process.exit(1);
103+
}
104+
}
105+
81106
if (command === "format") {
82107
const absolutePath = resolveFile("format", maybeSubcommand);
83108
const result = buildModel(absolutePath);

0 commit comments

Comments
 (0)