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,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for State diagrams.
9
+ #
10
+ # Handles State diagram syntax including states, transitions,
11
+ # composite states, special state markers (choice, fork, join),
12
+ # and concurrent states.
13
+ class StateDiagram < Common
14
+ root(:diagram)
15
+
16
+ # Main diagram structure
17
+ rule(:diagram) do
18
+ ws? >>
19
+ header >>
20
+ ws? >>
21
+ statements.maybe >>
22
+ ws?
23
+ end
24
+
25
+ rule(:header) do
26
+ (str('stateDiagram-v2') | str('stateDiagram')).as(:header) >>
27
+ ws? >>
28
+ direction.maybe.as(:direction)
29
+ end
30
+
31
+ rule(:direction) do
32
+ (str('TD') | str('TB') | str('LR') | str('RL')).as(:dir_value)
33
+ end
34
+
35
+ rule(:statements) do
36
+ (statement >> ws?).repeat(1)
37
+ end
38
+
39
+ rule(:statement) do
40
+ state_declaration |
41
+ transition |
42
+ note_statement |
43
+ standalone_state
44
+ end
45
+
46
+ # State declaration with description, marker, or composite body
47
+ rule(:state_declaration) do
48
+ str('state').as(:keyword) >> space >>
49
+ state_id.as(:state_id) >> space? >>
50
+ (
51
+ state_marker.as(:marker) |
52
+ state_description.as(:description) |
53
+ composite_body.as(:composite)
54
+ ).maybe >>
55
+ line_end
56
+ end
57
+
58
+ # Transition between states
59
+ rule(:transition) do
60
+ from_state.as(:from) >> space? >>
61
+ arrow >>
62
+ space? >>
63
+ to_state.as(:to) >>
64
+ transition_label.maybe.as(:label) >>
65
+ (
66
+ space? >> arrow >> space? >> to_state.as(:chain_to)
67
+ ).repeat.as(:chain) >>
68
+ line_end
69
+ end
70
+
71
+ # Note statement
72
+ rule(:note_statement) do
73
+ str('note').as(:note_keyword) >> space >>
74
+ note_position.as(:position) >> space >>
75
+ str('of') >> space >>
76
+ state_id.as(:note_target) >> space? >>
77
+ (colon >> space? >> note_text.as(:note_text)).maybe >>
78
+ line_end
79
+ end
80
+
81
+ # Standalone state (just an identifier)
82
+ rule(:standalone_state) do
83
+ state_id.as(:state_id) >> line_end
84
+ end
85
+
86
+ # From state in transition
87
+ rule(:from_state) do
88
+ start_end_marker | state_id
89
+ end
90
+
91
+ # To state in transition
92
+ rule(:to_state) do
93
+ start_end_marker | state_id
94
+ end
95
+
96
+ # Start/end marker [*]
97
+ rule(:start_end_marker) do
98
+ lbracket >> asterisk >> rbracket
99
+ end
100
+
101
+ # State ID (identifier or quoted string)
102
+ rule(:state_id) do
103
+ string | identifier
104
+ end
105
+
106
+ # State description (after colon)
107
+ rule(:state_description) do
108
+ colon >> space? >>
109
+ (line_end.absent? >> lbrace.absent? >> any).repeat(1)
110
+ end
111
+
112
+ # State marker: <<choice>>, <<fork>>, <<join>>
113
+ rule(:state_marker) do
114
+ str('<<') >>
115
+ (str('choice') | str('fork') | str('join')).as(:marker_type) >>
116
+ str('>>')
117
+ end
118
+
119
+ # Composite state body with nested statements
120
+ rule(:composite_body) do
121
+ lbrace >> ws? >>
122
+ composite_statements.maybe >>
123
+ ws? >> rbrace
124
+ end
125
+
126
+ # Statements within composite state
127
+ rule(:composite_statements) do
128
+ (composite_statement >> ws?).repeat(1)
129
+ end
130
+
131
+ rule(:composite_statement) do
132
+ concurrent_separator |
133
+ state_declaration |
134
+ transition |
135
+ note_statement |
136
+ standalone_state
137
+ end
138
+
139
+ # Concurrent state separator
140
+ rule(:concurrent_separator) do
141
+ str('--').as(:concurrent_sep) >> line_end
142
+ end
143
+
144
+ # Arrow for transitions
145
+ rule(:arrow) do
146
+ str('-->').as(:arrow)
147
+ end
148
+
149
+ # Transition label (after colon)
150
+ rule(:transition_label) do
151
+ space? >> colon >> space? >>
152
+ (line_end.absent? >> arrow.absent? >> any).repeat(1).as(:label_text)
153
+ end
154
+
155
+ # Note position
156
+ rule(:note_position) do
157
+ str('left') | str('right')
158
+ end
159
+
160
+ # Note text
161
+ rule(:note_text) do
162
+ (line_end.absent? >> any).repeat(1)
163
+ end
164
+
165
+ # Line terminators for State diagrams
166
+ rule(:line_end) do
167
+ semicolon.maybe >> space? >> (comment.maybe >> newline | eof)
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for timeline diagrams.
9
+ #
10
+ # Handles timeline syntax including title, sections, events with
11
+ # timestamps and descriptions, and accessibility features.
12
+ #
13
+ # @example Simple timeline
14
+ # timeline
15
+ # title History of Social Media
16
+ # 2002 : LinkedIn
17
+ # 2004 : Facebook : Google
18
+ # 2005 : YouTube
19
+ #
20
+ # @example Timeline with sections
21
+ # timeline
22
+ # section 20th Century
23
+ # 1903 : Wright Brothers flight
24
+ # section 21st Century
25
+ # 2007 : iPhone released
26
+ class Timeline < Common
27
+ root(:diagram)
28
+
29
+ # Main diagram structure
30
+ rule(:diagram) do
31
+ ws? >>
32
+ header >>
33
+ ws? >>
34
+ statements.maybe >>
35
+ ws?
36
+ end
37
+
38
+ # Header: timeline
39
+ rule(:header) do
40
+ str("timeline").as(:header) >> ws?
41
+ end
42
+
43
+ # Statements (title, sections, events, tasks)
44
+ rule(:statements) do
45
+ (statement >> ws?).repeat(1)
46
+ end
47
+
48
+ rule(:statement) do
49
+ acc_title_declaration |
50
+ acc_descr_declaration |
51
+ title_declaration |
52
+ section_declaration |
53
+ event_entry |
54
+ task_entry |
55
+ comment >> line_end
56
+ end
57
+
58
+ # Title
59
+ rule(:title_declaration) do
60
+ str("title") >> space.repeat(1) >>
61
+ (line_end.absent? >> any).repeat(1).as(:title) >>
62
+ line_end
63
+ end
64
+
65
+ # Accessibility title
66
+ rule(:acc_title_declaration) do
67
+ str("accTitle") >> space? >> colon >> space? >>
68
+ (line_end.absent? >> any).repeat.as(:acc_title) >>
69
+ line_end
70
+ end
71
+
72
+ # Accessibility description (single or multi-line)
73
+ rule(:acc_descr_declaration) do
74
+ acc_descr_single_line | acc_descr_multi_line
75
+ end
76
+
77
+ rule(:acc_descr_single_line) do
78
+ str("accDescr") >> space? >> colon >> space? >>
79
+ (line_end.absent? >> any).repeat.as(:acc_descr) >>
80
+ line_end
81
+ end
82
+
83
+ rule(:acc_descr_multi_line) do
84
+ str("accDescr") >> space? >> lbrace >> ws? >>
85
+ (rbrace.absent? >> any).repeat.as(:acc_descr) >>
86
+ ws? >> rbrace >> line_end
87
+ end
88
+
89
+ # Section declaration
90
+ rule(:section_declaration) do
91
+ str("section") >> space.repeat(1) >>
92
+ (line_end.absent? >> any).repeat(1).as(:section) >>
93
+ line_end
94
+ end
95
+
96
+ # Event entry: time : description(s)
97
+ # Can have multiple descriptions separated by colons
98
+ # Example: 2004 : Facebook : Google
99
+ rule(:event_entry) do
100
+ (space? >> event_time.as(:time) >>
101
+ space? >> colon >>
102
+ event_descriptions.as(:descriptions) >>
103
+ line_end).as(:event_entry) |
104
+ (space? >> colon >>
105
+ event_descriptions.as(:descriptions) >>
106
+ line_end).as(:continuation_entry)
107
+ end
108
+
109
+ # Event time (year, date, task name, or any time identifier)
110
+ # Can include spaces, alphanumeric, and common punctuation
111
+ rule(:event_time) do
112
+ (colon.absent? >> line_end.absent? >> any).repeat(1)
113
+ end
114
+
115
+ # Event descriptions (one or more, separated by colons)
116
+ rule(:event_descriptions) do
117
+ event_description.as(:desc) >>
118
+ (space? >> colon >> space? >> event_description.as(:desc)).repeat
119
+ end
120
+
121
+ # Single event description (can include HTML tags like <br>)
122
+ rule(:event_description) do
123
+ space? >>
124
+ (colon.absent? >> line_end.absent? >> any).repeat(1) >>
125
+ space?
126
+ end
127
+
128
+ # Task entry (plain text without colon, for sections)
129
+ rule(:task_entry) do
130
+ (colon.absent? >>
131
+ str("section").absent? >>
132
+ str("title").absent? >>
133
+ str("accTitle").absent? >>
134
+ str("accDescr").absent? >>
135
+ line_end.absent? >>
136
+ any).repeat(1).as(:task) >>
137
+ line_end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parslet'
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for treemap diagrams
9
+ class Treemap < Parslet::Parser
10
+ rule(:space) { match[' \t'] }
11
+ rule(:space?) { space.maybe }
12
+ rule(:spaces) { space.repeat(1) }
13
+ rule(:spaces?) { space.repeat }
14
+ rule(:newline) { str("\n") | str("\r\n") }
15
+ rule(:newlines) { newline.repeat(1) }
16
+ rule(:newlines?) { newline.repeat }
17
+ rule(:eof) { any.absent? }
18
+
19
+ # Comments
20
+ rule(:comment) { str('%%') >> (newline.absent? >> any).repeat }
21
+
22
+ # Numbers
23
+ rule(:number) do
24
+ (match['-'].maybe >> match['0-9'].repeat(1) >>
25
+ (str('.') >> match['0-9'].repeat(1)).maybe).as(:number)
26
+ end
27
+
28
+ # Quoted strings
29
+ rule(:quoted_string) do
30
+ str('"') >> (
31
+ str('\\') >> any |
32
+ str('"').absent? >> any
33
+ ).repeat.as(:string) >> str('"')
34
+ end
35
+
36
+ # Identifiers
37
+ rule(:identifier) do
38
+ (match['a-zA-Z_'] >> match['a-zA-Z0-9_-'].repeat).as(:identifier)
39
+ end
40
+
41
+ # Keywords
42
+ rule(:treemap_keyword) do
43
+ (str('treemap-beta') | str('treemap')).as(:keyword)
44
+ end
45
+
46
+ # Title declaration
47
+ rule(:title_decl) do
48
+ str('title') >> spaces >> (newline.absent? >> any).repeat(1).as(:title)
49
+ end
50
+
51
+ # Accessibility declarations
52
+ rule(:acc_title) do
53
+ str('accTitle:') >> spaces? >> (newline.absent? >> any).repeat(1).as(:acc_title)
54
+ end
55
+
56
+ rule(:acc_descr) do
57
+ str('accDescr') >> spaces? >> str(':').maybe >> spaces? >>
58
+ (newline.absent? >> any).repeat(1).as(:acc_descr)
59
+ end
60
+
61
+ # CSS class reference
62
+ rule(:css_class) do
63
+ str(':::') >> identifier.as(:css_class)
64
+ end
65
+
66
+ # Value separator (: or ,) with optional spaces before and after
67
+ rule(:value_separator) { spaces? >> (str(':') | str(',')) >> spaces? }
68
+
69
+ # Node with optional value and CSS class
70
+ rule(:node_value) do
71
+ quoted_string.as(:label) >>
72
+ (value_separator >> number.as(:value)).maybe >>
73
+ css_class.maybe
74
+ end
75
+
76
+ # Capture leading spaces as a string to count indentation
77
+ rule(:indent_str) do
78
+ match[' '].repeat.as(:indent)
79
+ end
80
+
81
+ # Node line (with indentation captured)
82
+ rule(:node_line) do
83
+ indent_str >> node_value >> spaces? >>
84
+ (comment.maybe >> (newline | eof))
85
+ end
86
+
87
+ # Class definition
88
+ rule(:class_def) do
89
+ str('classDef') >> spaces >>
90
+ identifier.as(:class_name) >> spaces >>
91
+ (str(';').absent? >> any).repeat(1).as(:class_styles) >>
92
+ str(';').maybe
93
+ end
94
+
95
+ # Statement (title, acc, node, or class def)
96
+ rule(:statement) do
97
+ (
98
+ title_decl >> spaces? |
99
+ acc_title >> spaces? |
100
+ acc_descr >> spaces? |
101
+ class_def.as(:class_def) >> spaces? |
102
+ node_line.as(:node) |
103
+ comment >> spaces? |
104
+ spaces? >> newline
105
+ )
106
+ end
107
+
108
+ # Main diagram
109
+ rule(:diagram) do
110
+ treemap_keyword >>
111
+ spaces? >> newline >>
112
+ statement.repeat.as(:statements) >>
113
+ spaces? >> eof
114
+ end
115
+
116
+ root(:diagram)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+ require_relative "common"
5
+
6
+ module Sirena
7
+ module Parser
8
+ module Grammars
9
+ # Grammar for parsing Mermaid xychart-beta syntax
10
+ class XYChart < Common
11
+
12
+ rule(:diagram_type) { str("xychart-beta") >> space? }
13
+
14
+ # Common line patterns
15
+ rule(:eol) { line_end }
16
+ rule(:indent?) { space? }
17
+ rule(:comment_line) { comment >> newline }
18
+ rule(:empty_line) { space? >> newline }
19
+ rule(:text) { match['[^"\n\r]'].repeat(1) }
20
+
21
+ rule(:title_line) do
22
+ str("title") >> space >> quoted_string.as(:title) >> eol
23
+ end
24
+
25
+ # X-axis: x-axis [jan, feb, mar] or x-axis "Label" [1, 2, 3]
26
+ rule(:axis_value) do
27
+ space? >>
28
+ (integer.as(:value) | identifier.as(:value)) >>
29
+ space?
30
+ end
31
+
32
+ rule(:axis_values) do
33
+ str("[") >>
34
+ axis_value >> (str(",") >> axis_value).repeat >>
35
+ str("]")
36
+ end
37
+
38
+ rule(:x_axis_line) do
39
+ str("x-axis") >>
40
+ (space >> quoted_string.as(:x_label)).maybe >>
41
+ space >> axis_values.as(:x_values) >>
42
+ eol
43
+ end
44
+
45
+ # Y-axis: y-axis "Label" min --> max or y-axis min --> max
46
+ rule(:range_separator) { str("-->") }
47
+
48
+ rule(:y_axis_line) do
49
+ str("y-axis") >>
50
+ (space >> quoted_string.as(:y_label)).maybe >>
51
+ space >> integer.as(:y_min) >>
52
+ space >> range_separator >>
53
+ space >> integer.as(:y_max) >>
54
+ eol
55
+ end
56
+
57
+ # Dataset values: [1, 2, 3, 4] or [1.5, 2.7, 3.2]
58
+ rule(:number_value) do
59
+ space? >>
60
+ (
61
+ integer >> (str(".") >> match["0-9"].repeat(1)).maybe
62
+ ).as(:value) >>
63
+ space?
64
+ end
65
+
66
+ rule(:value_array) do
67
+ str("[") >>
68
+ number_value >> (str(",") >> number_value).repeat >>
69
+ str("]")
70
+ end
71
+
72
+ # Line dataset: line [values]
73
+ rule(:line_dataset) do
74
+ str("line") >>
75
+ space >> value_array.as(:line_values) >>
76
+ eol
77
+ end
78
+
79
+ # Bar dataset: bar [values]
80
+ rule(:bar_dataset) do
81
+ str("bar") >>
82
+ space >> value_array.as(:bar_values) >>
83
+ eol
84
+ end
85
+
86
+ # Named dataset: dataset "Name" [values]
87
+ rule(:named_dataset) do
88
+ str("dataset") >>
89
+ space >> quoted_string.as(:dataset_label) >>
90
+ space >> value_array.as(:dataset_values) >>
91
+ eol
92
+ end
93
+
94
+ rule(:dataset_line) do
95
+ line_dataset | bar_dataset | named_dataset
96
+ end
97
+
98
+ rule(:statement) do
99
+ indent? >> (
100
+ title_line |
101
+ x_axis_line |
102
+ y_axis_line |
103
+ dataset_line |
104
+ comment_line |
105
+ empty_line
106
+ )
107
+ end
108
+
109
+ rule(:body) { statement.repeat }
110
+
111
+ rule(:xychart_diagram) do
112
+ diagram_type >> eol >>
113
+ body.as(:statements)
114
+ end
115
+
116
+ root(:xychart_diagram)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'grammars/info'
5
+ require_relative 'transforms/info'
6
+ require_relative '../diagram/info'
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Info diagram parser for Mermaid info diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle simple info diagrams.
13
+ #
14
+ # Parses info diagrams with support for:
15
+ # - Basic info keyword
16
+ # - Optional showInfo flag
17
+ #
18
+ # @example Parse a simple info diagram
19
+ # parser = InfoParser.new
20
+ # diagram = parser.parse("info")
21
+ #
22
+ # @example Parse info diagram with showInfo
23
+ # parser = InfoParser.new
24
+ # diagram = parser.parse("info showInfo")
25
+ class InfoParser < Base
26
+ # Parses info diagram source into an Info diagram model.
27
+ #
28
+ # @param source [String] the Mermaid info diagram source
29
+ # @return [Diagram::Info] the parsed info diagram
30
+ # @raise [ParseError] if syntax is invalid
31
+ def parse(source)
32
+ grammar = Grammars::Info.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::Info.new
43
+ diagram = transform.apply(parse_tree)
44
+
45
+ diagram
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "grammars/kanban"
5
+ require_relative "transforms/kanban"
6
+ require_relative "../diagram/kanban"
7
+
8
+ module Sirena
9
+ module Parser
10
+ # Kanban parser for Mermaid kanban diagram syntax.
11
+ #
12
+ # Uses Parslet grammar-based parsing to handle kanban syntax
13
+ # with columns, cards, and metadata.
14
+ #
15
+ # Parses kanban boards with support for:
16
+ # - Column definitions: id[Title]
17
+ # - Card definitions: id[Text]
18
+ # - Metadata: @{ key: 'value' }
19
+ # - Properties: assigned, ticket, icon, label, priority
20
+ #
21
+ # @example Parse a simple kanban board
22
+ # parser = KanbanParser.new
23
+ # source = <<~MERMAID
24
+ # kanban
25
+ # id1[Todo]
26
+ # docs[Create Documentation]
27
+ # id2[Done]
28
+ # release[Release v1.0]
29
+ # MERMAID
30
+ # diagram = parser.parse(source)
31
+ class KanbanParser < Base
32
+ # Parses kanban diagram source into a Kanban model.
33
+ #
34
+ # @param source [String] the Mermaid kanban diagram source
35
+ # @return [Diagram::Kanban] the parsed kanban diagram
36
+ # @raise [ParseError] if syntax is invalid
37
+ def parse(source)
38
+ grammar = Grammars::Kanban.new
39
+
40
+ begin
41
+ parse_tree = grammar.parse(source)
42
+ rescue Parslet::ParseFailed => e
43
+ raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
44
+ "#{e.parse_failure_cause}"
45
+ end
46
+
47
+ # Transform parse tree to diagram model
48
+ transform = Transforms::Kanban.new
49
+ result = transform.apply(parse_tree)
50
+
51
+ # Create the diagram model
52
+ create_diagram(result)
53
+ end
54
+
55
+ private
56
+
57
+ def create_diagram(result)
58
+ diagram = Diagram::Kanban.new
59
+
60
+ # Build columns and cards
61
+ result[:columns]&.each do |column_data|
62
+ column = build_column(column_data)
63
+ diagram.add_column(column)
64
+ end
65
+
66
+ diagram
67
+ end
68
+
69
+ def build_column(column_data)
70
+ column = Diagram::KanbanColumn.new(
71
+ id: column_data[:id],
72
+ title: column_data[:title]
73
+ )
74
+
75
+ # Add cards to column
76
+ column_data[:cards]&.each do |card_data|
77
+ card = build_card(card_data)
78
+ column.add_card(card)
79
+ end
80
+
81
+ column
82
+ end
83
+
84
+ def build_card(card_data)
85
+ Diagram::KanbanCard.new(
86
+ id: card_data[:id],
87
+ text: card_data[:text],
88
+ assigned: card_data[:assigned],
89
+ ticket: card_data[:ticket],
90
+ icon: card_data[:icon],
91
+ label: card_data[:label],
92
+ priority: card_data[:priority]
93
+ )
94
+ end
95
+ end
96
+ end
97
+ end