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.
Files changed (44) hide show
  1. c4studio-0.2.0/LICENSE +21 -0
  2. c4studio-0.2.0/PKG-INFO +283 -0
  3. c4studio-0.2.0/README.md +258 -0
  4. c4studio-0.2.0/pyproject.toml +73 -0
  5. c4studio-0.2.0/src/c4studio/__init__.py +28 -0
  6. c4studio-0.2.0/src/c4studio/__main__.py +5 -0
  7. c4studio-0.2.0/src/c4studio/cli/__init__.py +0 -0
  8. c4studio-0.2.0/src/c4studio/cli/main.py +329 -0
  9. c4studio-0.2.0/src/c4studio/diagnostics.py +84 -0
  10. c4studio-0.2.0/src/c4studio/generators/__init__.py +4 -0
  11. c4studio-0.2.0/src/c4studio/generators/flowchart.py +354 -0
  12. c4studio-0.2.0/src/c4studio/generators/json_export.py +678 -0
  13. c4studio-0.2.0/src/c4studio/generators/mermaid.py +169 -0
  14. c4studio-0.2.0/src/c4studio/generators/mermaid_common.py +65 -0
  15. c4studio-0.2.0/src/c4studio/graph/__init__.py +37 -0
  16. c4studio-0.2.0/src/c4studio/graph/view_graph.py +1176 -0
  17. c4studio-0.2.0/src/c4studio/icons.py +100 -0
  18. c4studio-0.2.0/src/c4studio/models/__init__.py +135 -0
  19. c4studio-0.2.0/src/c4studio/models/deployment.py +96 -0
  20. c4studio-0.2.0/src/c4studio/models/documentation.py +63 -0
  21. c4studio-0.2.0/src/c4studio/models/elements.py +141 -0
  22. c4studio-0.2.0/src/c4studio/models/enums.py +152 -0
  23. c4studio-0.2.0/src/c4studio/models/views.py +336 -0
  24. c4studio-0.2.0/src/c4studio/models/workspace.py +226 -0
  25. c4studio-0.2.0/src/c4studio/parser/__init__.py +4 -0
  26. c4studio-0.2.0/src/c4studio/parser/docs.py +109 -0
  27. c4studio-0.2.0/src/c4studio/parser/dsl.py +2254 -0
  28. c4studio-0.2.0/src/c4studio/parser/expressions.py +310 -0
  29. c4studio-0.2.0/src/c4studio/parser/implied.py +79 -0
  30. c4studio-0.2.0/src/c4studio/parser/json_parser.py +726 -0
  31. c4studio-0.2.0/src/c4studio/parser/locations.py +156 -0
  32. c4studio-0.2.0/src/c4studio/parser/sourcemap.py +52 -0
  33. c4studio-0.2.0/src/c4studio/py.typed +0 -0
  34. c4studio-0.2.0/src/c4studio/render.py +146 -0
  35. c4studio-0.2.0/src/c4studio/renderer/diagram-render.mjs +9757 -0
  36. c4studio-0.2.0/src/c4studio/themes.py +146 -0
  37. c4studio-0.2.0/src/c4studio/webapp/__init__.py +12 -0
  38. c4studio-0.2.0/src/c4studio/webapp/graph.py +132 -0
  39. c4studio-0.2.0/src/c4studio/webapp/loader.py +64 -0
  40. c4studio-0.2.0/src/c4studio/webapp/model_graph.py +227 -0
  41. c4studio-0.2.0/src/c4studio/webapp/server.py +713 -0
  42. c4studio-0.2.0/src/c4studio/webapp/static/assets/index-CibNm4nc.js +68 -0
  43. c4studio-0.2.0/src/c4studio/webapp/static/assets/index-Px2v-U7I.css +1 -0
  44. 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.
@@ -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
+ ```
@@ -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
+ ]
@@ -0,0 +1,5 @@
1
+ """Allow ``python -m c4studio`` as an alternative to the console script."""
2
+
3
+ from c4studio.cli.main import cli
4
+
5
+ cli()
File without changes