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,298 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for Flowchart diagrams.
9
+ #
10
+ # Handles flowchart syntax including nodes with various shapes,
11
+ # edges with labels, edge chaining, subgraphs, and styling directives.
12
+ class Flowchart < Common
13
+ root(:diagram)
14
+
15
+ # Main diagram structure
16
+ rule(:diagram) do
17
+ ws? >>
18
+ header >>
19
+ ws? >>
20
+ statements.maybe >>
21
+ ws?
22
+ end
23
+
24
+ rule(:header) do
25
+ (str('flowchart') | str('graph')).as(:header) >>
26
+ ws? >>
27
+ direction.maybe.as(:direction)
28
+ end
29
+
30
+ rule(:direction) do
31
+ (str('TD') | str('TB') | str('LR') | str('RL') | str('BT')).as(:dir_value)
32
+ end
33
+
34
+ rule(:statements) do
35
+ (statement >> ws?).repeat(1)
36
+ end
37
+
38
+ rule(:statement) do
39
+ subgraph_statement |
40
+ style_statement |
41
+ class_def_statement |
42
+ class_assignment_statement |
43
+ click_statement |
44
+ node_edge_statement |
45
+ standalone_node
46
+ end
47
+
48
+ # Subgraph: subgraph id [title] ... end
49
+ rule(:subgraph_statement) do
50
+ str('subgraph').as(:subgraph_keyword) >> space >>
51
+ node_id.as(:subgraph_id) >>
52
+ (space >> subgraph_title.as(:subgraph_title)).maybe >>
53
+ ws? >>
54
+ statements.maybe.as(:subgraph_statements) >>
55
+ ws? >>
56
+ str('end').as(:subgraph_end) >>
57
+ line_end
58
+ end
59
+
60
+ rule(:subgraph_title) do
61
+ lbracket >> (rbracket.absent? >> any).repeat(1) >> rbracket
62
+ end
63
+
64
+ # Style: style nodeId fill:#f9f
65
+ rule(:style_statement) do
66
+ str('style').as(:style_keyword) >> space >>
67
+ node_id.as(:style_target) >>
68
+ (space >> style_property).repeat(1).as(:style_props) >>
69
+ line_end
70
+ end
71
+
72
+ rule(:style_property) do
73
+ (line_end.absent? >> comma.absent? >> any).repeat(1)
74
+ end
75
+
76
+ # ClassDef: classDef className fill:#f9f
77
+ rule(:class_def_statement) do
78
+ str('classDef').as(:classdef_keyword) >> space >>
79
+ identifier.as(:class_name) >>
80
+ (space >> style_property).repeat(1).as(:class_props) >>
81
+ line_end
82
+ end
83
+
84
+ # Class assignment: class nodeId className
85
+ rule(:class_assignment_statement) do
86
+ str('class').as(:class_keyword) >> space >>
87
+ node_id.as(:class_target) >> space >>
88
+ identifier.as(:class_name) >>
89
+ line_end
90
+ end
91
+
92
+ # Click: click nodeId href (may not fully implement, just parse)
93
+ rule(:click_statement) do
94
+ str('click').as(:click_keyword) >> space >>
95
+ node_id.as(:click_target) >>
96
+ (space >> (line_end.absent? >> any).repeat(1)).maybe.as(:click_action) >>
97
+ line_end
98
+ end
99
+
100
+ # Node with optional shape and edges
101
+ rule(:node_edge_statement) do
102
+ node_with_shape.as(:node) >>
103
+ (ws? >> edge_chain).maybe.as(:edges) >>
104
+ line_end
105
+ end
106
+
107
+ # Standalone node (just an identifier)
108
+ rule(:standalone_node) do
109
+ node_id.as(:node_id) >> line_end
110
+ end
111
+
112
+ # Node with optional shape definition
113
+ rule(:node_with_shape) do
114
+ node_id.as(:node_id) >>
115
+ (ws? >> inline_class.as(:inline_class)).maybe >>
116
+ (ws? >> node_shape.as(:shape)).maybe
117
+ end
118
+
119
+ # Inline class syntax: :::className
120
+ rule(:inline_class) do
121
+ str(':::') >> identifier
122
+ end
123
+
124
+ # Node shape with label
125
+ rule(:node_shape) do
126
+ # Order matters: try longer delimiters first
127
+ shape_triple_circle |
128
+ shape_stadium |
129
+ shape_subroutine |
130
+ shape_cylindrical |
131
+ shape_double_circle |
132
+ shape_hexagon |
133
+ shape_parallelogram |
134
+ shape_parallelogram_alt |
135
+ shape_trapezoid |
136
+ shape_trapezoid_alt |
137
+ shape_asymmetric |
138
+ shape_rectangle |
139
+ shape_rounded |
140
+ shape_rhombus
141
+ end
142
+
143
+ # Shape definitions (15+ shapes)
144
+ # Rectangle: [label]
145
+ rule(:shape_rectangle) do
146
+ lbracket.as(:open) >>
147
+ (rbracket.absent? >> any).repeat.as(:label) >>
148
+ rbracket.as(:close)
149
+ end
150
+
151
+ # Rounded: (label)
152
+ rule(:shape_rounded) do
153
+ lparen.as(:open) >>
154
+ (rparen.absent? >> any).repeat.as(:label) >>
155
+ rparen.as(:close)
156
+ end
157
+
158
+ # Stadium: ([label])
159
+ rule(:shape_stadium) do
160
+ str('([').as(:open) >>
161
+ (str('])').absent? >> any).repeat.as(:label) >>
162
+ str('])').as(:close)
163
+ end
164
+
165
+ # Subroutine: [[label]]
166
+ rule(:shape_subroutine) do
167
+ str('[[').as(:open) >>
168
+ (str(']]').absent? >> any).repeat.as(:label) >>
169
+ str(']]').as(:close)
170
+ end
171
+
172
+ # Cylindrical/Database: [(label)]
173
+ rule(:shape_cylindrical) do
174
+ str('[(').as(:open) >>
175
+ (str(')]').absent? >> any).repeat.as(:label) >>
176
+ str(')]').as(:close)
177
+ end
178
+
179
+ # Circle: ((label))
180
+ rule(:shape_double_circle) do
181
+ str('((').as(:open) >>
182
+ (str('))').absent? >> any).repeat.as(:label) >>
183
+ str('))').as(:close)
184
+ end
185
+
186
+ # Triple Circle: (((label)))
187
+ rule(:shape_triple_circle) do
188
+ str('(((').as(:open) >>
189
+ (str(')))').absent? >> any).repeat.as(:label) >>
190
+ str(')))').as(:close)
191
+ end
192
+
193
+ # Asymmetric: >label]
194
+ rule(:shape_asymmetric) do
195
+ str('>').as(:open) >>
196
+ (rbracket.absent? >> any).repeat.as(:label) >>
197
+ rbracket.as(:close)
198
+ end
199
+
200
+ # Rhombus/Diamond: {label}
201
+ rule(:shape_rhombus) do
202
+ lbrace.as(:open) >>
203
+ (rbrace.absent? >> any).repeat.as(:label) >>
204
+ rbrace.as(:close)
205
+ end
206
+
207
+ # Hexagon: {{label}}
208
+ rule(:shape_hexagon) do
209
+ str('{{').as(:open) >>
210
+ (str('}}').absent? >> any).repeat.as(:label) >>
211
+ str('}}').as(:close)
212
+ end
213
+
214
+ # Parallelogram: [/label/]
215
+ rule(:shape_parallelogram) do
216
+ str('[/').as(:open) >>
217
+ (str('/]').absent? >> any).repeat.as(:label) >>
218
+ str('/]').as(:close)
219
+ end
220
+
221
+ # Parallelogram Alt: [\label\]
222
+ rule(:shape_parallelogram_alt) do
223
+ str('[\\').as(:open) >>
224
+ (str('\\]').absent? >> any).repeat.as(:label) >>
225
+ str('\\]').as(:close)
226
+ end
227
+
228
+ # Trapezoid: [/label\]
229
+ rule(:shape_trapezoid) do
230
+ str('[/').as(:open) >>
231
+ (str('\\]').absent? >> any).repeat.as(:label) >>
232
+ str('\\]').as(:close)
233
+ end
234
+
235
+ # Trapezoid Alt: [\label/]
236
+ rule(:shape_trapezoid_alt) do
237
+ str('[\\').as(:open) >>
238
+ (str('/]').absent? >> any).repeat.as(:label) >>
239
+ str('/]').as(:close)
240
+ end
241
+
242
+ # Edge chain: can have multiple edges from one node
243
+ rule(:edge_chain) do
244
+ edge >> (ws? >> edge).repeat
245
+ end
246
+
247
+ # Single edge with optional label
248
+ rule(:edge) do
249
+ arrow.as(:arrow) >>
250
+ ws? >>
251
+ edge_label.maybe.as(:label) >>
252
+ ws? >>
253
+ node_with_shape.as(:target)
254
+ end
255
+
256
+ # Arrow types
257
+ rule(:arrow) do
258
+ thick_arrow | dotted_arrow | plain_arrow
259
+ end
260
+
261
+ # Thick arrow: ==> or ==
262
+ rule(:thick_arrow) do
263
+ (str('==>') | str('==')).as(:thick)
264
+ end
265
+
266
+ # Dotted arrow: -.-> or -.-
267
+ rule(:dotted_arrow) do
268
+ (str('-.->') | str('-.-')).as(:dotted)
269
+ end
270
+
271
+ # Plain arrow: --> or --- or ->
272
+ rule(:plain_arrow) do
273
+ (str('-->') | str('---') | str('->')).as(:plain)
274
+ end
275
+
276
+ # Edge label: can be in pipes |label|
277
+ rule(:edge_label) do
278
+ pipe_label
279
+ end
280
+
281
+ # Pipe label: |label|
282
+ rule(:pipe_label) do
283
+ pipe >> (pipe.absent? >> any).repeat(1) >> pipe
284
+ end
285
+
286
+ # Node identifier
287
+ rule(:node_id) do
288
+ quoted_string | identifier
289
+ end
290
+
291
+ # Line terminator
292
+ rule(:line_end) do
293
+ semicolon.maybe >> space? >> (comment.maybe >> newline | eof)
294
+ end
295
+ end
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for Gantt chart diagrams.
9
+ #
10
+ # Handles Gantt chart syntax including title, date formatting,
11
+ # sections, tasks with dependencies, and timeline configuration.
12
+ #
13
+ # @example Simple Gantt chart
14
+ # gantt
15
+ # title Project Timeline
16
+ # dateFormat YYYY-MM-DD
17
+ # section Planning
18
+ # Task 1 :a1, 2024-01-01, 30d
19
+ # Task 2 :after a1, 20d
20
+ class Gantt < Common
21
+ root(:diagram)
22
+
23
+ # Main diagram structure
24
+ rule(:diagram) do
25
+ ws? >>
26
+ header >>
27
+ ws? >>
28
+ statements.maybe >>
29
+ ws?
30
+ end
31
+
32
+ # Header: gantt
33
+ rule(:header) do
34
+ str("gantt").as(:header) >> ws?
35
+ end
36
+
37
+ # Statements (configuration, sections, tasks, clicks)
38
+ rule(:statements) do
39
+ (ws? >> statement >> ws?).repeat(1)
40
+ end
41
+
42
+ rule(:statement) do
43
+ acc_title_declaration |
44
+ acc_descr_declaration |
45
+ title_declaration |
46
+ date_format_declaration |
47
+ axis_format_declaration |
48
+ tick_interval_declaration |
49
+ excludes_declaration |
50
+ today_marker_declaration |
51
+ section_declaration |
52
+ click_declaration |
53
+ task_entry |
54
+ comment
55
+ end
56
+
57
+ # Title
58
+ rule(:title_declaration) do
59
+ str("title") >> space.repeat(1) >>
60
+ (line_end.absent? >> any).repeat(1).as(:title) >>
61
+ line_end
62
+ end
63
+
64
+ # Date format
65
+ rule(:date_format_declaration) do
66
+ str("dateFormat") >> space.repeat(1) >>
67
+ (line_end.absent? >> any).repeat(1).as(:date_format) >>
68
+ line_end
69
+ end
70
+
71
+ # Axis format
72
+ rule(:axis_format_declaration) do
73
+ str("axisFormat") >> space.repeat(1) >>
74
+ (line_end.absent? >> any).repeat(1).as(:axis_format) >>
75
+ line_end
76
+ end
77
+
78
+ # Tick interval
79
+ rule(:tick_interval_declaration) do
80
+ str("tickInterval") >> space.repeat(1) >>
81
+ (line_end.absent? >> any).repeat(1).as(:tick_interval) >>
82
+ line_end
83
+ end
84
+
85
+ # Excludes (weekends, weekdays, or specific dates)
86
+ rule(:excludes_declaration) do
87
+ str("excludes") >> space.repeat(1) >>
88
+ (line_end.absent? >> any).repeat(1).as(:excludes) >>
89
+ line_end
90
+ end
91
+
92
+ # Today marker
93
+ rule(:today_marker_declaration) do
94
+ str("todayMarker") >> space.repeat(1) >>
95
+ (line_end.absent? >> any).repeat(1).as(:today_marker) >>
96
+ line_end
97
+ end
98
+
99
+ # Accessibility title
100
+ rule(:acc_title_declaration) do
101
+ str("accTitle") >> space? >> colon >> space? >>
102
+ (line_end.absent? >> any).repeat.as(:acc_title) >>
103
+ line_end
104
+ end
105
+
106
+ # Accessibility description (single or multi-line)
107
+ rule(:acc_descr_declaration) do
108
+ acc_descr_single_line | acc_descr_multi_line
109
+ end
110
+
111
+ rule(:acc_descr_single_line) do
112
+ str("accDescr") >> space? >> colon >> space? >>
113
+ (line_end.absent? >> any).repeat.as(:acc_descr) >>
114
+ line_end
115
+ end
116
+
117
+ rule(:acc_descr_multi_line) do
118
+ str("accDescr") >> space? >> lbrace >> ws? >>
119
+ (rbrace.absent? >> any).repeat.as(:acc_descr) >>
120
+ ws? >> rbrace >> line_end
121
+ end
122
+
123
+ # Section declaration
124
+ rule(:section_declaration) do
125
+ str("section") >> space.repeat(1) >>
126
+ (line_end.absent? >> any).repeat(1).as(:section) >>
127
+ line_end
128
+ end
129
+
130
+ # Click declaration for interactivity
131
+ rule(:click_declaration) do
132
+ str("click") >> space.repeat(1) >>
133
+ identifier.as(:click_id) >>
134
+ space.repeat(1) >>
135
+ (click_href | click_callback) >>
136
+ line_end
137
+ end
138
+
139
+ rule(:click_href) do
140
+ str("href") >> space.repeat(1) >>
141
+ (line_end.absent? >> any).repeat(1).as(:href)
142
+ end
143
+
144
+ rule(:click_callback) do
145
+ str("call") >> space.repeat(1) >>
146
+ (line_end.absent? >> any).repeat(1).as(:callback)
147
+ end
148
+
149
+ # Task entry with various formats
150
+ rule(:task_entry) do
151
+ (task_description.as(:description) >>
152
+ space? >> colon >> space? >>
153
+ task_details.as(:task_details) >>
154
+ line_end).as(:task_entry)
155
+ end
156
+
157
+ rule(:task_description) do
158
+ (colon.absent? >> line_end.absent? >> any).repeat(1)
159
+ end
160
+
161
+ # Task details can have multiple formats:
162
+ # :tag, date, duration
163
+ # :id, after other_id, duration
164
+ # :id, start, end
165
+ # :after id, duration
166
+ # :duration
167
+ rule(:task_details) do
168
+ task_with_tags |
169
+ task_with_id_and_dependency |
170
+ task_with_dependency |
171
+ task_with_dates |
172
+ task_with_duration_only
173
+ end
174
+
175
+ # Task with tags (done, active, crit, milestone)
176
+ rule(:task_with_tags) do
177
+ tags.as(:tags) >>
178
+ (space? >> comma >> space? >> task_timing).maybe
179
+ end
180
+
181
+ # Task with ID and after dependency (:id, after other_id, duration)
182
+ rule(:task_with_id_and_dependency) do
183
+ task_id.as(:id) >> space? >> comma >> space? >>
184
+ str("after") >> space.repeat(1) >>
185
+ task_id.as(:after_task) >>
186
+ (space? >> comma >> space? >> (task_end_date | task_duration)).maybe
187
+ end
188
+
189
+ # Task with after dependency (after other_id, duration)
190
+ rule(:task_with_dependency) do
191
+ str("after") >> space.repeat(1) >>
192
+ task_id.as(:after_task) >>
193
+ (space? >> comma >> space? >> (task_end_date | task_duration)).maybe
194
+ end
195
+
196
+ # Task with until dependency
197
+ rule(:task_with_until) do
198
+ task_date.as(:start_date) >>
199
+ comma >> space? >>
200
+ str("until") >> space.repeat(1) >>
201
+ task_id.as(:until_task)
202
+ end
203
+
204
+ # Task with explicit dates
205
+ rule(:task_with_dates) do
206
+ task_id.as(:id) >> space? >> comma >> space? >> task_timing
207
+ end
208
+
209
+ # Task with duration only
210
+ rule(:task_with_duration_only) do
211
+ space? >> task_timing
212
+ end
213
+
214
+ # Task timing (dates or duration)
215
+ rule(:task_timing) do
216
+ task_date.as(:start_date) >>
217
+ (space? >> comma >> space? >> (task_end_date | task_duration)).maybe |
218
+ task_duration.as(:duration)
219
+ end
220
+
221
+ rule(:task_end_date) do
222
+ str("until") >> space.repeat(1) >> task_id.as(:until_task) |
223
+ task_date.as(:end_date)
224
+ end
225
+
226
+ # Tags (space-separated only, no comma between tags)
227
+ rule(:tags) do
228
+ space? >> task_tag >> (space.repeat(1) >> task_tag).repeat
229
+ end
230
+
231
+ rule(:task_tag) do
232
+ str("done") | str("active") | str("crit") | str("milestone")
233
+ end
234
+
235
+ # Task ID
236
+ rule(:task_id) do
237
+ match["a-zA-Z0-9_-"].repeat(1)
238
+ end
239
+
240
+ # Date in various formats (must contain date separator)
241
+ rule(:task_date) do
242
+ match["0-9"].repeat(1) >> match["-/:"] >> match["0-9-/:"].repeat
243
+ end
244
+
245
+ # Duration (e.g., 30d, 2w, 48h, 1M)
246
+ rule(:task_duration) do
247
+ match["0-9"].repeat(1) >> match["dwMh"]
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+
5
+ module Sirena
6
+ module Parser
7
+ module Grammars
8
+ # Parslet grammar for Git Graph diagrams
9
+ class GitGraph < Common
10
+
11
+ rule(:diagram) do
12
+ ws? >>
13
+ header >>
14
+ ws? >>
15
+ statements.maybe.as(:statements) >>
16
+ ws?
17
+ end
18
+
19
+ rule(:header) do
20
+ str("gitGraph") >>
21
+ (str(" TB:") | str(" LR:") | str("TB:") | str("LR:") | str(":")).maybe >>
22
+ ws?
23
+ end
24
+
25
+ rule(:statements) do
26
+ (statement >> ws?).repeat(1)
27
+ end
28
+
29
+ rule(:statement) do
30
+ commit_stmt |
31
+ branch_stmt |
32
+ checkout_stmt |
33
+ switch_stmt |
34
+ merge_stmt |
35
+ cherry_pick_stmt
36
+ end
37
+
38
+ rule(:commit_stmt) do
39
+ (
40
+ str("commit") >>
41
+ commit_options.maybe.as(:options)
42
+ ).as(:commit) >>
43
+ line_end
44
+ end
45
+
46
+ rule(:commit_options) do
47
+ space >> (commit_option >> space?).repeat(1)
48
+ end
49
+
50
+ rule(:commit_option) do
51
+ commit_id | commit_type | commit_tag
52
+ end
53
+
54
+ rule(:commit_id) do
55
+ str("id:") >> space? >>
56
+ (str('"') >> match('[^"]').repeat(1).as(:id) >> str('"') |
57
+ str("'") >> match("[^']").repeat(1).as(:id) >> str("'") |
58
+ match('[^\s,]').repeat(1).as(:id))
59
+ end
60
+
61
+ rule(:commit_type) do
62
+ str("type:") >> space? >>
63
+ (str("NORMAL") | str("REVERSE") | str("HIGHLIGHT")).as(:type)
64
+ end
65
+
66
+ rule(:commit_tag) do
67
+ str("tag:") >> space? >>
68
+ (str('"') >> match('[^"]').repeat(1).as(:tag) >> str('"') |
69
+ str("'") >> match("[^']").repeat(1).as(:tag) >> str("'") |
70
+ match('[^\s,]').repeat(1).as(:tag))
71
+ end
72
+
73
+ rule(:branch_stmt) do
74
+ (
75
+ str("branch") >> space >>
76
+ branch_name.as(:name) >>
77
+ branch_options.maybe.as(:options)
78
+ ).as(:branch) >>
79
+ line_end
80
+ end
81
+
82
+ rule(:branch_name) do
83
+ match('[a-zA-Z0-9_-]').repeat(1)
84
+ end
85
+
86
+ rule(:branch_options) do
87
+ space >> (branch_option >> space?).repeat(1)
88
+ end
89
+
90
+ rule(:branch_option) do
91
+ str("order:") >> space? >> match('[0-9]').repeat(1).as(:order)
92
+ end
93
+
94
+ rule(:checkout_stmt) do
95
+ (
96
+ str("checkout") >> space >>
97
+ branch_name.as(:branch)
98
+ ).as(:checkout) >>
99
+ line_end
100
+ end
101
+
102
+ rule(:switch_stmt) do
103
+ (
104
+ str("switch") >> space >>
105
+ branch_name.as(:branch)
106
+ ).as(:switch) >>
107
+ line_end
108
+ end
109
+
110
+ rule(:merge_stmt) do
111
+ str("merge") >> space >>
112
+ (
113
+ branch_name.as(:branch) >>
114
+ merge_options.maybe.as(:options)
115
+ ).as(:merge) >>
116
+ line_end
117
+ end
118
+
119
+ rule(:merge_options) do
120
+ space >> (merge_option >> space?).repeat(1)
121
+ end
122
+
123
+ rule(:merge_option) do
124
+ commit_id | commit_type | commit_tag |
125
+ (str("random:") >> quoted_string)
126
+ end
127
+
128
+ rule(:cherry_pick_stmt) do
129
+ (
130
+ str("cherry-pick") >> space >>
131
+ cherry_pick_options.as(:options)
132
+ ).as(:cherry_pick) >>
133
+ line_end
134
+ end
135
+
136
+ rule(:cherry_pick_options) do
137
+ (cherry_pick_option >> space?).repeat(1)
138
+ end
139
+
140
+ rule(:cherry_pick_option) do
141
+ cherry_pick_id | cherry_pick_parent | commit_tag
142
+ end
143
+
144
+ rule(:cherry_pick_id) do
145
+ str("id:") >> space? >>
146
+ (str('"') >> match('[^"]').repeat(1).as(:id) >> str('"') |
147
+ str("'") >> match("[^']").repeat(1).as(:id) >> str("'") |
148
+ match('[^\s,]').repeat(1).as(:id))
149
+ end
150
+
151
+ rule(:cherry_pick_parent) do
152
+ str("parent:") >> space? >>
153
+ (str('"') >> match('[^"]').repeat(1).as(:parent) >> str('"') |
154
+ str("'") >> match("[^']").repeat(1).as(:parent) >> str("'") |
155
+ match('[^\s,]').repeat(1).as(:parent))
156
+ end
157
+
158
+ rule(:quoted_string) do
159
+ str('"') >> match('[^"]').repeat(0) >> str('"') |
160
+ str("'") >> match("[^']").repeat(0) >> str("'")
161
+ end
162
+
163
+ root(:diagram)
164
+ end
165
+ end
166
+ end
167
+ end