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,273 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sirena
4
+ module Transform
5
+ # Transforms an XYChart diagram into a positioned layout structure.
6
+ #
7
+ # The layout algorithm handles:
8
+ # - Chart area calculation and margins
9
+ # - Axis positioning and scaling
10
+ # - Data point coordinate mapping
11
+ # - Grid line calculations
12
+ #
13
+ # @example Transform an XY chart
14
+ # transform = Transform::XYChart.new
15
+ # layout = transform.to_graph(diagram)
16
+ class XYChart
17
+ # Default chart dimensions
18
+ DEFAULT_WIDTH = 800
19
+ DEFAULT_HEIGHT = 500
20
+
21
+ # Margins around the chart
22
+ MARGIN_TOP = 80
23
+ MARGIN_RIGHT = 60
24
+ MARGIN_BOTTOM = 80
25
+ MARGIN_LEFT = 100
26
+
27
+ # Transforms the diagram into a layout structure.
28
+ #
29
+ # @param diagram [Diagram::XYChart] the XY chart diagram
30
+ # @return [Hash] layout data with axes, datasets, and dimensions
31
+ def to_graph(diagram)
32
+ # Calculate plot area
33
+ plot_width = DEFAULT_WIDTH - MARGIN_LEFT - MARGIN_RIGHT
34
+ plot_height = DEFAULT_HEIGHT - MARGIN_TOP - MARGIN_BOTTOM
35
+
36
+ # Position axes
37
+ x_axis_layout = position_x_axis(diagram.x_axis, plot_width)
38
+ y_axis_layout = position_y_axis(diagram.y_axis, plot_height)
39
+
40
+ # Position datasets
41
+ datasets_layout = position_datasets(
42
+ diagram.datasets,
43
+ x_axis_layout,
44
+ y_axis_layout,
45
+ plot_width,
46
+ plot_height
47
+ )
48
+
49
+ {
50
+ width: DEFAULT_WIDTH,
51
+ height: DEFAULT_HEIGHT,
52
+ plot_x: MARGIN_LEFT,
53
+ plot_y: MARGIN_TOP,
54
+ plot_width: plot_width,
55
+ plot_height: plot_height,
56
+ x_axis: x_axis_layout,
57
+ y_axis: y_axis_layout,
58
+ datasets: datasets_layout,
59
+ title: diagram.title
60
+ }
61
+ end
62
+
63
+ private
64
+
65
+ # Positions the X-axis.
66
+ #
67
+ # @param axis [Diagram::XYAxis] X-axis
68
+ # @param width [Numeric] plot width
69
+ # @return [Hash] X-axis layout
70
+ def position_x_axis(axis, width)
71
+ return default_x_axis(width) unless axis
72
+
73
+ if axis.categorical?
74
+ position_categorical_axis(axis, width)
75
+ else
76
+ position_numeric_axis(axis, width)
77
+ end
78
+ end
79
+
80
+ # Positions a categorical X-axis.
81
+ #
82
+ # @param axis [Diagram::XYAxis] axis
83
+ # @param width [Numeric] plot width
84
+ # @return [Hash] axis layout
85
+ def position_categorical_axis(axis, width)
86
+ num_categories = axis.values.length
87
+ return default_x_axis(width) if num_categories == 0
88
+
89
+ # Calculate spacing between categories
90
+ spacing = width / [num_categories, 1].max
91
+
92
+ # Position each category
93
+ positions = axis.values.map.with_index do |label, idx|
94
+ {
95
+ label: label,
96
+ position: idx * spacing + spacing / 2,
97
+ index: idx
98
+ }
99
+ end
100
+
101
+ {
102
+ label: axis.label,
103
+ type: :categorical,
104
+ positions: positions,
105
+ min: 0,
106
+ max: num_categories - 1,
107
+ width: width
108
+ }
109
+ end
110
+
111
+ # Positions a numeric X-axis.
112
+ #
113
+ # @param axis [Diagram::XYAxis] axis
114
+ # @param width [Numeric] plot width
115
+ # @return [Hash] axis layout
116
+ def position_numeric_axis(axis, width)
117
+ min, max = axis.range
118
+
119
+ {
120
+ label: axis.label,
121
+ type: :numeric,
122
+ min: min,
123
+ max: max,
124
+ width: width,
125
+ scale: width / (max - min).to_f
126
+ }
127
+ end
128
+
129
+ # Returns a default X-axis layout.
130
+ #
131
+ # @param width [Numeric] plot width
132
+ # @return [Hash] default axis layout
133
+ def default_x_axis(width)
134
+ {
135
+ label: nil,
136
+ type: :numeric,
137
+ min: 0,
138
+ max: 10,
139
+ width: width,
140
+ scale: width / 10.0
141
+ }
142
+ end
143
+
144
+ # Positions the Y-axis.
145
+ #
146
+ # @param axis [Diagram::XYAxis] Y-axis
147
+ # @param height [Numeric] plot height
148
+ # @return [Hash] Y-axis layout
149
+ def position_y_axis(axis, height)
150
+ return default_y_axis(height) unless axis
151
+
152
+ min = axis.min || 0
153
+ max = axis.max || 100
154
+
155
+ {
156
+ label: axis.label,
157
+ min: min,
158
+ max: max,
159
+ height: height,
160
+ scale: height / (max - min).to_f
161
+ }
162
+ end
163
+
164
+ # Returns a default Y-axis layout.
165
+ #
166
+ # @param height [Numeric] plot height
167
+ # @return [Hash] default axis layout
168
+ def default_y_axis(height)
169
+ {
170
+ label: nil,
171
+ min: 0,
172
+ max: 100,
173
+ height: height,
174
+ scale: height / 100.0
175
+ }
176
+ end
177
+
178
+ # Positions all datasets.
179
+ #
180
+ # @param datasets [Array<Diagram::XYDataset>] datasets
181
+ # @param x_axis [Hash] X-axis layout
182
+ # @param y_axis [Hash] Y-axis layout
183
+ # @param width [Numeric] plot width
184
+ # @param height [Numeric] plot height
185
+ # @return [Array<Hash>] positioned datasets
186
+ def position_datasets(datasets, x_axis, y_axis, width, height)
187
+ datasets.map do |dataset|
188
+ points = position_dataset_points(
189
+ dataset,
190
+ x_axis,
191
+ y_axis,
192
+ width,
193
+ height
194
+ )
195
+
196
+ {
197
+ id: dataset.id,
198
+ label: dataset.label,
199
+ chart_type: dataset.chart_type,
200
+ points: points
201
+ }
202
+ end
203
+ end
204
+
205
+ # Positions points for a single dataset.
206
+ #
207
+ # @param dataset [Diagram::XYDataset] dataset
208
+ # @param x_axis [Hash] X-axis layout
209
+ # @param y_axis [Hash] Y-axis layout
210
+ # @param width [Numeric] plot width
211
+ # @param height [Numeric] plot height
212
+ # @return [Array<Hash>] positioned points
213
+ def position_dataset_points(dataset, x_axis, y_axis, width, height)
214
+ dataset.values.map.with_index do |y_value, idx|
215
+ x = calculate_x_position(idx, x_axis, width)
216
+ y = calculate_y_position(y_value, y_axis, height)
217
+
218
+ {
219
+ x: x,
220
+ y: y,
221
+ value: y_value,
222
+ index: idx
223
+ }
224
+ end
225
+ end
226
+
227
+ # Calculates X position for a data point.
228
+ #
229
+ # @param index [Integer] data point index
230
+ # @param x_axis [Hash] X-axis layout
231
+ # @param width [Numeric] plot width
232
+ # @return [Numeric] X coordinate
233
+ def calculate_x_position(index, x_axis, width)
234
+ if x_axis[:type] == :categorical && x_axis[:positions]
235
+ # Use pre-calculated positions for categories
236
+ position = x_axis[:positions][index]
237
+ position ? position[:position] : 0
238
+ else
239
+ # Distribute points evenly across width
240
+ num_points = 1 # Will be overridden by caller if needed
241
+ spacing = width / [index + 1, 1].max
242
+ index * spacing
243
+ end
244
+ end
245
+
246
+ # Calculates Y position for a data point.
247
+ #
248
+ # @param value [Numeric] Y value
249
+ # @param y_axis [Hash] Y-axis layout
250
+ # @param height [Numeric] plot height
251
+ # @return [Numeric] Y coordinate (inverted, 0 is top)
252
+ def calculate_y_position(value, y_axis, height)
253
+ # Normalize value to 0-1 range
254
+ normalized = normalize_value(value, y_axis[:min], y_axis[:max])
255
+
256
+ # Convert to pixel position (inverted, 0 is top)
257
+ height - (normalized * height)
258
+ end
259
+
260
+ # Normalizes a value to the 0-1 range.
261
+ #
262
+ # @param value [Numeric] value to normalize
263
+ # @param min_value [Numeric] minimum value
264
+ # @param max_value [Numeric] maximum value
265
+ # @return [Numeric] normalized value
266
+ def normalize_value(value, min_value, max_value)
267
+ return 0 if max_value == min_value
268
+
269
+ ((value - min_value).to_f / (max_value - min_value)).clamp(0, 1)
270
+ end
271
+ end
272
+ end
273
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'transform/base'
4
+
5
+ module Sirena
6
+ module Transform
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sirena
4
+ VERSION = '0.1.0'
5
+ end
data/lib/sirena.rb ADDED
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'sirena/version'
4
+
5
+ module Sirena
6
+ class Error < StandardError; end
7
+
8
+ # Convenience method for rendering mermaid diagrams to SVG
9
+ #
10
+ # @param mermaid_source [String] Mermaid diagram source code
11
+ # @param options [Hash] Rendering options
12
+ # @return [String] SVG output
13
+ def self.render(mermaid_source, options = {})
14
+ Engine.new.render(mermaid_source, options)
15
+ end
16
+ end
17
+
18
+ # Load modules in dependency order
19
+ require_relative 'sirena/text_measurement'
20
+ require_relative 'sirena/diagram_registry'
21
+ require_relative 'sirena/theme'
22
+ require_relative 'sirena/theme/registry'
23
+ require_relative 'sirena/svg'
24
+ require_relative 'sirena/parser'
25
+ require_relative 'sirena/diagram'
26
+ require_relative 'sirena/transform'
27
+ require_relative 'sirena/renderer'
28
+ require_relative 'sirena/engine'
29
+
30
+ # Initialize theme registry with built-in themes
31
+ Sirena::Theme::Registry.load_builtin_themes
32
+
33
+ # Convenience method for rendering mermaid diagrams to SVG
34
+ #
35
+ # @param mermaid_source [String] Mermaid diagram source code
36
+ # @param options [Hash] Rendering options
37
+ # @return [String] SVG output
38
+ def self.render(mermaid_source, options = {})
39
+ Engine.new.render(mermaid_source, options)
40
+ end
41
+
42
+ # Load and register flowchart handlers
43
+ require_relative 'sirena/parser/flowchart'
44
+ require_relative 'sirena/transform/flowchart'
45
+ require_relative 'sirena/renderer/flowchart'
46
+
47
+ Sirena::DiagramRegistry.register(
48
+ :flowchart,
49
+ parser: Sirena::Parser::FlowchartParser,
50
+ transform: Sirena::Transform::FlowchartTransform,
51
+ renderer: Sirena::Renderer::FlowchartRenderer
52
+ )
53
+
54
+ # Load and register sequence diagram handlers
55
+ require_relative 'sirena/parser/sequence'
56
+ require_relative 'sirena/transform/sequence'
57
+ require_relative 'sirena/renderer/sequence'
58
+
59
+ Sirena::DiagramRegistry.register(
60
+ :sequence,
61
+ parser: Sirena::Parser::SequenceParser,
62
+ transform: Sirena::Transform::SequenceTransform,
63
+ renderer: Sirena::Renderer::SequenceRenderer
64
+ )
65
+
66
+ # Load and register class diagram handlers
67
+ require_relative 'sirena/parser/class_diagram'
68
+ require_relative 'sirena/transform/class_diagram'
69
+ require_relative 'sirena/renderer/class_diagram'
70
+
71
+ Sirena::DiagramRegistry.register(
72
+ :class_diagram,
73
+ parser: Sirena::Parser::ClassDiagramParser,
74
+ transform: Sirena::Transform::ClassDiagramTransform,
75
+ renderer: Sirena::Renderer::ClassDiagramRenderer
76
+ )
77
+
78
+ # Load and register state diagram handlers
79
+ require_relative 'sirena/parser/state_diagram'
80
+ require_relative 'sirena/transform/state_diagram'
81
+ require_relative 'sirena/renderer/state_diagram'
82
+
83
+ Sirena::DiagramRegistry.register(
84
+ :state_diagram,
85
+ parser: Sirena::Parser::StateDiagramParser,
86
+ transform: Sirena::Transform::StateDiagramTransform,
87
+ renderer: Sirena::Renderer::StateDiagramRenderer
88
+ )
89
+
90
+ # Load and register ER diagram handlers
91
+ require_relative 'sirena/parser/er_diagram'
92
+ require_relative 'sirena/transform/er_diagram'
93
+ require_relative 'sirena/renderer/er_diagram'
94
+
95
+ Sirena::DiagramRegistry.register(
96
+ :er_diagram,
97
+ parser: Sirena::Parser::ErDiagramParser,
98
+ transform: Sirena::Transform::ErDiagramTransform,
99
+ renderer: Sirena::Renderer::ErDiagramRenderer
100
+ )
101
+
102
+ # Load and register user journey diagram handlers
103
+ require_relative 'sirena/parser/user_journey'
104
+ require_relative 'sirena/transform/user_journey'
105
+ require_relative 'sirena/renderer/user_journey'
106
+
107
+ Sirena::DiagramRegistry.register(
108
+ :user_journey,
109
+ parser: Sirena::Parser::UserJourneyParser,
110
+ transform: Sirena::Transform::UserJourneyTransform,
111
+ renderer: Sirena::Renderer::UserJourneyRenderer
112
+ )
113
+
114
+ # Load and register pie chart diagram handlers
115
+ require_relative 'sirena/parser/pie'
116
+ require_relative 'sirena/transform/pie'
117
+ require_relative 'sirena/renderer/pie'
118
+
119
+ Sirena::DiagramRegistry.register(
120
+ :pie,
121
+ parser: Sirena::Parser::PieParser,
122
+ transform: Sirena::Transform::PieTransform,
123
+ renderer: Sirena::Renderer::PieRenderer
124
+ )
125
+
126
+ # Load and register Gantt chart diagram handlers
127
+ require_relative 'sirena/parser/gantt'
128
+ require_relative 'sirena/transform/gantt'
129
+ require_relative 'sirena/renderer/gantt'
130
+
131
+ Sirena::DiagramRegistry.register(
132
+ :gantt,
133
+ parser: Sirena::Parser::GanttParser,
134
+ transform: Sirena::Transform::GanttTransform,
135
+ renderer: Sirena::Renderer::GanttRenderer
136
+ )
137
+
138
+ # Load and register Timeline diagram handlers
139
+ require_relative 'sirena/parser/timeline'
140
+ require_relative 'sirena/transform/timeline'
141
+ require_relative 'sirena/renderer/timeline'
142
+
143
+ Sirena::DiagramRegistry.register(
144
+ :timeline,
145
+ parser: Sirena::Parser::TimelineParser,
146
+ transform: Sirena::Transform::TimelineTransform,
147
+ renderer: Sirena::Renderer::TimelineRenderer
148
+ )
149
+
150
+ # Load and register Quadrant chart diagram handlers
151
+ require_relative 'sirena/parser/quadrant'
152
+ require_relative 'sirena/transform/quadrant'
153
+ require_relative 'sirena/renderer/quadrant'
154
+
155
+ Sirena::DiagramRegistry.register(
156
+ :quadrant,
157
+ parser: Sirena::Parser::QuadrantParser,
158
+ transform: Sirena::Transform::QuadrantTransform,
159
+ renderer: Sirena::Renderer::QuadrantRenderer
160
+ )
161
+
162
+ # Load and register Git Graph diagram handlers
163
+ require_relative 'sirena/parser/git_graph'
164
+ require_relative 'sirena/transform/git_graph'
165
+ require_relative 'sirena/renderer/git_graph'
166
+
167
+ Sirena::DiagramRegistry.register(
168
+ :git_graph,
169
+ parser: Sirena::Parser::GitGraphParser,
170
+ transform: Sirena::Transform::GitGraph,
171
+ renderer: Sirena::Renderer::GitGraph
172
+ )
173
+
174
+ # Load and register Mindmap diagram handlers
175
+ require_relative 'sirena/parser/mindmap'
176
+ require_relative 'sirena/transform/mindmap'
177
+ require_relative 'sirena/renderer/mindmap'
178
+
179
+ Sirena::DiagramRegistry.register(
180
+ :mindmap,
181
+ parser: Sirena::Parser::MindmapParser,
182
+ transform: Sirena::Transform::Mindmap,
183
+ renderer: Sirena::Renderer::Mindmap
184
+ )
185
+
186
+ # Load and register Kanban diagram handlers
187
+ require_relative 'sirena/parser/kanban'
188
+ require_relative 'sirena/transform/kanban'
189
+ require_relative 'sirena/renderer/kanban'
190
+
191
+ Sirena::DiagramRegistry.register(
192
+ :kanban,
193
+ parser: Sirena::Parser::KanbanParser,
194
+ transform: Sirena::Transform::Kanban,
195
+ renderer: Sirena::Renderer::Kanban
196
+ )
197
+
198
+ # Load and register Radar chart diagram handlers
199
+ require_relative 'sirena/parser/radar'
200
+ require_relative 'sirena/transform/radar'
201
+ require_relative 'sirena/renderer/radar'
202
+
203
+ Sirena::DiagramRegistry.register(
204
+ :radar,
205
+ parser: Sirena::Parser::RadarParser,
206
+ transform: Sirena::Transform::Radar,
207
+ renderer: Sirena::Renderer::Radar
208
+ )
209
+
210
+ # Load and register Block diagram handlers
211
+ require_relative 'sirena/parser/block'
212
+ require_relative 'sirena/transform/block'
213
+ require_relative 'sirena/renderer/block'
214
+
215
+ Sirena::DiagramRegistry.register(
216
+ :block,
217
+ parser: Sirena::Parser::BlockParser,
218
+ transform: Sirena::Transform::BlockTransform,
219
+ renderer: Sirena::Renderer::BlockRenderer
220
+ )
221
+
222
+
223
+ # Load and register Requirement diagram handlers
224
+ require_relative 'sirena/parser/requirement'
225
+ require_relative 'sirena/transform/requirement'
226
+ require_relative 'sirena/renderer/requirement'
227
+
228
+ Sirena::DiagramRegistry.register(
229
+ :requirement,
230
+ parser: Sirena::Parser::RequirementParser,
231
+ transform: Sirena::Transform::RequirementTransform,
232
+ renderer: Sirena::Renderer::RequirementRenderer
233
+ )
234
+
235
+ # Load and register XY Chart diagram handlers
236
+ require_relative 'sirena/parser/xy_chart'
237
+ require_relative 'sirena/transform/xy_chart'
238
+ require_relative 'sirena/renderer/xy_chart'
239
+
240
+ Sirena::DiagramRegistry.register(
241
+ :xychart,
242
+ parser: Sirena::Parser::XYChartParser,
243
+ transform: Sirena::Transform::XYChart,
244
+ renderer: Sirena::Renderer::XYChart
245
+ )
246
+
247
+ # Load and register Architecture diagram handlers
248
+ require_relative 'sirena/parser/architecture'
249
+ require_relative 'sirena/transform/architecture'
250
+ require_relative 'sirena/renderer/architecture'
251
+
252
+ Sirena::DiagramRegistry.register(
253
+ :architecture,
254
+ parser: Sirena::Parser::Architecture,
255
+ transform: Sirena::Transform::ArchitectureTransform,
256
+ renderer: Sirena::Renderer::ArchitectureRenderer
257
+ )
258
+
259
+ # Load and register Sankey diagram handlers
260
+ require_relative 'sirena/parser/sankey'
261
+ require_relative 'sirena/transform/sankey'
262
+ require_relative 'sirena/renderer/sankey'
263
+
264
+ Sirena::DiagramRegistry.register(
265
+ :sankey,
266
+ parser: Sirena::Parser::SankeyParser,
267
+ transform: Sirena::Transform::SankeyTransform,
268
+ renderer: Sirena::Renderer::SankeyRenderer
269
+ )
270
+ # Load and register Packet diagram handlers
271
+ require_relative 'sirena/parser/packet'
272
+ require_relative 'sirena/transform/packet'
273
+ require_relative 'sirena/renderer/packet'
274
+
275
+ Sirena::DiagramRegistry.register(
276
+ :packet,
277
+ parser: Sirena::Parser::PacketParser,
278
+ transform: Sirena::Transform::Packet,
279
+ renderer: Sirena::Renderer::Packet
280
+ )
281
+
282
+ # Load and register Treemap diagram handlers
283
+ require_relative 'sirena/parser/treemap'
284
+ require_relative 'sirena/transform/treemap'
285
+ require_relative 'sirena/renderer/treemap'
286
+
287
+ Sirena::DiagramRegistry.register(
288
+ :treemap,
289
+ parser: Sirena::Parser::TreemapParser,
290
+ transform: Sirena::Transform::Treemap,
291
+ renderer: Sirena::Renderer::Treemap
292
+ )
293
+
294
+ # Load and register C4 diagram handlers
295
+ require_relative 'sirena/parser/c4'
296
+ require_relative 'sirena/transform/c4'
297
+ require_relative 'sirena/renderer/c4'
298
+
299
+ Sirena::DiagramRegistry.register(
300
+ :c4,
301
+ parser: Sirena::Parser::C4Parser,
302
+ transform: Sirena::Transform::C4Transform,
303
+ renderer: Sirena::Renderer::C4Renderer
304
+ )
305
+
306
+ # Load and register Info diagram handlers
307
+ require_relative 'sirena/parser/info'
308
+ require_relative 'sirena/transform/info'
309
+ require_relative 'sirena/renderer/info'
310
+
311
+ Sirena::DiagramRegistry.register(
312
+ :info,
313
+ parser: Sirena::Parser::InfoParser,
314
+ transform: Sirena::Transform::InfoTransform,
315
+ renderer: Sirena::Renderer::InfoRenderer
316
+ )
317
+
318
+ # Load and register Error diagram handlers
319
+ require_relative 'sirena/parser/error'
320
+ require_relative 'sirena/transform/error'
321
+ require_relative 'sirena/renderer/error'
322
+
323
+ Sirena::DiagramRegistry.register(
324
+ :error,
325
+ parser: Sirena::Parser::ErrorParser,
326
+ transform: Sirena::Transform::ErrorTransform,
327
+ renderer: Sirena::Renderer::ErrorRenderer
328
+ )