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,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "grammars/architecture"
5
+ require_relative "transforms/architecture"
6
+
7
+ module Sirena
8
+ module Parser
9
+ # Parser for architecture diagrams
10
+ class Architecture < Base
11
+ def parse(input)
12
+ input = input.strip
13
+
14
+ grammar = Grammars::Architecture.new
15
+ tree = grammar.parse(input)
16
+
17
+ transform = Transforms::Architecture.new
18
+ transform.apply(tree)
19
+ rescue Parslet::ParseFailed => e
20
+ raise ParseError, format_error(e, input)
21
+ end
22
+
23
+ private
24
+
25
+ def format_error(error, input)
26
+ lines = input.split("\n")
27
+ line_no = error.parse_failure_cause.source.line_and_column[0]
28
+ column = error.parse_failure_cause.source.line_and_column[1]
29
+
30
+ context = []
31
+ context << lines[line_no - 2] if line_no > 1
32
+ context << lines[line_no - 1] if line_no > 0
33
+ context << " " * (column - 1) + "^"
34
+
35
+ "Parse error at line #{line_no}, column #{column}:\n" \
36
+ "#{context.join("\n")}\n" \
37
+ "#{error.parse_failure_cause.message}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sirena
4
+ module Parser
5
+ # Abstract base class for diagram parsers.
6
+ #
7
+ # This class defines the interface that all diagram-specific parsers
8
+ # must implement. Parsers are responsible for converting source code
9
+ # into a typed diagram model using Parslet grammars.
10
+ #
11
+ # @example Define a custom parser
12
+ # class FlowchartParser < Parser::Base
13
+ # def parse(source)
14
+ # grammar = Grammars::Flowchart.new
15
+ # tree = grammar.parse(source)
16
+ # transform = Transforms::Flowchart.new
17
+ # transform.apply(tree)
18
+ # end
19
+ # end
20
+ #
21
+ # @abstract Subclass and implement #parse
22
+ class Base
23
+
24
+ # Parses Mermaid source code into a diagram model.
25
+ #
26
+ # This method should be overridden by subclasses to implement
27
+ # diagram-specific parsing logic using Parslet grammars.
28
+ #
29
+ # @param source [String] the Mermaid source code to parse
30
+ # @return [Diagram::Base] the parsed diagram model
31
+ # @raise [NotImplementedError] if not implemented by subclass
32
+ def parse(source)
33
+ raise NotImplementedError,
34
+ "#{self.class} must implement #parse(source)"
35
+ end
36
+ end
37
+
38
+ # Error raised during parsing.
39
+ class ParseError < StandardError; end
40
+ end
41
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/block'
5
+ require_relative 'transforms/block'
6
+ require_relative '../diagram/block'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Block diagram parser for Mermaid block diagram syntax.
11
+ #
12
+ # Parses block diagrams with support for:
13
+ # - Column-based layouts
14
+ # - Blocks with various shapes (rectangle, circle)
15
+ # - Block width specifications
16
+ # - Compound/nested blocks
17
+ # - Space placeholders
18
+ # - Arrow blocks with directions
19
+ # - Connections between blocks
20
+ # - Styling directives
21
+ #
22
+ # @example Parse a simple block diagram
23
+ # parser = BlockParser.new
24
+ # diagram = parser.parse("block-beta\n columns 2\n A\n B")
25
+ class BlockParser < Base
26
+ # Parses block diagram source into a BlockDiagram model.
27
+ #
28
+ # @param source [String] the Mermaid block diagram source
29
+ # @return [Diagram::BlockDiagram] the parsed block diagram
30
+ # @raise [ParseError] if syntax is invalid
31
+ def parse(source)
32
+ grammar = Grammars::Block.new
33
+
34
+ begin
35
+ tree = grammar.parse(source)
36
+ diagram = Transforms::Block.apply(tree)
37
+ diagram
38
+ rescue Parslet::ParseFailed => e
39
+ raise ParseError, format_parse_error(e, source)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ # Formats a Parslet parse error with context.
46
+ #
47
+ # @param error [Parslet::ParseFailed] the parse error
48
+ # @param source [String] the source that failed to parse
49
+ # @return [String] formatted error message
50
+ def format_parse_error(error, source)
51
+ lines = source.lines
52
+ line_num = error.parse_failure_cause.source.line_and_column[0]
53
+ col_num = error.parse_failure_cause.source.line_and_column[1]
54
+
55
+ context = []
56
+ context << "Parse error at line #{line_num}, column #{col_num}:"
57
+
58
+ # Show the problematic line
59
+ if line_num > 0 && line_num <= lines.length
60
+ context << lines[line_num - 1].chomp
61
+ context << (' ' * (col_num - 1)) + '^'
62
+ end
63
+
64
+ context << error.parse_failure_cause.to_s
65
+ context.join("\n")
66
+ rescue StandardError
67
+ # Fallback to simple error message
68
+ "Parse error: #{error.message}"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/c4'
5
+ require_relative 'transforms/c4'
6
+ require_relative '../diagram/c4'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # C4 parser for Mermaid C4 diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle C4 diagram syntax including
13
+ # elements, relationships, and boundaries.
14
+ #
15
+ # Parses C4 diagrams with support for:
16
+ # - Multiple C4 levels (Context, Container, Component, Dynamic, Deployment)
17
+ # - Person, System, Container, Component elements
18
+ # - External variants (_Ext suffix)
19
+ # - Database and Queue variants (SystemDb, ContainerQueue, etc.)
20
+ # - Relationships (Rel, BiRel)
21
+ # - Boundaries (Enterprise_Boundary, System_Boundary, Boundary)
22
+ # - Nested boundaries
23
+ # - Element attributes (sprite, link, tags)
24
+ # - Layout configuration
25
+ #
26
+ # @example Parse a simple C4 Context diagram
27
+ # parser = C4Parser.new
28
+ # diagram = parser.parse("C4Context\ntitle My System\nPerson(user, \"User\")")
29
+ class C4Parser < Base
30
+ # Parses C4 diagram source into a C4 diagram model.
31
+ #
32
+ # @param source [String] the Mermaid C4 diagram source
33
+ # @return [Diagram::C4] the parsed C4 diagram
34
+ # @raise [ParseError] if syntax is invalid
35
+ def parse(source)
36
+ grammar = Grammars::C4.new
37
+
38
+ begin
39
+ parse_tree = grammar.parse(source)
40
+ rescue Parslet::ParseFailed => e
41
+ raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
42
+ "#{e.parse_failure_cause}"
43
+ end
44
+
45
+ # Transform parse tree to diagram model
46
+ transform = Transforms::C4.new
47
+ diagram = transform.apply(parse_tree)
48
+
49
+ diagram
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/class_diagram'
5
+ require_relative 'transforms/class_diagram'
6
+ require_relative '../diagram/class_diagram'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Class diagram parser for Mermaid class diagram syntax.
11
+ #
12
+ # Parses class diagrams with support for:
13
+ # - Class declarations with stereotypes
14
+ # - Attributes with visibility modifiers
15
+ # - Methods with parameters and return types
16
+ # - Relationships (inheritance, composition, aggregation, association)
17
+ # - Generic types (e.g., List~String~)
18
+ # - Namespaces
19
+ # - Cardinality labels
20
+ #
21
+ # @example Parse a simple class diagram
22
+ # parser = ClassDiagramParser.new
23
+ # diagram = parser.parse("classDiagram\nAnimal <|-- Dog")
24
+ class ClassDiagramParser < Base
25
+ # Parses class diagram source into a ClassDiagram model.
26
+ #
27
+ # @param source [String] the Mermaid class diagram source
28
+ # @return [Diagram::ClassDiagram] the parsed class diagram
29
+ # @raise [ParseError] if syntax is invalid
30
+ def parse(source)
31
+ grammar = Grammars::ClassDiagram.new
32
+ transform = Transforms::ClassDiagram.new
33
+
34
+ begin
35
+ parse_tree = grammar.parse(source)
36
+ diagram = transform.apply(parse_tree)
37
+ diagram
38
+ rescue Parslet::ParseFailed => e
39
+ raise ParseError, format_parse_error(e, source)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def format_parse_error(error, source)
46
+ lines = source.lines
47
+ line_num = error.parse_failure_cause.source.line_and_column[0]
48
+ col_num = error.parse_failure_cause.source.line_and_column[1]
49
+
50
+ context = if line_num <= lines.length
51
+ lines[line_num - 1].chomp
52
+ else
53
+ '(end of input)'
54
+ end
55
+
56
+ "Parse error at line #{line_num}, column #{col_num}:\n" \
57
+ "#{context}\n" \
58
+ "#{' ' * (col_num - 1)}^\n" \
59
+ "Expected: #{error.parse_failure_cause.message}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative '../diagram/er_diagram'
5
+ require_relative 'grammars/er_diagram'
6
+ require_relative 'transforms/er_diagram'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # ER diagram parser for Mermaid ER diagram syntax.
11
+ #
12
+ # Parses ER diagrams with support for:
13
+ # - Entity declarations with attributes
14
+ # - Attribute types and key markers (PK, FK, UK)
15
+ # - Relationships with cardinality notation
16
+ # - Identifying and non-identifying relationships
17
+ #
18
+ # @example Parse a simple ER diagram
19
+ # parser = ErDiagramParser.new
20
+ # diagram = parser.parse("erDiagram\nCUSTOMER ||--o{ ORDER : places")
21
+ class ErDiagramParser < Base
22
+ # Parses ER diagram source into an ErDiagram model.
23
+ #
24
+ # @param source [String] the Mermaid ER diagram source
25
+ # @return [Diagram::ErDiagram] the parsed ER diagram
26
+ # @raise [ParseError] if syntax is invalid
27
+ def parse(source)
28
+ grammar = Grammars::ErDiagram.new
29
+ transform = Transforms::ErDiagram.new
30
+
31
+ tree = grammar.parse(source)
32
+ diagram = transform.apply(tree)
33
+
34
+ diagram
35
+ rescue Parslet::ParseFailed => e
36
+ raise ParseError, e.parse_failure_cause.ascii_tree
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/error'
5
+ require_relative 'transforms/error'
6
+ require_relative '../diagram/error'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Error diagram parser for Mermaid error diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle simple error diagrams.
13
+ #
14
+ # Parses error diagrams with support for:
15
+ # - Basic error keyword
16
+ # - Optional error message text
17
+ #
18
+ # @example Parse a simple error diagram
19
+ # parser = ErrorParser.new
20
+ # diagram = parser.parse("error")
21
+ #
22
+ # @example Parse error diagram with message
23
+ # parser = ErrorParser.new
24
+ # diagram = parser.parse("Error Diagrams")
25
+ class ErrorParser < Base
26
+ # Parses error diagram source into an Error diagram model.
27
+ #
28
+ # @param source [String] the Mermaid error diagram source
29
+ # @return [Diagram::Error] the parsed error diagram
30
+ # @raise [ParseError] if syntax is invalid
31
+ def parse(source)
32
+ grammar = Grammars::Error.new
33
+
34
+ begin
35
+ parse_tree = grammar.parse(source)
36
+ rescue Parslet::ParseFailed => e
37
+ raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
38
+ "#{e.parse_failure_cause}"
39
+ end
40
+
41
+ # Transform parse tree to diagram model
42
+ transform = Transforms::Error.new
43
+ diagram = transform.apply(parse_tree)
44
+
45
+ diagram
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/flowchart'
5
+ require_relative 'transforms/flowchart'
6
+ require_relative '../diagram/flowchart'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Flowchart parser for Mermaid flowchart syntax.
11
+ #
12
+ # Parses flowchart diagrams with support for:
13
+ # - Multiple node shapes (rectangle, rounded, rhombus, circle, etc.)
14
+ # - Multiple edge types (arrow, line, dotted, etc.)
15
+ # - Node labels with special characters
16
+ # - Edge chaining (A --> B --> C)
17
+ # - Subgraphs
18
+ # - Styling directives
19
+ # - Direction specification (TD, LR, etc.)
20
+ #
21
+ # @example Parse a simple flowchart
22
+ # parser = FlowchartParser.new
23
+ # diagram = parser.parse("graph TD\nA[Start]-->B[End]")
24
+ class FlowchartParser < Base
25
+ # Parses flowchart source into a Flowchart diagram model.
26
+ #
27
+ # @param source [String] the Mermaid flowchart source
28
+ # @return [Diagram::Flowchart] the parsed flowchart
29
+ # @raise [ParseError] if syntax is invalid
30
+ def parse(source)
31
+ grammar = Grammars::Flowchart.new
32
+
33
+ begin
34
+ tree = grammar.parse(source)
35
+ diagram = Transforms::Flowchart.apply(tree)
36
+ diagram
37
+ rescue Parslet::ParseFailed => e
38
+ raise ParseError, format_parse_error(e, source)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # Formats a Parslet parse error with context.
45
+ #
46
+ # @param error [Parslet::ParseFailed] the parse error
47
+ # @param source [String] the source that failed to parse
48
+ # @return [String] formatted error message
49
+ def format_parse_error(error, source)
50
+ lines = source.lines
51
+ line_num = error.parse_failure_cause.source.line_and_column[0]
52
+ col_num = error.parse_failure_cause.source.line_and_column[1]
53
+
54
+ context = []
55
+ context << "Parse error at line #{line_num}, column #{col_num}:"
56
+
57
+ # Show the problematic line
58
+ if line_num > 0 && line_num <= lines.length
59
+ context << lines[line_num - 1].chomp
60
+ context << (' ' * (col_num - 1)) + '^'
61
+ end
62
+
63
+ context << error.parse_failure_cause.to_s
64
+ context.join("\n")
65
+ rescue StandardError
66
+ # Fallback to simple error message
67
+ "Parse error: #{error.message}"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "grammars/gantt"
5
+ require_relative "transforms/gantt"
6
+ require_relative "../diagram/gantt"
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Gantt chart parser for Mermaid gantt diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle Gantt chart syntax
13
+ # with sections, tasks, dependencies, and timeline configuration.
14
+ #
15
+ # Parses Gantt charts with support for:
16
+ # - Title and date format declarations
17
+ # - Axis formatting and tick intervals
18
+ # - Excludes (weekends, weekdays, specific dates)
19
+ # - Section grouping
20
+ # - Tasks with dates, durations, and dependencies
21
+ # - Task status tags (done, active, crit, milestone)
22
+ # - Click handlers for interactivity
23
+ # - Accessibility features (accTitle, accDescr)
24
+ # - Comments
25
+ #
26
+ # @example Parse a simple Gantt chart
27
+ # parser = GanttParser.new
28
+ # diagram = parser.parse(<<~GANTT)
29
+ # gantt
30
+ # title Project Timeline
31
+ # dateFormat YYYY-MM-DD
32
+ # section Planning
33
+ # Task 1 :a1, 2024-01-01, 30d
34
+ # Task 2 :after a1, 20d
35
+ # GANTT
36
+ class GanttParser < Base
37
+ # Parses Gantt chart diagram source into a GanttChart diagram model.
38
+ #
39
+ # @param source [String] the Mermaid Gantt chart diagram source
40
+ # @return [Diagram::GanttChart] the parsed Gantt chart diagram
41
+ # @raise [ParseError] if syntax is invalid
42
+ def parse(source)
43
+ grammar = Grammars::Gantt.new
44
+
45
+ begin
46
+ parse_tree = grammar.parse(source)
47
+ rescue Parslet::ParseFailed => e
48
+ raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
49
+ "#{e.parse_failure_cause}"
50
+ end
51
+
52
+ # Transform parse tree to diagram model
53
+ transform = Transforms::Gantt.new
54
+ diagram = transform.apply(parse_tree)
55
+
56
+ diagram
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "grammars/git_graph"
5
+ require_relative "transforms/git_graph"
6
+ require_relative "../diagram/git_graph"
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Git Graph parser for Mermaid gitGraph diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle git graph syntax
13
+ # with commits, branches, merges, and cherry-picks.
14
+ #
15
+ # Parses git graphs with support for:
16
+ # - Commit declarations with id, type, and tag
17
+ # - Branch creation with optional order
18
+ # - Checkout/switch operations
19
+ # - Merge operations
20
+ # - Cherry-pick operations
21
+ # - Commit types (NORMAL, REVERSE, HIGHLIGHT)
22
+ #
23
+ # @example Parse a simple git graph
24
+ # parser = GitGraphParser.new
25
+ # source = <<~MERMAID
26
+ # gitGraph
27
+ # commit id: "Initial"
28
+ # branch develop
29
+ # checkout develop
30
+ # commit id: "Feature"
31
+ # checkout main
32
+ # merge develop
33
+ # MERMAID
34
+ # diagram = parser.parse(source)
35
+ class GitGraphParser < Base
36
+ # Parses git graph diagram source into a GitGraph model.
37
+ #
38
+ # @param source [String] the Mermaid git graph diagram source
39
+ # @return [Diagram::GitGraph] the parsed git graph diagram
40
+ # @raise [ParseError] if syntax is invalid
41
+ def parse(source)
42
+ grammar = Grammars::GitGraph.new
43
+
44
+ begin
45
+ parse_tree = grammar.parse(source)
46
+ rescue Parslet::ParseFailed => e
47
+ raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
48
+ "#{e.parse_failure_cause}"
49
+ end
50
+
51
+ # Transform parse tree to diagram model
52
+ transform = Transforms::GitGraph.new
53
+ result = transform.apply(parse_tree)
54
+
55
+ # Create the diagram model
56
+ create_diagram(result)
57
+ end
58
+
59
+ private
60
+
61
+ def create_diagram(result)
62
+ diagram = Diagram::GitGraph.new
63
+
64
+ # Add commits
65
+ result[:commits].each do |commit_data|
66
+ commit = Diagram::GitGraph::Commit.new(
67
+ id: commit_data[:id],
68
+ type: commit_data[:type],
69
+ tag: commit_data[:tag],
70
+ branch_name: commit_data[:branch_name],
71
+ parent_ids: commit_data[:parent_ids],
72
+ is_merge: commit_data[:is_merge],
73
+ merge_branch: commit_data[:merge_branch],
74
+ is_cherry_pick: commit_data[:is_cherry_pick],
75
+ cherry_pick_parent: commit_data[:cherry_pick_parent]
76
+ )
77
+ diagram.commits << commit
78
+ end
79
+
80
+ # Add branches
81
+ result[:branches].each do |branch_data|
82
+ branch = Diagram::GitGraph::Branch.new(
83
+ name: branch_data[:name],
84
+ order: branch_data[:order],
85
+ parent_branch: branch_data[:parent_branch],
86
+ created_at_commit: branch_data[:created_at_commit]
87
+ )
88
+ diagram.branches << branch
89
+ end
90
+
91
+ diagram
92
+ end
93
+ end
94
+ end
95
+ end