etassia 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 (727) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +140 -0
  3. data/LICENSE +25 -0
  4. data/README.adoc +436 -0
  5. data/exe/etassia +7 -0
  6. data/lib/etassia/cli.rb +187 -0
  7. data/lib/etassia/commands/batch.rb +210 -0
  8. data/lib/etassia/commands/notation_loader.rb +22 -0
  9. data/lib/etassia/commands/render.rb +98 -0
  10. data/lib/etassia/commands/types.rb +33 -0
  11. data/lib/etassia/commands/version.rb +24 -0
  12. data/lib/etassia/corpus_type_names.rb +52 -0
  13. data/lib/etassia/diagram/architecture.rb +108 -0
  14. data/lib/etassia/diagram/base.rb +61 -0
  15. data/lib/etassia/diagram/block.rb +102 -0
  16. data/lib/etassia/diagram/c4.rb +337 -0
  17. data/lib/etassia/diagram/class_diagram.rb +466 -0
  18. data/lib/etassia/diagram/class_namespace.rb +17 -0
  19. data/lib/etassia/diagram/class_note.rb +17 -0
  20. data/lib/etassia/diagram/containment.rb +107 -0
  21. data/lib/etassia/diagram/er_diagram.rb +317 -0
  22. data/lib/etassia/diagram/error.rb +38 -0
  23. data/lib/etassia/diagram/flowchart.rb +419 -0
  24. data/lib/etassia/diagram/flowchart_label_text.rb +63 -0
  25. data/lib/etassia/diagram/gantt.rb +94 -0
  26. data/lib/etassia/diagram/generic_text.rb +30 -0
  27. data/lib/etassia/diagram/git_graph.rb +57 -0
  28. data/lib/etassia/diagram/info.rb +38 -0
  29. data/lib/etassia/diagram/kanban.rb +198 -0
  30. data/lib/etassia/diagram/mindmap.rb +71 -0
  31. data/lib/etassia/diagram/packet.rb +93 -0
  32. data/lib/etassia/diagram/pie.rb +115 -0
  33. data/lib/etassia/diagram/quadrant.rb +135 -0
  34. data/lib/etassia/diagram/radar.rb +65 -0
  35. data/lib/etassia/diagram/requirement.rb +168 -0
  36. data/lib/etassia/diagram/sankey.rb +217 -0
  37. data/lib/etassia/diagram/sequence.rb +299 -0
  38. data/lib/etassia/diagram/sequence_box.rb +18 -0
  39. data/lib/etassia/diagram/sequence_frame.rb +37 -0
  40. data/lib/etassia/diagram/sequence_frame_section.rb +23 -0
  41. data/lib/etassia/diagram/sequence_text.rb +69 -0
  42. data/lib/etassia/diagram/sequence_wrap.rb +23 -0
  43. data/lib/etassia/diagram/state_diagram.rb +282 -0
  44. data/lib/etassia/diagram/timeline.rb +183 -0
  45. data/lib/etassia/diagram/treemap.rb +95 -0
  46. data/lib/etassia/diagram/user_journey.rb +153 -0
  47. data/lib/etassia/diagram/xy_chart.rb +90 -0
  48. data/lib/etassia/diagram.rb +8 -0
  49. data/lib/etassia/diagram_registry.rb +34 -0
  50. data/lib/etassia/engine.rb +334 -0
  51. data/lib/etassia/error/diagram_type_error.rb +10 -0
  52. data/lib/etassia/error/layout_error.rb +12 -0
  53. data/lib/etassia/error/notation_registration_error.rb +10 -0
  54. data/lib/etassia/error/parse_error.rb +11 -0
  55. data/lib/etassia/error/pipeline_error.rb +10 -0
  56. data/lib/etassia/error/render_error.rb +12 -0
  57. data/lib/etassia/error/score_error.rb +12 -0
  58. data/lib/etassia/error.rb +10 -0
  59. data/lib/etassia/error_report.rb +69 -0
  60. data/lib/etassia/ir/data.rb +39 -0
  61. data/lib/etassia/ir/data_value.rb +35 -0
  62. data/lib/etassia/ir/dimension.rb +10 -0
  63. data/lib/etassia/ir/edge.rb +34 -0
  64. data/lib/etassia/ir/graph.rb +28 -0
  65. data/lib/etassia/ir/integrity.rb +80 -0
  66. data/lib/etassia/ir/item.rb +46 -0
  67. data/lib/etassia/ir/model.rb +56 -0
  68. data/lib/etassia/ir/node.rb +10 -0
  69. data/lib/etassia/ir/placement.rb +47 -0
  70. data/lib/etassia/ir/prepositioned.rb +25 -0
  71. data/lib/etassia/ir/prepositioned_item.rb +26 -0
  72. data/lib/etassia/ir/property_set.rb +43 -0
  73. data/lib/etassia/ir/scalar.rb +25 -0
  74. data/lib/etassia/ir/series.rb +10 -0
  75. data/lib/etassia/ir.rb +17 -0
  76. data/lib/etassia/js_math.rb +511 -0
  77. data/lib/etassia/js_number.rb +64 -0
  78. data/lib/etassia/layout/architecture.rb +1472 -0
  79. data/lib/etassia/layout/base.rb +276 -0
  80. data/lib/etassia/layout/block.rb +738 -0
  81. data/lib/etassia/layout/c4.rb +876 -0
  82. data/lib/etassia/layout/c4_boundary_metrics.rb +35 -0
  83. data/lib/etassia/layout/c4_bounds.rb +106 -0
  84. data/lib/etassia/layout/c4_intersection.rb +77 -0
  85. data/lib/etassia/layout/c4_placement.rb +135 -0
  86. data/lib/etassia/layout/c4_shape_metrics.rb +97 -0
  87. data/lib/etassia/layout/c4_shape_outline.rb +67 -0
  88. data/lib/etassia/layout/c4_stereotype.rb +30 -0
  89. data/lib/etassia/layout/c4_text.rb +54 -0
  90. data/lib/etassia/layout/class_cell_placement.rb +148 -0
  91. data/lib/etassia/layout/class_diagram.rb +1116 -0
  92. data/lib/etassia/layout/class_diagram_namespaces.rb +26 -0
  93. data/lib/etassia/layout/class_diagram_notes.rb +26 -0
  94. data/lib/etassia/layout/class_name_advances.rb +31 -0
  95. data/lib/etassia/layout/class_namespace_box.rb +21 -0
  96. data/lib/etassia/layout/class_namespace_nodes.rb +197 -0
  97. data/lib/etassia/layout/class_namespace_placement.rb +71 -0
  98. data/lib/etassia/layout/class_note.rb +44 -0
  99. data/lib/etassia/layout/class_note_nodes.rb +84 -0
  100. data/lib/etassia/layout/elk_notices.rb +48 -0
  101. data/lib/etassia/layout/elk_placement.rb +197 -0
  102. data/lib/etassia/layout/er_diagram.rb +1002 -0
  103. data/lib/etassia/layout/er_diagram_adjacency.rb +20 -0
  104. data/lib/etassia/layout/er_diagram_alignment.rb +72 -0
  105. data/lib/etassia/layout/er_diagram_compaction.rb +85 -0
  106. data/lib/etassia/layout/er_diagram_conflicts.rb +70 -0
  107. data/lib/etassia/layout/er_diagram_coordinates.rb +104 -0
  108. data/lib/etassia/layout/er_diagram_entity_size.rb +82 -0
  109. data/lib/etassia/layout/er_diagram_layering.rb +109 -0
  110. data/lib/etassia/layout/er_diagram_ordering.rb +143 -0
  111. data/lib/etassia/layout/er_diagram_placement.rb +163 -0
  112. data/lib/etassia/layout/er_diagram_placement_node.rb +22 -0
  113. data/lib/etassia/layout/error.rb +133 -0
  114. data/lib/etassia/layout/flowchart/brandes_koepf.rb +208 -0
  115. data/lib/etassia/layout/flowchart/cluster_reach.rb +70 -0
  116. data/lib/etassia/layout/flowchart/component_packing.rb +129 -0
  117. data/lib/etassia/layout/flowchart/directed_placement.rb +428 -0
  118. data/lib/etassia/layout/flowchart/edge_chains.rb +111 -0
  119. data/lib/etassia/layout/flowchart/edge_order.rb +34 -0
  120. data/lib/etassia/layout/flowchart/edge_router.rb +533 -0
  121. data/lib/etassia/layout/flowchart/label_backdrop_geometry.rb +62 -0
  122. data/lib/etassia/layout/flowchart/layer_spacing.rb +85 -0
  123. data/lib/etassia/layout/flowchart/level_edges.rb +74 -0
  124. data/lib/etassia/layout/flowchart/level_frame.rb +47 -0
  125. data/lib/etassia/layout/flowchart/minimum_rank_spacing.rb +74 -0
  126. data/lib/etassia/layout/flowchart/row_centering.rb +229 -0
  127. data/lib/etassia/layout/flowchart.rb +1290 -0
  128. data/lib/etassia/layout/gantt.rb +814 -0
  129. data/lib/etassia/layout/gantt_duration.rb +49 -0
  130. data/lib/etassia/layout/gantt_exclusions.rb +74 -0
  131. data/lib/etassia/layout/gantt_ticks.rb +165 -0
  132. data/lib/etassia/layout/git_graph.rb +1075 -0
  133. data/lib/etassia/layout/grid.rb +165 -0
  134. data/lib/etassia/layout/info.rb +113 -0
  135. data/lib/etassia/layout/kanban.rb +452 -0
  136. data/lib/etassia/layout/kanban_card_text.rb +95 -0
  137. data/lib/etassia/layout/mindmap.rb +425 -0
  138. data/lib/etassia/layout/mindmap_cose.rb +81 -0
  139. data/lib/etassia/layout/mindmap_cose_body.rb +93 -0
  140. data/lib/etassia/layout/mindmap_cose_geometry.rb +190 -0
  141. data/lib/etassia/layout/mindmap_cose_grid.rb +96 -0
  142. data/lib/etassia/layout/mindmap_cose_link.rb +42 -0
  143. data/lib/etassia/layout/mindmap_cose_relaxation.rb +166 -0
  144. data/lib/etassia/layout/mindmap_cose_seed.rb +93 -0
  145. data/lib/etassia/layout/mindmap_cose_wedge.rb +37 -0
  146. data/lib/etassia/layout/mindmap_node_size.rb +130 -0
  147. data/lib/etassia/layout/packet.rb +285 -0
  148. data/lib/etassia/layout/pie.rb +305 -0
  149. data/lib/etassia/layout/pie_legend.rb +64 -0
  150. data/lib/etassia/layout/pie_legend_entry.rb +21 -0
  151. data/lib/etassia/layout/quadrant.rb +402 -0
  152. data/lib/etassia/layout/radar.rb +442 -0
  153. data/lib/etassia/layout/requirement.rb +765 -0
  154. data/lib/etassia/layout/sankey.rb +501 -0
  155. data/lib/etassia/layout/scene.rb +18 -0
  156. data/lib/etassia/layout/sequence/actor_gaps.rb +151 -0
  157. data/lib/etassia/layout/sequence/box_shape.rb +23 -0
  158. data/lib/etassia/layout/sequence/creations.rb +73 -0
  159. data/lib/etassia/layout/sequence/frame_divider.rb +22 -0
  160. data/lib/etassia/layout/sequence/frame_placement.rb +424 -0
  161. data/lib/etassia/layout/sequence/frame_reader.rb +75 -0
  162. data/lib/etassia/layout/sequence/frame_shape.rb +45 -0
  163. data/lib/etassia/layout/sequence/geometry.rb +24 -0
  164. data/lib/etassia/layout/sequence/message_rows.rb +165 -0
  165. data/lib/etassia/layout/sequence/note.rb +16 -0
  166. data/lib/etassia/layout/sequence/note_box.rb +114 -0
  167. data/lib/etassia/layout/sequence/note_placement.rb +223 -0
  168. data/lib/etassia/layout/sequence/text_width.rb +69 -0
  169. data/lib/etassia/layout/sequence/text_wrap.rb +93 -0
  170. data/lib/etassia/layout/sequence.rb +936 -0
  171. data/lib/etassia/layout/state_diagram.rb +1277 -0
  172. data/lib/etassia/layout/timeline.rb +165 -0
  173. data/lib/etassia/layout/timeline_card.rb +142 -0
  174. data/lib/etassia/layout/timeline_flow.rb +164 -0
  175. data/lib/etassia/layout/timeline_line.rb +33 -0
  176. data/lib/etassia/layout/timeline_rounding.rb +19 -0
  177. data/lib/etassia/layout/timeline_text.rb +105 -0
  178. data/lib/etassia/layout/treemap.rb +303 -0
  179. data/lib/etassia/layout/treemap_placement.rb +52 -0
  180. data/lib/etassia/layout/treemap_squarify.rb +108 -0
  181. data/lib/etassia/layout/user_journey.rb +300 -0
  182. data/lib/etassia/layout/user_journey_face.rb +33 -0
  183. data/lib/etassia/layout/user_journey_face_geometry.rb +80 -0
  184. data/lib/etassia/layout/user_journey_geometry.rb +336 -0
  185. data/lib/etassia/layout/user_journey_legend.rb +84 -0
  186. data/lib/etassia/layout/xy_chart.rb +620 -0
  187. data/lib/etassia/layout.rb +19 -0
  188. data/lib/etassia/lint_debt_scoreboard.rb +219 -0
  189. data/lib/etassia/markdown_text/emphasis_simulator.rb +373 -0
  190. data/lib/etassia/markdown_text.rb +393 -0
  191. data/lib/etassia/notation/builtin.rb +39 -0
  192. data/lib/etassia/notation/entry.rb +15 -0
  193. data/lib/etassia/notation/mermaid/class_diagram_config.rb +42 -0
  194. data/lib/etassia/notation/mermaid/git_graph_config.rb +46 -0
  195. data/lib/etassia/notation/mermaid/ir_adapter.rb +27 -0
  196. data/lib/etassia/notation/mermaid/ir_adapters/architecture.rb +196 -0
  197. data/lib/etassia/notation/mermaid/ir_adapters/block.rb +138 -0
  198. data/lib/etassia/notation/mermaid/ir_adapters/c4.rb +258 -0
  199. data/lib/etassia/notation/mermaid/ir_adapters/class_diagram.rb +257 -0
  200. data/lib/etassia/notation/mermaid/ir_adapters/er_diagram.rb +220 -0
  201. data/lib/etassia/notation/mermaid/ir_adapters/error.rb +32 -0
  202. data/lib/etassia/notation/mermaid/ir_adapters/flowchart.rb +208 -0
  203. data/lib/etassia/notation/mermaid/ir_adapters/gantt.rb +236 -0
  204. data/lib/etassia/notation/mermaid/ir_adapters/git_graph.rb +186 -0
  205. data/lib/etassia/notation/mermaid/ir_adapters/info.rb +34 -0
  206. data/lib/etassia/notation/mermaid/ir_adapters/kanban.rb +110 -0
  207. data/lib/etassia/notation/mermaid/ir_adapters/mindmap.rb +76 -0
  208. data/lib/etassia/notation/mermaid/ir_adapters/packet.rb +51 -0
  209. data/lib/etassia/notation/mermaid/ir_adapters/pie.rb +71 -0
  210. data/lib/etassia/notation/mermaid/ir_adapters/quadrant.rb +116 -0
  211. data/lib/etassia/notation/mermaid/ir_adapters/radar.rb +142 -0
  212. data/lib/etassia/notation/mermaid/ir_adapters/requirement.rb +237 -0
  213. data/lib/etassia/notation/mermaid/ir_adapters/sankey.rb +74 -0
  214. data/lib/etassia/notation/mermaid/ir_adapters/sequence.rb +304 -0
  215. data/lib/etassia/notation/mermaid/ir_adapters/state_diagram.rb +225 -0
  216. data/lib/etassia/notation/mermaid/ir_adapters/timeline.rb +93 -0
  217. data/lib/etassia/notation/mermaid/ir_adapters/treemap.rb +143 -0
  218. data/lib/etassia/notation/mermaid/ir_adapters/user_journey.rb +127 -0
  219. data/lib/etassia/notation/mermaid/ir_adapters/xychart.rb +131 -0
  220. data/lib/etassia/notation/mermaid.rb +399 -0
  221. data/lib/etassia/notation/parsed.rb +31 -0
  222. data/lib/etassia/notation/plantuml/activity/arrow_head.rb +45 -0
  223. data/lib/etassia/notation/plantuml/activity/arrow_style.rb +53 -0
  224. data/lib/etassia/notation/plantuml/activity/bar_columns.rb +75 -0
  225. data/lib/etassia/notation/plantuml/activity/box.rb +60 -0
  226. data/lib/etassia/notation/plantuml/activity/builder.rb +77 -0
  227. data/lib/etassia/notation/plantuml/activity/canvas.rb +117 -0
  228. data/lib/etassia/notation/plantuml/activity/column_centres.rb +151 -0
  229. data/lib/etassia/notation/plantuml/activity/columns.rb +224 -0
  230. data/lib/etassia/notation/plantuml/activity/diagram.rb +35 -0
  231. data/lib/etassia/notation/plantuml/activity/edge.rb +35 -0
  232. data/lib/etassia/notation/plantuml/activity/edge_marks.rb +68 -0
  233. data/lib/etassia/notation/plantuml/activity/exits.rb +61 -0
  234. data/lib/etassia/notation/plantuml/activity/frame_marks.rb +116 -0
  235. data/lib/etassia/notation/plantuml/activity/lane_steps.rb +82 -0
  236. data/lib/etassia/notation/plantuml/activity/lane_titles.rb +46 -0
  237. data/lib/etassia/notation/plantuml/activity/layout.rb +50 -0
  238. data/lib/etassia/notation/plantuml/activity/legacy_parser.rb +181 -0
  239. data/lib/etassia/notation/plantuml/activity/legacy_row_gaps.rb +65 -0
  240. data/lib/etassia/notation/plantuml/activity/mark.rb +23 -0
  241. data/lib/etassia/notation/plantuml/activity/marks.rb +62 -0
  242. data/lib/etassia/notation/plantuml/activity/metrics.rb +169 -0
  243. data/lib/etassia/notation/plantuml/activity/new_parser/blocks.rb +166 -0
  244. data/lib/etassia/notation/plantuml/activity/new_parser.rb +177 -0
  245. data/lib/etassia/notation/plantuml/activity/node.rb +50 -0
  246. data/lib/etassia/notation/plantuml/activity/node_marks.rb +174 -0
  247. data/lib/etassia/notation/plantuml/activity/note.rb +27 -0
  248. data/lib/etassia/notation/plantuml/activity/parser.rb +51 -0
  249. data/lib/etassia/notation/plantuml/activity/placement.rb +327 -0
  250. data/lib/etassia/notation/plantuml/activity/ranking.rb +142 -0
  251. data/lib/etassia/notation/plantuml/activity/reach.rb +58 -0
  252. data/lib/etassia/notation/plantuml/activity/renderer.rb +220 -0
  253. data/lib/etassia/notation/plantuml/activity/route.rb +22 -0
  254. data/lib/etassia/notation/plantuml/activity/router.rb +308 -0
  255. data/lib/etassia/notation/plantuml/activity/row_gaps.rb +105 -0
  256. data/lib/etassia/notation/plantuml/activity/row_spread.rb +59 -0
  257. data/lib/etassia/notation/plantuml/activity/scene.rb +20 -0
  258. data/lib/etassia/notation/plantuml/activity/text.rb +36 -0
  259. data/lib/etassia/notation/plantuml/activity.rb +50 -0
  260. data/lib/etassia/notation/plantuml/arrow.rb +135 -0
  261. data/lib/etassia/notation/plantuml/caption.rb +50 -0
  262. data/lib/etassia/notation/plantuml/caption_layout.rb +97 -0
  263. data/lib/etassia/notation/plantuml/caption_rows.rb +67 -0
  264. data/lib/etassia/notation/plantuml/class_header.rb +178 -0
  265. data/lib/etassia/notation/plantuml/class_name.rb +51 -0
  266. data/lib/etassia/notation/plantuml/component.rb +37 -0
  267. data/lib/etassia/notation/plantuml/creole.rb +278 -0
  268. data/lib/etassia/notation/plantuml/creole_icons.rb +33 -0
  269. data/lib/etassia/notation/plantuml/diagram.rb +60 -0
  270. data/lib/etassia/notation/plantuml/diagram_builder.rb +442 -0
  271. data/lib/etassia/notation/plantuml/diagram_name.rb +51 -0
  272. data/lib/etassia/notation/plantuml/directives.rb +33 -0
  273. data/lib/etassia/notation/plantuml/drawing/box.rb +28 -0
  274. data/lib/etassia/notation/plantuml/drawing/face.rb +39 -0
  275. data/lib/etassia/notation/plantuml/drawing/pen.rb +105 -0
  276. data/lib/etassia/notation/plantuml/drawing/renderer.rb +36 -0
  277. data/lib/etassia/notation/plantuml/drawing/scene.rb +28 -0
  278. data/lib/etassia/notation/plantuml/drawing.rb +19 -0
  279. data/lib/etassia/notation/plantuml/ebnf/blocks.rb +272 -0
  280. data/lib/etassia/notation/plantuml/ebnf/layout.rb +117 -0
  281. data/lib/etassia/notation/plantuml/ebnf/model.rb +22 -0
  282. data/lib/etassia/notation/plantuml/ebnf/reader.rb +131 -0
  283. data/lib/etassia/notation/plantuml/ebnf.rb +34 -0
  284. data/lib/etassia/notation/plantuml/end_texts.rb +78 -0
  285. data/lib/etassia/notation/plantuml/entity.rb +54 -0
  286. data/lib/etassia/notation/plantuml/further.rb +38 -0
  287. data/lib/etassia/notation/plantuml/gantt/layout.rb +269 -0
  288. data/lib/etassia/notation/plantuml/gantt/reader.rb +210 -0
  289. data/lib/etassia/notation/plantuml/gantt/renderer.rb +81 -0
  290. data/lib/etassia/notation/plantuml/gantt.rb +34 -0
  291. data/lib/etassia/notation/plantuml/include/blocks.rb +66 -0
  292. data/lib/etassia/notation/plantuml/include/finder.rb +61 -0
  293. data/lib/etassia/notation/plantuml/include.rb +78 -0
  294. data/lib/etassia/notation/plantuml/ir_adapter/annotations.rb +40 -0
  295. data/lib/etassia/notation/plantuml/ir_adapter/links.rb +91 -0
  296. data/lib/etassia/notation/plantuml/ir_adapter/sink.rb +49 -0
  297. data/lib/etassia/notation/plantuml/ir_adapter/structure.rb +86 -0
  298. data/lib/etassia/notation/plantuml/ir_adapter.rb +32 -0
  299. data/lib/etassia/notation/plantuml/ir_reader/annotations.rb +51 -0
  300. data/lib/etassia/notation/plantuml/ir_reader/index.rb +49 -0
  301. data/lib/etassia/notation/plantuml/ir_reader/links.rb +133 -0
  302. data/lib/etassia/notation/plantuml/ir_reader/structure.rb +83 -0
  303. data/lib/etassia/notation/plantuml/ir_reader.rb +42 -0
  304. data/lib/etassia/notation/plantuml/junction.rb +20 -0
  305. data/lib/etassia/notation/plantuml/klass.rb +41 -0
  306. data/lib/etassia/notation/plantuml/label_clearance.rb +67 -0
  307. data/lib/etassia/notation/plantuml/layout.rb +2806 -0
  308. data/lib/etassia/notation/plantuml/member.rb +37 -0
  309. data/lib/etassia/notation/plantuml/member_icon.rb +87 -0
  310. data/lib/etassia/notation/plantuml/member_icon_elements.rb +91 -0
  311. data/lib/etassia/notation/plantuml/member_pitch.rb +76 -0
  312. data/lib/etassia/notation/plantuml/member_rule.rb +48 -0
  313. data/lib/etassia/notation/plantuml/network/grid.rb +170 -0
  314. data/lib/etassia/notation/plantuml/network/layout.rb +158 -0
  315. data/lib/etassia/notation/plantuml/network/model.rb +22 -0
  316. data/lib/etassia/notation/plantuml/network/placement.rb +64 -0
  317. data/lib/etassia/notation/plantuml/network/reader.rb +126 -0
  318. data/lib/etassia/notation/plantuml/network/shapes.rb +109 -0
  319. data/lib/etassia/notation/plantuml/network.rb +37 -0
  320. data/lib/etassia/notation/plantuml/node_graph/archimate.rb +49 -0
  321. data/lib/etassia/notation/plantuml/node_graph/box_reader.rb +86 -0
  322. data/lib/etassia/notation/plantuml/node_graph/cloud.rb +73 -0
  323. data/lib/etassia/notation/plantuml/node_graph/crows_foot.rb +85 -0
  324. data/lib/etassia/notation/plantuml/node_graph/curve.rb +66 -0
  325. data/lib/etassia/notation/plantuml/node_graph/data_reader.rb +77 -0
  326. data/lib/etassia/notation/plantuml/node_graph/data_shape.rb +39 -0
  327. data/lib/etassia/notation/plantuml/node_graph/detour.rb +98 -0
  328. data/lib/etassia/notation/plantuml/node_graph/edge.rb +26 -0
  329. data/lib/etassia/notation/plantuml/node_graph/entity_metrics.rb +49 -0
  330. data/lib/etassia/notation/plantuml/node_graph/entity_reader.rb +65 -0
  331. data/lib/etassia/notation/plantuml/node_graph/entity_shape.rb +111 -0
  332. data/lib/etassia/notation/plantuml/node_graph/figures.rb +92 -0
  333. data/lib/etassia/notation/plantuml/node_graph/frame_ports.rb +73 -0
  334. data/lib/etassia/notation/plantuml/node_graph/graph.rb +40 -0
  335. data/lib/etassia/notation/plantuml/node_graph/heads.rb +89 -0
  336. data/lib/etassia/notation/plantuml/node_graph/label_fan.rb +76 -0
  337. data/lib/etassia/notation/plantuml/node_graph/label_placer.rb +310 -0
  338. data/lib/etassia/notation/plantuml/node_graph/label_waypoint.rb +47 -0
  339. data/lib/etassia/notation/plantuml/node_graph/layout.rb +293 -0
  340. data/lib/etassia/notation/plantuml/node_graph/link.rb +78 -0
  341. data/lib/etassia/notation/plantuml/node_graph/macros.rb +39 -0
  342. data/lib/etassia/notation/plantuml/node_graph/metrics.rb +113 -0
  343. data/lib/etassia/notation/plantuml/node_graph/node.rb +44 -0
  344. data/lib/etassia/notation/plantuml/node_graph/note_tail.rb +58 -0
  345. data/lib/etassia/notation/plantuml/node_graph/packer.rb +126 -0
  346. data/lib/etassia/notation/plantuml/node_graph/parser.rb +309 -0
  347. data/lib/etassia/notation/plantuml/node_graph/paths.rb +48 -0
  348. data/lib/etassia/notation/plantuml/node_graph/ranking.rb +231 -0
  349. data/lib/etassia/notation/plantuml/node_graph/reader.rb +53 -0
  350. data/lib/etassia/notation/plantuml/node_graph/references.rb +38 -0
  351. data/lib/etassia/notation/plantuml/node_graph/renderer.rb +160 -0
  352. data/lib/etassia/notation/plantuml/node_graph/scene.rb +22 -0
  353. data/lib/etassia/notation/plantuml/node_graph/shapes.rb +302 -0
  354. data/lib/etassia/notation/plantuml/node_graph/skipped_ranks.rb +61 -0
  355. data/lib/etassia/notation/plantuml/node_graph/tab.rb +68 -0
  356. data/lib/etassia/notation/plantuml/node_graph/usecase_ellipse.rb +100 -0
  357. data/lib/etassia/notation/plantuml/node_graph.rb +38 -0
  358. data/lib/etassia/notation/plantuml/note.rb +27 -0
  359. data/lib/etassia/notation/plantuml/note_layout.rb +257 -0
  360. data/lib/etassia/notation/plantuml/note_outline.rb +68 -0
  361. data/lib/etassia/notation/plantuml/objects/map_rows.rb +46 -0
  362. data/lib/etassia/notation/plantuml/objects/reader.rb +208 -0
  363. data/lib/etassia/notation/plantuml/objects.rb +39 -0
  364. data/lib/etassia/notation/plantuml/package.rb +45 -0
  365. data/lib/etassia/notation/plantuml/package_color.rb +32 -0
  366. data/lib/etassia/notation/plantuml/package_frames.rb +178 -0
  367. data/lib/etassia/notation/plantuml/parser.rb +622 -0
  368. data/lib/etassia/notation/plantuml/portion_visibility.rb +91 -0
  369. data/lib/etassia/notation/plantuml/qualified_association_layout.rb +332 -0
  370. data/lib/etassia/notation/plantuml/qualifier_box.rb +78 -0
  371. data/lib/etassia/notation/plantuml/rank_chain.rb +527 -0
  372. data/lib/etassia/notation/plantuml/rank_hierarchy.rb +347 -0
  373. data/lib/etassia/notation/plantuml/relation.rb +103 -0
  374. data/lib/etassia/notation/plantuml/relation_label_separator.rb +199 -0
  375. data/lib/etassia/notation/plantuml/relation_path_points.rb +84 -0
  376. data/lib/etassia/notation/plantuml/renderer.rb +490 -0
  377. data/lib/etassia/notation/plantuml/scene.rb +134 -0
  378. data/lib/etassia/notation/plantuml/segment_box.rb +85 -0
  379. data/lib/etassia/notation/plantuml/sequence/activation.rb +28 -0
  380. data/lib/etassia/notation/plantuml/sequence/appearance.rb +71 -0
  381. data/lib/etassia/notation/plantuml/sequence/arrow_end.rb +23 -0
  382. data/lib/etassia/notation/plantuml/sequence/arrow_marks.rb +111 -0
  383. data/lib/etassia/notation/plantuml/sequence/arrow_style.rb +42 -0
  384. data/lib/etassia/notation/plantuml/sequence/arrow_syntax.rb +122 -0
  385. data/lib/etassia/notation/plantuml/sequence/bar_tracker.rb +59 -0
  386. data/lib/etassia/notation/plantuml/sequence/box.rb +23 -0
  387. data/lib/etassia/notation/plantuml/sequence/chrome.rb +60 -0
  388. data/lib/etassia/notation/plantuml/sequence/chrome_rows.rb +184 -0
  389. data/lib/etassia/notation/plantuml/sequence/create.rb +34 -0
  390. data/lib/etassia/notation/plantuml/sequence/delay.rb +19 -0
  391. data/lib/etassia/notation/plantuml/sequence/destroy.rb +20 -0
  392. data/lib/etassia/notation/plantuml/sequence/diagram.rb +86 -0
  393. data/lib/etassia/notation/plantuml/sequence/divider.rb +19 -0
  394. data/lib/etassia/notation/plantuml/sequence/edge.rb +53 -0
  395. data/lib/etassia/notation/plantuml/sequence/embedded.rb +77 -0
  396. data/lib/etassia/notation/plantuml/sequence/fill.rb +56 -0
  397. data/lib/etassia/notation/plantuml/sequence/fragment.rb +28 -0
  398. data/lib/etassia/notation/plantuml/sequence/fragment_shape.rb +138 -0
  399. data/lib/etassia/notation/plantuml/sequence/head_style.rb +43 -0
  400. data/lib/etassia/notation/plantuml/sequence/ir_adapter/blocks.rb +73 -0
  401. data/lib/etassia/notation/plantuml/sequence/ir_adapter/fills.rb +24 -0
  402. data/lib/etassia/notation/plantuml/sequence/ir_adapter/items.rb +48 -0
  403. data/lib/etassia/notation/plantuml/sequence/ir_adapter/messages.rb +62 -0
  404. data/lib/etassia/notation/plantuml/sequence/ir_adapter/participants.rb +42 -0
  405. data/lib/etassia/notation/plantuml/sequence/ir_adapter/settings.rb +54 -0
  406. data/lib/etassia/notation/plantuml/sequence/ir_adapter.rb +38 -0
  407. data/lib/etassia/notation/plantuml/sequence/ir_reader/blocks.rb +77 -0
  408. data/lib/etassia/notation/plantuml/sequence/ir_reader/fills.rb +27 -0
  409. data/lib/etassia/notation/plantuml/sequence/ir_reader/index.rb +36 -0
  410. data/lib/etassia/notation/plantuml/sequence/ir_reader/items.rb +35 -0
  411. data/lib/etassia/notation/plantuml/sequence/ir_reader/messages.rb +70 -0
  412. data/lib/etassia/notation/plantuml/sequence/ir_reader/participants.rb +42 -0
  413. data/lib/etassia/notation/plantuml/sequence/ir_reader/settings.rb +74 -0
  414. data/lib/etassia/notation/plantuml/sequence/ir_reader.rb +38 -0
  415. data/lib/etassia/notation/plantuml/sequence/keyword_defaults.rb +28 -0
  416. data/lib/etassia/notation/plantuml/sequence/layout.rb +1567 -0
  417. data/lib/etassia/notation/plantuml/sequence/message.rb +97 -0
  418. data/lib/etassia/notation/plantuml/sequence/message_wrap.rb +77 -0
  419. data/lib/etassia/notation/plantuml/sequence/note.rb +61 -0
  420. data/lib/etassia/notation/plantuml/sequence/note_fill.rb +35 -0
  421. data/lib/etassia/notation/plantuml/sequence/note_geometry.rb +126 -0
  422. data/lib/etassia/notation/plantuml/sequence/note_shape.rb +51 -0
  423. data/lib/etassia/notation/plantuml/sequence/numbered_label.rb +57 -0
  424. data/lib/etassia/notation/plantuml/sequence/numbering.rb +49 -0
  425. data/lib/etassia/notation/plantuml/sequence/outline.rb +204 -0
  426. data/lib/etassia/notation/plantuml/sequence/page_break.rb +17 -0
  427. data/lib/etassia/notation/plantuml/sequence/paint.rb +79 -0
  428. data/lib/etassia/notation/plantuml/sequence/parallel_message.rb +19 -0
  429. data/lib/etassia/notation/plantuml/sequence/parser.rb +844 -0
  430. data/lib/etassia/notation/plantuml/sequence/participant.rb +27 -0
  431. data/lib/etassia/notation/plantuml/sequence/picture.rb +29 -0
  432. data/lib/etassia/notation/plantuml/sequence/ref.rb +24 -0
  433. data/lib/etassia/notation/plantuml/sequence/ref_shape.rb +74 -0
  434. data/lib/etassia/notation/plantuml/sequence/refusals.rb +47 -0
  435. data/lib/etassia/notation/plantuml/sequence/renderer.rb +501 -0
  436. data/lib/etassia/notation/plantuml/sequence/scene.rb +200 -0
  437. data/lib/etassia/notation/plantuml/sequence/skin.rb +76 -0
  438. data/lib/etassia/notation/plantuml/sequence/spacing.rb +28 -0
  439. data/lib/etassia/notation/plantuml/sequence/style.rb +151 -0
  440. data/lib/etassia/notation/plantuml/sequence/tab_size.rb +42 -0
  441. data/lib/etassia/notation/plantuml/sequence/walker.rb +1190 -0
  442. data/lib/etassia/notation/plantuml/sequence.rb +47 -0
  443. data/lib/etassia/notation/plantuml/source_lines.rb +33 -0
  444. data/lib/etassia/notation/plantuml/state/axis_solver.rb +272 -0
  445. data/lib/etassia/notation/plantuml/state/cluster_padding.rb +75 -0
  446. data/lib/etassia/notation/plantuml/state/curve.rb +73 -0
  447. data/lib/etassia/notation/plantuml/state/dot_axis.rb +248 -0
  448. data/lib/etassia/notation/plantuml/state/extent.rb +42 -0
  449. data/lib/etassia/notation/plantuml/state/hierarchy.rb +355 -0
  450. data/lib/etassia/notation/plantuml/state/label_clearance.rb +148 -0
  451. data/lib/etassia/notation/plantuml/state/label_reach.rb +139 -0
  452. data/lib/etassia/notation/plantuml/state/layout.rb +173 -0
  453. data/lib/etassia/notation/plantuml/state/level_edges.rb +113 -0
  454. data/lib/etassia/notation/plantuml/state/look.rb +36 -0
  455. data/lib/etassia/notation/plantuml/state/note_shape.rb +73 -0
  456. data/lib/etassia/notation/plantuml/state/plane.rb +85 -0
  457. data/lib/etassia/notation/plantuml/state/ranking.rb +181 -0
  458. data/lib/etassia/notation/plantuml/state/reader.rb +310 -0
  459. data/lib/etassia/notation/plantuml/state/renderer.rb +253 -0
  460. data/lib/etassia/notation/plantuml/state/route_detour.rb +115 -0
  461. data/lib/etassia/notation/plantuml/state/route_geometry.rb +186 -0
  462. data/lib/etassia/notation/plantuml/state/routes.rb +196 -0
  463. data/lib/etassia/notation/plantuml/state/row.rb +88 -0
  464. data/lib/etassia/notation/plantuml/state/rows.rb +50 -0
  465. data/lib/etassia/notation/plantuml/state/stretch.rb +71 -0
  466. data/lib/etassia/notation/plantuml/state.rb +62 -0
  467. data/lib/etassia/notation/plantuml/stereotype_head.rb +58 -0
  468. data/lib/etassia/notation/plantuml/style/bound.rb +34 -0
  469. data/lib/etassia/notation/plantuml/style/colour.rb +41 -0
  470. data/lib/etassia/notation/plantuml/style/colour_names.rb +89 -0
  471. data/lib/etassia/notation/plantuml/style/defaults.rb +33 -0
  472. data/lib/etassia/notation/plantuml/style/inline.rb +56 -0
  473. data/lib/etassia/notation/plantuml/style/reader.rb +242 -0
  474. data/lib/etassia/notation/plantuml/style/sheet.rb +103 -0
  475. data/lib/etassia/notation/plantuml/style.rb +32 -0
  476. data/lib/etassia/notation/plantuml/style_reader.rb +160 -0
  477. data/lib/etassia/notation/plantuml/style_sheet.rb +27 -0
  478. data/lib/etassia/notation/plantuml/styled_relation_curve.rb +71 -0
  479. data/lib/etassia/notation/plantuml/timing/arrows.rb +81 -0
  480. data/lib/etassia/notation/plantuml/timing/axis.rb +100 -0
  481. data/lib/etassia/notation/plantuml/timing/layout.rb +172 -0
  482. data/lib/etassia/notation/plantuml/timing/model.rb +34 -0
  483. data/lib/etassia/notation/plantuml/timing/reader.rb +173 -0
  484. data/lib/etassia/notation/plantuml/timing/signals.rb +328 -0
  485. data/lib/etassia/notation/plantuml/timing.rb +38 -0
  486. data/lib/etassia/notation/plantuml/tree/layout.rb +276 -0
  487. data/lib/etassia/notation/plantuml/tree/mindmap_layout.rb +157 -0
  488. data/lib/etassia/notation/plantuml/tree/reader.rb +186 -0
  489. data/lib/etassia/notation/plantuml/tree/renderer.rb +67 -0
  490. data/lib/etassia/notation/plantuml/tree/role.rb +57 -0
  491. data/lib/etassia/notation/plantuml/tree/rules.rb +156 -0
  492. data/lib/etassia/notation/plantuml/tree/wbs_layout.rb +164 -0
  493. data/lib/etassia/notation/plantuml/tree.rb +41 -0
  494. data/lib/etassia/notation/plantuml/unsupported_construct_error.rb +39 -0
  495. data/lib/etassia/notation/plantuml/unsupported_constructs.rb +103 -0
  496. data/lib/etassia/notation/plantuml/usecase.rb +36 -0
  497. data/lib/etassia/notation/plantuml.rb +132 -0
  498. data/lib/etassia/notation/plantuml_data/boxes/frames.rb +101 -0
  499. data/lib/etassia/notation/plantuml_data/boxes/graph_layout.rb +348 -0
  500. data/lib/etassia/notation/plantuml_data/boxes/heads.rb +65 -0
  501. data/lib/etassia/notation/plantuml_data/boxes/highlights.rb +70 -0
  502. data/lib/etassia/notation/plantuml_data/boxes/inline_rows.rb +99 -0
  503. data/lib/etassia/notation/plantuml_data/boxes/json_reader.rb +24 -0
  504. data/lib/etassia/notation/plantuml_data/boxes/link_text.rb +94 -0
  505. data/lib/etassia/notation/plantuml_data/boxes/marks.rb +76 -0
  506. data/lib/etassia/notation/plantuml_data/boxes/ornaments.rb +130 -0
  507. data/lib/etassia/notation/plantuml_data/boxes/renderer.rb +95 -0
  508. data/lib/etassia/notation/plantuml_data/boxes/row_alignment.rb +58 -0
  509. data/lib/etassia/notation/plantuml_data/boxes/row_bend.rb +43 -0
  510. data/lib/etassia/notation/plantuml_data/boxes/scene.rb +27 -0
  511. data/lib/etassia/notation/plantuml_data/boxes/table.rb +56 -0
  512. data/lib/etassia/notation/plantuml_data/boxes/table_box.rb +355 -0
  513. data/lib/etassia/notation/plantuml_data/boxes/text.rb +101 -0
  514. data/lib/etassia/notation/plantuml_data/boxes/tree_builder.rb +82 -0
  515. data/lib/etassia/notation/plantuml_data/boxes/tree_layout.rb +82 -0
  516. data/lib/etassia/notation/plantuml_data/boxes/yaml_reader.rb +105 -0
  517. data/lib/etassia/notation/plantuml_data/openiconic.LICENSE +6 -0
  518. data/lib/etassia/notation/plantuml_data/openiconic.json +1 -0
  519. data/lib/etassia/notation/plantuml_data.rb +84 -0
  520. data/lib/etassia/notation/plantuml_salt/block.rb +80 -0
  521. data/lib/etassia/notation/plantuml_salt/box.rb +30 -0
  522. data/lib/etassia/notation/plantuml_salt/font_metrics.rb +28 -0
  523. data/lib/etassia/notation/plantuml_salt/grid_marks.rb +66 -0
  524. data/lib/etassia/notation/plantuml_salt/group_marks.rb +77 -0
  525. data/lib/etassia/notation/plantuml_salt/layout.rb +206 -0
  526. data/lib/etassia/notation/plantuml_salt/mark.rb +36 -0
  527. data/lib/etassia/notation/plantuml_salt/markup.rb +57 -0
  528. data/lib/etassia/notation/plantuml_salt/parser.rb +239 -0
  529. data/lib/etassia/notation/plantuml_salt/renderer.rb +138 -0
  530. data/lib/etassia/notation/plantuml_salt/row.rb +19 -0
  531. data/lib/etassia/notation/plantuml_salt/run.rb +34 -0
  532. data/lib/etassia/notation/plantuml_salt/scene.rb +23 -0
  533. data/lib/etassia/notation/plantuml_salt/scroll_marks.rb +94 -0
  534. data/lib/etassia/notation/plantuml_salt/tab_marks.rb +74 -0
  535. data/lib/etassia/notation/plantuml_salt/tree_marks.rb +127 -0
  536. data/lib/etassia/notation/plantuml_salt/widget.rb +40 -0
  537. data/lib/etassia/notation/plantuml_salt/widget_marks.rb +319 -0
  538. data/lib/etassia/notation/plantuml_salt.rb +66 -0
  539. data/lib/etassia/notation/plugin_failure.rb +42 -0
  540. data/lib/etassia/notation.rb +289 -0
  541. data/lib/etassia/parser/architecture.rb +25 -0
  542. data/lib/etassia/parser/atoms/delimited_run.rb +82 -0
  543. data/lib/etassia/parser/atoms/greedy_run.rb +116 -0
  544. data/lib/etassia/parser/atoms/joined.rb +47 -0
  545. data/lib/etassia/parser/atoms/trimmed_run.rb +47 -0
  546. data/lib/etassia/parser/base.rb +258 -0
  547. data/lib/etassia/parser/block.rb +32 -0
  548. data/lib/etassia/parser/builders/architecture.rb +135 -0
  549. data/lib/etassia/parser/builders/block.rb +288 -0
  550. data/lib/etassia/parser/builders/c4.rb +275 -0
  551. data/lib/etassia/parser/builders/capture_string.rb +17 -0
  552. data/lib/etassia/parser/builders/class_diagram.rb +539 -0
  553. data/lib/etassia/parser/builders/er_diagram.rb +308 -0
  554. data/lib/etassia/parser/builders/error.rb +51 -0
  555. data/lib/etassia/parser/builders/flowchart.rb +1150 -0
  556. data/lib/etassia/parser/builders/gantt.rb +267 -0
  557. data/lib/etassia/parser/builders/git_graph.rb +301 -0
  558. data/lib/etassia/parser/builders/info.rb +57 -0
  559. data/lib/etassia/parser/builders/kanban.rb +411 -0
  560. data/lib/etassia/parser/builders/mindmap.rb +271 -0
  561. data/lib/etassia/parser/builders/packet.rb +85 -0
  562. data/lib/etassia/parser/builders/pie.rb +105 -0
  563. data/lib/etassia/parser/builders/quadrant.rb +165 -0
  564. data/lib/etassia/parser/builders/radar.rb +157 -0
  565. data/lib/etassia/parser/builders/requirement.rb +230 -0
  566. data/lib/etassia/parser/builders/sankey.rb +142 -0
  567. data/lib/etassia/parser/builders/sequence.rb +431 -0
  568. data/lib/etassia/parser/builders/sequence_blocks.rb +117 -0
  569. data/lib/etassia/parser/builders/sequence_box_title.rb +57 -0
  570. data/lib/etassia/parser/builders/state_diagram.rb +364 -0
  571. data/lib/etassia/parser/builders/timeline.rb +133 -0
  572. data/lib/etassia/parser/builders/treemap.rb +138 -0
  573. data/lib/etassia/parser/builders/xy_chart.rb +148 -0
  574. data/lib/etassia/parser/c4.rb +37 -0
  575. data/lib/etassia/parser/class_diagram.rb +58 -0
  576. data/lib/etassia/parser/class_namespaces.rb +62 -0
  577. data/lib/etassia/parser/class_notes.rb +54 -0
  578. data/lib/etassia/parser/er_diagram.rb +28 -0
  579. data/lib/etassia/parser/error.rb +30 -0
  580. data/lib/etassia/parser/flowchart.rb +87 -0
  581. data/lib/etassia/parser/gantt.rb +43 -0
  582. data/lib/etassia/parser/git_graph.rb +106 -0
  583. data/lib/etassia/parser/grammars/architecture.rb +165 -0
  584. data/lib/etassia/parser/grammars/block.rb +190 -0
  585. data/lib/etassia/parser/grammars/c4.rb +229 -0
  586. data/lib/etassia/parser/grammars/class_diagram.rb +606 -0
  587. data/lib/etassia/parser/grammars/common.rb +107 -0
  588. data/lib/etassia/parser/grammars/er_diagram.rb +232 -0
  589. data/lib/etassia/parser/grammars/error.rb +32 -0
  590. data/lib/etassia/parser/grammars/flowchart.rb +1722 -0
  591. data/lib/etassia/parser/grammars/gantt.rb +198 -0
  592. data/lib/etassia/parser/grammars/git_graph.rb +234 -0
  593. data/lib/etassia/parser/grammars/info.rb +53 -0
  594. data/lib/etassia/parser/grammars/kanban.rb +417 -0
  595. data/lib/etassia/parser/grammars/mermaid_unicode_text.rb +108 -0
  596. data/lib/etassia/parser/grammars/mindmap.rb +220 -0
  597. data/lib/etassia/parser/grammars/packet.rb +71 -0
  598. data/lib/etassia/parser/grammars/pie.rb +128 -0
  599. data/lib/etassia/parser/grammars/quadrant.rb +202 -0
  600. data/lib/etassia/parser/grammars/radar.rb +158 -0
  601. data/lib/etassia/parser/grammars/requirement.rb +258 -0
  602. data/lib/etassia/parser/grammars/sankey.rb +104 -0
  603. data/lib/etassia/parser/grammars/sequence.rb +940 -0
  604. data/lib/etassia/parser/grammars/state_diagram.rb +382 -0
  605. data/lib/etassia/parser/grammars/timeline.rb +153 -0
  606. data/lib/etassia/parser/grammars/treemap.rb +122 -0
  607. data/lib/etassia/parser/grammars/xy_chart.rb +119 -0
  608. data/lib/etassia/parser/info.rb +32 -0
  609. data/lib/etassia/parser/kanban.rb +131 -0
  610. data/lib/etassia/parser/mermaid_shapes.rb +106 -0
  611. data/lib/etassia/parser/metadata_yaml.rb +452 -0
  612. data/lib/etassia/parser/mindmap.rb +92 -0
  613. data/lib/etassia/parser/native/builders/architecture.rb +103 -0
  614. data/lib/etassia/parser/native/builders/block.rb +68 -0
  615. data/lib/etassia/parser/native/builders/c4.rb +16 -0
  616. data/lib/etassia/parser/native/builders/class_diagram.rb +63 -0
  617. data/lib/etassia/parser/native/builders/er_diagram.rb +47 -0
  618. data/lib/etassia/parser/native/builders/flowchart.rb +58 -0
  619. data/lib/etassia/parser/native/builders/gantt.rb +35 -0
  620. data/lib/etassia/parser/native/builders/gitgraph.rb +35 -0
  621. data/lib/etassia/parser/native/builders/info.rb +30 -0
  622. data/lib/etassia/parser/native/builders/kanban.rb +37 -0
  623. data/lib/etassia/parser/native/builders/mindmap.rb +26 -0
  624. data/lib/etassia/parser/native/builders/packet.rb +63 -0
  625. data/lib/etassia/parser/native/builders/pie.rb +82 -0
  626. data/lib/etassia/parser/native/builders/quadrant.rb +27 -0
  627. data/lib/etassia/parser/native/builders/radar.rb +84 -0
  628. data/lib/etassia/parser/native/builders/requirement.rb +25 -0
  629. data/lib/etassia/parser/native/builders/sankey.rb +18 -0
  630. data/lib/etassia/parser/native/builders/sequence.rb +48 -0
  631. data/lib/etassia/parser/native/builders/state_diagram.rb +61 -0
  632. data/lib/etassia/parser/native/builders/timeline.rb +46 -0
  633. data/lib/etassia/parser/native/builders/treemap.rb +60 -0
  634. data/lib/etassia/parser/native/builders/user_journey.rb +83 -0
  635. data/lib/etassia/parser/native/builders/xy_chart.rb +94 -0
  636. data/lib/etassia/parser/native/declined.rb +12 -0
  637. data/lib/etassia/parser/native/mermaid.json +1 -0
  638. data/lib/etassia/parser/native/text.rb +31 -0
  639. data/lib/etassia/parser/native.rb +99 -0
  640. data/lib/etassia/parser/packet.rb +56 -0
  641. data/lib/etassia/parser/pie.rb +32 -0
  642. data/lib/etassia/parser/quadrant.rb +77 -0
  643. data/lib/etassia/parser/radar.rb +99 -0
  644. data/lib/etassia/parser/requirement.rb +32 -0
  645. data/lib/etassia/parser/sankey.rb +47 -0
  646. data/lib/etassia/parser/sequence.rb +34 -0
  647. data/lib/etassia/parser/state_diagram.rb +29 -0
  648. data/lib/etassia/parser/timeline.rb +40 -0
  649. data/lib/etassia/parser/treemap.rb +25 -0
  650. data/lib/etassia/parser/user_journey.rb +253 -0
  651. data/lib/etassia/parser/xy_chart.rb +98 -0
  652. data/lib/etassia/parser.rb +18 -0
  653. data/lib/etassia/renderer/architecture.rb +232 -0
  654. data/lib/etassia/renderer/architecture_edge_router.rb +379 -0
  655. data/lib/etassia/renderer/base.rb +295 -0
  656. data/lib/etassia/renderer/block.rb +157 -0
  657. data/lib/etassia/renderer/c4.rb +294 -0
  658. data/lib/etassia/renderer/class_diagram.rb +671 -0
  659. data/lib/etassia/renderer/er_diagram.rb +842 -0
  660. data/lib/etassia/renderer/error.rb +131 -0
  661. data/lib/etassia/renderer/flowchart.rb +315 -0
  662. data/lib/etassia/renderer/gantt.rb +177 -0
  663. data/lib/etassia/renderer/git_graph.rb +224 -0
  664. data/lib/etassia/renderer/info.rb +59 -0
  665. data/lib/etassia/renderer/kanban.rb +157 -0
  666. data/lib/etassia/renderer/line_break_text.rb +56 -0
  667. data/lib/etassia/renderer/markdown_text.rb +106 -0
  668. data/lib/etassia/renderer/mindmap.rb +290 -0
  669. data/lib/etassia/renderer/packet.rb +87 -0
  670. data/lib/etassia/renderer/pie.rb +113 -0
  671. data/lib/etassia/renderer/quadrant.rb +189 -0
  672. data/lib/etassia/renderer/radar.rb +191 -0
  673. data/lib/etassia/renderer/requirement.rb +209 -0
  674. data/lib/etassia/renderer/sankey.rb +114 -0
  675. data/lib/etassia/renderer/sequence/frame_drawing.rb +169 -0
  676. data/lib/etassia/renderer/sequence/note_drawing.rb +69 -0
  677. data/lib/etassia/renderer/sequence.rb +490 -0
  678. data/lib/etassia/renderer/state_diagram.rb +202 -0
  679. data/lib/etassia/renderer/timeline.rb +134 -0
  680. data/lib/etassia/renderer/timeline_palette.rb +18 -0
  681. data/lib/etassia/renderer/treemap/section_total.rb +33 -0
  682. data/lib/etassia/renderer/treemap.rb +128 -0
  683. data/lib/etassia/renderer/user_journey.rb +209 -0
  684. data/lib/etassia/renderer/xy_chart.rb +180 -0
  685. data/lib/etassia/renderer.rb +22 -0
  686. data/lib/etassia/runtime.rb +125 -0
  687. data/lib/etassia/source/frontmatter.rb +501 -0
  688. data/lib/etassia/source.rb +224 -0
  689. data/lib/etassia/svg/arrowhead.rb +205 -0
  690. data/lib/etassia/svg/circle.rb +19 -0
  691. data/lib/etassia/svg/document.rb +106 -0
  692. data/lib/etassia/svg/element.rb +209 -0
  693. data/lib/etassia/svg/ellipse.rb +23 -0
  694. data/lib/etassia/svg/escaping.rb +149 -0
  695. data/lib/etassia/svg/group.rb +64 -0
  696. data/lib/etassia/svg/line.rb +21 -0
  697. data/lib/etassia/svg/numbers.rb +53 -0
  698. data/lib/etassia/svg/path.rb +67 -0
  699. data/lib/etassia/svg/path_geometry.rb +378 -0
  700. data/lib/etassia/svg/polygon.rb +25 -0
  701. data/lib/etassia/svg/polyline.rb +28 -0
  702. data/lib/etassia/svg/rect.rb +34 -0
  703. data/lib/etassia/svg/style.rb +50 -0
  704. data/lib/etassia/svg/text.rb +181 -0
  705. data/lib/etassia/svg/tspan.rb +48 -0
  706. data/lib/etassia/svg.rb +38 -0
  707. data/lib/etassia/text_measurement/arial_advances.rb +122 -0
  708. data/lib/etassia/text_measurement/dejavu_advances.rb +111 -0
  709. data/lib/etassia/text_measurement/times_advances.rb +64 -0
  710. data/lib/etassia/text_measurement/trebuchet_advances.rb +53 -0
  711. data/lib/etassia/text_measurement/trebuchet_kerning.rb +29 -0
  712. data/lib/etassia/text_measurement.rb +198 -0
  713. data/lib/etassia/theme/builtin/dark.yml +229 -0
  714. data/lib/etassia/theme/builtin/default.yml +239 -0
  715. data/lib/etassia/theme/builtin/high_contrast.yml +231 -0
  716. data/lib/etassia/theme/builtin/light.yml +229 -0
  717. data/lib/etassia/theme/color_palette.rb +97 -0
  718. data/lib/etassia/theme/completion.rb +50 -0
  719. data/lib/etassia/theme/effect_styles.rb +34 -0
  720. data/lib/etassia/theme/registry.rb +45 -0
  721. data/lib/etassia/theme/shape_styles.rb +34 -0
  722. data/lib/etassia/theme/spacing_config.rb +30 -0
  723. data/lib/etassia/theme/typography.rb +40 -0
  724. data/lib/etassia/theme.rb +73 -0
  725. data/lib/etassia/version.rb +5 -0
  726. data/lib/etassia.rb +40 -0
  727. metadata +865 -0
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../layout/mindmap"
4
+ require_relative "reader"
5
+ require_relative "role"
6
+
7
+ module Etassia
8
+ module Notation
9
+ module PlantUML
10
+ module Tree
11
+ # One laid-out node of a tree: the box it draws and the text in it.
12
+ class Node < Etassia::Layout::Mindmap::Node
13
+ attribute :boxed, :boolean
14
+ attribute :fill, :string
15
+ attribute :corner_radius, :float
16
+ attribute :stroke, :string
17
+ attribute :stroke_width, :float
18
+ attribute :dasharray, :string
19
+ attribute :font_colour, :string
20
+ end
21
+
22
+ # A connector, as the path it draws.
23
+ class Edge < Etassia::Layout::Mindmap::Edge
24
+ attribute :stroke_width, :float
25
+ attribute :stroke, :string
26
+ attribute :dasharray, :string
27
+ end
28
+
29
+ # What a tree layout hands its renderer.
30
+ class Scene < Etassia::Layout::Scene
31
+ attribute :view_box, :string
32
+ attribute :children, Node, collection: true, default: -> { [] }
33
+ attribute :edges, Edge, collection: true, default: -> { [] }
34
+ end
35
+
36
+ # The part of a PlantUML tree layout that mindmaps and work breakdown
37
+ # structures share: it reads the hierarchy graph into a forest, sizes
38
+ # each box from its text, and returns the finished scene. The
39
+ # Mermaid mindmap layout it extends is a force layout; a subclass
40
+ # supplies the tree one through {#place_tree}.
41
+ #
42
+ # @abstract
43
+ class Layout < Etassia::Layout::Mindmap
44
+ MARGIN = 20.0
45
+ PAD_X = 10.0
46
+ PAD_Y = 10.0
47
+ LINE_RATIO = 1.1777
48
+ BASELINE_RATIO = 0.9667
49
+ # DejaVu Sans Mono, the JAR's `monospace`: line height and ascent.
50
+ MONO_LINE_RATIO = 1.1641
51
+ MONO_BASELINE_RATIO = 0.928
52
+ FILL = "#F1F1F1"
53
+ private_constant :MARGIN, :PAD_X, :PAD_Y, :LINE_RATIO,
54
+ :BASELINE_RATIO, :FILL,
55
+ :MONO_LINE_RATIO, :MONO_BASELINE_RATIO
56
+
57
+ # A node of the forest with its text measured.
58
+ Item = Struct.new(:id, :level, :side, :boxless, :fill, :lines,
59
+ :width, :height, :children, :mono)
60
+ # A placed box.
61
+ Box = Struct.new(:item, :x, :y) do
62
+ def right
63
+ x + item.width
64
+ end
65
+
66
+ def mid_y
67
+ y + (item.height / 2.0)
68
+ end
69
+ end
70
+ private_constant :Item, :Box
71
+
72
+ # @param rules [Rules] what the source's `<style>` blocks set
73
+ # @return [Class] this layout, drawing with those rules
74
+ def self.styled(rules)
75
+ return self unless rules.any?
76
+
77
+ Class.new(self) { define_method(:rules) { rules } }
78
+ end
79
+
80
+ private
81
+
82
+ def rules
83
+ @rules ||= Rules.new
84
+ end
85
+
86
+ def scene(graph)
87
+ @boxes = []
88
+ @segments = []
89
+ @depths = []
90
+ @row_end = nil
91
+ top = MARGIN
92
+ forest(graph).each do |root|
93
+ top = place_tree(root, top) + gap_between_trees
94
+ end
95
+ build_scene
96
+ end
97
+
98
+ def font_size
99
+ raise NotImplementedError
100
+ end
101
+
102
+ def gap_between_trees
103
+ raise NotImplementedError
104
+ end
105
+
106
+ # @return [Float] the bottom of the placed tree
107
+ def place_tree(_root, _top)
108
+ raise NotImplementedError
109
+ end
110
+
111
+ def line_height
112
+ font_size * LINE_RATIO
113
+ end
114
+
115
+ def forest(graph)
116
+ by_parent = graph.nodes.group_by(&:parent_id)
117
+ by_parent.fetch(nil, []).map { |node| item(node, by_parent, 1) }
118
+ end
119
+
120
+ def item(node, by_parent, level)
121
+ children = by_parent.fetch(node.id, []).map do |child|
122
+ item(child, by_parent, level + 1)
123
+ end
124
+ sized_item(node, level, children)
125
+ end
126
+
127
+ def sized_item(node, level, children)
128
+ role = Role.parse(node.role)
129
+ lines, mono = text_lines(node)
130
+ width, height = measured(lines, mono, boxless: role.boxless)
131
+ Item.new(node.id, level, role.side, role.boxless, role.fill, lines,
132
+ width, height, children, mono)
133
+ end
134
+
135
+ def text_lines(node)
136
+ lines = node.label.to_s.split("\n", -1)
137
+ lines = [""] if lines.empty?
138
+ [lines.map { |line| line.delete_prefix(Reader::MONO_MARK) },
139
+ lines.map { |line| line.start_with?(Reader::MONO_MARK) }]
140
+ end
141
+
142
+ def measured(lines, mono, boxless: false)
143
+ widest = lines.zip(mono).map do |line, mono_line|
144
+ line_width(line, mono_line)
145
+ end.max
146
+ [widest + (2 * PAD_X),
147
+ mono.sum { |mono_line| pitch(mono_line) } + (2 * pad_y(boxless))]
148
+ end
149
+
150
+ def line_width(line, mono)
151
+ return measure_text(line, font_size: font_size)[:width] unless mono
152
+
153
+ TextMeasurement.measure_mono(line, font_size: font_size)[:width]
154
+ end
155
+
156
+ def pitch(mono)
157
+ mono ? font_size * MONO_LINE_RATIO : line_height
158
+ end
159
+
160
+ # The room above and below a box's text; a boxless node's own
161
+ # layout may keep it tighter.
162
+ def pad_y(boxless)
163
+ boxless ? boxless_pad_y : PAD_Y
164
+ end
165
+
166
+ def boxless_pad_y
167
+ PAD_Y
168
+ end
169
+
170
+ def box(item, left, top)
171
+ Box.new(item, left, top).tap { |placed| @boxes << placed }
172
+ end
173
+
174
+ # @param depth [Integer] the depth of the parent the line leaves
175
+ def segment(from_x, from_y, to_x, to_y, depth)
176
+ curve("M#{from_x.round(3)},#{from_y.round(3)} " \
177
+ "L#{to_x.round(3)},#{to_y.round(3)}", depth)
178
+ end
179
+
180
+ def curve(path, depth)
181
+ @segments << path
182
+ @depths << depth
183
+ end
184
+
185
+ def build_scene
186
+ shift = MARGIN - @boxes.map(&:x).min.to_f
187
+ width, height = scene_size(shift)
188
+ Scene.new(width: width, height: height,
189
+ view_box: "0 0 #{width.round(3)} #{height.round(3)}",
190
+ children: @boxes.map { |b| node(b, shift) },
191
+ edges: edges(shift))
192
+ end
193
+
194
+ def scene_size(shift)
195
+ [(@boxes.map(&:right).max + shift) + MARGIN,
196
+ @boxes.map { |b| b.y + b.item.height }.max + MARGIN]
197
+ end
198
+
199
+ def edges(shift)
200
+ @segments.each_with_index.map do |path, index|
201
+ Edge.new(id: "link#{index}", path: shift_path(path, shift),
202
+ **connector_look(@depths[index]))
203
+ end
204
+ end
205
+
206
+ def connector_look(depth)
207
+ look = rules.arrow(depth)
208
+ { stroke_width: look.fetch(:stroke_width, stroke_width),
209
+ stroke: look[:stroke], dasharray: look[:dasharray] }
210
+ end
211
+
212
+ def stroke_width
213
+ 1.0
214
+ end
215
+
216
+ # Every number pair in a path is an `x,y` point.
217
+ def shift_path(path, shift)
218
+ path.gsub(/(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)/) do
219
+ px = Regexp.last_match(1).to_f + shift
220
+ "#{px.round(3)},#{Regexp.last_match(2)}"
221
+ end
222
+ end
223
+
224
+ def node(placed, shift)
225
+ item = placed.item
226
+ left = placed.x + shift
227
+ Node.new(id: item.id, level: item.level,
228
+ labels: [label(item, left, placed.y)],
229
+ **box_geometry(placed, left), **appearance(item))
230
+ end
231
+
232
+ def box_geometry(placed, left)
233
+ item = placed.item
234
+ { x: left, y: placed.y, width: item.width, height: item.height,
235
+ center_x: left + (item.width / 2.0), center_y: placed.mid_y }
236
+ end
237
+
238
+ def appearance(item)
239
+ look = rules.node(item.level - 1, boxless: item.boxless)
240
+ { shape: item.boxless ? "boxless" : "default",
241
+ boxed: !item.boxless, fill: item.fill || look[:fill] || FILL,
242
+ corner_radius: corner_of(look) }.merge(
243
+ look.slice(:stroke, :stroke_width, :dasharray, :font_colour),
244
+ )
245
+ end
246
+
247
+ def corner_radius
248
+ 0.0
249
+ end
250
+
251
+ # PlantUML draws a corner of half the RoundCorner it is given.
252
+ def corner_of(look)
253
+ look[:round_corner] ? look[:round_corner] / 2.0 : corner_radius
254
+ end
255
+
256
+ def label(item, left_edge, top)
257
+ left = left_edge + PAD_X
258
+ first = top + pad_y(item.boxless) + (font_size * BASELINE_RATIO)
259
+ Label.new(text: item.lines.join("\n"), x: left, y: first.round(3),
260
+ font_size: font_size,
261
+ lines: positioned_lines(item, left, top + PAD_Y))
262
+ end
263
+
264
+ def positioned_lines(item, left, line_top)
265
+ item.lines.zip(item.mono).map do |text, mono|
266
+ ascent = mono ? MONO_BASELINE_RATIO : BASELINE_RATIO
267
+ LabelLine.new(text: text, x: left, mono: mono,
268
+ y: (line_top + (font_size * ascent)).round(3))
269
+ .tap { line_top += pitch(mono) }
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "layout"
4
+
5
+ module Etassia
6
+ module Notation
7
+ module PlantUML
8
+ module Tree
9
+ # PlantUML's mindmap: the root in the middle, its right-hand
10
+ # branches growing right and its left-hand ones growing left, every
11
+ # parent centred on its children and joined to them by a curve.
12
+ class MindmapLayout < Layout
13
+ SIBLING_GAP = 20.0
14
+ LEVEL_GAP = 50.0
15
+ LEAD = 10.0
16
+ BEND = 25.0
17
+ private_constant :SIBLING_GAP, :LEVEL_GAP, :LEAD, :BEND
18
+
19
+ private
20
+
21
+ def font_size
22
+ 14.0
23
+ end
24
+
25
+ def gap_between_trees
26
+ SIBLING_GAP
27
+ end
28
+
29
+ def corner_radius
30
+ 12.5
31
+ end
32
+
33
+ # A subtree measured on its own: where each child sits relative to
34
+ # the item's centre, and how far the subtree reaches above and
35
+ # below that centre at each depth.
36
+ Subtree = Struct.new(:item, :children, :offsets, :contour)
37
+ private_constant :Subtree
38
+
39
+ def place_tree(root, top)
40
+ sides = fan_sides(root)
41
+ half = root.height / 2.0
42
+ low, high = extent(sides, half)
43
+ centre = top - low
44
+ place_sides(box(root, 0.0, centre - half), sides)
45
+ centre + high
46
+ end
47
+
48
+ def extent(sides, half)
49
+ reach = sides.flat_map { |(_, _, deep), _| deep.flatten }
50
+ [[reach.min, -half].compact.min, [reach.max, half].compact.max]
51
+ end
52
+
53
+ def fan_sides(root)
54
+ right, left = root.children.partition { |c| c.side == "right" }
55
+ [[fan(right), 1], [fan(left), -1]]
56
+ end
57
+
58
+ def place_sides(hub, sides)
59
+ sides.each do |(subs, offsets, _), direction|
60
+ place(hub, subs, offsets, direction)
61
+ end
62
+ end
63
+
64
+ def tree(item)
65
+ subs, offsets, deep = fan(item.children)
66
+ half = item.height / 2.0
67
+ Subtree.new(item, subs, offsets, [[-half, half]] + deep)
68
+ end
69
+
70
+ # Subtrees of siblings packed top to bottom, each as close to the
71
+ # one before as their contours allow, and centred on the middle of
72
+ # what they cover. Returns [subtrees, offsets from that middle,
73
+ # contour about it].
74
+ def fan(items)
75
+ subs = items.map { |item| tree(item) }
76
+ return [subs, [], []] if subs.empty?
77
+
78
+ [subs, *recentre(*stack(subs))]
79
+ end
80
+
81
+ def recentre(offsets, covered)
82
+ mid = (covered.flatten.min + covered.flatten.max) / 2.0
83
+ [offsets.map { |o| o - mid },
84
+ covered.map { |top, bottom| [top - mid, bottom - mid] }]
85
+ end
86
+
87
+ def stack(subs)
88
+ offsets = []
89
+ covered = []
90
+ subs.each do |sub|
91
+ offset = covered.empty? ? 0.0 : clearance(covered, sub.contour)
92
+ offsets << offset
93
+ absorb(covered, sub.contour, offset)
94
+ end
95
+ [offsets, covered]
96
+ end
97
+
98
+ def clearance(covered, contour)
99
+ shared = [covered.length, contour.length].min
100
+ (0...shared).map do |depth|
101
+ covered[depth].last + SIBLING_GAP - contour[depth].first
102
+ end.max
103
+ end
104
+
105
+ def absorb(covered, contour, offset)
106
+ contour.each_with_index do |(top, bottom), depth|
107
+ reach = [top + offset, bottom + offset]
108
+ covered[depth] = if covered[depth]
109
+ [[covered[depth].first, reach.first].min,
110
+ [covered[depth].last, reach.last].max]
111
+ else
112
+ reach
113
+ end
114
+ end
115
+ end
116
+
117
+ def place(parent, subs, offsets, direction)
118
+ subs.zip(offsets).each do |sub, offset|
119
+ child = child_box(parent, sub.item, direction,
120
+ parent.mid_y + offset)
121
+ join(parent, child, direction)
122
+ place(child, sub.children, sub.offsets, direction)
123
+ end
124
+ end
125
+
126
+ def child_box(parent, item, direction, centre)
127
+ left = if direction.positive?
128
+ parent.right + LEVEL_GAP
129
+ else
130
+ parent.x - LEVEL_GAP - item.width
131
+ end
132
+ box(item, left, centre - (item.height / 2.0))
133
+ end
134
+
135
+ def join(parent, child, direction)
136
+ start = direction.positive? ? parent.right : parent.x
137
+ stop = direction.positive? ? child.x : child.right
138
+ curve(connector(start, parent.mid_y, stop, child.mid_y, direction),
139
+ parent.item.level - 1)
140
+ end
141
+
142
+ def connector(from_x, from_y, to_x, to_y, direction)
143
+ lead = direction * LEAD
144
+ bend = direction * BEND
145
+ "M#{point(from_x, from_y)} L#{point(from_x + lead, from_y)} " \
146
+ "C#{point(from_x + bend, from_y)} #{point(to_x - bend, to_y)} " \
147
+ "#{point(to_x - lead, to_y)} L#{point(to_x, to_y)}"
148
+ end
149
+
150
+ def point(x_pos, y_pos)
151
+ "#{x_pos.round(3)},#{y_pos.round(3)}"
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../ir"
4
+ require_relative "../source_lines"
5
+ require_relative "../unsupported_construct_error"
6
+ require_relative "role"
7
+ require_relative "rules"
8
+
9
+ module Etassia
10
+ module Notation
11
+ module PlantUML
12
+ module Tree
13
+ # Reads a PlantUML mindmap or work breakdown structure into the
14
+ # hierarchy graph Etassia's mindmap already uses.
15
+ #
16
+ # A line is a run of `*` (or `+` and `-`, which also pick the side of
17
+ # the root) followed by the text; the run's length is the depth. A
18
+ # `:` in place of the space opens a multi-line text closed by a line
19
+ # ending in `;`. A `_` after the run draws no box, a `[#colour]`
20
+ # fills the box, and `<<name>>` at the end of the text applies the
21
+ # `.name` colour of a `<style>` block. A `<style>` block's other
22
+ # rules are kept in {#rules}. A line outside this subset raises
23
+ # {UnsupportedConstructError}.
24
+ class Reader
25
+ ITEM = /\A([*+-]+)([<>])?(_)?(?:\[(\#?\w+)\])?(:|[ \t])[ \t]*(.*)\z/
26
+ SKIPPED = /\A(?:title|header|footer|caption|legend|skinparam|scale|
27
+ !theme|hide|show|left[ ]to[ ]right[ ]direction|
28
+ top[ ]to[ ]bottom[ ]direction)\b/xi
29
+ STYLE_OPEN = /\A<style>/i
30
+ STYLE_CLOSE = %r{</style>\z}i
31
+ CLASS_STYLE = /\.(\w+)[ \t]*\{([^{}]*)\}/m
32
+ BACKGROUND = /BackgroundColor[ \t]+(\#?\w+)/i
33
+ TRAILING_CLASS = /[ \t]*<<(\w+)>>\z/
34
+ CODE_TAG = %r{\A</?code>\z}i
35
+ # A line of a `<code>` block carries this mark in front, which the
36
+ # layout reads back as "draw in the monospace family".
37
+ MONO_MARK = "\u{E000}"
38
+ private_constant :ITEM, :SKIPPED, :STYLE_OPEN, :STYLE_CLOSE,
39
+ :CLASS_STYLE, :BACKGROUND, :TRAILING_CLASS,
40
+ :CODE_TAG
41
+
42
+ # One line of the source, as read.
43
+ Entry = Struct.new(:id, :depth, :side, :boxless, :fill, :lines,
44
+ :parent, keyword_init: true)
45
+ private_constant :Entry
46
+
47
+ # @return [Rules] what the source's `<style>` blocks set
48
+ attr_reader :rules
49
+
50
+ # @param source [String] PlantUML source
51
+ # @param id [String] the graph's id, which names the kind
52
+ # @return [Etassia::IR::Graph]
53
+ # @raise [UnsupportedConstructError] on a line outside the subset
54
+ def parse(source, id:)
55
+ @entries = []
56
+ @rules = Rules.new
57
+ @classes = {}
58
+ @open = nil
59
+ @code = false
60
+ @style = nil
61
+ SourceLines.of(source).each { |text, number| read(text, number) }
62
+ IR::Graph.new(id: id, role: "hierarchy", nodes: nodes,
63
+ edges: edges)
64
+ end
65
+
66
+ private
67
+
68
+ def read(text, number)
69
+ return continue_text(text) if @open
70
+ return style_line(text) if @style
71
+ return if SKIPPED.match?(text)
72
+ return style_line(text.sub(STYLE_OPEN, ""), opening: true) if
73
+ STYLE_OPEN.match?(text)
74
+
75
+ item = ITEM.match(text)
76
+ raise refused(text, number) unless item
77
+
78
+ start_item(item)
79
+ end
80
+
81
+ def refused(text, number)
82
+ UnsupportedConstructError.new(
83
+ construct: "mindmap statement", line: number, text: text,
84
+ )
85
+ end
86
+
87
+ def style_line(text, opening: false)
88
+ @style = [] if opening
89
+ @style << text.sub(STYLE_CLOSE, "")
90
+ close_style if STYLE_CLOSE.match?(text)
91
+ end
92
+
93
+ def close_style
94
+ @rules.add(@style.join("\n"))
95
+ sheet = @style.join("\n").gsub(%r{//[^\n]*}, "")
96
+ sheet.scan(CLASS_STYLE) do |name, properties|
97
+ colour = BACKGROUND.match(properties)
98
+ @classes[name] = colour[1] if colour
99
+ end
100
+ @style = nil
101
+ end
102
+
103
+ def start_item(match)
104
+ marks, hang, boxless, colour, joint, rest = match.captures
105
+ entry = Entry.new(depth: marks.length, boxless: !boxless.nil?,
106
+ fill: colour, lines: [])
107
+ attach(entry, marks[0], hang)
108
+ settle(entry, joint, rest)
109
+ end
110
+
111
+ def settle(entry, joint, rest)
112
+ return @open = entry.tap { entry.lines << rest } if
113
+ joint == ":" && !rest.end_with?(";")
114
+
115
+ finish(entry, joint == ":" ? rest.delete_suffix(";") : rest)
116
+ end
117
+
118
+ def continue_text(text)
119
+ return @code = !text.start_with?("</") if CODE_TAG.match?(text)
120
+ return @open.lines << marked(text) unless text.end_with?(";")
121
+
122
+ entry = @open
123
+ @open = nil
124
+ last = text == ";" ? "" : marked(text.delete_suffix(";"))
125
+ @code = false
126
+ finish(entry, last, continued: true)
127
+ end
128
+
129
+ def marked(text)
130
+ @code ? "#{MONO_MARK}#{text}" : text
131
+ end
132
+
133
+ def finish(entry, last, continued: false)
134
+ entry.lines.pop if continued && entry.lines.last.to_s.empty?
135
+ entry.lines << last
136
+ entry.lines[-1] = classed(entry, entry.lines.last)
137
+ entry
138
+ end
139
+
140
+ def classed(entry, text)
141
+ match = TRAILING_CLASS.match(text)
142
+ return text unless match
143
+
144
+ entry.fill ||= @classes[match[1]]
145
+ text.sub(TRAILING_CLASS, "")
146
+ end
147
+
148
+ # The parent is the nearest earlier entry one level up; a first
149
+ # level entry is a root of its own.
150
+ def attach(entry, mark, hang)
151
+ entry.id = "n#{@entries.length + 1}"
152
+ entry.parent = @entries.reverse.find do |other|
153
+ other.depth < entry.depth
154
+ end
155
+ entry.side = side_of(entry.parent, mark, hang)
156
+ @entries << entry
157
+ end
158
+
159
+ def side_of(parent, mark, hang)
160
+ return "left" if mark == "-" || hang == "<"
161
+ return "right" if mark == "+" || hang == ">"
162
+
163
+ parent ? parent.side : "right"
164
+ end
165
+
166
+ def nodes
167
+ @entries.map do |entry|
168
+ role = Role.spell(side: entry.side, boxless: entry.boxless,
169
+ fill: entry.fill)
170
+ IR::Node.new(id: entry.id, label: entry.lines.join("\n"),
171
+ parent_id: entry.parent&.id, role: role)
172
+ end
173
+ end
174
+
175
+ def edges
176
+ @entries.select(&:parent).map do |entry|
177
+ IR::Edge.new(id: "#{entry.parent.id}_to_#{entry.id}",
178
+ source_id: entry.parent.id, target_id: entry.id,
179
+ role: "parent_child")
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../renderer/mindmap"
4
+
5
+ module Etassia
6
+ module Notation
7
+ module PlantUML
8
+ module Tree
9
+ # Draws a PlantUML tree: grey boxes with a dark outline, text set
10
+ # from the left of the box, and thin dark connectors under them. The
11
+ # Mermaid mindmap renderer it extends draws coloured, centred shapes.
12
+ class Renderer < Etassia::Renderer::Mindmap
13
+ INK = "#181818"
14
+ INK_TEXT = "#000000"
15
+ FONT = "sans-serif"
16
+ MONO_FONT = "monospace"
17
+ private_constant :INK, :INK_TEXT, :FONT, :MONO_FONT
18
+
19
+ protected
20
+
21
+ def render_connection(edge, svg)
22
+ svg.add_element(Svg::Path.new.tap do |path|
23
+ path.d = edge.path
24
+ path.stroke = edge.stroke || INK
25
+ path.stroke_width = edge.stroke_width.to_s
26
+ path.stroke_dasharray = edge.dasharray
27
+ path.fill = "none"
28
+ end)
29
+ end
30
+
31
+ def render_node(node, svg)
32
+ group = Svg::Group.new
33
+ group.add_child(outline(node)) if node.boxed
34
+ label = node.labels.first
35
+ label.lines.each do |line|
36
+ group.add_child(text_line(line, label.font_size,
37
+ node.font_colour || INK_TEXT))
38
+ end
39
+ svg.add_element(group)
40
+ end
41
+
42
+ private
43
+
44
+ def outline(node)
45
+ Svg::Rect.new(x: node.x, y: node.y, width: node.width,
46
+ height: node.height, rx: node.corner_radius,
47
+ ry: node.corner_radius, fill: node.fill,
48
+ stroke: node.stroke || INK,
49
+ stroke_width: (node.stroke_width || 1.5).to_s,
50
+ stroke_dasharray: node.dasharray)
51
+ end
52
+
53
+ def text_line(line, size, colour)
54
+ Svg::Text.new.tap do |text|
55
+ text.x = line.x
56
+ text.y = line.y
57
+ text.content = line.text
58
+ text.fill = colour
59
+ text.font_size = size.to_s
60
+ text.font_family = line.mono ? MONO_FONT : FONT
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end