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,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/model'
4
+ require_relative 'base'
5
+
6
+ module Sirena
7
+ module Diagram
8
+ # Represents a flowchart node.
9
+ #
10
+ # A node has an identifier, label text, and a shape type that
11
+ # determines how it should be rendered visually.
12
+ class FlowchartNode < Lutaml::Model::Serializable
13
+ # Unique identifier for the node
14
+ attribute :id, :string
15
+
16
+ # Display text/label for the node
17
+ attribute :label, :string
18
+
19
+ # Shape type: :rect, :rounded, :stadium, :subroutine, :cylindrical,
20
+ # :circle, :asymmetric, :rhombus, :hexagon, :parallelogram,
21
+ # :parallelogram_alt, :trapezoid, :trapezoid_alt, :double_circle
22
+ attribute :shape, :string
23
+
24
+ # Optional classes/styles
25
+ attribute :classes, :string
26
+
27
+ # Initialize with default shape
28
+ def initialize(*args)
29
+ super
30
+ self.shape ||= 'rect'
31
+ end
32
+
33
+ # Validates the node has required attributes.
34
+ #
35
+ # @return [Boolean] true if node is valid
36
+ def valid?
37
+ !id.nil? && !id.empty? && !label.nil?
38
+ end
39
+ end
40
+
41
+ # Represents a flowchart edge (connection between nodes).
42
+ #
43
+ # An edge connects a source node to a target node, with optional
44
+ # label text and arrow styling.
45
+ class FlowchartEdge < Lutaml::Model::Serializable
46
+ # Source node identifier
47
+ attribute :source_id, :string
48
+
49
+ # Target node identifier
50
+ attribute :target_id, :string
51
+
52
+ # Optional edge label
53
+ attribute :label, :string
54
+
55
+ # Arrow type: :arrow, :dotted_arrow, :thick_arrow, :line,
56
+ # :dotted_line, :thick_line
57
+ attribute :arrow_type, :string
58
+
59
+ # Initialize with default arrow type
60
+ def initialize(*args)
61
+ super
62
+ self.arrow_type ||= 'arrow'
63
+ end
64
+
65
+ # Validates the edge has required attributes.
66
+ #
67
+ # @return [Boolean] true if edge is valid
68
+ def valid?
69
+ !source_id.nil? && !source_id.empty? &&
70
+ !target_id.nil? && !target_id.empty?
71
+ end
72
+ end
73
+
74
+ # Flowchart diagram model.
75
+ #
76
+ # Represents a complete flowchart with nodes and edges. Flowcharts
77
+ # support various node shapes and edge types to create flow diagrams,
78
+ # decision trees, and process flows.
79
+ #
80
+ # @example Creating a simple flowchart
81
+ # flowchart = Flowchart.new(direction: 'TD')
82
+ # flowchart.nodes << FlowchartNode.new(
83
+ # id: 'A',
84
+ # label: 'Start',
85
+ # shape: 'stadium'
86
+ # )
87
+ # flowchart.nodes << FlowchartNode.new(
88
+ # id: 'B',
89
+ # label: 'Process',
90
+ # shape: 'rect'
91
+ # )
92
+ # flowchart.edges << FlowchartEdge.new(
93
+ # source_id: 'A',
94
+ # target_id: 'B',
95
+ # arrow_type: 'arrow'
96
+ # )
97
+ class Flowchart < Base
98
+ # Collection of nodes in the flowchart
99
+ attribute :nodes, FlowchartNode, collection: true, default: -> { [] }
100
+
101
+ # Collection of edges connecting nodes
102
+ attribute :edges, FlowchartEdge, collection: true, default: -> { [] }
103
+
104
+ # Returns the diagram type identifier.
105
+ #
106
+ # @return [Symbol] :flowchart
107
+ def diagram_type
108
+ :flowchart
109
+ end
110
+
111
+ # Validates the flowchart structure.
112
+ #
113
+ # A flowchart is valid if:
114
+ # - It has at least one node
115
+ # - All nodes are valid
116
+ # - All edges are valid
117
+ # - All edge references point to existing nodes
118
+ #
119
+ # @return [Boolean] true if flowchart is valid
120
+ def valid?
121
+ return false if nodes.nil? || nodes.empty?
122
+ return false unless nodes.all?(&:valid?)
123
+ return false unless edges.nil? || edges.all?(&:valid?)
124
+
125
+ # Validate edge references
126
+ node_ids = nodes.map(&:id)
127
+ edges&.each do |edge|
128
+ return false unless node_ids.include?(edge.source_id)
129
+ return false unless node_ids.include?(edge.target_id)
130
+ end
131
+
132
+ true
133
+ end
134
+
135
+ # Finds a node by its identifier.
136
+ #
137
+ # @param id [String] the node identifier to find
138
+ # @return [FlowchartNode, nil] the node or nil if not found
139
+ def find_node(id)
140
+ nodes.find { |n| n.id == id }
141
+ end
142
+
143
+ # Finds all edges originating from a specific node.
144
+ #
145
+ # @param node_id [String] the source node identifier
146
+ # @return [Array<FlowchartEdge>] edges from the node
147
+ def edges_from(node_id)
148
+ edges.select { |e| e.source_id == node_id }
149
+ end
150
+
151
+ # Finds all edges targeting a specific node.
152
+ #
153
+ # @param node_id [String] the target node identifier
154
+ # @return [Array<FlowchartEdge>] edges to the node
155
+ def edges_to(node_id)
156
+ edges.select { |e| e.target_id == node_id }
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Gantt chart task
8
+ class GanttTask < Lutaml::Model::Serializable
9
+ attribute :description, :string
10
+ attribute :id, :string
11
+ attribute :start_date, :string
12
+ attribute :end_date, :string
13
+ attribute :duration, :string
14
+ attribute :after_task, :string
15
+ attribute :until_task, :string
16
+ attribute :tags, :string, collection: true
17
+ attribute :click_href, :string
18
+ attribute :click_callback, :string
19
+
20
+ def initialize
21
+ super
22
+ @tags ||= []
23
+ end
24
+
25
+ def done?
26
+ tags.include?("done")
27
+ end
28
+
29
+ def active?
30
+ tags.include?("active")
31
+ end
32
+
33
+ def critical?
34
+ tags.include?("crit")
35
+ end
36
+
37
+ def milestone?
38
+ tags.include?("milestone")
39
+ end
40
+ end
41
+
42
+ # Gantt chart section grouping
43
+ class GanttSection < Lutaml::Model::Serializable
44
+ attribute :name, :string
45
+ attribute :tasks, GanttTask, collection: true
46
+
47
+ def initialize(name = nil)
48
+ super()
49
+ @name = name
50
+ @tasks ||= []
51
+ end
52
+ end
53
+
54
+ # Gantt chart diagram model
55
+ class GanttChart < Lutaml::Model::Serializable
56
+ attribute :title, :string
57
+ attribute :date_format, :string, default: -> { "YYYY-MM-DD" }
58
+ attribute :axis_format, :string
59
+ attribute :tick_interval, :string
60
+ attribute :excludes, :string, collection: true
61
+ attribute :today_marker, :string
62
+ attribute :sections, GanttSection, collection: true
63
+
64
+ def initialize
65
+ super
66
+ @sections ||= []
67
+ @excludes ||= []
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Represents a Git Graph diagram
8
+ class GitGraph < Base
9
+ # Represents a commit in the git graph
10
+ class Commit < Lutaml::Model::Serializable
11
+ attribute :id, :string
12
+ attribute :message, :string
13
+ attribute :type, :string, default: -> { "NORMAL" }
14
+ attribute :tag, :string
15
+ attribute :branch_name, :string
16
+ attribute :parent_ids, :string, collection: true, default: -> { [] }
17
+ attribute :is_merge, :boolean, default: -> { false }
18
+ attribute :merge_branch, :string
19
+ attribute :is_cherry_pick, :boolean, default: -> { false }
20
+ attribute :cherry_pick_parent, :string
21
+ end
22
+
23
+ # Represents a branch in the git graph
24
+ class Branch < Lutaml::Model::Serializable
25
+ attribute :name, :string
26
+ attribute :order, :integer
27
+ attribute :parent_branch, :string
28
+ attribute :created_at_commit, :string
29
+ end
30
+
31
+ attribute :orientation, :string, default: -> { "LR" }
32
+ attribute :commits, Commit, collection: true, default: -> { [] }
33
+ attribute :branches, Branch, collection: true, default: -> { [] }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/model'
4
+ require_relative 'base'
5
+
6
+ module Sirena
7
+ module Diagram
8
+ # Info diagram model.
9
+ #
10
+ # Represents a simple informational diagram that displays a message
11
+ # or status information. Info diagrams are typically used to show
12
+ # system information, help text, or status messages.
13
+ #
14
+ # @example Creating an info diagram
15
+ # info = Info.new
16
+ # info.show_info = true
17
+ class Info < Base
18
+ # Whether to show additional info
19
+ attribute :show_info, :boolean, default: -> { false }
20
+
21
+ # Returns the diagram type identifier.
22
+ #
23
+ # @return [Symbol] :info
24
+ def diagram_type
25
+ :info
26
+ end
27
+
28
+ # Validates the info diagram structure.
29
+ #
30
+ # Info diagrams are always valid as they have no required content.
31
+ #
32
+ # @return [Boolean] true
33
+ def valid?
34
+ true
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+ require_relative "base"
5
+
6
+ module Sirena
7
+ module Diagram
8
+ # Represents a card in a Kanban column.
9
+ #
10
+ # A card has an id, text content, and optional metadata like
11
+ # assigned user, ticket number, icon, priority, etc.
12
+ class KanbanCard < Lutaml::Model::Serializable
13
+ # Card identifier
14
+ attribute :id, :string
15
+
16
+ # Card text content
17
+ attribute :text, :string
18
+
19
+ # Optional metadata
20
+ attribute :assigned, :string
21
+ attribute :ticket, :string
22
+ attribute :icon, :string
23
+ attribute :label, :string
24
+ attribute :priority, :string
25
+
26
+ # Validates the card has required fields.
27
+ #
28
+ # @return [Boolean] true if card is valid
29
+ def valid?
30
+ !id.nil? && !id.empty? && !text.nil? && !text.empty?
31
+ end
32
+
33
+ # Returns all metadata as a hash.
34
+ #
35
+ # @return [Hash] metadata hash
36
+ def metadata
37
+ {
38
+ assigned: assigned,
39
+ ticket: ticket,
40
+ icon: icon,
41
+ label: label,
42
+ priority: priority
43
+ }.compact
44
+ end
45
+
46
+ # Checks if card has any metadata.
47
+ #
48
+ # @return [Boolean] true if card has metadata
49
+ def has_metadata?
50
+ !metadata.empty?
51
+ end
52
+ end
53
+
54
+ # Represents a column in a Kanban board.
55
+ #
56
+ # A column has an id, title, and contains multiple cards.
57
+ class KanbanColumn < Lutaml::Model::Serializable
58
+ # Column identifier
59
+ attribute :id, :string
60
+
61
+ # Column title/name
62
+ attribute :title, :string
63
+
64
+ # Collection of cards in this column
65
+ attribute :cards, KanbanCard, collection: true, default: -> { [] }
66
+
67
+ # Validates the column has required fields.
68
+ #
69
+ # @return [Boolean] true if column is valid
70
+ def valid?
71
+ !id.nil? && !id.empty? &&
72
+ !title.nil? && !title.empty? &&
73
+ cards.all?(&:valid?)
74
+ end
75
+
76
+ # Adds a card to this column.
77
+ #
78
+ # @param card [KanbanCard] the card to add
79
+ # @return [void]
80
+ def add_card(card)
81
+ cards << card
82
+ end
83
+ end
84
+
85
+ # Kanban board diagram model.
86
+ #
87
+ # Represents a complete Kanban board with columns and cards
88
+ # for workflow visualization.
89
+ #
90
+ # @example Creating a simple kanban board
91
+ # diagram = Kanban.new
92
+ # column = KanbanColumn.new.tap do |c|
93
+ # c.id = "todo"
94
+ # c.title = "Todo"
95
+ # end
96
+ # card = KanbanCard.new.tap do |c|
97
+ # c.id = "docs"
98
+ # c.text = "Create Documentation"
99
+ # c.priority = "High"
100
+ # end
101
+ # column.add_card(card)
102
+ # diagram.add_column(column)
103
+ class Kanban < Base
104
+ # Collection of columns in the board
105
+ attribute :columns, KanbanColumn, collection: true,
106
+ default: -> { [] }
107
+
108
+ # Returns the diagram type identifier.
109
+ #
110
+ # @return [Symbol] :kanban
111
+ def diagram_type
112
+ :kanban
113
+ end
114
+
115
+ # Validates the kanban board structure.
116
+ #
117
+ # A kanban is valid if:
118
+ # - It has at least one column
119
+ # - All columns are valid
120
+ # - All cards within columns are valid
121
+ #
122
+ # @return [Boolean] true if kanban board is valid
123
+ def valid?
124
+ return false if columns.nil? || columns.empty?
125
+ return false unless columns.all?(&:valid?)
126
+
127
+ true
128
+ end
129
+
130
+ # Adds a column to the board.
131
+ #
132
+ # @param column [KanbanColumn] the column to add
133
+ # @return [void]
134
+ def add_column(column)
135
+ columns << column
136
+ end
137
+
138
+ # Returns all cards across all columns.
139
+ #
140
+ # @return [Array<KanbanCard>] all cards in the board
141
+ def all_cards
142
+ columns.flat_map(&:cards)
143
+ end
144
+
145
+ # Finds a column by id.
146
+ #
147
+ # @param id [String] the column id
148
+ # @return [KanbanColumn, nil] the column or nil if not found
149
+ def find_column(id)
150
+ columns.find { |c| c.id == id }
151
+ end
152
+
153
+ # Finds cards by assigned user.
154
+ #
155
+ # @param user [String] the assigned user
156
+ # @return [Array<KanbanCard>] cards assigned to the user
157
+ def cards_by_assigned(user)
158
+ all_cards.select { |c| c.assigned == user }
159
+ end
160
+
161
+ # Finds cards by priority.
162
+ #
163
+ # @param priority [String] the priority level
164
+ # @return [Array<KanbanCard>] cards with the given priority
165
+ def cards_by_priority(priority)
166
+ all_cards.select { |c| c.priority == priority }
167
+ end
168
+
169
+ # Finds cards by ticket.
170
+ #
171
+ # @param ticket [String] the ticket number
172
+ # @return [Array<KanbanCard>] cards with the given ticket
173
+ def cards_by_ticket(ticket)
174
+ all_cards.select { |c| c.ticket == ticket }
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Sirena
6
+ module Diagram
7
+ # Represents a Mindmap diagram
8
+ class Mindmap < Base
9
+ # Represents a node in the mindmap
10
+ class MindmapNode < Lutaml::Model::Serializable
11
+ attribute :id, :string
12
+ attribute :content, :string
13
+ attribute :level, :integer, default: -> { 0 }
14
+ attribute :shape, :string, default: -> { "default" }
15
+ attribute :icon, :string
16
+ attribute :classes, :string, collection: true, default: -> { [] }
17
+ attribute :children, MindmapNode, collection: true, default: -> { [] }
18
+ attribute :parent, MindmapNode
19
+
20
+ # Shape constants
21
+ SHAPES = {
22
+ circle: "circle", # ((text))
23
+ cloud: "cloud", # )text(
24
+ bang: "bang", # ))text((
25
+ hexagon: "hexagon", # {{text}}
26
+ square: "square", # [text]
27
+ default: "default" # plain text (rounded rectangle)
28
+ }.freeze
29
+
30
+ def add_child(child)
31
+ child.parent = self
32
+ child.level = level + 1
33
+ children << child
34
+ end
35
+
36
+ def root?
37
+ level == 0
38
+ end
39
+
40
+ def leaf?
41
+ children.empty?
42
+ end
43
+ end
44
+
45
+ attribute :root, MindmapNode
46
+ attribute :nodes, MindmapNode, collection: true, default: -> { [] }
47
+
48
+ def add_node(node)
49
+ nodes << node
50
+ @root = node if node.root?
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sirena
4
+ module Diagram
5
+ # Represents a packet diagram showing network packet structures
6
+ class PacketDiagram < Base
7
+ attr_accessor :title, :fields
8
+
9
+ def initialize
10
+ super
11
+ @fields = []
12
+ end
13
+
14
+ def type
15
+ :packet
16
+ end
17
+
18
+ # Add a field to the packet
19
+ def add_field(field)
20
+ @fields << field
21
+ end
22
+
23
+ # Get the maximum bit position used in the packet
24
+ def max_bit_position
25
+ return 0 if @fields.empty?
26
+
27
+ @fields.map(&:bit_end).max
28
+ end
29
+
30
+ # Calculate the number of rows needed (assuming 32-bit width)
31
+ def row_count(bits_per_row = 32)
32
+ return 1 if @fields.empty?
33
+
34
+ ((max_bit_position + 1).to_f / bits_per_row).ceil
35
+ end
36
+ end
37
+
38
+ # Represents a field in a packet diagram
39
+ class PacketField
40
+ attr_accessor :bit_start, :bit_end, :label
41
+
42
+ def initialize(bit_start, bit_end, label)
43
+ @bit_start = bit_start.to_i
44
+ @bit_end = bit_end.to_i
45
+ @label = label
46
+ end
47
+
48
+ # Get the size of the field in bits
49
+ def size
50
+ @bit_end - @bit_start + 1
51
+ end
52
+
53
+ # Get the row this field starts in (for 32-bit rows)
54
+ def start_row(bits_per_row = 32)
55
+ @bit_start / bits_per_row
56
+ end
57
+
58
+ # Get the row this field ends in (for 32-bit rows)
59
+ def end_row(bits_per_row = 32)
60
+ @bit_end / bits_per_row
61
+ end
62
+
63
+ # Check if this field spans multiple rows
64
+ def spans_rows?(bits_per_row = 32)
65
+ start_row(bits_per_row) != end_row(bits_per_row)
66
+ end
67
+
68
+ # Get the bit position within a row (0-31 for 32-bit rows)
69
+ def start_bit_in_row(bits_per_row = 32)
70
+ @bit_start % bits_per_row
71
+ end
72
+
73
+ # Get the ending bit position within a row
74
+ def end_bit_in_row(bits_per_row = 32)
75
+ @bit_end % bits_per_row
76
+ end
77
+ end
78
+ end
79
+ end