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,493 @@
1
+ #!/usr/bin/env ruby
2
+ # Comprehensive test extraction from mermaid-js repository
3
+ # Extracts ALL Mermaid diagram test cases for sirena validation
4
+
5
+ require 'fileutils'
6
+ require 'json'
7
+
8
+ MERMAID_JS_ROOT = "/Users/mulgogi/src/external/mermaid-js"
9
+ SIRENA_ROOT = File.expand_path('../..', __FILE__)
10
+ OUTPUT_DIR = "#{SIRENA_ROOT}/spec/mermaid"
11
+
12
+ # All Mermaid diagram types discovered from packages/mermaid/src/diagrams/
13
+ DIAGRAM_TYPES = {
14
+ architecture: /^architecture/i,
15
+ block: /^block-beta|^block\s/i,
16
+ c4: /^C4/i,
17
+ class: /^classDiagram/i,
18
+ er: /^erDiagram/i,
19
+ error: /^error/i,
20
+ flowchart: /^(?:graph|flowchart)\s/i,
21
+ gantt: /^gantt/i,
22
+ git: /^gitGraph/i,
23
+ info: /^info/i,
24
+ kanban: /^kanban/i,
25
+ mindmap: /^mindmap/i,
26
+ packet: /^packet-beta/i,
27
+ pie: /^pie/i,
28
+ quadrant: /^quadrantChart/i,
29
+ radar: /^radar/i,
30
+ requirement: /^requirementDiagram/i,
31
+ sankey: /^sankey-beta/i,
32
+ sequence: /^sequenceDiagram/i,
33
+ state: /^stateDiagram/i,
34
+ timeline: /^timeline/i,
35
+ treemap: /^treemap/i,
36
+ user_journey: /^journey/i,
37
+ xychart: /^xychart-beta/i,
38
+ zenuml: /^zenuml/i
39
+ }.freeze
40
+
41
+ # Test case structure
42
+ class TestCase
43
+ attr_accessor :name, :diagram_type, :source, :source_file, :line_number, :metadata
44
+
45
+ def initialize(name:, type:, source:, file:, line:, metadata: {})
46
+ @name = name
47
+ @diagram_type = type
48
+ @source = source
49
+ @source_file = file
50
+ @line_number = line
51
+ @metadata = metadata
52
+ end
53
+
54
+ def to_mmd_filename
55
+ safe_name = name.gsub(/[^a-zA-Z0-9_-]/, '_').downcase
56
+ "#{safe_name}.mmd"
57
+ end
58
+ end
59
+
60
+ class MermaidTestExtractor
61
+ def initialize
62
+ @test_cases = []
63
+ @stats = Hash.new(0)
64
+ @file_stats = Hash.new(0)
65
+ end
66
+
67
+ def extract_all
68
+ puts "Extracting Mermaid tests from #{MERMAID_JS_ROOT}"
69
+ puts "=" * 80
70
+ puts "Searching for #{DIAGRAM_TYPES.keys.length} diagram types"
71
+ puts "=" * 80
72
+
73
+ extract_cypress_configuration_tests
74
+ extract_cypress_rendering_tests
75
+ extract_cypress_platform_tests
76
+ extract_package_examples
77
+ extract_diagram_parser_tests
78
+ extract_parser_tests
79
+ extract_rendering_spec_files
80
+
81
+ organize_and_save
82
+ print_summary
83
+ end
84
+
85
+ private
86
+
87
+ # 1. cypress/integration/other/configuration.spec.js - all diagram types
88
+ def extract_cypress_configuration_tests
89
+ file = "#{MERMAID_JS_ROOT}/cypress/integration/other/configuration.spec.js"
90
+ return unless File.exist?(file)
91
+
92
+ puts "\n[1/7] Extracting from configuration.spec.js..."
93
+ content = File.read(file)
94
+
95
+ # Build regex pattern for all diagram keywords
96
+ keywords = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '').gsub(/\|/, '\\|') }.join('|')
97
+
98
+ # Find all backtick diagram blocks
99
+ content.scan(/`((?:#{keywords})[^`]*)`/mi) do
100
+ match_pos = $~.begin(0)
101
+ diagram_src = $1.strip
102
+ next if diagram_src.length < 5
103
+
104
+ type = detect_diagram_type(diagram_src)
105
+ next if type == :unknown
106
+
107
+ add_test(
108
+ name: "config_#{type}_#{@stats[type]}",
109
+ type: type,
110
+ source: diagram_src,
111
+ file: file,
112
+ line: content[0...match_pos].count("\n")
113
+ )
114
+ @file_stats[file] += 1
115
+ end
116
+
117
+ puts " Found #{@file_stats[file]} tests"
118
+ end
119
+
120
+ # 2. cypress/integration/rendering/*.{js,ts} - all rendering tests
121
+ def extract_cypress_rendering_tests
122
+ puts "\n[2/7] Extracting from cypress/integration/rendering/*.{js,ts}..."
123
+
124
+ Dir.glob("#{MERMAID_JS_ROOT}/cypress/integration/rendering/*.{js,ts}").each do |file|
125
+ content = File.read(file)
126
+ file_count = 0
127
+
128
+ # Pattern 1: Backtick strings
129
+ keywords_pattern = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '') }.join('|')
130
+ content.scan(/`((?:#{keywords_pattern})[^`]*)`/mi) do
131
+ match_pos = $~.begin(0)
132
+ diagram_src = $1.strip
133
+ type = detect_diagram_type(diagram_src)
134
+ next if type == :unknown
135
+
136
+ add_test(
137
+ name: "rendering_#{File.basename(file, '.*')}_#{type}_#{@stats[type]}",
138
+ type: type,
139
+ source: diagram_src,
140
+ file: file,
141
+ line: content[0...match_pos].count("\n")
142
+ )
143
+ file_count += 1
144
+ end
145
+
146
+ # Pattern 2: Single-quoted strings
147
+ content.scan(/'((?:#{keywords_pattern})[^']*(?:\n[^']*)*?)'/mi) do
148
+ match_pos = $~.begin(0)
149
+ diagram_src = $1.strip
150
+ type = detect_diagram_type(diagram_src)
151
+ next if type == :unknown
152
+
153
+ add_test(
154
+ name: "rendering_#{File.basename(file, '.*')}_#{type}_#{@stats[type]}",
155
+ type: type,
156
+ source: diagram_src,
157
+ file: file,
158
+ line: content[0...match_pos].count("\n")
159
+ )
160
+ file_count += 1
161
+ end
162
+
163
+ @file_stats[file] = file_count
164
+ puts " #{File.basename(file)}: #{file_count} tests" if file_count > 0
165
+ end
166
+ end
167
+
168
+ # 3. cypress/platform/*.html - all HTML embedded diagrams
169
+ def extract_cypress_platform_tests
170
+ puts "\n[3/7] Extracting from cypress/platform/*.html..."
171
+
172
+ Dir.glob("#{MERMAID_JS_ROOT}/cypress/platform/**/*.html").each do |file|
173
+ content = File.read(file)
174
+ file_count = 0
175
+
176
+ # Pattern 1: <pre class="mermaid"> blocks
177
+ content.scan(/<pre\s+class="mermaid"[^>]*>(.*?)<\/pre>/mi) do
178
+ match_pos = $~.begin(0)
179
+ diagram_src = $1.strip
180
+ diagram_src = diagram_src.gsub(/&lt;/, '<').gsub(/&gt;/, '>').gsub(/&amp;/, '&')
181
+ type = detect_diagram_type(diagram_src)
182
+ next if type == :unknown
183
+
184
+ add_test(
185
+ name: "platform_#{File.basename(file, '.html')}_#{type}_#{@stats[type]}",
186
+ type: type,
187
+ source: diagram_src,
188
+ file: file,
189
+ line: content[0...match_pos].count("\n")
190
+ )
191
+ file_count += 1
192
+ end
193
+
194
+ # Pattern 2: <div class="mermaid"> blocks
195
+ content.scan(/<div\s+class="mermaid"[^>]*>(.*?)<\/div>/mi) do
196
+ match_pos = $~.begin(0)
197
+ diagram_src = $1.strip
198
+ diagram_src = diagram_src.gsub(/&lt;/, '<').gsub(/&gt;/, '>').gsub(/&amp;/, '&')
199
+ type = detect_diagram_type(diagram_src)
200
+ next if type == :unknown
201
+
202
+ add_test(
203
+ name: "platform_#{File.basename(file, '.html')}_#{type}_#{@stats[type]}",
204
+ type: type,
205
+ source: diagram_src,
206
+ file: file,
207
+ line: content[0...match_pos].count("\n")
208
+ )
209
+ file_count += 1
210
+ end
211
+
212
+ @file_stats[file] = file_count
213
+ puts " #{File.basename(file)}: #{file_count} tests" if file_count > 0
214
+ end
215
+ end
216
+
217
+ # 4. packages/examples/src/examples/*.ts - official examples
218
+ def extract_package_examples
219
+ puts "\n[4/7] Extracting from packages/examples/src/examples/*.ts..."
220
+
221
+ Dir.glob("#{MERMAID_JS_ROOT}/packages/examples/src/examples/*.ts").each do |file|
222
+ content = File.read(file)
223
+ file_count = 0
224
+
225
+ # Pattern 1: diagram: `...`
226
+ keywords_pattern = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '') }.join('|')
227
+ content.scan(/diagram\s*:\s*`((?:#{keywords_pattern})[^`]*)`/mi) do
228
+ match_pos = $~.begin(0)
229
+ diagram_src = $1.strip
230
+ type = detect_diagram_type(diagram_src)
231
+ next if type == :unknown
232
+
233
+ add_test(
234
+ name: "example_#{File.basename(file, '.ts')}_#{@stats[type]}",
235
+ type: type,
236
+ source: diagram_src,
237
+ file: file,
238
+ line: content[0...match_pos].count("\n")
239
+ )
240
+ file_count += 1
241
+ end
242
+
243
+ # Pattern 2: code: `...` or src: `...`
244
+ content.scan(/(?:code|src)\s*:\s*`((?:#{keywords_pattern})[^`]*)`/mi) do
245
+ match_pos = $~.begin(0)
246
+ diagram_src = $1.strip
247
+ type = detect_diagram_type(diagram_src)
248
+ next if type == :unknown
249
+
250
+ add_test(
251
+ name: "example_#{File.basename(file, '.ts')}_#{@stats[type]}",
252
+ type: type,
253
+ source: diagram_src,
254
+ file: file,
255
+ line: content[0...match_pos].count("\n")
256
+ )
257
+ file_count += 1
258
+ end
259
+
260
+ @file_stats[file] = file_count
261
+ puts " #{File.basename(file)}: #{file_count} tests" if file_count > 0
262
+ end
263
+ end
264
+
265
+ # 5. packages/mermaid/src/diagrams/**/*.{spec,test}.{ts,js} - parser tests
266
+ def extract_diagram_parser_tests
267
+ puts "\n[5/7] Extracting from packages/mermaid/src/diagrams/**/*.{spec,test}.{ts,js}..."
268
+
269
+ Dir.glob("#{MERMAID_JS_ROOT}/packages/mermaid/src/diagrams/**/*.{spec,test}.{ts,js}").each do |file|
270
+ content = File.read(file)
271
+ file_count = 0
272
+
273
+ # Pattern 1: it/test with const str = string concatenation
274
+ content.scan(/(?:it|test)\s*\(\s*['"]([^'"]+)['"]\s*,\s*(?:function\s*\(\s*\)\s*\{|\(\s*\)\s*=>|async\s*(?:function\s*)?\(\s*\)\s*(?:=>)?\s*\{)(.*?)(?:parser\.parse|expect)/mi) do
275
+ match_pos = $~.begin(0)
276
+ test_name = $1
277
+ test_body = $2
278
+ if test_body =~ /const\s+str\s*=\s*([^;]+);/mi
279
+ str_value = $1
280
+ diagram_src = extract_concatenated_string(str_value)
281
+ type = detect_diagram_type(diagram_src)
282
+ next if type == :unknown || diagram_src.length < 5
283
+
284
+ add_test(
285
+ name: "parser_#{sanitize_test_name(test_name)}_#{@stats[type]}",
286
+ type: type,
287
+ source: diagram_src.strip,
288
+ file: file,
289
+ line: content[0...match_pos].count("\n"),
290
+ metadata: { test_name: test_name }
291
+ )
292
+ file_count += 1
293
+ end
294
+ end
295
+
296
+ # Pattern 2: Direct backtick strings in tests
297
+ keywords_pattern = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '') }.join('|')
298
+ content.scan(/(?:it|test)\s*\(\s*['"]([^'"]+)['"]\s*,.*?`((?:#{keywords_pattern})[^`]*)`/mi) do
299
+ match_pos = $~.begin(0)
300
+ test_name = $1
301
+ diagram_src = $2
302
+ type = detect_diagram_type(diagram_src)
303
+ next if type == :unknown
304
+
305
+ add_test(
306
+ name: "parser_#{sanitize_test_name(test_name)}_#{@stats[type]}",
307
+ type: type,
308
+ source: diagram_src.strip,
309
+ file: file,
310
+ line: content[0...match_pos].count("\n"),
311
+ metadata: { test_name: test_name }
312
+ )
313
+ file_count += 1
314
+ end
315
+
316
+ @file_stats[file] = file_count
317
+ puts " #{File.basename(file)}: #{file_count} tests" if file_count > 0
318
+ end
319
+ end
320
+
321
+ # 6. packages/parser/tests/*.{spec,test}.{ts,js} - parser package tests
322
+ def extract_parser_tests
323
+ puts "\n[6/7] Extracting from packages/parser/tests/*.{spec,test}.{ts,js}..."
324
+
325
+ Dir.glob("#{MERMAID_JS_ROOT}/packages/parser/tests/**/*.{spec,test}.{ts,js}").each do |file|
326
+ content = File.read(file)
327
+ file_count = 0
328
+
329
+ keywords_pattern = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '') }.join('|')
330
+
331
+ # Backtick strings
332
+ content.scan(/`((?:#{keywords_pattern})[^`]*)`/mi) do
333
+ match_pos = $~.begin(0)
334
+ diagram_src = $1.strip
335
+ type = detect_diagram_type(diagram_src)
336
+ next if type == :unknown
337
+
338
+ add_test(
339
+ name: "parsertest_#{File.basename(file, '.*')}_#{@stats[type]}",
340
+ type: type,
341
+ source: diagram_src,
342
+ file: file,
343
+ line: content[0...match_pos].count("\n")
344
+ )
345
+ file_count += 1
346
+ end
347
+
348
+ @file_stats[file] = file_count
349
+ puts " #{File.basename(file)}: #{file_count} tests" if file_count > 0
350
+ end
351
+ end
352
+
353
+ # 7. Additional rendering spec files
354
+ def extract_rendering_spec_files
355
+ puts "\n[7/7] Scanning additional spec files..."
356
+
357
+ # Check for any missed spec files
358
+ additional_patterns = [
359
+ "#{MERMAID_JS_ROOT}/cypress/integration/**/*.spec.{js,ts}",
360
+ "#{MERMAID_JS_ROOT}/packages/mermaid/src/**/*.spec.{ts,js}"
361
+ ]
362
+
363
+ additional_patterns.each do |pattern|
364
+ Dir.glob(pattern).each do |file|
365
+ next if @file_stats[file] && @file_stats[file] > 0 # Skip already processed
366
+
367
+ content = File.read(file)
368
+ file_count = 0
369
+
370
+ keywords_pattern = DIAGRAM_TYPES.values.map { |r| r.source.gsub(/[\\^$]/, '') }.join('|')
371
+
372
+ content.scan(/[`'"]((?:#{keywords_pattern})[^`'"]*)[`'"]/mi) do
373
+ match_pos = $~.begin(0)
374
+ diagram_src = $1.strip
375
+ type = detect_diagram_type(diagram_src)
376
+ next if type == :unknown || diagram_src.length < 5
377
+
378
+ add_test(
379
+ name: "spec_#{File.basename(file, '.*')}_#{@stats[type]}",
380
+ type: type,
381
+ source: diagram_src,
382
+ file: file,
383
+ line: content[0...match_pos].count("\n")
384
+ )
385
+ file_count += 1
386
+ end
387
+
388
+ if file_count > 0
389
+ @file_stats[file] = file_count
390
+ puts " #{File.basename(file)}: #{file_count} tests"
391
+ end
392
+ end
393
+ end
394
+ end
395
+
396
+ def extract_concatenated_string(str_value)
397
+ parts = []
398
+ # Match both single and double quoted strings, handling escaped characters
399
+ str_value.scan(/['"]([^'"\\]*(?:\\.[^'"\\]*)*)['"]/) do |match|
400
+ parts << match[0].gsub(/\\n/, "\n").gsub(/\\t/, "\t").gsub(/\\"/, '"').gsub(/\\'/, "'")
401
+ end
402
+ parts.join('')
403
+ end
404
+
405
+ def detect_diagram_type(source)
406
+ return :unknown if source.nil? || source.empty?
407
+
408
+ # Try each diagram type pattern
409
+ DIAGRAM_TYPES.each do |type, pattern|
410
+ return type if source.strip =~ pattern
411
+ end
412
+
413
+ :unknown
414
+ end
415
+
416
+ def sanitize_test_name(name)
417
+ name.gsub(/[^a-zA-Z0-9_-]/, '_').gsub(/_+/, '_')
418
+ end
419
+
420
+ def add_test(name:, type:, source:, file:, line:, metadata: {})
421
+ @test_cases << TestCase.new(
422
+ name: name,
423
+ type: type,
424
+ source: source,
425
+ file: file,
426
+ line: line,
427
+ metadata: metadata
428
+ )
429
+ @stats[type] += 1
430
+ end
431
+
432
+ def organize_and_save
433
+ puts "\n" + "=" * 80
434
+ puts "Organizing extracted tests..."
435
+ puts "=" * 80
436
+
437
+ FileUtils.mkdir_p(OUTPUT_DIR)
438
+
439
+ by_type = @test_cases.group_by(&:diagram_type)
440
+
441
+ by_type.each do |type, cases|
442
+ type_dir = "#{OUTPUT_DIR}/#{type}"
443
+ FileUtils.mkdir_p(type_dir)
444
+
445
+ cases.each_with_index do |test_case, idx|
446
+ filename = "#{type_dir}/#{sprintf('%03d', idx+1)}_#{test_case.to_mmd_filename}"
447
+ File.write(filename, test_case.source)
448
+
449
+ # Write metadata
450
+ meta_file = filename.sub('.mmd', '.meta.json')
451
+ File.write(meta_file, JSON.pretty_generate({
452
+ name: test_case.name,
453
+ type: test_case.diagram_type,
454
+ source_file: test_case.source_file.sub(MERMAID_JS_ROOT, ''),
455
+ line_number: test_case.line_number,
456
+ metadata: test_case.metadata
457
+ }))
458
+ end
459
+
460
+ puts " ✓ #{type}: #{cases.length} test cases"
461
+ end
462
+ end
463
+
464
+ def print_summary
465
+ puts "\n" + "=" * 80
466
+ puts "EXTRACTION COMPLETE"
467
+ puts "=" * 80
468
+ puts "Total test cases extracted: #{@test_cases.length}"
469
+ puts "Files processed: #{@file_stats.length}"
470
+ puts "\nBy diagram type (sorted by count):"
471
+ @stats.sort_by { |_,v| -v }.each do |type, count|
472
+ puts " #{sprintf('%-20s', type)}: #{sprintf('%4d', count)} tests"
473
+ end
474
+ puts "\nOutput directory: #{OUTPUT_DIR}"
475
+
476
+ # Show diagram types with no tests
477
+ missing = DIAGRAM_TYPES.keys - @stats.keys
478
+ if missing.any?
479
+ puts "\nDiagram types with no tests found:"
480
+ missing.each { |type| puts " ⚠ #{type}" }
481
+ end
482
+
483
+ puts "\nNext steps:"
484
+ puts " 1. Review extracted tests in spec/mermaid/"
485
+ puts " 2. Run: ruby scripts/create_diagram_inventory.rb"
486
+ puts " 3. Generate fixtures: bundle exec rake fixtures:generate_from_mermaidjs"
487
+ puts " 4. Create RSpec tests for each type"
488
+ end
489
+ end
490
+
491
+ # Run extraction
492
+ extractor = MermaidTestExtractor.new
493
+ extractor.extract_all
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+ # Script to rename sirena to sirena throughout the codebase
3
+
4
+ require 'fileutils'
5
+
6
+ PROJECT_ROOT = File.expand_path('../..', __FILE__)
7
+
8
+ puts "Renaming project from sirena to sirena..."
9
+ puts "Project root: #{PROJECT_ROOT}"
10
+
11
+ # Step 1: Rename directories
12
+ puts "\n1. Renaming directories..."
13
+ Dir.chdir(PROJECT_ROOT) do
14
+ if Dir.exist?('lib/sirena')
15
+ FileUtils.mv('lib/sirena', 'lib/sirena')
16
+ puts " ✓ Renamed lib/sirena -> lib/sirena"
17
+ end
18
+ end
19
+
20
+ # Step 2: Rename files
21
+ puts "\n2. Renaming files..."
22
+ Dir.chdir(PROJECT_ROOT) do
23
+ # Rename gemspec
24
+ if File.exist?('sirena.gemspec')
25
+ FileUtils.mv('sirena.gemspec', 'sirena.gemspec')
26
+ puts " ✓ Renamed sirena.gemspec -> sirena.gemspec"
27
+ end
28
+
29
+ # Rename executable
30
+ if File.exist?('exe/sirena')
31
+ FileUtils.mv('exe/sirena', 'exe/sirena')
32
+ puts " ✓ Renamed exe/sirena -> exe/sirena"
33
+ end
34
+ end
35
+
36
+ # Step 3: Update file contents
37
+ puts "\n3. Updating file contents..."
38
+ replacements = {
39
+ 'sirena' => 'sirena',
40
+ 'sirena' => 'sirena',
41
+ 'Sirena' => 'Sirena',
42
+ 'SIRENA' => 'SIRENA'
43
+ }
44
+
45
+ files_to_update = Dir.glob("#{PROJECT_ROOT}/**/*.{rb,gemspec,md,adoc,rake}",
46
+ File::FNM_DOTMATCH).reject do |f|
47
+ f.include?('/.git/') ||
48
+ f.include?('/vendor/') ||
49
+ f.include?('/node_modules/')
50
+ end
51
+
52
+ files_updated = 0
53
+ files_to_update.each do |file_path|
54
+ content = File.read(file_path)
55
+ original = content.dup
56
+
57
+ replacements.each do |old_val, new_val|
58
+ content.gsub!(old_val, new_val)
59
+ end
60
+
61
+ if content != original
62
+ File.write(file_path, content)
63
+ files_updated += 1
64
+ puts " ✓ Updated #{file_path.sub(PROJECT_ROOT + '/', '')}"
65
+ end
66
+ end
67
+
68
+ puts "\n✓ Rename complete!"
69
+ puts " - #{files_updated} files updated"
70
+ puts "\nNext steps:"
71
+ puts " 1. Review changes with: git diff"
72
+ puts " 2. Run tests: bundle exec rspec"
73
+ puts " 3. Update any remaining manual references"
data/sirena.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/sirena/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sirena'
7
+ spec.version = Sirena::VERSION
8
+ spec.authors = ['Ribose Inc.']
9
+ spec.email = ['open.source@ribose.com']
10
+
11
+ spec.summary = 'Pure Ruby Mermaid diagram renderer with SVG output'
12
+ spec.description = 'Sirena is a pure Ruby implementation of Mermaid ' \
13
+ 'diagram rendering. It parses Mermaid syntax and ' \
14
+ 'generates SVG output using Parslet grammars and ' \
15
+ 'ELK layout. Supports 24 diagram types: flowcharts, ' \
16
+ 'sequence, class, state, ER, C4, block, architecture, ' \
17
+ 'Gantt, timeline, Git graph, mindmap, Kanban, user journey, ' \
18
+ 'pie, quadrant, radar, XY charts, requirement, Sankey, ' \
19
+ 'packet, treemap, info, and error displays.'
20
+ spec.homepage = 'https://github.com/claricle/sirena'
21
+ spec.license = 'BSD-2-Clause'
22
+ spec.required_ruby_version = '>= 2.7.0'
23
+
24
+ spec.metadata['homepage_uri'] = spec.homepage
25
+ spec.metadata['source_code_uri'] = spec.homepage
26
+ spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
27
+
28
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
+ `git ls-files -z`.split("\x0").reject do |f|
30
+ f.match(%r{^(test|spec|features)/})
31
+ end
32
+ end
33
+ spec.bindir = 'exe'
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ['lib']
36
+
37
+ # TODO: Uncomment when elkrb is available
38
+ # spec.add_dependency "elkrb"
39
+ spec.add_dependency 'lutaml-model', '~> 0.7'
40
+ spec.add_dependency 'moxml'
41
+ spec.add_dependency 'plurimath-parslet', '~> 3.0'
42
+ spec.add_dependency 'thor'
43
+
44
+ spec.add_development_dependency 'rake'
45
+ spec.add_development_dependency 'rspec'
46
+ spec.add_development_dependency 'rubocop'
47
+ end