c4studio 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- c4studio-0.2.0/LICENSE +21 -0
- c4studio-0.2.0/PKG-INFO +283 -0
- c4studio-0.2.0/README.md +258 -0
- c4studio-0.2.0/pyproject.toml +73 -0
- c4studio-0.2.0/src/c4studio/__init__.py +28 -0
- c4studio-0.2.0/src/c4studio/__main__.py +5 -0
- c4studio-0.2.0/src/c4studio/cli/__init__.py +0 -0
- c4studio-0.2.0/src/c4studio/cli/main.py +329 -0
- c4studio-0.2.0/src/c4studio/diagnostics.py +84 -0
- c4studio-0.2.0/src/c4studio/generators/__init__.py +4 -0
- c4studio-0.2.0/src/c4studio/generators/flowchart.py +354 -0
- c4studio-0.2.0/src/c4studio/generators/json_export.py +678 -0
- c4studio-0.2.0/src/c4studio/generators/mermaid.py +169 -0
- c4studio-0.2.0/src/c4studio/generators/mermaid_common.py +65 -0
- c4studio-0.2.0/src/c4studio/graph/__init__.py +37 -0
- c4studio-0.2.0/src/c4studio/graph/view_graph.py +1176 -0
- c4studio-0.2.0/src/c4studio/icons.py +100 -0
- c4studio-0.2.0/src/c4studio/models/__init__.py +135 -0
- c4studio-0.2.0/src/c4studio/models/deployment.py +96 -0
- c4studio-0.2.0/src/c4studio/models/documentation.py +63 -0
- c4studio-0.2.0/src/c4studio/models/elements.py +141 -0
- c4studio-0.2.0/src/c4studio/models/enums.py +152 -0
- c4studio-0.2.0/src/c4studio/models/views.py +336 -0
- c4studio-0.2.0/src/c4studio/models/workspace.py +226 -0
- c4studio-0.2.0/src/c4studio/parser/__init__.py +4 -0
- c4studio-0.2.0/src/c4studio/parser/docs.py +109 -0
- c4studio-0.2.0/src/c4studio/parser/dsl.py +2254 -0
- c4studio-0.2.0/src/c4studio/parser/expressions.py +310 -0
- c4studio-0.2.0/src/c4studio/parser/implied.py +79 -0
- c4studio-0.2.0/src/c4studio/parser/json_parser.py +726 -0
- c4studio-0.2.0/src/c4studio/parser/locations.py +156 -0
- c4studio-0.2.0/src/c4studio/parser/sourcemap.py +52 -0
- c4studio-0.2.0/src/c4studio/py.typed +0 -0
- c4studio-0.2.0/src/c4studio/render.py +146 -0
- c4studio-0.2.0/src/c4studio/renderer/diagram-render.mjs +9757 -0
- c4studio-0.2.0/src/c4studio/themes.py +146 -0
- c4studio-0.2.0/src/c4studio/webapp/__init__.py +12 -0
- c4studio-0.2.0/src/c4studio/webapp/graph.py +132 -0
- c4studio-0.2.0/src/c4studio/webapp/loader.py +64 -0
- c4studio-0.2.0/src/c4studio/webapp/model_graph.py +227 -0
- c4studio-0.2.0/src/c4studio/webapp/server.py +713 -0
- c4studio-0.2.0/src/c4studio/webapp/static/assets/index-CibNm4nc.js +68 -0
- c4studio-0.2.0/src/c4studio/webapp/static/assets/index-Px2v-U7I.css +1 -0
- c4studio-0.2.0/src/c4studio/webapp/static/index.html +13 -0
c4studio-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geoffrey Koh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
c4studio-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: c4studio
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Parse Structurizr DSL/JSON and generate C4 diagrams in Mermaid, with a CLI and a React web app
|
|
5
|
+
Keywords: structurizr,c4,architecture,diagrams,dsl
|
|
6
|
+
Author: Geoffrey Koh
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Web Environment
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Documentation
|
|
14
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
15
|
+
Requires-Dist: click>=8.1
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: fastapi>=0.115
|
|
18
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
19
|
+
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest-cov>=5.0 ; extra == 'dev'
|
|
21
|
+
Requires-Python: >=3.13
|
|
22
|
+
Project-URL: Repository, https://github.com/geoffkoh/c4studio
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# c4studio
|
|
27
|
+
|
|
28
|
+
Python implementation of [Structurizr](https://structurizr.com/) for architecture modeling and C4 diagram generation.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Published on PyPI as **`c4studio`**; the import package is `c4studio`
|
|
33
|
+
and the command is `c4`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pipx install c4studio # or: pip install c4studio
|
|
37
|
+
c4 webapp my-architecture.dsl
|
|
38
|
+
|
|
39
|
+
# or run without installing:
|
|
40
|
+
uvx --from c4studio c4 webapp my-architecture.dsl
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Requires Python 3.13+ (uv/uvx can provision it automatically).
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from c4studio.models import Workspace, Person, SoftwareSystem, Container, Relationship, View, ViewType
|
|
49
|
+
|
|
50
|
+
# Create workspace
|
|
51
|
+
ws = Workspace(
|
|
52
|
+
name="My Architecture",
|
|
53
|
+
description="System architecture model"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Define people and systems
|
|
57
|
+
user = Person(id="user", name="User")
|
|
58
|
+
system = SoftwareSystem(id="sys", name="System")
|
|
59
|
+
ws.people.append(user)
|
|
60
|
+
ws.software_systems.append(system)
|
|
61
|
+
|
|
62
|
+
# Add relationship
|
|
63
|
+
rel = Relationship(
|
|
64
|
+
source_id="user",
|
|
65
|
+
destination_id="sys",
|
|
66
|
+
description="Uses"
|
|
67
|
+
)
|
|
68
|
+
ws.relationships.append(rel)
|
|
69
|
+
|
|
70
|
+
# Create view
|
|
71
|
+
view = View(type=ViewType.SYSTEM_CONTEXT, key="context")
|
|
72
|
+
ws.views.append(view)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Documentation
|
|
76
|
+
|
|
77
|
+
- **[DSL Language Support](./docs/dsl-support.md)** - Every keyword in the Structurizr DSL and whether c4studio supports it
|
|
78
|
+
- **[Data Models Reference](./docs/data-models.md)** - Complete guide to all Structurizr models and their fields
|
|
79
|
+
- **[Getting Started](./docs/README.md)** - Workflow and common patterns
|
|
80
|
+
- **[Enterprise Roadmap](./docs/roadmap.md)** - Parked phases 2-4 (model intelligence, headless rendering, differentiators)
|
|
81
|
+
|
|
82
|
+
## Features
|
|
83
|
+
|
|
84
|
+
- ✅ Full Structurizr metamodel support (C4 architecture model)
|
|
85
|
+
- ✅ DSL and JSON parsing
|
|
86
|
+
- ✅ Mermaid diagram generation — C4 syntax or `flowchart`/`subgraph`
|
|
87
|
+
- ✅ Comprehensive type hints
|
|
88
|
+
- ✅ Custom properties and perspectives on all elements
|
|
89
|
+
- ✅ Deployment infrastructure modeling
|
|
90
|
+
- ✅ Style and configuration management
|
|
91
|
+
|
|
92
|
+
## Parsing
|
|
93
|
+
|
|
94
|
+
Parse Structurizr DSL or JSON files:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from c4studio.parser.dsl import parse_dsl_file
|
|
98
|
+
from c4studio.parser.json_parser import parse_json_file
|
|
99
|
+
|
|
100
|
+
# Parse DSL
|
|
101
|
+
ws = parse_dsl_file("architecture.dsl")
|
|
102
|
+
|
|
103
|
+
# Parse JSON
|
|
104
|
+
ws = parse_json_file("workspace.json")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Diagram Generation
|
|
108
|
+
|
|
109
|
+
Two Mermaid targets, both rendering from the same view graph — so what they
|
|
110
|
+
show matches the web app's view semantics exactly:
|
|
111
|
+
|
|
112
|
+
| Target | Syntax | Covers |
|
|
113
|
+
| --- | --- | --- |
|
|
114
|
+
| `MermaidGenerator` | `C4Context` / `C4Container` / `C4Component` | system landscape, system context, container, component views |
|
|
115
|
+
| `FlowchartGenerator` | `flowchart` + `subgraph` | all of the above **plus** dynamic, deployment and filtered views |
|
|
116
|
+
|
|
117
|
+
Mermaid's C4 diagram types are experimental upstream and lay out poorly on
|
|
118
|
+
dense models, and GitHub pins its own Mermaid version — so prefer the
|
|
119
|
+
flowchart target for anything rendered on GitHub or in a wiki.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from c4studio.generators import FlowchartGenerator, MermaidGenerator
|
|
123
|
+
|
|
124
|
+
for view_name, mermaid_code in MermaidGenerator(ws).generate_all().items():
|
|
125
|
+
print(f"{view_name}:\n{mermaid_code}\n")
|
|
126
|
+
|
|
127
|
+
# Or the flowchart target, which renders every view type:
|
|
128
|
+
diagrams = FlowchartGenerator(ws).generate_all()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
From the CLI:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
uv run c4 generate architecture.dsl # C4 (default)
|
|
135
|
+
uv run c4 generate architecture.dsl -f flowchart # flowchart
|
|
136
|
+
uv run c4 generate architecture.dsl -f flowchart -o out # one .mmd per view
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Headless SVG Rendering
|
|
140
|
+
|
|
141
|
+
`c4 render` draws diagrams as standalone SVG with no browser
|
|
142
|
+
and no server — for CI, docs-as-code pipelines and static sites. Layout is
|
|
143
|
+
the same code the web app runs, so positions match what you see in the
|
|
144
|
+
viewer, including any layout you have saved for a view.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
uv run c4 render architecture.dsl -o diagrams/ # one .svg per view
|
|
148
|
+
uv run c4 render architecture.dsl -v Containers # one view to stdout
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each diagram carries its own title and a legend of the styles it actually
|
|
152
|
+
uses, so an exported file explains itself to someone who did not build it.
|
|
153
|
+
Pass `--no-title` or `--no-legend` to leave either out.
|
|
154
|
+
|
|
155
|
+
The output is self-contained: no external fonts or stylesheets, and theme
|
|
156
|
+
icons (the AWS/Azure/GCP service logos) are fetched once and embedded as
|
|
157
|
+
`data:` URIs, so a file renders identically wherever it is opened — even
|
|
158
|
+
offline. An icon that cannot be fetched is simply left out.
|
|
159
|
+
|
|
160
|
+
> **This is the only command that needs [Node.js](https://nodejs.org) 18+**
|
|
161
|
+
> (the renderer is bundled into the wheel, so there is no `npm install`).
|
|
162
|
+
> Set `C4STUDIO_NODE` if `node` is not on your `PATH`. Parsing,
|
|
163
|
+
> Mermaid generation, JSON export and the web app all work without it.
|
|
164
|
+
|
|
165
|
+
## GitHub Action
|
|
166
|
+
|
|
167
|
+
Render the diagrams on every push and pull request, so reviewers see the
|
|
168
|
+
architecture change alongside the code change:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
name: Diagrams
|
|
172
|
+
on: [push, pull_request]
|
|
173
|
+
|
|
174
|
+
jobs:
|
|
175
|
+
render:
|
|
176
|
+
runs-on: ubuntu-latest
|
|
177
|
+
steps:
|
|
178
|
+
- uses: actions/checkout@v4
|
|
179
|
+
- uses: geoffkoh/c4studio@v0.2.0
|
|
180
|
+
id: diagrams
|
|
181
|
+
with:
|
|
182
|
+
workspace: docs/architecture.dsl
|
|
183
|
+
- uses: actions/upload-artifact@v4
|
|
184
|
+
with:
|
|
185
|
+
name: diagrams
|
|
186
|
+
path: ${{ steps.diagrams.outputs.diagrams-path }}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Input | Default | What it does |
|
|
190
|
+
| --- | --- | --- |
|
|
191
|
+
| `workspace` | *required* | The `.dsl` or `.json` file to render |
|
|
192
|
+
| `output` | `diagrams` | Directory for the SVGs, one per view |
|
|
193
|
+
| `view` | *(all)* | Render a single view key |
|
|
194
|
+
| `mode` | `render` | `render`, `commit` (push the files back when they change) or `comment` (comment on the PR) |
|
|
195
|
+
| `version` | `c4studio` | pip requirement to install; `local` uses the checkout |
|
|
196
|
+
| `python-version` | `3.13` | Python to set up first — runners still default to an older one than this package needs. Empty string skips the step |
|
|
197
|
+
|
|
198
|
+
The action checks the workspace before rendering, so a parse error fails
|
|
199
|
+
the job with diagnostics rather than a traceback, and sets a `changed`
|
|
200
|
+
output. Because rendering is deterministic, `mode: commit` produces no
|
|
201
|
+
diff when the model has not changed.
|
|
202
|
+
|
|
203
|
+
## Workspace JSON Export
|
|
204
|
+
|
|
205
|
+
Export any workspace (DSL or JSON) back to Structurizr workspace JSON,
|
|
206
|
+
round-tripping with structurizr.com, Structurizr Lite, and this package's
|
|
207
|
+
own parser:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv run c4 export workspace.dsl -o workspace.json
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Or programmatically via `c4studio.generators.json_export.export_json`.
|
|
214
|
+
|
|
215
|
+
## VS Code Extension
|
|
216
|
+
|
|
217
|
+
[`editors/vscode/`](./editors/vscode/) ships a VS Code extension with
|
|
218
|
+
Structurizr DSL syntax highlighting and an in-editor C4 diagram preview
|
|
219
|
+
(the full web app in a side panel, live-reloading as you save). Build and
|
|
220
|
+
install it locally:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cd editors/vscode && npm install && npm run package
|
|
224
|
+
code --install-extension c4studio-vscode-*.vsix
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## React Web App
|
|
228
|
+
|
|
229
|
+
A React (Vite + TypeScript) single-page app, served by a FastAPI backend
|
|
230
|
+
and launched from the CLI, for loading DSL/JSON files from disk and
|
|
231
|
+
exploring each view as an interactive [React Flow](https://reactflow.dev/)
|
|
232
|
+
graph (draggable nodes, pan/zoom, minimap).
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
uv run c4 webapp samples/ # browse a directory
|
|
236
|
+
uv run c4 webapp file.dsl # preload a single file
|
|
237
|
+
# → opens http://127.0.0.1:8090 (use --no-browser to skip, --port to change)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Select several nodes (Shift+drag, or ⌘/Ctrl+click) to align or distribute
|
|
241
|
+
them from the toolbar that appears, and nudge a selection with the arrow
|
|
242
|
+
keys — 10px with Shift. Everything persists to the layout sidecar.
|
|
243
|
+
|
|
244
|
+
Pass a directory to browse and load any `.dsl`/`.json` file from the
|
|
245
|
+
in-app file picker, or a single file to preload it. The element tree and
|
|
246
|
+
per-view graph come from the parser and `graph/view_graph`;
|
|
247
|
+
`systemLandscape`, `systemContext`, `container`, `component`, `dynamic`
|
|
248
|
+
and `deployment` views all render as interactive graphs (other view
|
|
249
|
+
types are flagged "not renderable yet").
|
|
250
|
+
|
|
251
|
+
The **Explorer** tab renders the entire static model as one graph —
|
|
252
|
+
independent of any curated view — at a selectable abstraction level
|
|
253
|
+
(systems / containers / components), with search across every element
|
|
254
|
+
(press `/`), and a details panel showing an element's metadata,
|
|
255
|
+
relationships, the views it appears in (click to jump) and a
|
|
256
|
+
show-definition link into the Source pane.
|
|
257
|
+
|
|
258
|
+
The built SPA ships inside the package (`c4studio/webapp/static/`),
|
|
259
|
+
so end users need no Node toolchain. To rebuild the frontend after
|
|
260
|
+
changes (requires Node 18+):
|
|
261
|
+
|
|
262
|
+
The frontend is an npm workspace: `packages/diagram-core` holds the
|
|
263
|
+
diagram layer (layout, node/edge components, image export) and
|
|
264
|
+
`frontend/` is the SPA that consumes it, so build from the repo root.
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
npm install
|
|
268
|
+
npm run build # diagram-core, then the SPA
|
|
269
|
+
# outputs to src/c4studio/webapp/static/
|
|
270
|
+
# dev loop: `npm run dev --workspace c4studio-frontend`
|
|
271
|
+
# (Vite :5173, proxies /api → :8090) alongside
|
|
272
|
+
# `uv run c4 webapp samples/ --no-browser`
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
> **Security**: the web app has no authentication and is intended for
|
|
276
|
+
> local use on `127.0.0.1`.
|
|
277
|
+
|
|
278
|
+
### Tests
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
uv run pytest # full suite
|
|
282
|
+
uv run pytest tests/test_webapp # web app tests only
|
|
283
|
+
```
|
c4studio-0.2.0/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# c4studio
|
|
2
|
+
|
|
3
|
+
Python implementation of [Structurizr](https://structurizr.com/) for architecture modeling and C4 diagram generation.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Published on PyPI as **`c4studio`**; the import package is `c4studio`
|
|
8
|
+
and the command is `c4`:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pipx install c4studio # or: pip install c4studio
|
|
12
|
+
c4 webapp my-architecture.dsl
|
|
13
|
+
|
|
14
|
+
# or run without installing:
|
|
15
|
+
uvx --from c4studio c4 webapp my-architecture.dsl
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Requires Python 3.13+ (uv/uvx can provision it automatically).
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from c4studio.models import Workspace, Person, SoftwareSystem, Container, Relationship, View, ViewType
|
|
24
|
+
|
|
25
|
+
# Create workspace
|
|
26
|
+
ws = Workspace(
|
|
27
|
+
name="My Architecture",
|
|
28
|
+
description="System architecture model"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Define people and systems
|
|
32
|
+
user = Person(id="user", name="User")
|
|
33
|
+
system = SoftwareSystem(id="sys", name="System")
|
|
34
|
+
ws.people.append(user)
|
|
35
|
+
ws.software_systems.append(system)
|
|
36
|
+
|
|
37
|
+
# Add relationship
|
|
38
|
+
rel = Relationship(
|
|
39
|
+
source_id="user",
|
|
40
|
+
destination_id="sys",
|
|
41
|
+
description="Uses"
|
|
42
|
+
)
|
|
43
|
+
ws.relationships.append(rel)
|
|
44
|
+
|
|
45
|
+
# Create view
|
|
46
|
+
view = View(type=ViewType.SYSTEM_CONTEXT, key="context")
|
|
47
|
+
ws.views.append(view)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Documentation
|
|
51
|
+
|
|
52
|
+
- **[DSL Language Support](./docs/dsl-support.md)** - Every keyword in the Structurizr DSL and whether c4studio supports it
|
|
53
|
+
- **[Data Models Reference](./docs/data-models.md)** - Complete guide to all Structurizr models and their fields
|
|
54
|
+
- **[Getting Started](./docs/README.md)** - Workflow and common patterns
|
|
55
|
+
- **[Enterprise Roadmap](./docs/roadmap.md)** - Parked phases 2-4 (model intelligence, headless rendering, differentiators)
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- ✅ Full Structurizr metamodel support (C4 architecture model)
|
|
60
|
+
- ✅ DSL and JSON parsing
|
|
61
|
+
- ✅ Mermaid diagram generation — C4 syntax or `flowchart`/`subgraph`
|
|
62
|
+
- ✅ Comprehensive type hints
|
|
63
|
+
- ✅ Custom properties and perspectives on all elements
|
|
64
|
+
- ✅ Deployment infrastructure modeling
|
|
65
|
+
- ✅ Style and configuration management
|
|
66
|
+
|
|
67
|
+
## Parsing
|
|
68
|
+
|
|
69
|
+
Parse Structurizr DSL or JSON files:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from c4studio.parser.dsl import parse_dsl_file
|
|
73
|
+
from c4studio.parser.json_parser import parse_json_file
|
|
74
|
+
|
|
75
|
+
# Parse DSL
|
|
76
|
+
ws = parse_dsl_file("architecture.dsl")
|
|
77
|
+
|
|
78
|
+
# Parse JSON
|
|
79
|
+
ws = parse_json_file("workspace.json")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Diagram Generation
|
|
83
|
+
|
|
84
|
+
Two Mermaid targets, both rendering from the same view graph — so what they
|
|
85
|
+
show matches the web app's view semantics exactly:
|
|
86
|
+
|
|
87
|
+
| Target | Syntax | Covers |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `MermaidGenerator` | `C4Context` / `C4Container` / `C4Component` | system landscape, system context, container, component views |
|
|
90
|
+
| `FlowchartGenerator` | `flowchart` + `subgraph` | all of the above **plus** dynamic, deployment and filtered views |
|
|
91
|
+
|
|
92
|
+
Mermaid's C4 diagram types are experimental upstream and lay out poorly on
|
|
93
|
+
dense models, and GitHub pins its own Mermaid version — so prefer the
|
|
94
|
+
flowchart target for anything rendered on GitHub or in a wiki.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from c4studio.generators import FlowchartGenerator, MermaidGenerator
|
|
98
|
+
|
|
99
|
+
for view_name, mermaid_code in MermaidGenerator(ws).generate_all().items():
|
|
100
|
+
print(f"{view_name}:\n{mermaid_code}\n")
|
|
101
|
+
|
|
102
|
+
# Or the flowchart target, which renders every view type:
|
|
103
|
+
diagrams = FlowchartGenerator(ws).generate_all()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
From the CLI:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run c4 generate architecture.dsl # C4 (default)
|
|
110
|
+
uv run c4 generate architecture.dsl -f flowchart # flowchart
|
|
111
|
+
uv run c4 generate architecture.dsl -f flowchart -o out # one .mmd per view
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Headless SVG Rendering
|
|
115
|
+
|
|
116
|
+
`c4 render` draws diagrams as standalone SVG with no browser
|
|
117
|
+
and no server — for CI, docs-as-code pipelines and static sites. Layout is
|
|
118
|
+
the same code the web app runs, so positions match what you see in the
|
|
119
|
+
viewer, including any layout you have saved for a view.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv run c4 render architecture.dsl -o diagrams/ # one .svg per view
|
|
123
|
+
uv run c4 render architecture.dsl -v Containers # one view to stdout
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Each diagram carries its own title and a legend of the styles it actually
|
|
127
|
+
uses, so an exported file explains itself to someone who did not build it.
|
|
128
|
+
Pass `--no-title` or `--no-legend` to leave either out.
|
|
129
|
+
|
|
130
|
+
The output is self-contained: no external fonts or stylesheets, and theme
|
|
131
|
+
icons (the AWS/Azure/GCP service logos) are fetched once and embedded as
|
|
132
|
+
`data:` URIs, so a file renders identically wherever it is opened — even
|
|
133
|
+
offline. An icon that cannot be fetched is simply left out.
|
|
134
|
+
|
|
135
|
+
> **This is the only command that needs [Node.js](https://nodejs.org) 18+**
|
|
136
|
+
> (the renderer is bundled into the wheel, so there is no `npm install`).
|
|
137
|
+
> Set `C4STUDIO_NODE` if `node` is not on your `PATH`. Parsing,
|
|
138
|
+
> Mermaid generation, JSON export and the web app all work without it.
|
|
139
|
+
|
|
140
|
+
## GitHub Action
|
|
141
|
+
|
|
142
|
+
Render the diagrams on every push and pull request, so reviewers see the
|
|
143
|
+
architecture change alongside the code change:
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
name: Diagrams
|
|
147
|
+
on: [push, pull_request]
|
|
148
|
+
|
|
149
|
+
jobs:
|
|
150
|
+
render:
|
|
151
|
+
runs-on: ubuntu-latest
|
|
152
|
+
steps:
|
|
153
|
+
- uses: actions/checkout@v4
|
|
154
|
+
- uses: geoffkoh/c4studio@v0.2.0
|
|
155
|
+
id: diagrams
|
|
156
|
+
with:
|
|
157
|
+
workspace: docs/architecture.dsl
|
|
158
|
+
- uses: actions/upload-artifact@v4
|
|
159
|
+
with:
|
|
160
|
+
name: diagrams
|
|
161
|
+
path: ${{ steps.diagrams.outputs.diagrams-path }}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| Input | Default | What it does |
|
|
165
|
+
| --- | --- | --- |
|
|
166
|
+
| `workspace` | *required* | The `.dsl` or `.json` file to render |
|
|
167
|
+
| `output` | `diagrams` | Directory for the SVGs, one per view |
|
|
168
|
+
| `view` | *(all)* | Render a single view key |
|
|
169
|
+
| `mode` | `render` | `render`, `commit` (push the files back when they change) or `comment` (comment on the PR) |
|
|
170
|
+
| `version` | `c4studio` | pip requirement to install; `local` uses the checkout |
|
|
171
|
+
| `python-version` | `3.13` | Python to set up first — runners still default to an older one than this package needs. Empty string skips the step |
|
|
172
|
+
|
|
173
|
+
The action checks the workspace before rendering, so a parse error fails
|
|
174
|
+
the job with diagnostics rather than a traceback, and sets a `changed`
|
|
175
|
+
output. Because rendering is deterministic, `mode: commit` produces no
|
|
176
|
+
diff when the model has not changed.
|
|
177
|
+
|
|
178
|
+
## Workspace JSON Export
|
|
179
|
+
|
|
180
|
+
Export any workspace (DSL or JSON) back to Structurizr workspace JSON,
|
|
181
|
+
round-tripping with structurizr.com, Structurizr Lite, and this package's
|
|
182
|
+
own parser:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
uv run c4 export workspace.dsl -o workspace.json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Or programmatically via `c4studio.generators.json_export.export_json`.
|
|
189
|
+
|
|
190
|
+
## VS Code Extension
|
|
191
|
+
|
|
192
|
+
[`editors/vscode/`](./editors/vscode/) ships a VS Code extension with
|
|
193
|
+
Structurizr DSL syntax highlighting and an in-editor C4 diagram preview
|
|
194
|
+
(the full web app in a side panel, live-reloading as you save). Build and
|
|
195
|
+
install it locally:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
cd editors/vscode && npm install && npm run package
|
|
199
|
+
code --install-extension c4studio-vscode-*.vsix
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## React Web App
|
|
203
|
+
|
|
204
|
+
A React (Vite + TypeScript) single-page app, served by a FastAPI backend
|
|
205
|
+
and launched from the CLI, for loading DSL/JSON files from disk and
|
|
206
|
+
exploring each view as an interactive [React Flow](https://reactflow.dev/)
|
|
207
|
+
graph (draggable nodes, pan/zoom, minimap).
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv run c4 webapp samples/ # browse a directory
|
|
211
|
+
uv run c4 webapp file.dsl # preload a single file
|
|
212
|
+
# → opens http://127.0.0.1:8090 (use --no-browser to skip, --port to change)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Select several nodes (Shift+drag, or ⌘/Ctrl+click) to align or distribute
|
|
216
|
+
them from the toolbar that appears, and nudge a selection with the arrow
|
|
217
|
+
keys — 10px with Shift. Everything persists to the layout sidecar.
|
|
218
|
+
|
|
219
|
+
Pass a directory to browse and load any `.dsl`/`.json` file from the
|
|
220
|
+
in-app file picker, or a single file to preload it. The element tree and
|
|
221
|
+
per-view graph come from the parser and `graph/view_graph`;
|
|
222
|
+
`systemLandscape`, `systemContext`, `container`, `component`, `dynamic`
|
|
223
|
+
and `deployment` views all render as interactive graphs (other view
|
|
224
|
+
types are flagged "not renderable yet").
|
|
225
|
+
|
|
226
|
+
The **Explorer** tab renders the entire static model as one graph —
|
|
227
|
+
independent of any curated view — at a selectable abstraction level
|
|
228
|
+
(systems / containers / components), with search across every element
|
|
229
|
+
(press `/`), and a details panel showing an element's metadata,
|
|
230
|
+
relationships, the views it appears in (click to jump) and a
|
|
231
|
+
show-definition link into the Source pane.
|
|
232
|
+
|
|
233
|
+
The built SPA ships inside the package (`c4studio/webapp/static/`),
|
|
234
|
+
so end users need no Node toolchain. To rebuild the frontend after
|
|
235
|
+
changes (requires Node 18+):
|
|
236
|
+
|
|
237
|
+
The frontend is an npm workspace: `packages/diagram-core` holds the
|
|
238
|
+
diagram layer (layout, node/edge components, image export) and
|
|
239
|
+
`frontend/` is the SPA that consumes it, so build from the repo root.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npm install
|
|
243
|
+
npm run build # diagram-core, then the SPA
|
|
244
|
+
# outputs to src/c4studio/webapp/static/
|
|
245
|
+
# dev loop: `npm run dev --workspace c4studio-frontend`
|
|
246
|
+
# (Vite :5173, proxies /api → :8090) alongside
|
|
247
|
+
# `uv run c4 webapp samples/ --no-browser`
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
> **Security**: the web app has no authentication and is intended for
|
|
251
|
+
> local use on `127.0.0.1`.
|
|
252
|
+
|
|
253
|
+
### Tests
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
uv run pytest # full suite
|
|
257
|
+
uv run pytest tests/test_webapp # web app tests only
|
|
258
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
# Renamed from "pystructurizr-studio" in PP-106: the old name was a
|
|
3
|
+
# mouthful, and "pystructurizr" itself belongs to an unrelated PyPI
|
|
4
|
+
# project. C4 is the notation, not a vendor's product, so the name stays
|
|
5
|
+
# honest even if support broadens beyond Structurizr DSL.
|
|
6
|
+
name = "c4studio"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Parse Structurizr DSL/JSON and generate C4 diagrams in Mermaid, with a CLI and a React web app"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "Geoffrey Koh" }]
|
|
13
|
+
requires-python = ">=3.13"
|
|
14
|
+
keywords = ["structurizr", "c4", "architecture", "diagrams", "dsl"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Web Environment",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Documentation",
|
|
21
|
+
"Topic :: Software Development :: Documentation",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"click>=8.1",
|
|
25
|
+
"pydantic>=2.0",
|
|
26
|
+
"fastapi>=0.115",
|
|
27
|
+
"uvicorn[standard]>=0.30",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Repository = "https://github.com/geoffkoh/c4studio"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=8.0",
|
|
36
|
+
"pytest-cov>=5.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
# Short on purpose: this is the thing typed daily.
|
|
41
|
+
c4 = "c4studio.cli.main:cli"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["uv_build>=0.11.8,<0.12.0"]
|
|
45
|
+
build-backend = "uv_build"
|
|
46
|
+
|
|
47
|
+
[tool.uv.build-backend]
|
|
48
|
+
module-name = "c4studio"
|
|
49
|
+
|
|
50
|
+
[tool.mypy]
|
|
51
|
+
# Strict by default, so `uv run mypy .` — the command in CLAUDE.md and the
|
|
52
|
+
# one run before every PR — is the strict one. Without this it ran with
|
|
53
|
+
# default settings and strictness could regress unnoticed.
|
|
54
|
+
strict = true
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
58
|
+
asyncio_mode = "auto"
|
|
59
|
+
|
|
60
|
+
[dependency-groups]
|
|
61
|
+
dev = [
|
|
62
|
+
"pytest-asyncio>=1.4.0",
|
|
63
|
+
"httpx>=0.27",
|
|
64
|
+
# tests/test_action.py parses action.yml and the dogfood workflow.
|
|
65
|
+
# pyyaml is already present transitively (uvicorn[standard]), but the
|
|
66
|
+
# tests should not lean on another package's dependency tree.
|
|
67
|
+
"pyyaml>=6.0",
|
|
68
|
+
"types-PyYAML>=6.0",
|
|
69
|
+
# Declared so `uv run mypy .` runs inside the project environment. Left
|
|
70
|
+
# undeclared it resolved to an ephemeral install that could not see
|
|
71
|
+
# project-installed type stubs, and the version drifted per machine.
|
|
72
|
+
"mypy>=1.11",
|
|
73
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""c4studio – parse Structurizr DSL/JSON and generate C4 Mermaid diagrams."""
|
|
2
|
+
|
|
3
|
+
from c4studio.models import (
|
|
4
|
+
Component,
|
|
5
|
+
Container,
|
|
6
|
+
Person,
|
|
7
|
+
Relationship,
|
|
8
|
+
SoftwareSystem,
|
|
9
|
+
View,
|
|
10
|
+
ViewType,
|
|
11
|
+
Workspace,
|
|
12
|
+
)
|
|
13
|
+
from c4studio.parser import parse_dsl, parse_json
|
|
14
|
+
from c4studio.generators import MermaidGenerator
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"parse_dsl",
|
|
18
|
+
"parse_json",
|
|
19
|
+
"MermaidGenerator",
|
|
20
|
+
"Workspace",
|
|
21
|
+
"SoftwareSystem",
|
|
22
|
+
"Container",
|
|
23
|
+
"Component",
|
|
24
|
+
"Person",
|
|
25
|
+
"Relationship",
|
|
26
|
+
"View",
|
|
27
|
+
"ViewType",
|
|
28
|
+
]
|
|
File without changes
|