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,468 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :examples do
4
+ desc "Generate all example SVGs from source files"
5
+ task :generate do
6
+ require 'sirena'
7
+ require 'yaml'
8
+ require 'fileutils'
9
+
10
+ examples_dir = File.expand_path('../../examples', __dir__)
11
+
12
+ unless Dir.exist?(examples_dir)
13
+ puts "⚠️ Examples directory not found: #{examples_dir}"
14
+ puts "Run 'rake examples:init' to create the directory structure"
15
+ exit 1
16
+ end
17
+
18
+ # Find all diagram type directories
19
+ diagram_dirs = Dir.glob(File.join(examples_dir, '*')).select { |f| File.directory?(f) }
20
+
21
+ total_generated = 0
22
+ total_failed = 0
23
+
24
+ diagram_dirs.sort.each do |dir|
25
+ diagram_type = File.basename(dir)
26
+ next if diagram_type == '.git' || diagram_type.start_with?('.')
27
+
28
+ puts "\n📊 Generating examples for #{diagram_type}..."
29
+
30
+ # Create generated/ directory
31
+ generated_dir = File.join(dir, 'generated')
32
+ FileUtils.mkdir_p(generated_dir)
33
+
34
+ # Find all .mmd files
35
+ mmd_files = Dir.glob(File.join(dir, '*.mmd'))
36
+
37
+ if mmd_files.empty?
38
+ puts " ⚠️ No examples found for #{diagram_type}"
39
+ next
40
+ end
41
+
42
+ mmd_files.sort.each do |mmd_file|
43
+ basename = File.basename(mmd_file, '.mmd')
44
+ yml_file = File.join(dir, "#{basename}.yml")
45
+ svg_file = File.join(generated_dir, "#{basename}.svg")
46
+
47
+ # Read source
48
+ source = File.read(mmd_file)
49
+
50
+ # Read metadata if exists
51
+ metadata = File.exist?(yml_file) ? YAML.load_file(yml_file) : {}
52
+ theme = metadata['theme'] || 'default'
53
+
54
+ begin
55
+ # Render to SVG
56
+ svg = Sirena.render(source, theme: theme)
57
+
58
+ # Write SVG
59
+ File.write(svg_file, svg)
60
+
61
+ puts " ✓ #{basename}.svg"
62
+ total_generated += 1
63
+ rescue => e
64
+ puts " ✗ #{basename}.svg - ERROR: #{e.message}"
65
+ total_failed += 1
66
+ end
67
+ end
68
+ end
69
+
70
+ puts "\n" + "=" * 60
71
+ puts "✅ Example generation complete!"
72
+ puts " Generated: #{total_generated}"
73
+ puts " Failed: #{total_failed}"
74
+ puts "=" * 60
75
+ end
76
+
77
+ desc "Copy generated examples to docs/assets/examples"
78
+ task :copy_to_docs do
79
+ require 'fileutils'
80
+
81
+ examples_dir = File.expand_path('../../examples', __dir__)
82
+ docs_assets_dir = File.expand_path('../../docs/assets/examples', __dir__)
83
+
84
+ FileUtils.mkdir_p(docs_assets_dir)
85
+
86
+ total_copied = 0
87
+
88
+ # Find all generated/ directories
89
+ Dir.glob(File.join(examples_dir, '*/generated')).sort.each do |generated_dir|
90
+ diagram_type = File.basename(File.dirname(generated_dir))
91
+ target_dir = File.join(docs_assets_dir, diagram_type)
92
+
93
+ FileUtils.mkdir_p(target_dir)
94
+
95
+ # Copy all SVG files
96
+ svg_files = Dir.glob(File.join(generated_dir, '*.svg'))
97
+ svg_files.each do |svg_file|
98
+ FileUtils.cp(svg_file, target_dir)
99
+ total_copied += 1
100
+ end
101
+
102
+ puts "✓ Copied #{svg_files.size} #{diagram_type} examples to docs/assets/examples/"
103
+ end
104
+
105
+ puts "\n✅ #{total_copied} examples copied to documentation!"
106
+ end
107
+
108
+ desc "Generate AsciiDoc include files for documentation"
109
+ task :generate_docs do
110
+ require 'yaml'
111
+ require 'fileutils'
112
+
113
+ examples_dir = File.expand_path('../../examples', __dir__)
114
+ docs_examples_dir = File.expand_path('../../docs/_diagram_types/examples', __dir__)
115
+
116
+ FileUtils.mkdir_p(docs_examples_dir)
117
+
118
+ diagram_dirs = Dir.glob(File.join(examples_dir, '*')).select { |f| File.directory?(f) }
119
+
120
+ diagram_dirs.sort.each do |dir|
121
+ diagram_type = File.basename(dir)
122
+ next if diagram_type == '.git' || diagram_type.start_with?('.')
123
+
124
+ mmd_files = Dir.glob(File.join(dir, '*.mmd')).sort
125
+ next if mmd_files.empty?
126
+
127
+ # Generate AsciiDoc include file
128
+ adoc_file = File.join(docs_examples_dir, "#{diagram_type}-examples.adoc")
129
+
130
+ content = []
131
+ content << "// Auto-generated examples for #{diagram_type}"
132
+ content << "// Generated: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
133
+ content << ""
134
+
135
+ mmd_files.each_with_index do |mmd_file, index|
136
+ basename = File.basename(mmd_file, '.mmd')
137
+ yml_file = File.join(dir, "#{basename}.yml")
138
+
139
+ # Read metadata
140
+ metadata = File.exist?(yml_file) ? YAML.load_file(yml_file) : {}
141
+ title = metadata['title'] || basename.split('-').map(&:capitalize).join(' ')
142
+ description = metadata['description'] || 'Example diagram'
143
+ complexity = metadata['complexity'] || 'basic'
144
+ use_cases = metadata['use_cases'] || []
145
+ keywords = metadata['keywords'] || []
146
+
147
+ content << "==== Example #{index + 1}: #{title}"
148
+ content << ""
149
+ content << ".#{description}"
150
+
151
+ if !use_cases.empty? || complexity != 'basic'
152
+ content << "[NOTE]"
153
+ content << "===="
154
+ content << "Complexity: #{complexity.capitalize}"
155
+ if !use_cases.empty?
156
+ content << " +"
157
+ content << "Use Cases: #{use_cases.join(', ')}"
158
+ end
159
+ content << "===="
160
+ end
161
+
162
+ content << ""
163
+ content << ".Source Code"
164
+ content << "[source,mermaid]"
165
+ content << "----"
166
+ content << File.read(mmd_file).strip
167
+ content << "----"
168
+ content << ""
169
+ content << ".Rendered Output"
170
+ content << "image::../../assets/examples/#{diagram_type}/#{basename}.svg[#{title},600]"
171
+ content << ""
172
+ content << "'''"
173
+ content << ""
174
+ end
175
+
176
+ File.write(adoc_file, content.join("\n"))
177
+ puts "✓ Generated #{diagram_type}-examples.adoc (#{mmd_files.size} examples)"
178
+ end
179
+
180
+ puts "\n✅ Documentation includes generated!"
181
+ end
182
+
183
+ desc "Validate all examples (parse and render)"
184
+ task :validate do
185
+ require 'sirena'
186
+
187
+ examples_dir = File.expand_path('../../examples', __dir__)
188
+
189
+ failed = []
190
+ passed = 0
191
+ total = 0
192
+
193
+ puts "Validating examples..."
194
+ puts ""
195
+
196
+ Dir.glob(File.join(examples_dir, '*/*.mmd')).sort.each do |mmd_file|
197
+ total += 1
198
+ source = File.read(mmd_file)
199
+ relative_path = mmd_file.sub(examples_dir + '/', '')
200
+
201
+ begin
202
+ Sirena.render(source)
203
+ passed += 1
204
+ print '.'
205
+ rescue => e
206
+ failed << { file: relative_path, error: e.message }
207
+ print 'F'
208
+ end
209
+ end
210
+
211
+ puts "\n\n"
212
+ puts "=" * 60
213
+ puts "Validation Results"
214
+ puts "=" * 60
215
+ puts "Total: #{total}"
216
+ puts "Passed: #{passed} (#{(passed.to_f / total * 100).round(1)}%)"
217
+ puts "Failed: #{failed.size}"
218
+ puts "=" * 60
219
+
220
+ if failed.any?
221
+ puts "\nFailures:"
222
+ failed.each do |f|
223
+ puts " ✗ #{f[:file]}"
224
+ puts " #{f[:error]}"
225
+ end
226
+ exit 1
227
+ else
228
+ puts "\n✅ All examples validated successfully!"
229
+ end
230
+ end
231
+
232
+ desc "Generate all examples and copy to docs"
233
+ task :build => [:generate, :generate_docs, :copy_to_docs]
234
+
235
+ desc "Create example template for a diagram type"
236
+ task :create, [:type, :name] do |t, args|
237
+ require 'fileutils'
238
+
239
+ type = args[:type]
240
+ name = args[:name]
241
+
242
+ if type.nil? || name.nil?
243
+ puts "Usage: rake examples:create[type,name]"
244
+ puts "Example: rake examples:create[flowchart,basic-flow]"
245
+ exit 1
246
+ end
247
+
248
+ examples_dir = File.expand_path('../../examples', __dir__)
249
+ type_dir = File.join(examples_dir, type)
250
+
251
+ FileUtils.mkdir_p(type_dir)
252
+
253
+ # Find next number
254
+ existing = Dir.glob(File.join(type_dir, '*.mmd')).map do |f|
255
+ File.basename(f).split('-').first.to_i
256
+ end.max || 0
257
+ number = existing + 1
258
+
259
+ basename = format("%02d-%s", number, name)
260
+
261
+ # Create .mmd file
262
+ mmd_file = File.join(type_dir, "#{basename}.mmd")
263
+ File.write(mmd_file, "#{type}\n A --> B\n")
264
+
265
+ # Create .yml file
266
+ yml_file = File.join(type_dir, "#{basename}.yml")
267
+ yml_content = <<~YAML
268
+ title: "#{name.split('-').map(&:capitalize).join(' ')}"
269
+ description: "Description of this example"
270
+ complexity: basic
271
+ keywords:
272
+ - #{type}
273
+ use_cases:
274
+ - "Example use case"
275
+ theme: default
276
+ YAML
277
+ File.write(yml_file, yml_content)
278
+
279
+ puts "✓ Created #{basename}.mmd"
280
+ puts "✓ Created #{basename}.yml"
281
+ puts "\nEdit these files and run: rake examples:generate"
282
+ end
283
+
284
+ desc "List all examples with status"
285
+ task :list do
286
+ require 'yaml'
287
+
288
+ examples_dir = File.expand_path('../../examples', __dir__)
289
+
290
+ unless Dir.exist?(examples_dir)
291
+ puts "Examples directory not found: #{examples_dir}"
292
+ puts "Run 'rake examples:init' to create it"
293
+ exit 1
294
+ end
295
+
296
+ diagram_dirs = Dir.glob(File.join(examples_dir, '*')).select { |f| File.directory?(f) }
297
+
298
+ total_examples = 0
299
+
300
+ diagram_dirs.sort.each do |dir|
301
+ diagram_type = File.basename(dir)
302
+ next if diagram_type == '.git' || diagram_type.start_with?('.')
303
+
304
+ examples = Dir.glob(File.join(dir, '*.mmd'))
305
+ total_examples += examples.size
306
+
307
+ puts "\n#{diagram_type.upcase.tr('-', ' ')} (#{examples.size} examples)"
308
+ puts "─" * 60
309
+
310
+ if examples.empty?
311
+ puts " (no examples yet)"
312
+ next
313
+ end
314
+
315
+ examples.sort.each do |mmd_file|
316
+ basename = File.basename(mmd_file, '.mmd')
317
+ yml_file = File.join(dir, "#{basename}.yml")
318
+ svg_file = File.join(dir, 'generated', "#{basename}.svg")
319
+
320
+ metadata = File.exist?(yml_file) ? YAML.load_file(yml_file) : {}
321
+ title = metadata['title'] || basename
322
+ complexity = metadata['complexity'] || 'basic'
323
+
324
+ svg_status = File.exist?(svg_file) ? "✓" : "✗"
325
+
326
+ puts " #{svg_status} #{basename}: #{title} [#{complexity}]"
327
+ end
328
+ end
329
+
330
+ puts "\n" + "=" * 60
331
+ puts "Total: #{total_examples} examples across #{diagram_dirs.size} diagram types"
332
+ puts "=" * 60
333
+ end
334
+
335
+ desc "Initialize examples directory structure"
336
+ task :init do
337
+ require 'fileutils'
338
+
339
+ examples_dir = File.expand_path('../../examples', __dir__)
340
+
341
+ # Create main examples directory
342
+ FileUtils.mkdir_p(examples_dir)
343
+
344
+ # Create README
345
+ readme_content = <<~README
346
+ # Sirena Examples
347
+
348
+ This directory contains example diagrams for all supported diagram types.
349
+
350
+ ## Structure
351
+
352
+ Each diagram type has its own directory with:
353
+ - `*.mmd` - Mermaid source files
354
+ - `*.yml` - Metadata for each example
355
+ - `generated/` - Auto-generated SVG files (git-ignored)
356
+
357
+ ## Usage
358
+
359
+ ```bash
360
+ # Generate all SVGs
361
+ rake examples:generate
362
+
363
+ # Create a new example
364
+ rake examples:create[flowchart,my-example]
365
+
366
+ # Validate all examples
367
+ rake examples:validate
368
+
369
+ # List all examples
370
+ rake examples:list
371
+
372
+ # Build everything (generate + docs + copy)
373
+ rake examples:build
374
+ ```
375
+
376
+ ## Adding Examples
377
+
378
+ 1. Create example files:
379
+ ```bash
380
+ rake examples:create[type,name]
381
+ ```
382
+
383
+ 2. Edit the `.mmd` and `.yml` files
384
+
385
+ 3. Generate SVG:
386
+ ```bash
387
+ rake examples:generate
388
+ ```
389
+
390
+ 4. Build documentation:
391
+ ```bash
392
+ rake examples:build
393
+ ```
394
+
395
+ ## Example Metadata
396
+
397
+ Each `.yml` file should contain:
398
+
399
+ ```yaml
400
+ title: "Example Title"
401
+ description: "What this example demonstrates"
402
+ complexity: basic # basic, intermediate, advanced
403
+ keywords:
404
+ - keyword1
405
+ - keyword2
406
+ use_cases:
407
+ - "Use case description"
408
+ theme: default # default, dark, light, high-contrast
409
+ ```
410
+ README
411
+
412
+ File.write(File.join(examples_dir, 'README.md'), readme_content)
413
+
414
+ # Create .gitignore
415
+ gitignore_content = <<~GITIGNORE
416
+ # Ignore generated SVG files
417
+ */generated/
418
+
419
+ # Ignore macOS files
420
+ .DS_Store
421
+
422
+ # Ignore editor files
423
+ *.swp
424
+ *.swo
425
+ *~
426
+ GITIGNORE
427
+
428
+ File.write(File.join(examples_dir, '.gitignore'), gitignore_content)
429
+
430
+ puts "✓ Created examples/ directory"
431
+ puts "✓ Created README.md"
432
+ puts "✓ Created .gitignore"
433
+ puts "\n✅ Examples directory initialized!"
434
+ puts "\nNext steps:"
435
+ puts " 1. Create examples: rake examples:create[type,name]"
436
+ puts " 2. Generate SVGs: rake examples:generate"
437
+ puts " 3. Build docs: rake examples:build"
438
+ end
439
+
440
+ desc "Clean all generated files"
441
+ task :clean do
442
+ require 'fileutils'
443
+
444
+ examples_dir = File.expand_path('../../examples', __dir__)
445
+ docs_assets_dir = File.expand_path('../../docs/assets/examples', __dir__)
446
+ docs_examples_dir = File.expand_path('../../docs/_diagram_types/examples', __dir__)
447
+
448
+ # Clean generated/ directories
449
+ Dir.glob(File.join(examples_dir, '*/generated')).each do |dir|
450
+ FileUtils.rm_rf(dir)
451
+ puts "✓ Removed #{dir}"
452
+ end
453
+
454
+ # Clean docs assets
455
+ if Dir.exist?(docs_assets_dir)
456
+ FileUtils.rm_rf(docs_assets_dir)
457
+ puts "✓ Removed #{docs_assets_dir}"
458
+ end
459
+
460
+ # Clean docs includes
461
+ if Dir.exist?(docs_examples_dir)
462
+ FileUtils.rm_rf(docs_examples_dir)
463
+ puts "✓ Removed #{docs_examples_dir}"
464
+ end
465
+
466
+ puts "\n✅ Cleaned all generated files!"
467
+ end
468
+ end