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,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Etassia
4
+ module Notation
5
+ module PlantUML
6
+ # One line of a class body.
7
+ #
8
+ # `kind` is :field or :method. `visibility` is :public, :private,
9
+ # :protected, :package, or nil when the line carries no marker.
10
+ # `parameters` is the text between a method's parentheses and is nil
11
+ # for a field and for a `{method}` written without parentheses. `type`
12
+ # is the declared type or nil. `type_position` preserves whether that
13
+ # type preceded the name or followed `:`; it defaults to :suffix for
14
+ # callers and older IR that do not record the distinction. `modifiers`
15
+ # holds :abstract and :static as written. `type_separator` is the
16
+ # text written around the `:` before a suffix type, ": " by default.
17
+ class Member
18
+ attr_reader :kind, :visibility, :name, :type, :parameters, :modifiers,
19
+ :type_position, :type_separator
20
+
21
+ # @param detail [Hash] optional `:parameters`, nil by default, and
22
+ # `:modifiers`, empty by default
23
+ def initialize(kind:, visibility:, name:, type:, **detail)
24
+ @kind = kind
25
+ @visibility = visibility
26
+ @name = name
27
+ @type = type
28
+ @parameters = detail[:parameters]
29
+ @modifiers = detail.fetch(:modifiers, [].freeze)
30
+ @type_position = detail.fetch(:type_position, :suffix)
31
+ @type_separator = detail.fetch(:type_separator, ": ")
32
+ freeze
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "scene"
4
+
5
+ module Etassia
6
+ module Notation
7
+ module PlantUML
8
+ # The visibility icon PlantUML draws before a class member: a circle for
9
+ # `+`, a square for `-`, a diamond for `#` and a triangle for `~`. A
10
+ # field's icon is hollow and a method's is filled. `skinparam
11
+ # classAttributeIconSize 0` turns the icons off and keeps the prefix
12
+ # character in the text. Geometry is measured against PlantUML 1.2026.6.
13
+ module MemberIcon
14
+ extend self
15
+
16
+ # The icon is centred this far from the box's left edge and the text
17
+ # of a row that has one starts this far from it; any other row starts
18
+ # at TEXT_PLAIN.
19
+ CENTRE_INSET = 11.0
20
+ TEXT_INSET = 20.0
21
+ TEXT_PLAIN = 6.0
22
+ # Offset of the icon's centre above the row's baseline.
23
+ CENTRE_RISE = { circle: 3.79, square: 3.79, diamond: 4.79,
24
+ triangle: 4.79 }.freeze
25
+ SHAPES = { public: :circle, private: :square, protected: :diamond,
26
+ package: :triangle }.freeze
27
+ MARKS = { public: "+", private: "-", protected: "#",
28
+ package: "~" }.freeze
29
+ DISABLED = /\Askinparam[ \t]+classAttributeIconSize[ \t]+0\z/i
30
+ private_constant :CENTRE_RISE, :SHAPES, :MARKS, :DISABLED
31
+
32
+ # @param directives [Array<String>] a diagram's directive lines
33
+ # @return [Boolean] whether member icons are drawn
34
+ def enabled?(directives)
35
+ directives.none? { |line| DISABLED.match?(line) }
36
+ end
37
+
38
+ # @return [String] the written prefix character of a visibility
39
+ def mark(visibility)
40
+ MARKS.fetch(visibility, "")
41
+ end
42
+
43
+ # @param kinds [Array<Symbol>] each row's kind (:separator included)
44
+ # @param visibilities [Array<Symbol, nil>] each row's visibility
45
+ # @param enabled [Boolean] whether icons are drawn
46
+ # @return [Array<Float, nil>] how far each row's text starts from the
47
+ # box's left edge: the whole of a field or method group is pushed
48
+ # in when any of its members carries an icon; nil for a separator
49
+ def insets(kinds, visibilities, enabled)
50
+ iconed = enabled ? iconed_kinds(kinds, visibilities) : []
51
+ kinds.map do |kind|
52
+ next if kind == :separator
53
+
54
+ iconed.include?(kind) ? TEXT_INSET : TEXT_PLAIN
55
+ end
56
+ end
57
+
58
+ def iconed_kinds(kinds, visibilities)
59
+ kinds.zip(visibilities).filter_map do |kind, visibility|
60
+ kind if SHAPES.key?(visibility)
61
+ end
62
+ end
63
+
64
+ # @return [String] the row's text without the prefix an icon replaces
65
+ def visible_text(content, visibility, enabled)
66
+ return content unless enabled && SHAPES.key?(visibility)
67
+
68
+ content.delete_prefix(mark(visibility))
69
+ end
70
+
71
+ # @param visibility [Symbol, nil]
72
+ # @param kind [Symbol] :field or :method
73
+ # @param left [Float] the box's left edge
74
+ # @param baseline [Float] the member text's baseline
75
+ # @return [Scene::Icon, nil] nil when the member has no visibility
76
+ def at(visibility, kind, left, baseline)
77
+ shape = SHAPES[visibility]
78
+ return unless shape
79
+
80
+ Scene::Icon.new(shape: shape.to_s, visibility: visibility.to_s,
81
+ filled: kind == :method, cx: left + CENTRE_INSET,
82
+ cy: baseline - CENTRE_RISE.fetch(shape))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../svg"
4
+
5
+ module Etassia
6
+ module Notation
7
+ module PlantUML
8
+ # Draws a {Scene::Icon} as SVG, in the colours PlantUML gives each
9
+ # visibility: a stroke and, for a method's filled icon, a fill.
10
+ module MemberIconElements
11
+ extend self
12
+
13
+ # visibility => [stroke, fill]
14
+ COLOURS = { "public" => %w[#038048 #84BE84],
15
+ "private" => %w[#C82930 #F24D5C],
16
+ "protected" => %w[#B38D22 #FFFF44],
17
+ "package" => %w[#1963A0 #4177AF] }.freeze
18
+ MODIFIERS = { "public" => "PUBLIC", "private" => "PRIVATE",
19
+ "protected" => "PROTECTED",
20
+ "package" => "PACKAGE_PRIVATE" }.freeze
21
+ HALF = { "circle" => 3.0, "square" => 3.0, "diamond" => 4.0,
22
+ "triangle" => 4.0 }.freeze
23
+ private_constant :COLOURS, :MODIFIERS, :HALF
24
+
25
+ # @param icon [Scene::Icon]
26
+ # @return [Svg::Group] the icon, marked with the visibility and kind
27
+ # of its member as PlantUML marks it
28
+ def group(icon)
29
+ modifier = "#{MODIFIERS.fetch(icon.visibility)}_" \
30
+ "#{icon.filled ? 'METHOD' : 'FIELD'}"
31
+ Svg::Group.new(data_visibility_modifier: modifier)
32
+ .tap { |group| group << element(icon) }
33
+ end
34
+
35
+ # @param icon [Scene::Icon]
36
+ # @return [Svg::Element]
37
+ def element(icon)
38
+ stroke, fill = COLOURS.fetch(icon.visibility)
39
+ fill = "none" unless icon.filled
40
+ return circle(icon, stroke, fill) if icon.shape == "circle"
41
+
42
+ styled(shape_of(icon), stroke, fill)
43
+ end
44
+
45
+ private
46
+
47
+ def shape_of(icon)
48
+ icon.shape == "square" ? square(icon) : polygon(icon)
49
+ end
50
+
51
+ def styled(shape, stroke, fill)
52
+ shape.tap do |element|
53
+ element.fill = fill
54
+ element.stroke = stroke
55
+ element.stroke_width = "1"
56
+ end
57
+ end
58
+
59
+ def circle(icon, stroke, fill)
60
+ Svg::Circle.new(cx: icon.cx, cy: icon.cy, r: HALF.fetch("circle"),
61
+ fill: fill, stroke: stroke, stroke_width: "1")
62
+ end
63
+
64
+ def square(icon)
65
+ Svg::Rect.new(x: icon.cx - 3.0, y: icon.cy - 3.0, width: 6.0,
66
+ height: 6.0)
67
+ end
68
+
69
+ def polygon(icon)
70
+ half = HALF.fetch(icon.shape)
71
+ points = if icon.shape == "diamond"
72
+ diamond_points(icon, half)
73
+ else
74
+ triangle_points(icon, half)
75
+ end
76
+ Svg::Polygon.new(points: Svg::Polygon.build_points(points))
77
+ end
78
+
79
+ def triangle_points(icon, half)
80
+ [[icon.cx, icon.cy - 3.0], [icon.cx - half, icon.cy + 3.0],
81
+ [icon.cx + half, icon.cy + 3.0]]
82
+ end
83
+
84
+ def diamond_points(icon, half)
85
+ [[icon.cx, icon.cy - half], [icon.cx + half, icon.cy],
86
+ [icon.cx, icon.cy + half], [icon.cx - half, icon.cy]]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Etassia
4
+ module Notation
5
+ module PlantUML
6
+ # How far apart PlantUML sets the rows of a class box's members,
7
+ # measured against 1.2026.6. A row is 16.49 below the one before, with
8
+ # 8 more between a field group and a method group; an empty group
9
+ # keeps a gap of its own, unless a separator already splits the rows
10
+ # into compartments of their own. A separator with a title is a row of
11
+ # its own, drawn 3.5 low and followed 4 further down; one without a
12
+ # title is no row but 8 of gap, its rule 6.95 under the row before.
13
+ module MemberPitch
14
+ extend self
15
+
16
+ ROW = 16.48828125
17
+ GROUP_GAP = 8.0
18
+ TITLED_DROP = 3.5
19
+ TITLED_EXTRA = 4.0
20
+ BARE_GAP = 8.0
21
+ BARE_RULE_DROP = 10.95
22
+ private_constant :ROW, :GROUP_GAP, :TITLED_DROP, :TITLED_EXTRA,
23
+ :BARE_GAP, :BARE_RULE_DROP
24
+
25
+ # @param kinds [Array<Symbol>] each row's kind, :separator included
26
+ # @param titles [Array<String>] each row's text
27
+ # @param gaps [Boolean] whether an empty field or method group keeps
28
+ # its gap; `hide` and `show` lines on members remove it
29
+ # @return [Array(Array<Float>, Float)] each row's offset from the
30
+ # first row's baseline, and the extent the rows add to a box
31
+ def layout(kinds, titles, gaps: true)
32
+ cursor = gaps ? lead(kinds) : 0.0
33
+ last = -ROW
34
+ offsets = kinds.each_index.map do |index|
35
+ cursor += GROUP_GAP if group_opens?(kinds, index)
36
+ offset, cursor, last = place(kinds[index], titles[index], cursor,
37
+ last)
38
+ offset
39
+ end
40
+ [offsets, cursor + (gaps ? tail(kinds) : 0.0)]
41
+ end
42
+
43
+ # @return [Float] the gap above the rows of a box with methods and no
44
+ # fields: PlantUML draws the empty field compartment there
45
+ def lead(kinds)
46
+ return 0.0 if kinds.include?(:separator)
47
+
48
+ kinds.include?(:method) && !kinds.include?(:field) ? GROUP_GAP : 0.0
49
+ end
50
+
51
+ # @return [Float] the gap below the rows of a box with fields and no
52
+ # methods: the empty method compartment
53
+ def tail(kinds)
54
+ return 0.0 if kinds.include?(:separator)
55
+
56
+ kinds.include?(:field) && !kinds.include?(:method) ? GROUP_GAP : 0.0
57
+ end
58
+
59
+ private
60
+
61
+ def group_opens?(kinds, index)
62
+ index.positive? && kinds[index - 1] == :field &&
63
+ kinds[index] == :method
64
+ end
65
+
66
+ def place(kind, title, cursor, last)
67
+ return [cursor, cursor + ROW, cursor] unless kind == :separator
68
+ return [last + BARE_RULE_DROP, cursor + BARE_GAP, last] if
69
+ title.empty?
70
+
71
+ [cursor + TITLED_DROP, cursor + ROW + TITLED_EXTRA, cursor]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "scene"
4
+
5
+ module Etassia
6
+ module Notation
7
+ module PlantUML
8
+ # How PlantUML draws the rule of a class body's separator line: `..`
9
+ # dotted, `==` two solid lines two pixels apart, `__` a hairline and
10
+ # `--` a solid line.
11
+ module MemberRule
12
+ extend self
13
+
14
+ Style = Struct.new(:width, :dash, :double)
15
+ DOUBLE_GAP = 2.0
16
+ STYLES = {
17
+ "." => Style.new(1.0, "1,2", false),
18
+ "=" => Style.new(1.0, nil, true),
19
+ "_" => Style.new(0.5, nil, false),
20
+ "-" => Style.new(1.0, nil, false),
21
+ }.freeze
22
+ private_constant :DOUBLE_GAP, :STYLES
23
+
24
+ # @param character [String] the separator's character: . = _ or -
25
+ # @param pieces [Array<Scene::Segment>] the rule's unstyled parts
26
+ # @return [Array<Scene::Segment>] the parts as drawn
27
+ def style(character, pieces)
28
+ rule = STYLES.fetch(character, STYLES["-"])
29
+ drawn = pieces.map { |piece| styled(piece, rule) }
30
+ rule.double ? drawn + drawn.map { |piece| lowered(piece) } : drawn
31
+ end
32
+
33
+ private
34
+
35
+ def styled(piece, rule)
36
+ Scene::Segment.new(x1: piece.x1, y1: piece.y1, x2: piece.x2,
37
+ y2: piece.y2, width: rule.width, dash: rule.dash)
38
+ end
39
+
40
+ def lowered(piece)
41
+ Scene::Segment.new(x1: piece.x1, y1: piece.y1 + DOUBLE_GAP,
42
+ x2: piece.x2, y2: piece.y2 + DOUBLE_GAP,
43
+ width: piece.width, dash: piece.dash)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../drawing"
4
+ require_relative "shapes"
5
+
6
+ module Etassia
7
+ module Notation
8
+ module PlantUML
9
+ module Network
10
+ # Where the bars, the rows of boxes under them and the boxes
11
+ # themselves fall, in the JAR's measures.
12
+ class Grid
13
+ # One bar and the row of nodes hung from it: `top` is the bar's;
14
+ # `level` and `height` the row's; `after` where the next bar's
15
+ # top falls.
16
+ Row = Struct.new(:top, :spans, :level, :height, :bottom, :after)
17
+
18
+ LEFT = 5.0
19
+ BAR = 5.0
20
+ INSET = 15.0
21
+ COLUMN_GAP = 30.0
22
+ MIN_BAR = 70.0
23
+ # Space between a bar and the row under it, and between a row and
24
+ # the next bar; every address on a node's lines widens both.
25
+ ABOVE = 30.0
26
+ BELOW = 35.0
27
+ LABEL_ROOM = 6.4775
28
+ # Where a bar sits against its name's baseline.
29
+ BAR_RISE = 7.0352
30
+ NAME_STEP = 14.1328
31
+ FIRST_BASELINE = 16.6016
32
+ TAIL = 47.75
33
+ BARE_TAIL = 51.15
34
+ private_constant :INSET, :COLUMN_GAP, :MIN_BAR, :ABOVE, :BELOW,
35
+ :LABEL_ROOM, :BAR_RISE, :FIRST_BASELINE, :TAIL,
36
+ :BARE_TAIL
37
+
38
+ # @return [Float] x where the bars start
39
+ attr_reader :left
40
+ # @return [Float] the bars' width
41
+ attr_reader :bars
42
+
43
+ # @param diagram [Diagram]
44
+ # @param placement [Placement]
45
+ def initialize(diagram, placement)
46
+ @diagram = diagram
47
+ @placement = placement
48
+ @left = LEFT + label_width + LEFT
49
+ @sizes = diagram.shapes.to_h do |name, shape|
50
+ [name, Shapes.size(shape, face(name))]
51
+ end
52
+ @widths = column_widths
53
+ @bars = bar_width
54
+ @rows = build_rows
55
+ end
56
+
57
+ # @return [Row] the bar of a network and the row under it
58
+ def row(index)
59
+ @rows.fetch(index)
60
+ end
61
+
62
+ # @return [Drawing::Box]
63
+ def box(span)
64
+ width, height = @sizes.fetch(span.name)
65
+ Drawing::Box.new(box_left(span, width), box_top(span, height),
66
+ width, height)
67
+ end
68
+
69
+ # @return [Float] y of the name's baseline at a network's bar
70
+ def baseline(index)
71
+ row(index).top + BAR_RISE - lift(@diagram.networks[index])
72
+ end
73
+
74
+ # @return [Float] the canvas' width and height
75
+ def canvas
76
+ [(@left + @bars + 6).floor + 1, foot.ceil]
77
+ end
78
+
79
+ private
80
+
81
+ def box_left(span, width)
82
+ slot_left(span.column) + ((@widths[span.column] - width) / 2)
83
+ end
84
+
85
+ def box_top(span, height)
86
+ row = row(span.entry)
87
+ row.level + ((row.height - height) / 2)
88
+ end
89
+
90
+ # Where the canvas ends: under the last row, or under a last bar
91
+ # that has none.
92
+ def foot
93
+ last = @rows.last
94
+ return last.bottom + TAIL if last.spans.any?
95
+
96
+ last.top + BAR + BARE_TAIL
97
+ end
98
+
99
+ def face(text)
100
+ Drawing::Face.width(text, size: 12)
101
+ end
102
+
103
+ def lift(network)
104
+ network.address ? NAME_STEP / 2 : 0
105
+ end
106
+
107
+ def label_width
108
+ texts = @diagram.networks.flat_map { |n| [n.name, n.address] }
109
+ texts.compact.map { |text| face(text) }.max.to_f
110
+ end
111
+
112
+ def column_widths
113
+ Array.new(@placement.columns) do |column|
114
+ spans = @placement.spans.select { |s| s.column == column }
115
+ spans.map { |s| @sizes.fetch(s.name).first }.max
116
+ end
117
+ end
118
+
119
+ def bar_width
120
+ inner = @widths.sum + (COLUMN_GAP * (@widths.size - 1))
121
+ [INSET + inner + INSET, MIN_BAR].max
122
+ end
123
+
124
+ def slot_left(column)
125
+ @left + INSET + @widths.first(column).sum + (COLUMN_GAP * column)
126
+ end
127
+
128
+ def build_rows
129
+ top = FIRST_BASELINE - BAR_RISE + lift(@diagram.networks.first)
130
+ @diagram.networks.each_index.map do |index|
131
+ row_at(index, top).tap { |row| top = row.after }
132
+ end
133
+ end
134
+
135
+ def row_at(index, top)
136
+ spans = @placement.spans.select { |s| s.entry == index }
137
+ return bare_row(top) if spans.empty?
138
+
139
+ hung_row(top, spans)
140
+ end
141
+
142
+ def bare_row(top)
143
+ Row.new(top, [], top + BAR + ABOVE, 0.0, top + BAR,
144
+ top + BAR + ABOVE + BELOW)
145
+ end
146
+
147
+ def hung_row(top, spans)
148
+ height = spans.map { |s| @sizes.fetch(s.name).last }.max
149
+ extra = room(spans)
150
+ level = top + BAR + ABOVE + extra
151
+ Row.new(top, spans, level, height, level + height,
152
+ level + height + BELOW + extra)
153
+ end
154
+
155
+ def room(spans)
156
+ LABEL_ROOM * spans.map { |s| lines(s) }.max
157
+ end
158
+
159
+ # How many address lines a node's lines carry in all.
160
+ def lines(span)
161
+ @diagram.networks.sum do |network|
162
+ member = network.nodes.find { |m| m.name == span.name }
163
+ member&.address ? member.address.split(/\s*,\s*/).size : 0
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../drawing"
4
+ require_relative "grid"
5
+ require_relative "placement"
6
+ require_relative "shapes"
7
+
8
+ module Etassia
9
+ module Notation
10
+ module PlantUML
11
+ module Network
12
+ # Stacks the networks as horizontal bars with their names at the left
13
+ # and hangs each node's box in a row below the first bar it belongs
14
+ # to, with a line to every bar after. Measures are the JAR's.
15
+ class Layout
16
+ include Drawing::Pen
17
+
18
+ BAR = 5.0
19
+ LINE_STEP = 12.9551
20
+ NAME_STEP = 14.1328
21
+ SLOT = 2.0
22
+ SHADE = "#E7E7E7"
23
+ DEFAULT_BAR = "#E2E2F0"
24
+ INK = "#000000"
25
+ COLOR = /\A#?[A-Za-z0-9]+\z/
26
+ private_constant :BAR, :LINE_STEP, :NAME_STEP, :SLOT, :SHADE,
27
+ :DEFAULT_BAR, :INK, :COLOR
28
+
29
+ # @param diagram [Diagram]
30
+ # @return [Drawing::Scene]
31
+ def call(diagram, **)
32
+ @diagram = diagram
33
+ @placement = Placement.new(diagram)
34
+ @grid = Grid.new(diagram, @placement)
35
+ draw_all
36
+ scene(*@grid.canvas)
37
+ end
38
+
39
+ private
40
+
41
+ def draw_all
42
+ @diagram.networks.each_index do |index|
43
+ draw_groups(index)
44
+ draw_bar(index)
45
+ end
46
+ @placement.spans.each { |span| draw_node(span) }
47
+ end
48
+
49
+ def draw_bar(index)
50
+ rect(@grid.left, @grid.row(index).top, @grid.bars, BAR,
51
+ fill: paint(@diagram.networks[index].color))
52
+ draw_names(@diagram.networks[index], @grid.baseline(index))
53
+ end
54
+
55
+ def draw_names(network, baseline)
56
+ name_line(network.name, baseline)
57
+ return unless network.address
58
+
59
+ name_line(network.address, baseline + NAME_STEP)
60
+ end
61
+
62
+ def name_line(content, baseline)
63
+ text(content, @grid.left - 5, Drawing::Face.middle(baseline, 12),
64
+ anchor: "end", fill: INK)
65
+ end
66
+
67
+ def paint(color)
68
+ color&.match?(COLOR) ? color : DEFAULT_BAR
69
+ end
70
+
71
+ def draw_node(span)
72
+ box = @grid.box(span)
73
+ draw_links(span, box)
74
+ shape = @diagram.shapes[span.name]
75
+ Shapes.draw(self, shape, box)
76
+ text(span.name, Shapes.label_x(shape, box),
77
+ Drawing::Face.middle(Shapes.baseline(shape, box), 12),
78
+ anchor: "middle", fill: INK)
79
+ draw_addresses(span, box)
80
+ end
81
+
82
+ # A node reached through a network that already holds an earlier
83
+ # node hangs its line left of its centre; the others, right.
84
+ def link_x(span, box)
85
+ box.centre + (carried?(span) ? -SLOT : SLOT)
86
+ end
87
+
88
+ def carried?(span)
89
+ @diagram.networks[span.entry].nodes.any? do |member|
90
+ @placement[member.name].entry < span.entry
91
+ end
92
+ end
93
+
94
+ def draw_links(span, box)
95
+ x = link_x(span, box)
96
+ line(x, bar_bottom(span.entry), x, box.top)
97
+ return unless span.exit > span.entry
98
+
99
+ line(x, box.bottom, x, @grid.row(span.exit).top)
100
+ end
101
+
102
+ def bar_bottom(index)
103
+ @grid.row(index).top + BAR
104
+ end
105
+
106
+ def draw_addresses(span, box)
107
+ @diagram.networks.each_with_index do |network, index|
108
+ member = network.nodes.find { |m| m.name == span.name }
109
+ next unless member&.address
110
+
111
+ draw_address(member.address.split(/\s*,\s*/), span, box, index)
112
+ end
113
+ end
114
+
115
+ # The addresses sit along the line between a bar and the box,
116
+ # centred on it, one step apart.
117
+ def draw_address(entries, span, box, index)
118
+ middle = address_middle(span, box, index)
119
+ entries.each_with_index do |entry, row|
120
+ base = middle + ((row - ((entries.size - 1) / 2.0)) * LINE_STEP)
121
+ text(entry, link_x(span, box), Drawing::Face.middle(base, 11),
122
+ size: 11, anchor: "middle", fill: INK)
123
+ end
124
+ end
125
+
126
+ # Where the line that carries the address runs: from the entry
127
+ # bar to the box, or from the box to a later bar.
128
+ def address_middle(span, box, index)
129
+ return ((bar_bottom(index) + box.top) / 2) + 1.66 if
130
+ index == span.entry
131
+
132
+ ((box.bottom + @grid.row(index).top) / 2) + 4.15
133
+ end
134
+
135
+ def draw_groups(index)
136
+ @diagram.networks[index].groups.each do |group|
137
+ spans = group.names.map { |name| @placement[name] }
138
+ spans = spans.select { |span| span.entry == index }
139
+ draw_group(spans, group, @grid.row(index)) if spans.any?
140
+ end
141
+ end
142
+
143
+ def draw_group(spans, group, row)
144
+ left, right = reach(spans.map { |span| @grid.box(span) })
145
+ color = paint(group.color || SHADE)
146
+ rect(left, row.level - 5, right - left, row.height + 10,
147
+ fill: color, stroke: color)
148
+ end
149
+
150
+ # How far a group's shading runs round its boxes.
151
+ def reach(boxes)
152
+ [boxes.map(&:left).min - 5, boxes.map(&:right).max + 5]
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Etassia
4
+ module Notation
5
+ module PlantUML
6
+ module Network
7
+ # A node's membership of one network.
8
+ Member = Struct.new(:name, :address, keyword_init: true)
9
+
10
+ # A named shaded cluster of nodes.
11
+ Group = Struct.new(:name, :color, :names, keyword_init: true)
12
+
13
+ # One horizontal bar and the nodes hanging from it.
14
+ Network = Struct.new(:name, :address, :color, :nodes, :groups,
15
+ keyword_init: true)
16
+
17
+ # The whole diagram: its networks, and each node's shape.
18
+ Diagram = Struct.new(:networks, :shapes, keyword_init: true)
19
+ end
20
+ end
21
+ end
22
+ end