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,368 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../svg/document"
4
+ require_relative "../svg/circle"
5
+ require_relative "../svg/line"
6
+ require_relative "../svg/path"
7
+ require_relative "../svg/text"
8
+ require_relative "../svg/group"
9
+
10
+ module Sirena
11
+ module Renderer
12
+ # Renders a Git Graph layout to SVG.
13
+ #
14
+ # The renderer converts the positioned layout structure from
15
+ # Transform::GitGraph into an SVG visualization showing:
16
+ # - Commit circles at calculated positions
17
+ # - Branch lines connecting parent-child commits
18
+ # - Merge arrows for merge commits
19
+ # - Cherry-pick indicators
20
+ # - Labels for commit IDs, tags, and branches
21
+ #
22
+ # @example Render a git graph
23
+ # renderer = Renderer::GitGraph.new(theme: my_theme)
24
+ # svg = renderer.render(layout)
25
+ class GitGraph < Base
26
+ # Renders the layout structure to SVG.
27
+ #
28
+ # @param layout [Hash] layout data from Transform::GitGraph
29
+ # @return [Svg::Document] rendered SVG document
30
+ def render(layout)
31
+ svg = create_document_from_layout(layout)
32
+
33
+ # Render in order: connections, then commits, then labels
34
+ render_connections(layout, svg)
35
+ render_commits(layout, svg)
36
+ render_labels(layout, svg)
37
+
38
+ svg
39
+ end
40
+
41
+ protected
42
+
43
+ # Creates an SVG document with dimensions from layout.
44
+ #
45
+ # @param layout [Hash] layout data
46
+ # @return [Svg::Document] new SVG document
47
+ def create_document_from_layout(layout)
48
+ padding = 40
49
+
50
+ Svg::Document.new.tap do |doc|
51
+ doc.width = layout[:width] + (padding * 2)
52
+ doc.height = layout[:height] + (padding * 2)
53
+ doc.view_box = "0 0 #{doc.width} #{doc.height}"
54
+
55
+ # Add a group with padding offset
56
+ @offset_x = padding
57
+ @offset_y = padding
58
+ end
59
+ end
60
+
61
+ # Renders all connections between commits.
62
+ #
63
+ # @param layout [Hash] layout data
64
+ # @param svg [Svg::Document] SVG document
65
+ # @return [void]
66
+ def render_connections(layout, svg)
67
+ # Get branch colors for connections
68
+ branch_colors = layout[:branches].each_with_object({}) do |b, h|
69
+ h[b[:name]] = b[:color]
70
+ end
71
+
72
+ layout[:connections].each do |connection|
73
+ case connection[:type]
74
+ when :merge
75
+ render_merge_connection(connection, branch_colors, svg)
76
+ when :cherry_pick
77
+ render_cherry_pick_connection(connection, branch_colors, svg)
78
+ else
79
+ render_normal_connection(connection, branch_colors, svg)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Renders a normal parent-child connection.
85
+ #
86
+ # @param connection [Hash] connection data
87
+ # @param branch_colors [Hash] branch name to color mapping
88
+ # @param svg [Svg::Document] SVG document
89
+ # @return [void]
90
+ def render_normal_connection(connection, branch_colors, svg)
91
+ color = branch_colors[connection[:from_branch]] ||
92
+ branch_colors[connection[:to_branch]] ||
93
+ theme_color(:edge_stroke) || "#666666"
94
+
95
+ from_x = connection[:from_x] + @offset_x
96
+ from_y = connection[:from_y] + @offset_y
97
+ to_x = connection[:to_x] + @offset_x
98
+ to_y = connection[:to_y] + @offset_y
99
+
100
+ # Draw line from parent to child
101
+ line = Svg::Line.new.tap do |l|
102
+ l.x1 = from_x
103
+ l.y1 = from_y
104
+ l.x2 = to_x
105
+ l.y2 = to_y
106
+ l.stroke = color
107
+ l.stroke_width = "2"
108
+ l.fill = "none"
109
+ end
110
+
111
+ svg.add_element(line)
112
+ end
113
+
114
+ # Renders a merge connection with curved path.
115
+ #
116
+ # @param connection [Hash] connection data
117
+ # @param branch_colors [Hash] branch name to color mapping
118
+ # @param svg [Svg::Document] SVG document
119
+ # @return [void]
120
+ def render_merge_connection(connection, branch_colors, svg)
121
+ color = branch_colors[connection[:from_branch]] ||
122
+ theme_color(:edge_stroke) || "#666666"
123
+
124
+ from_x = connection[:from_x] + @offset_x
125
+ from_y = connection[:from_y] + @offset_y
126
+ to_x = connection[:to_x] + @offset_x
127
+ to_y = connection[:to_y] + @offset_y
128
+
129
+ # Create curved path for merge
130
+ if from_y != to_y
131
+ # Different lanes - use bezier curve
132
+ control_x1 = from_x + (to_x - from_x) * 0.5
133
+ control_y1 = from_y
134
+ control_x2 = from_x + (to_x - from_x) * 0.5
135
+ control_y2 = to_y
136
+
137
+ path_data = "M #{from_x} #{from_y} " \
138
+ "C #{control_x1} #{control_y1}, " \
139
+ "#{control_x2} #{control_y2}, " \
140
+ "#{to_x} #{to_y}"
141
+ else
142
+ # Same lane - straight line
143
+ path_data = "M #{from_x} #{from_y} L #{to_x} #{to_y}"
144
+ end
145
+
146
+ path = Svg::Path.new.tap do |p|
147
+ p.d = path_data
148
+ p.stroke = color
149
+ p.stroke_width = "2"
150
+ p.fill = "none"
151
+ p.stroke_dasharray = "5,3" # Dashed for merge
152
+ end
153
+
154
+ svg.add_element(path)
155
+ end
156
+
157
+ # Renders a cherry-pick connection with dotted line.
158
+ #
159
+ # @param connection [Hash] connection data
160
+ # @param branch_colors [Hash] branch name to color mapping
161
+ # @param svg [Svg::Document] SVG document
162
+ # @return [void]
163
+ def render_cherry_pick_connection(connection, branch_colors, svg)
164
+ color = theme_color(:edge_stroke) || "#999999"
165
+
166
+ from_x = connection[:from_x] + @offset_x
167
+ from_y = connection[:from_y] + @offset_y
168
+ to_x = connection[:to_x] + @offset_x
169
+ to_y = connection[:to_y] + @offset_y
170
+
171
+ path = Svg::Path.new.tap do |p|
172
+ p.d = "M #{from_x} #{from_y} L #{to_x} #{to_y}"
173
+ p.stroke = color
174
+ p.stroke_width = "2"
175
+ p.fill = "none"
176
+ p.stroke_dasharray = "2,4" # Dotted for cherry-pick
177
+ end
178
+
179
+ svg.add_element(path)
180
+ end
181
+
182
+ # Renders all commits as circles.
183
+ #
184
+ # @param layout [Hash] layout data
185
+ # @param svg [Svg::Document] SVG document
186
+ # @return [void]
187
+ def render_commits(layout, svg)
188
+ # Get branch colors
189
+ branch_colors = layout[:branches].each_with_object({}) do |b, h|
190
+ h[b[:name]] = b[:color]
191
+ end
192
+
193
+ layout[:commits].each do |commit|
194
+ render_commit_circle(commit, branch_colors, svg)
195
+ end
196
+ end
197
+
198
+ # Renders a single commit as a circle.
199
+ #
200
+ # @param commit [Hash] commit data
201
+ # @param branch_colors [Hash] branch name to color mapping
202
+ # @param svg [Svg::Document] SVG document
203
+ # @return [void]
204
+ def render_commit_circle(commit, branch_colors, svg)
205
+ x = commit[:x] + @offset_x
206
+ y = commit[:y] + @offset_y
207
+ radius = 8
208
+
209
+ # Get color based on branch and commit type
210
+ fill_color = get_commit_fill_color(commit, branch_colors)
211
+ stroke_color = get_commit_stroke_color(commit, branch_colors)
212
+
213
+ circle = Svg::Circle.new.tap do |c|
214
+ c.cx = x
215
+ c.cy = y
216
+ c.r = radius
217
+ c.fill = fill_color
218
+ c.stroke = stroke_color
219
+ c.stroke_width = "2"
220
+ end
221
+
222
+ svg.add_element(circle)
223
+ end
224
+
225
+ # Gets the fill color for a commit based on type and branch.
226
+ #
227
+ # @param commit [Hash] commit data
228
+ # @param branch_colors [Hash] branch colors
229
+ # @return [String] color value
230
+ def get_commit_fill_color(commit, branch_colors)
231
+ case commit[:type]
232
+ when "HIGHLIGHT"
233
+ theme_color(:highlight) || "#fbbf24"
234
+ when "REVERSE"
235
+ theme_color(:background) || "#ffffff"
236
+ else # NORMAL
237
+ branch_colors[commit[:branch]] || theme_color(:primary) || "#2563eb"
238
+ end
239
+ end
240
+
241
+ # Gets the stroke color for a commit.
242
+ #
243
+ # @param commit [Hash] commit data
244
+ # @param branch_colors [Hash] branch colors
245
+ # @return [String] color value
246
+ def get_commit_stroke_color(commit, branch_colors)
247
+ case commit[:type]
248
+ when "REVERSE"
249
+ branch_colors[commit[:branch]] || theme_color(:primary) || "#2563eb"
250
+ else
251
+ branch_colors[commit[:branch]] || theme_color(:primary) || "#2563eb"
252
+ end
253
+ end
254
+
255
+ # Renders all labels (commit IDs, tags, branches).
256
+ #
257
+ # @param layout [Hash] layout data
258
+ # @param svg [Svg::Document] SVG document
259
+ # @return [void]
260
+ def render_labels(layout, svg)
261
+ layout[:commits].each do |commit|
262
+ render_commit_labels(commit, svg)
263
+ end
264
+
265
+ # Render branch labels at the end of each branch
266
+ render_branch_labels(layout, svg)
267
+ end
268
+
269
+ # Renders labels for a single commit.
270
+ #
271
+ # @param commit [Hash] commit data
272
+ # @param svg [Svg::Document] SVG document
273
+ # @return [void]
274
+ def render_commit_labels(commit, svg)
275
+ x = commit[:x] + @offset_x
276
+ y = commit[:y] + @offset_y
277
+
278
+ # Render commit ID below the circle if present
279
+ if commit[:id] && !commit[:id].start_with?("commit_")
280
+ render_commit_id_label(commit[:id], x, y, svg)
281
+ end
282
+
283
+ # Render tag above the circle if present
284
+ render_tag_label(commit[:tag], x, y, svg) if commit[:tag]
285
+ end
286
+
287
+ # Renders a commit ID label.
288
+ #
289
+ # @param id [String] commit ID
290
+ # @param x [Numeric] X position
291
+ # @param y [Numeric] Y position
292
+ # @param svg [Svg::Document] SVG document
293
+ # @return [void]
294
+ def render_commit_id_label(id, x, y, svg)
295
+ text = Svg::Text.new.tap do |t|
296
+ t.x = x
297
+ t.y = y + 20
298
+ t.text_anchor = "middle"
299
+ t.fill = theme_color(:label_text) || "#000000"
300
+ t.font_size = (theme_typography(:font_size_small) || 10).to_s
301
+ t.font_family = theme_typography(:font_family) || "Arial, sans-serif"
302
+ t.content = id
303
+ end
304
+
305
+ svg.add_element(text)
306
+ end
307
+
308
+ # Renders a tag label.
309
+ #
310
+ # @param tag [String] tag name
311
+ # @param x [Numeric] X position
312
+ # @param y [Numeric] Y position
313
+ # @param svg [Svg::Document] SVG document
314
+ # @return [void]
315
+ def render_tag_label(tag, x, y, svg)
316
+ text = Svg::Text.new.tap do |t|
317
+ t.x = x
318
+ t.y = y - 15
319
+ t.text_anchor = "middle"
320
+ t.fill = theme_color(:accent) || "#7c3aed"
321
+ t.font_size = (theme_typography(:font_size_small) || 10).to_s
322
+ t.font_family = theme_typography(:font_family) || "Arial, sans-serif"
323
+ t.font_weight = "bold"
324
+ t.content = tag
325
+ end
326
+
327
+ svg.add_element(text)
328
+ end
329
+
330
+ # Renders branch name labels.
331
+ #
332
+ # @param layout [Hash] layout data
333
+ # @param svg [Svg::Document] SVG document
334
+ # @return [void]
335
+ def render_branch_labels(layout, svg)
336
+ # Find the last commit for each branch
337
+ branch_last_commits = {}
338
+
339
+ layout[:commits].each do |commit|
340
+ branch = commit[:branch]
341
+ branch_last_commits[branch] = commit
342
+ end
343
+
344
+ # Render label for each branch at its last commit
345
+ branch_last_commits.each do |branch_name, commit|
346
+ x = commit[:x] + @offset_x + 15
347
+ y = commit[:y] + @offset_y
348
+
349
+ branch_meta = layout[:branches].find { |b| b[:name] == branch_name }
350
+ color = branch_meta&.dig(:color) || theme_color(:primary) || "#2563eb"
351
+
352
+ text = Svg::Text.new.tap do |t|
353
+ t.x = x
354
+ t.y = y + 4
355
+ t.text_anchor = "start"
356
+ t.fill = color
357
+ t.font_size = (theme_typography(:font_size_small) || 10).to_s
358
+ t.font_family = theme_typography(:font_family) || "Arial, sans-serif"
359
+ t.font_weight = "bold"
360
+ t.content = branch_name
361
+ end
362
+
363
+ svg.add_element(text)
364
+ end
365
+ end
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative '../svg/document'
5
+ require_relative '../svg/rect'
6
+ require_relative '../svg/text'
7
+
8
+ module Sirena
9
+ module Renderer
10
+ # Info diagram renderer for converting info diagrams to SVG.
11
+ #
12
+ # Renders a simple informational message box with centered text.
13
+ #
14
+ # @example Render an info diagram
15
+ # renderer = InfoRenderer.new
16
+ # svg = renderer.render(info_diagram)
17
+ class InfoRenderer < Base
18
+ # Info box dimensions
19
+ BOX_WIDTH = 400
20
+ BOX_HEIGHT = 100
21
+ BOX_X = 50
22
+ BOX_Y = 50
23
+ TEXT_Y = 105
24
+
25
+ # Renders an info diagram to SVG.
26
+ #
27
+ # @param graph [Hash] the info diagram graph structure from transform
28
+ # @return [Svg::Document] the rendered SVG document
29
+ def render(graph)
30
+ svg = create_document_for_info(graph)
31
+
32
+ # Render info box
33
+ render_info_box(graph, svg)
34
+
35
+ # Render info text
36
+ render_info_text(graph, svg)
37
+
38
+ svg
39
+ end
40
+
41
+ protected
42
+
43
+ def create_document_for_info(_graph)
44
+ width = 500
45
+ height = 200
46
+
47
+ Svg::Document.new.tap do |doc|
48
+ doc.width = width
49
+ doc.height = height
50
+ doc.view_box = "0 0 #{width} #{height}"
51
+ end
52
+ end
53
+
54
+ def render_info_box(_graph, svg)
55
+ box = Svg::Rect.new.tap do |r|
56
+ r.x = BOX_X
57
+ r.y = BOX_Y
58
+ r.width = BOX_WIDTH
59
+ r.height = BOX_HEIGHT
60
+ r.fill = theme_color(:node_bg) || '#E3F2FD'
61
+ r.stroke = theme_color(:node_stroke) || '#2196F3'
62
+ r.stroke_width = '2'
63
+ r.rx = '8'
64
+ r.ry = '8'
65
+ end
66
+
67
+ svg << box
68
+ end
69
+
70
+ def render_info_text(graph, svg)
71
+ message = if graph[:show_info]
72
+ 'Info: showInfo enabled'
73
+ else
74
+ 'Info'
75
+ end
76
+
77
+ text = Svg::Text.new.tap do |t|
78
+ t.x = BOX_X + (BOX_WIDTH / 2)
79
+ t.y = TEXT_Y
80
+ t.content = message
81
+ t.fill = theme_color(:label_text) || '#1976D2'
82
+ t.font_family = theme_typography(:font_family) ||
83
+ 'Arial, sans-serif'
84
+ t.font_size = (theme_typography(:font_size_base) || 16).to_s
85
+ t.text_anchor = 'middle'
86
+ t.font_weight = 'bold'
87
+ end
88
+
89
+ svg << text
90
+ end
91
+ end
92
+ end
93
+ end