sirena 0.1.0

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 (382) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build_deploy.yml +59 -0
  3. data/.github/workflows/links.yml +85 -0
  4. data/.github/workflows/rake.yml +15 -0
  5. data/.github/workflows/release.yml +27 -0
  6. data/.gitignore +68 -0
  7. data/.rspec +3 -0
  8. data/.rubocop.yml +14 -0
  9. data/.rubocop_todo.yml +70 -0
  10. data/ARCHITECTURE.md +744 -0
  11. data/Gemfile +12 -0
  12. data/LICENSE +25 -0
  13. data/README.adoc +357 -0
  14. data/Rakefile +11 -0
  15. data/docs/.gitignore +1 -0
  16. data/docs/Gemfile +13 -0
  17. data/docs/_config.yml +182 -0
  18. data/docs/_diagram_types/architecture-diagram.adoc +314 -0
  19. data/docs/_diagram_types/block-diagram.adoc +345 -0
  20. data/docs/_diagram_types/c4-diagram.adoc +559 -0
  21. data/docs/_diagram_types/class-diagram.adoc +816 -0
  22. data/docs/_diagram_types/er-diagram.adoc +719 -0
  23. data/docs/_diagram_types/error-diagram.adoc +114 -0
  24. data/docs/_diagram_types/examples/flowchart-examples.adoc +29 -0
  25. data/docs/_diagram_types/flowchart.adoc +488 -0
  26. data/docs/_diagram_types/gantt-chart.adoc +502 -0
  27. data/docs/_diagram_types/git-graph.adoc +600 -0
  28. data/docs/_diagram_types/index.adoc +192 -0
  29. data/docs/_diagram_types/info-diagram.adoc +103 -0
  30. data/docs/_diagram_types/kanban-diagram.adoc +262 -0
  31. data/docs/_diagram_types/mindmap.adoc +603 -0
  32. data/docs/_diagram_types/packet-diagram.adoc +378 -0
  33. data/docs/_diagram_types/pie-chart.adoc +335 -0
  34. data/docs/_diagram_types/quadrant-chart.adoc +406 -0
  35. data/docs/_diagram_types/radar-chart.adoc +528 -0
  36. data/docs/_diagram_types/requirement-diagram.adoc +416 -0
  37. data/docs/_diagram_types/sankey-diagram.adoc +357 -0
  38. data/docs/_diagram_types/sequence-diagram.adoc +664 -0
  39. data/docs/_diagram_types/state-diagram.adoc +658 -0
  40. data/docs/_diagram_types/timeline.adoc +352 -0
  41. data/docs/_diagram_types/treemap-diagram.adoc +462 -0
  42. data/docs/_diagram_types/user-journey.adoc +602 -0
  43. data/docs/_features/index.adoc +129 -0
  44. data/docs/_guides/cli-reference.adoc +203 -0
  45. data/docs/_guides/index.adoc +56 -0
  46. data/docs/_guides/installation.adoc +100 -0
  47. data/docs/_guides/quick-start.adoc +132 -0
  48. data/docs/_pages/comparison.adoc +441 -0
  49. data/docs/_pages/compatibility.adoc +300 -0
  50. data/docs/_pages/index.adoc +39 -0
  51. data/docs/_references/index.adoc +103 -0
  52. data/docs/_tutorials/index.adoc +57 -0
  53. data/docs/index.adoc +166 -0
  54. data/docs/lychee.toml +54 -0
  55. data/examples/.gitignore +10 -0
  56. data/examples/README.adoc +196 -0
  57. data/examples/README.md +64 -0
  58. data/examples/architecture/01-basic-services.mmd +9 -0
  59. data/examples/architecture/01-basic-services.svg +37 -0
  60. data/examples/architecture/02-service-groups.mmd +16 -0
  61. data/examples/architecture/02-service-groups.svg +55 -0
  62. data/examples/architecture/README.adoc +79 -0
  63. data/examples/block/01-basic-blocks.mmd +13 -0
  64. data/examples/block/01-basic-blocks.svg +44 -0
  65. data/examples/block/02-block-shapes.mmd +13 -0
  66. data/examples/block/02-block-shapes.svg +47 -0
  67. data/examples/block/README.adoc +85 -0
  68. data/examples/c4/01-context-diagram.mmd +10 -0
  69. data/examples/c4/01-context-diagram.svg +45 -0
  70. data/examples/c4/02-container-diagram.mmd +24 -0
  71. data/examples/c4/02-container-diagram.svg +105 -0
  72. data/examples/c4/README.adoc +92 -0
  73. data/examples/class_diagram/01-basic-classes.mmd +61 -0
  74. data/examples/class_diagram/01-basic-classes.svg +117 -0
  75. data/examples/class_diagram/02-relationships.mmd +61 -0
  76. data/examples/class_diagram/02-relationships.svg +129 -0
  77. data/examples/class_diagram/README.adoc +93 -0
  78. data/examples/er_diagram/01-basic-entities.mmd +64 -0
  79. data/examples/er_diagram/01-basic-entities.svg +5 -0
  80. data/examples/er_diagram/02-cardinality.mmd +57 -0
  81. data/examples/er_diagram/02-cardinality.svg +125 -0
  82. data/examples/er_diagram/README.adoc +88 -0
  83. data/examples/error/01-basic-error.mmd +1 -0
  84. data/examples/error/01-basic-error.svg +13 -0
  85. data/examples/error/02-error-display.mmd +1 -0
  86. data/examples/error/02-error-display.svg +13 -0
  87. data/examples/error/README.adoc +71 -0
  88. data/examples/error_message_example.svg +13 -0
  89. data/examples/flowchart/00-original.mmd +13 -0
  90. data/examples/flowchart/00-original.svg +5 -0
  91. data/examples/flowchart/01-basic-flow.mmd +7 -0
  92. data/examples/flowchart/01-basic-flow.svg +52 -0
  93. data/examples/flowchart/01-basic-flow.yml +13 -0
  94. data/examples/flowchart/02*.svg +87 -0
  95. data/examples/flowchart/02-node-shapes.mmd +9 -0
  96. data/examples/flowchart/02-node-shapes.svg +33 -0
  97. data/examples/flowchart/03-edge-types.mmd +7 -0
  98. data/examples/flowchart/03-edge-types.svg +53 -0
  99. data/examples/flowchart/04-subgraphs.mmd +9 -0
  100. data/examples/flowchart/04-subgraphs.svg +33 -0
  101. data/examples/flowchart/05-styling.mmd +9 -0
  102. data/examples/flowchart/05-styling.svg +33 -0
  103. data/examples/flowchart/06-complex-flow.mmd +8 -0
  104. data/examples/flowchart/06-complex-flow.svg +59 -0
  105. data/examples/flowchart/README.adoc +167 -0
  106. data/examples/gantt/01-simple-timeline.* +14 -0
  107. data/examples/gantt/01-simple-timeline.mmd +6 -0
  108. data/examples/gantt/01-simple-timeline.svg +26 -0
  109. data/examples/gantt/02-task-dependencies.mmd +6 -0
  110. data/examples/gantt/02-task-dependencies.svg +26 -0
  111. data/examples/gantt/README.adoc +86 -0
  112. data/examples/git_graph/01-linear-history.mmd +12 -0
  113. data/examples/git_graph/01-linear-history.svg +26 -0
  114. data/examples/git_graph/02-branching.mmd +12 -0
  115. data/examples/git_graph/02-branching.svg +26 -0
  116. data/examples/git_graph/README.adoc +73 -0
  117. data/examples/info/02-showinfo.mmd +1 -0
  118. data/examples/info/02-showinfo.svg +10 -0
  119. data/examples/info/README.adoc +58 -0
  120. data/examples/info_showinfo_example.svg +10 -0
  121. data/examples/kanban/01-simple-board.mmd +8 -0
  122. data/examples/kanban/01-simple-board.svg +43 -0
  123. data/examples/kanban/02-workflow.mmd +8 -0
  124. data/examples/kanban/02-workflow.svg +43 -0
  125. data/examples/kanban/README.adoc +79 -0
  126. data/examples/mindmap/01-simple-tree.mmd +19 -0
  127. data/examples/mindmap/01-simple-tree.svg +61 -0
  128. data/examples/mindmap/02-knowledge-map.mmd +19 -0
  129. data/examples/mindmap/02-knowledge-map.svg +61 -0
  130. data/examples/mindmap/README.adoc +77 -0
  131. data/examples/packet/01-basic-packet.* +17 -0
  132. data/examples/packet/01-basic-packet.mmd +4 -0
  133. data/examples/packet/01-basic-packet.svg +82 -0
  134. data/examples/packet/README.adoc +58 -0
  135. data/examples/pie/01-simple-chart.mmd +5 -0
  136. data/examples/pie/01-simple-chart.svg +17 -0
  137. data/examples/pie/02-labeled-slices.mmd +6 -0
  138. data/examples/pie/02-labeled-slices.svg +19 -0
  139. data/examples/pie/README.adoc +75 -0
  140. data/examples/quadrant/01-basic-quadrant.mmd +13 -0
  141. data/examples/quadrant/01-basic-quadrant.svg +33 -0
  142. data/examples/quadrant/02-positioned-items.mmd +14 -0
  143. data/examples/quadrant/02-positioned-items.svg +35 -0
  144. data/examples/quadrant/README.adoc +84 -0
  145. data/examples/radar/01-simple-radar.* +5 -0
  146. data/examples/radar/01-simple-radar.mmd +3 -0
  147. data/examples/radar/01-simple-radar.svg +25 -0
  148. data/examples/radar/02-multiple-curves.mmd +4 -0
  149. data/examples/radar/02-multiple-curves.svg +43 -0
  150. data/examples/radar/README.adoc +75 -0
  151. data/examples/requirement/01-basic-requirements.mmd +23 -0
  152. data/examples/requirement/01-basic-requirements.svg +49 -0
  153. data/examples/requirement/02-risk-levels.mmd +23 -0
  154. data/examples/requirement/02-risk-levels.svg +49 -0
  155. data/examples/requirement/README.adoc +85 -0
  156. data/examples/sankey/01-simple-flow.mmd +7 -0
  157. data/examples/sankey/01-simple-flow.svg +34 -0
  158. data/examples/sankey/02-multi-stage.mmd +11 -0
  159. data/examples/sankey/02-multi-stage.svg +44 -0
  160. data/examples/sankey/README.adoc +74 -0
  161. data/examples/sequence/01-basic-sequence.mmd +27 -0
  162. data/examples/sequence/01-basic-sequence.svg +5 -0
  163. data/examples/sequence/02-activations.mmd +17 -0
  164. data/examples/sequence/02-activations.svg +78 -0
  165. data/examples/sequence/README.adoc +86 -0
  166. data/examples/state_diagram/01-simple-states.mmd +29 -0
  167. data/examples/state_diagram/01-simple-states.svg +5 -0
  168. data/examples/state_diagram/02-composite.mmd +19 -0
  169. data/examples/state_diagram/02-composite.svg +81 -0
  170. data/examples/state_diagram/README.adoc +90 -0
  171. data/examples/timeline/01-simple-timeline.mmd +11 -0
  172. data/examples/timeline/01-simple-timeline.svg +36 -0
  173. data/examples/timeline/02-periods.mmd +15 -0
  174. data/examples/timeline/02-periods.svg +47 -0
  175. data/examples/timeline/README.adoc +78 -0
  176. data/examples/treemap/01-basic-treemap.mmd +12 -0
  177. data/examples/treemap/01-basic-treemap.svg +59 -0
  178. data/examples/treemap/README.adoc +59 -0
  179. data/examples/user_journey/01-simple-journey.mmd +23 -0
  180. data/examples/user_journey/01-simple-journey.svg +5 -0
  181. data/examples/user_journey/02-multi-actor.mmd +18 -0
  182. data/examples/user_journey/02-multi-actor.svg +129 -0
  183. data/examples/user_journey/README.adoc +81 -0
  184. data/examples/xychart/01-line-chart.mmd +5 -0
  185. data/examples/xychart/01-line-chart.svg +43 -0
  186. data/examples/xychart/02-bar-chart.mmd +7 -0
  187. data/examples/xychart/02-bar-chart.svg +48 -0
  188. data/examples/xychart/README.adoc +80 -0
  189. data/exe/sirena +7 -0
  190. data/lib/sirena/cli.rb +138 -0
  191. data/lib/sirena/commands/batch.rb +117 -0
  192. data/lib/sirena/commands/render.rb +80 -0
  193. data/lib/sirena/commands/types.rb +29 -0
  194. data/lib/sirena/commands/version.rb +24 -0
  195. data/lib/sirena/diagram/architecture.rb +46 -0
  196. data/lib/sirena/diagram/base.rb +61 -0
  197. data/lib/sirena/diagram/block.rb +81 -0
  198. data/lib/sirena/diagram/c4.rb +328 -0
  199. data/lib/sirena/diagram/class_diagram.rb +385 -0
  200. data/lib/sirena/diagram/er_diagram.rb +238 -0
  201. data/lib/sirena/diagram/error.rb +38 -0
  202. data/lib/sirena/diagram/flowchart.rb +160 -0
  203. data/lib/sirena/diagram/gantt.rb +71 -0
  204. data/lib/sirena/diagram/git_graph.rb +36 -0
  205. data/lib/sirena/diagram/info.rb +38 -0
  206. data/lib/sirena/diagram/kanban.rb +178 -0
  207. data/lib/sirena/diagram/mindmap.rb +54 -0
  208. data/lib/sirena/diagram/packet.rb +79 -0
  209. data/lib/sirena/diagram/pie.rb +115 -0
  210. data/lib/sirena/diagram/quadrant.rb +138 -0
  211. data/lib/sirena/diagram/radar.rb +52 -0
  212. data/lib/sirena/diagram/requirement.rb +133 -0
  213. data/lib/sirena/diagram/sankey.rb +217 -0
  214. data/lib/sirena/diagram/sequence.rb +242 -0
  215. data/lib/sirena/diagram/state_diagram.rb +237 -0
  216. data/lib/sirena/diagram/timeline.rb +171 -0
  217. data/lib/sirena/diagram/treemap.rb +84 -0
  218. data/lib/sirena/diagram/user_journey.rb +149 -0
  219. data/lib/sirena/diagram/xy_chart.rb +76 -0
  220. data/lib/sirena/diagram.rb +8 -0
  221. data/lib/sirena/diagram_registry.rb +101 -0
  222. data/lib/sirena/engine.rb +292 -0
  223. data/lib/sirena/parser/architecture.rb +41 -0
  224. data/lib/sirena/parser/base.rb +41 -0
  225. data/lib/sirena/parser/block.rb +72 -0
  226. data/lib/sirena/parser/c4.rb +53 -0
  227. data/lib/sirena/parser/class_diagram.rb +63 -0
  228. data/lib/sirena/parser/er_diagram.rb +40 -0
  229. data/lib/sirena/parser/error.rb +49 -0
  230. data/lib/sirena/parser/flowchart.rb +71 -0
  231. data/lib/sirena/parser/gantt.rb +60 -0
  232. data/lib/sirena/parser/git_graph.rb +95 -0
  233. data/lib/sirena/parser/grammars/architecture.rb +145 -0
  234. data/lib/sirena/parser/grammars/block.rb +190 -0
  235. data/lib/sirena/parser/grammars/c4.rb +226 -0
  236. data/lib/sirena/parser/grammars/class_diagram.rb +284 -0
  237. data/lib/sirena/parser/grammars/common.rb +84 -0
  238. data/lib/sirena/parser/grammars/er_diagram.rb +114 -0
  239. data/lib/sirena/parser/grammars/error.rb +40 -0
  240. data/lib/sirena/parser/grammars/flowchart.rb +298 -0
  241. data/lib/sirena/parser/grammars/gantt.rb +252 -0
  242. data/lib/sirena/parser/grammars/git_graph.rb +167 -0
  243. data/lib/sirena/parser/grammars/info.rb +58 -0
  244. data/lib/sirena/parser/grammars/kanban.rb +83 -0
  245. data/lib/sirena/parser/grammars/mindmap.rb +115 -0
  246. data/lib/sirena/parser/grammars/packet.rb +73 -0
  247. data/lib/sirena/parser/grammars/pie.rb +128 -0
  248. data/lib/sirena/parser/grammars/quadrant.rb +199 -0
  249. data/lib/sirena/parser/grammars/radar.rb +150 -0
  250. data/lib/sirena/parser/grammars/requirement.rb +188 -0
  251. data/lib/sirena/parser/grammars/sankey.rb +104 -0
  252. data/lib/sirena/parser/grammars/sequence.rb +247 -0
  253. data/lib/sirena/parser/grammars/state_diagram.rb +172 -0
  254. data/lib/sirena/parser/grammars/timeline.rb +142 -0
  255. data/lib/sirena/parser/grammars/treemap.rb +120 -0
  256. data/lib/sirena/parser/grammars/xy_chart.rb +120 -0
  257. data/lib/sirena/parser/info.rb +49 -0
  258. data/lib/sirena/parser/kanban.rb +97 -0
  259. data/lib/sirena/parser/mindmap.rb +106 -0
  260. data/lib/sirena/parser/packet.rb +76 -0
  261. data/lib/sirena/parser/pie.rb +49 -0
  262. data/lib/sirena/parser/quadrant.rb +57 -0
  263. data/lib/sirena/parser/radar.rb +104 -0
  264. data/lib/sirena/parser/requirement.rb +70 -0
  265. data/lib/sirena/parser/sankey.rb +64 -0
  266. data/lib/sirena/parser/sequence.rb +51 -0
  267. data/lib/sirena/parser/state_diagram.rb +69 -0
  268. data/lib/sirena/parser/timeline.rb +57 -0
  269. data/lib/sirena/parser/transforms/architecture.rb +97 -0
  270. data/lib/sirena/parser/transforms/block.rb +254 -0
  271. data/lib/sirena/parser/transforms/c4.rb +347 -0
  272. data/lib/sirena/parser/transforms/class_diagram.rb +352 -0
  273. data/lib/sirena/parser/transforms/er_diagram.rb +169 -0
  274. data/lib/sirena/parser/transforms/error.rb +58 -0
  275. data/lib/sirena/parser/transforms/flowchart.rb +293 -0
  276. data/lib/sirena/parser/transforms/gantt.rb +215 -0
  277. data/lib/sirena/parser/transforms/git_graph.rb +160 -0
  278. data/lib/sirena/parser/transforms/info.rb +58 -0
  279. data/lib/sirena/parser/transforms/kanban.rb +176 -0
  280. data/lib/sirena/parser/transforms/mindmap.rb +227 -0
  281. data/lib/sirena/parser/transforms/packet.rb +63 -0
  282. data/lib/sirena/parser/transforms/pie.rb +143 -0
  283. data/lib/sirena/parser/transforms/quadrant.rb +177 -0
  284. data/lib/sirena/parser/transforms/radar.rb +126 -0
  285. data/lib/sirena/parser/transforms/requirement.rb +272 -0
  286. data/lib/sirena/parser/transforms/sankey.rb +122 -0
  287. data/lib/sirena/parser/transforms/sequence.rb +342 -0
  288. data/lib/sirena/parser/transforms/state_diagram.rb +292 -0
  289. data/lib/sirena/parser/transforms/timeline.rb +177 -0
  290. data/lib/sirena/parser/transforms/treemap.rb +81 -0
  291. data/lib/sirena/parser/transforms/xy_chart.rb +132 -0
  292. data/lib/sirena/parser/treemap.rb +98 -0
  293. data/lib/sirena/parser/user_journey.rb +120 -0
  294. data/lib/sirena/parser/xy_chart.rb +114 -0
  295. data/lib/sirena/parser.rb +8 -0
  296. data/lib/sirena/renderer/architecture.rb +251 -0
  297. data/lib/sirena/renderer/base.rb +251 -0
  298. data/lib/sirena/renderer/block.rb +286 -0
  299. data/lib/sirena/renderer/c4.rb +490 -0
  300. data/lib/sirena/renderer/class_diagram.rb +499 -0
  301. data/lib/sirena/renderer/er_diagram.rb +417 -0
  302. data/lib/sirena/renderer/error.rb +131 -0
  303. data/lib/sirena/renderer/flowchart.rb +301 -0
  304. data/lib/sirena/renderer/gantt.rb +331 -0
  305. data/lib/sirena/renderer/git_graph.rb +368 -0
  306. data/lib/sirena/renderer/info.rb +93 -0
  307. data/lib/sirena/renderer/kanban.rb +295 -0
  308. data/lib/sirena/renderer/mindmap.rb +396 -0
  309. data/lib/sirena/renderer/packet.rb +239 -0
  310. data/lib/sirena/renderer/pie.rb +235 -0
  311. data/lib/sirena/renderer/quadrant.rb +292 -0
  312. data/lib/sirena/renderer/radar.rb +323 -0
  313. data/lib/sirena/renderer/requirement.rb +371 -0
  314. data/lib/sirena/renderer/sankey.rb +255 -0
  315. data/lib/sirena/renderer/sequence.rb +424 -0
  316. data/lib/sirena/renderer/state_diagram.rb +328 -0
  317. data/lib/sirena/renderer/timeline.rb +304 -0
  318. data/lib/sirena/renderer/treemap.rb +152 -0
  319. data/lib/sirena/renderer/user_journey.rb +331 -0
  320. data/lib/sirena/renderer/xy_chart.rb +452 -0
  321. data/lib/sirena/renderer.rb +8 -0
  322. data/lib/sirena/svg/circle.rb +41 -0
  323. data/lib/sirena/svg/document.rb +103 -0
  324. data/lib/sirena/svg/element.rb +65 -0
  325. data/lib/sirena/svg/ellipse.rb +33 -0
  326. data/lib/sirena/svg/group.rb +71 -0
  327. data/lib/sirena/svg/line.rb +49 -0
  328. data/lib/sirena/svg/path.rb +76 -0
  329. data/lib/sirena/svg/polygon.rb +43 -0
  330. data/lib/sirena/svg/polyline.rb +35 -0
  331. data/lib/sirena/svg/rect.rb +57 -0
  332. data/lib/sirena/svg/style.rb +44 -0
  333. data/lib/sirena/svg/text.rb +72 -0
  334. data/lib/sirena/svg.rb +19 -0
  335. data/lib/sirena/text_measurement.rb +71 -0
  336. data/lib/sirena/theme/builtin/dark.yml +70 -0
  337. data/lib/sirena/theme/builtin/default.yml +80 -0
  338. data/lib/sirena/theme/builtin/high_contrast.yml +70 -0
  339. data/lib/sirena/theme/builtin/light.yml +70 -0
  340. data/lib/sirena/theme/color_palette.rb +48 -0
  341. data/lib/sirena/theme/effect_styles.rb +28 -0
  342. data/lib/sirena/theme/registry.rb +41 -0
  343. data/lib/sirena/theme/shape_styles.rb +28 -0
  344. data/lib/sirena/theme/spacing_config.rb +24 -0
  345. data/lib/sirena/theme/typography.rb +30 -0
  346. data/lib/sirena/theme.rb +69 -0
  347. data/lib/sirena/transform/architecture.rb +273 -0
  348. data/lib/sirena/transform/base.rb +199 -0
  349. data/lib/sirena/transform/block.rb +215 -0
  350. data/lib/sirena/transform/c4.rb +288 -0
  351. data/lib/sirena/transform/class_diagram.rb +296 -0
  352. data/lib/sirena/transform/er_diagram.rb +204 -0
  353. data/lib/sirena/transform/error.rb +39 -0
  354. data/lib/sirena/transform/flowchart.rb +161 -0
  355. data/lib/sirena/transform/gantt.rb +253 -0
  356. data/lib/sirena/transform/git_graph.rb +283 -0
  357. data/lib/sirena/transform/info.rb +39 -0
  358. data/lib/sirena/transform/kanban.rb +180 -0
  359. data/lib/sirena/transform/mindmap.rb +251 -0
  360. data/lib/sirena/transform/packet.rb +185 -0
  361. data/lib/sirena/transform/pie.rb +62 -0
  362. data/lib/sirena/transform/quadrant.rb +167 -0
  363. data/lib/sirena/transform/radar.rb +227 -0
  364. data/lib/sirena/transform/requirement.rb +233 -0
  365. data/lib/sirena/transform/sankey.rb +212 -0
  366. data/lib/sirena/transform/sequence.rb +143 -0
  367. data/lib/sirena/transform/state_diagram.rb +228 -0
  368. data/lib/sirena/transform/timeline.rb +139 -0
  369. data/lib/sirena/transform/treemap.rb +120 -0
  370. data/lib/sirena/transform/user_journey.rb +207 -0
  371. data/lib/sirena/transform/xy_chart.rb +273 -0
  372. data/lib/sirena/transform.rb +8 -0
  373. data/lib/sirena/version.rb +5 -0
  374. data/lib/sirena.rb +328 -0
  375. data/lib/tasks/benchmark.rake +532 -0
  376. data/lib/tasks/examples.rake +468 -0
  377. data/lib/tasks/generate_mermaid_fixtures.rake +363 -0
  378. data/lib/tasks/mermaid_fixtures.rake +46 -0
  379. data/scripts/extract_mermaid_tests.rb +493 -0
  380. data/scripts/rename_to_sirena.rb +73 -0
  381. data/sirena.gemspec +47 -0
  382. metadata +529 -0
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Architecture diagram model representing system architecture visualization
8
+ class ArchitectureDiagram < Lutaml::Model::Serializable
9
+ # Group (boundary) in architecture diagram
10
+ class Group < Lutaml::Model::Serializable
11
+ attribute :id, :string
12
+ attribute :label, :string
13
+ attribute :icon, :string
14
+ attribute :parent_id, :string
15
+ end
16
+
17
+ # Service/component in architecture diagram
18
+ class Service < Lutaml::Model::Serializable
19
+ attribute :id, :string
20
+ attribute :label, :string
21
+ attribute :icon, :string
22
+ attribute :group_id, :string
23
+ end
24
+
25
+ # Edge (relationship) between services
26
+ class Edge < Lutaml::Model::Serializable
27
+ attribute :from_id, :string
28
+ attribute :to_id, :string
29
+ attribute :from_position, :string
30
+ attribute :to_position, :string
31
+ attribute :label, :string
32
+ end
33
+
34
+ attribute :title, :string
35
+ attribute :acc_title, :string
36
+ attribute :acc_descr, :string
37
+ attribute :groups, Group, collection: true, default: -> { [] }
38
+ attribute :services, Service, collection: true, default: -> { [] }
39
+ attribute :edges, Edge, collection: true, default: -> { [] }
40
+
41
+ def type
42
+ "architecture"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/model'
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Abstract base class for all diagram models.
8
+ #
9
+ # This class provides common attributes and functionality shared across
10
+ # all diagram types. Specific diagram types (Flowchart, Sequence, etc.)
11
+ # inherit from this base and add their type-specific attributes.
12
+ #
13
+ # All diagram models use Lutaml::Model for serialization support.
14
+ #
15
+ # @example Define a custom diagram type
16
+ # class Flowchart < Diagram::Base
17
+ # attribute :nodes, :array
18
+ # attribute :edges, :array
19
+ # end
20
+ #
21
+ # @abstract Subclass and add diagram-specific attributes
22
+ class Base < Lutaml::Model::Serializable
23
+ # Unique identifier for the diagram
24
+ attribute :id, :string
25
+
26
+ # Optional title for the diagram
27
+ attribute :title, :string
28
+
29
+ # Direction or orientation of the diagram
30
+ # (e.g., 'TB' for top-to-bottom, 'LR' for left-to-right)
31
+ attribute :direction, :string
32
+
33
+ # Optional theme or style configuration
34
+ attribute :theme, :string
35
+
36
+ # Validates that required diagram structure is present.
37
+ #
38
+ # This method should be overridden by subclasses to implement
39
+ # diagram-specific validation logic.
40
+ #
41
+ # @return [Boolean] true if diagram is valid
42
+ # @raise [NotImplementedError] if not implemented by subclass
43
+ def valid?
44
+ raise NotImplementedError,
45
+ "#{self.class} must implement #valid?"
46
+ end
47
+
48
+ # Returns the diagram type identifier.
49
+ #
50
+ # This method should be overridden by subclasses to return their
51
+ # specific diagram type.
52
+ #
53
+ # @return [Symbol] the diagram type identifier
54
+ # @raise [NotImplementedError] if not implemented by subclass
55
+ def diagram_type
56
+ raise NotImplementedError,
57
+ "#{self.class} must implement #diagram_type"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Represents a block in the diagram
8
+ class Block < Lutaml::Model::Serializable
9
+ attribute :id, :string
10
+ attribute :label, :string
11
+ attribute :width, :integer, default: -> { 1 }
12
+ attribute :shape, :string, default: -> { "rect" }
13
+ attribute :children, Block, collection: true, default: -> { [] }
14
+ attribute :block_type, :string # "block", "space", "arrow"
15
+ attribute :direction, :string # for arrow blocks: "up", "down", "left", "right"
16
+ attribute :is_compound, :boolean, default: -> { false }
17
+
18
+ def compound?
19
+ is_compound
20
+ end
21
+
22
+ def space?
23
+ block_type == "space"
24
+ end
25
+
26
+ def arrow?
27
+ block_type == "arrow"
28
+ end
29
+
30
+ def add_child(child)
31
+ children << child
32
+ self.is_compound = true
33
+ end
34
+ end
35
+
36
+ # Represents a connection between blocks
37
+ class BlockConnection < Lutaml::Model::Serializable
38
+ attribute :from, :string
39
+ attribute :to, :string
40
+ attribute :connection_type, :string # "arrow" or "line"
41
+ attribute :label, :string
42
+
43
+ def arrow?
44
+ connection_type == "arrow"
45
+ end
46
+
47
+ def line?
48
+ connection_type == "line"
49
+ end
50
+ end
51
+
52
+ # Represents styling for a block
53
+ class BlockStyle < Lutaml::Model::Serializable
54
+ attribute :block_id, :string
55
+ attribute :fill, :string
56
+ attribute :stroke, :string
57
+ attribute :stroke_width, :string
58
+ attribute :properties, :string, collection: true, default: -> { [] }
59
+ end
60
+
61
+ # Represents a Mermaid block diagram
62
+ class BlockDiagram < Lutaml::Model::Serializable
63
+ attribute :columns, :integer, default: -> { 1 }
64
+ attribute :blocks, Block, collection: true, default: -> { [] }
65
+ attribute :connections, BlockConnection, collection: true, default: -> { [] }
66
+ attribute :styles, BlockStyle, collection: true, default: -> { [] }
67
+
68
+ def add_block(block)
69
+ blocks << block
70
+ end
71
+
72
+ def add_connection(connection)
73
+ connections << connection
74
+ end
75
+
76
+ def add_style(style)
77
+ styles << style
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/model'
4
+ require_relative 'base'
5
+
6
+ module Sirena
7
+ module Diagram
8
+ # Represents a C4 element (Person, System, Container, Component).
9
+ #
10
+ # Elements are the nodes in C4 diagrams representing various architectural
11
+ # entities like people, systems, containers, and components.
12
+ class C4Element < Lutaml::Model::Serializable
13
+ # Unique identifier for the element
14
+ attribute :id, :string
15
+
16
+ # Display label
17
+ attribute :label, :string
18
+
19
+ # Element type: Person, Person_Ext, System, System_Ext, SystemDb,
20
+ # SystemDb_Ext, SystemQueue, SystemQueue_Ext, Container, ContainerDb,
21
+ # ContainerQueue, Component
22
+ attribute :element_type, :string
23
+
24
+ # Description text
25
+ attribute :description, :string
26
+
27
+ # Technology stack (for Containers and Components)
28
+ attribute :technology, :string
29
+
30
+ # Sprite icon name
31
+ attribute :sprite, :string
32
+
33
+ # Link URL
34
+ attribute :link, :string
35
+
36
+ # Tags (comma-separated)
37
+ attribute :tags, :string
38
+
39
+ # Whether element is external (_Ext suffix)
40
+ attribute :external, :boolean, default: -> { false }
41
+
42
+ # Parent boundary ID (if nested)
43
+ attribute :boundary_id, :string
44
+
45
+ # Validates the element has required attributes.
46
+ #
47
+ # @return [Boolean] true if element is valid
48
+ def valid?
49
+ !id.nil? && !id.empty? &&
50
+ !label.nil? && !label.empty? &&
51
+ !element_type.nil?
52
+ end
53
+
54
+ # Returns base type without _Ext suffix
55
+ #
56
+ # @return [String] base element type
57
+ def base_type
58
+ element_type&.gsub(/_Ext$/, '') || element_type
59
+ end
60
+
61
+ # Check if element is a person
62
+ #
63
+ # @return [Boolean] true if person
64
+ def person?
65
+ base_type == 'Person'
66
+ end
67
+
68
+ # Check if element is a system
69
+ #
70
+ # @return [Boolean] true if system
71
+ def system?
72
+ %w[System SystemDb SystemQueue].include?(base_type)
73
+ end
74
+
75
+ # Check if element is a container
76
+ #
77
+ # @return [Boolean] true if container
78
+ def container?
79
+ %w[Container ContainerDb ContainerQueue].include?(base_type)
80
+ end
81
+
82
+ # Check if element is a component
83
+ #
84
+ # @return [Boolean] true if component
85
+ def component?
86
+ base_type == 'Component'
87
+ end
88
+ end
89
+
90
+ # Represents a C4 relationship between elements.
91
+ #
92
+ # Relationships show interactions or dependencies between architectural
93
+ # elements.
94
+ class C4Relationship < Lutaml::Model::Serializable
95
+ # Source element identifier
96
+ attribute :from_id, :string
97
+
98
+ # Target element identifier
99
+ attribute :to_id, :string
100
+
101
+ # Relationship label
102
+ attribute :label, :string
103
+
104
+ # Technology used in relationship
105
+ attribute :technology, :string
106
+
107
+ # Relationship type: Rel, BiRel
108
+ attribute :rel_type, :string
109
+
110
+ # Initialize with default type
111
+ def initialize(*args)
112
+ super
113
+ self.rel_type ||= 'Rel'
114
+ end
115
+
116
+ # Validates the relationship has required attributes.
117
+ #
118
+ # @return [Boolean] true if relationship is valid
119
+ def valid?
120
+ !from_id.nil? && !from_id.empty? &&
121
+ !to_id.nil? && !to_id.empty?
122
+ end
123
+
124
+ # Check if bidirectional relationship
125
+ #
126
+ # @return [Boolean] true if bidirectional
127
+ def bidirectional?
128
+ rel_type == 'BiRel'
129
+ end
130
+ end
131
+
132
+ # Represents a C4 boundary grouping.
133
+ #
134
+ # Boundaries group related elements together, representing enterprise
135
+ # boundaries, system boundaries, or custom boundaries.
136
+ class C4Boundary < Lutaml::Model::Serializable
137
+ # Unique identifier for the boundary
138
+ attribute :id, :string
139
+
140
+ # Display label
141
+ attribute :label, :string
142
+
143
+ # Boundary type: Enterprise_Boundary, System_Boundary, Boundary
144
+ attribute :boundary_type, :string
145
+
146
+ # Additional type parameter (for generic Boundary)
147
+ attribute :type_param, :string
148
+
149
+ # Link URL
150
+ attribute :link, :string
151
+
152
+ # Tags (comma-separated)
153
+ attribute :tags, :string
154
+
155
+ # Nested elements (element IDs)
156
+ attribute :element_ids, :string, collection: true, default: -> { [] }
157
+
158
+ # Nested boundaries (boundary IDs)
159
+ attribute :boundary_ids, :string, collection: true, default: -> { [] }
160
+
161
+ # Parent boundary ID (if nested)
162
+ attribute :parent_id, :string
163
+
164
+ # Initialize with default type
165
+ def initialize(*args)
166
+ super
167
+ self.boundary_type ||= 'Boundary'
168
+ end
169
+
170
+ # Validates the boundary has required attributes.
171
+ #
172
+ # @return [Boolean] true if boundary is valid
173
+ def valid?
174
+ !id.nil? && !id.empty? &&
175
+ !label.nil? && !label.empty?
176
+ end
177
+
178
+ # Check if enterprise boundary
179
+ #
180
+ # @return [Boolean] true if enterprise boundary
181
+ def enterprise?
182
+ boundary_type == 'Enterprise_Boundary'
183
+ end
184
+
185
+ # Check if system boundary
186
+ #
187
+ # @return [Boolean] true if system boundary
188
+ def system?
189
+ boundary_type == 'System_Boundary'
190
+ end
191
+ end
192
+
193
+ # C4 diagram model.
194
+ #
195
+ # Represents a complete C4 diagram showing software architecture at
196
+ # different levels of abstraction: Context, Container, Component, or Code.
197
+ #
198
+ # @example Creating a C4 Context diagram
199
+ # c4 = C4.new(level: 'Context')
200
+ # c4.title = 'System Context diagram'
201
+ # c4.elements << C4Element.new(
202
+ # id: 'customer',
203
+ # label: 'Customer',
204
+ # element_type: 'Person',
205
+ # description: 'A user of the system'
206
+ # )
207
+ # c4.elements << C4Element.new(
208
+ # id: 'system',
209
+ # label: 'Banking System',
210
+ # element_type: 'System',
211
+ # description: 'Main banking application'
212
+ # )
213
+ # c4.relationships << C4Relationship.new(
214
+ # from_id: 'customer',
215
+ # to_id: 'system',
216
+ # label: 'Uses'
217
+ # )
218
+ class C4 < Base
219
+ # C4 level: Context, Container, Component, Dynamic, Deployment
220
+ attribute :level, :string
221
+
222
+ # Diagram title
223
+ attribute :title, :string
224
+
225
+ # Collection of elements
226
+ attribute :elements, C4Element, collection: true, default: -> { [] }
227
+
228
+ # Collection of relationships
229
+ attribute :relationships, C4Relationship, collection: true,
230
+ default: -> { [] }
231
+
232
+ # Collection of boundaries
233
+ attribute :boundaries, C4Boundary, collection: true, default: -> { [] }
234
+
235
+ # Layout configuration
236
+ attribute :layout_config, :string
237
+
238
+ # Initialize with default level
239
+ def initialize(*args)
240
+ super
241
+ self.level ||= 'Context'
242
+ end
243
+
244
+ # Returns the diagram type identifier.
245
+ #
246
+ # @return [Symbol] :c4
247
+ def diagram_type
248
+ :c4
249
+ end
250
+
251
+ # Validates the C4 diagram structure.
252
+ #
253
+ # A C4 diagram is valid if:
254
+ # - It has a valid level
255
+ # - All elements are valid
256
+ # - All relationships are valid
257
+ # - All boundaries are valid
258
+ # - All relationship references point to existing elements
259
+ #
260
+ # @return [Boolean] true if C4 diagram is valid
261
+ def valid?
262
+ return false unless %w[Context Container Component Dynamic
263
+ Deployment].include?(level)
264
+ return false unless elements.nil? || elements.all?(&:valid?)
265
+ return false unless relationships.nil? ||
266
+ relationships.all?(&:valid?)
267
+ return false unless boundaries.nil? || boundaries.all?(&:valid?)
268
+
269
+ # Validate relationship references
270
+ element_ids = elements.map(&:id)
271
+ relationships&.each do |rel|
272
+ return false unless element_ids.include?(rel.from_id)
273
+ return false unless element_ids.include?(rel.to_id)
274
+ end
275
+
276
+ true
277
+ end
278
+
279
+ # Finds an element by its identifier.
280
+ #
281
+ # @param id [String] the element identifier to find
282
+ # @return [C4Element, nil] the element or nil if not found
283
+ def find_element(id)
284
+ elements.find { |e| e.id == id }
285
+ end
286
+
287
+ # Finds a boundary by its identifier.
288
+ #
289
+ # @param id [String] the boundary identifier to find
290
+ # @return [C4Boundary, nil] the boundary or nil if not found
291
+ def find_boundary(id)
292
+ boundaries.find { |b| b.id == id }
293
+ end
294
+
295
+ # Finds relationships from a specific element.
296
+ #
297
+ # @param element_id [String] the source element identifier
298
+ # @return [Array<C4Relationship>] relationships from the element
299
+ def relationships_from(element_id)
300
+ relationships.select { |r| r.from_id == element_id }
301
+ end
302
+
303
+ # Finds relationships to a specific element.
304
+ #
305
+ # @param element_id [String] the target element identifier
306
+ # @return [Array<C4Relationship>] relationships to the element
307
+ def relationships_to(element_id)
308
+ relationships.select { |r| r.to_id == element_id }
309
+ end
310
+
311
+ # Finds elements within a boundary.
312
+ #
313
+ # @param boundary_id [String] the boundary identifier
314
+ # @return [Array<C4Element>] elements in the boundary
315
+ def elements_in_boundary(boundary_id)
316
+ elements.select { |e| e.boundary_id == boundary_id }
317
+ end
318
+
319
+ # Finds child boundaries within a parent boundary.
320
+ #
321
+ # @param boundary_id [String] the parent boundary identifier
322
+ # @return [Array<C4Boundary>] child boundaries
323
+ def boundaries_in_boundary(boundary_id)
324
+ boundaries.select { |b| b.parent_id == boundary_id }
325
+ end
326
+ end
327
+ end
328
+ end