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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +140 -0
- data/LICENSE +25 -0
- data/README.adoc +436 -0
- data/exe/etassia +7 -0
- data/lib/etassia/cli.rb +187 -0
- data/lib/etassia/commands/batch.rb +210 -0
- data/lib/etassia/commands/notation_loader.rb +22 -0
- data/lib/etassia/commands/render.rb +98 -0
- data/lib/etassia/commands/types.rb +33 -0
- data/lib/etassia/commands/version.rb +24 -0
- data/lib/etassia/corpus_type_names.rb +52 -0
- data/lib/etassia/diagram/architecture.rb +108 -0
- data/lib/etassia/diagram/base.rb +61 -0
- data/lib/etassia/diagram/block.rb +102 -0
- data/lib/etassia/diagram/c4.rb +337 -0
- data/lib/etassia/diagram/class_diagram.rb +466 -0
- data/lib/etassia/diagram/class_namespace.rb +17 -0
- data/lib/etassia/diagram/class_note.rb +17 -0
- data/lib/etassia/diagram/containment.rb +107 -0
- data/lib/etassia/diagram/er_diagram.rb +317 -0
- data/lib/etassia/diagram/error.rb +38 -0
- data/lib/etassia/diagram/flowchart.rb +419 -0
- data/lib/etassia/diagram/flowchart_label_text.rb +63 -0
- data/lib/etassia/diagram/gantt.rb +94 -0
- data/lib/etassia/diagram/generic_text.rb +30 -0
- data/lib/etassia/diagram/git_graph.rb +57 -0
- data/lib/etassia/diagram/info.rb +38 -0
- data/lib/etassia/diagram/kanban.rb +198 -0
- data/lib/etassia/diagram/mindmap.rb +71 -0
- data/lib/etassia/diagram/packet.rb +93 -0
- data/lib/etassia/diagram/pie.rb +115 -0
- data/lib/etassia/diagram/quadrant.rb +135 -0
- data/lib/etassia/diagram/radar.rb +65 -0
- data/lib/etassia/diagram/requirement.rb +168 -0
- data/lib/etassia/diagram/sankey.rb +217 -0
- data/lib/etassia/diagram/sequence.rb +299 -0
- data/lib/etassia/diagram/sequence_box.rb +18 -0
- data/lib/etassia/diagram/sequence_frame.rb +37 -0
- data/lib/etassia/diagram/sequence_frame_section.rb +23 -0
- data/lib/etassia/diagram/sequence_text.rb +69 -0
- data/lib/etassia/diagram/sequence_wrap.rb +23 -0
- data/lib/etassia/diagram/state_diagram.rb +282 -0
- data/lib/etassia/diagram/timeline.rb +183 -0
- data/lib/etassia/diagram/treemap.rb +95 -0
- data/lib/etassia/diagram/user_journey.rb +153 -0
- data/lib/etassia/diagram/xy_chart.rb +90 -0
- data/lib/etassia/diagram.rb +8 -0
- data/lib/etassia/diagram_registry.rb +34 -0
- data/lib/etassia/engine.rb +334 -0
- data/lib/etassia/error/diagram_type_error.rb +10 -0
- data/lib/etassia/error/layout_error.rb +12 -0
- data/lib/etassia/error/notation_registration_error.rb +10 -0
- data/lib/etassia/error/parse_error.rb +11 -0
- data/lib/etassia/error/pipeline_error.rb +10 -0
- data/lib/etassia/error/render_error.rb +12 -0
- data/lib/etassia/error/score_error.rb +12 -0
- data/lib/etassia/error.rb +10 -0
- data/lib/etassia/error_report.rb +69 -0
- data/lib/etassia/ir/data.rb +39 -0
- data/lib/etassia/ir/data_value.rb +35 -0
- data/lib/etassia/ir/dimension.rb +10 -0
- data/lib/etassia/ir/edge.rb +34 -0
- data/lib/etassia/ir/graph.rb +28 -0
- data/lib/etassia/ir/integrity.rb +80 -0
- data/lib/etassia/ir/item.rb +46 -0
- data/lib/etassia/ir/model.rb +56 -0
- data/lib/etassia/ir/node.rb +10 -0
- data/lib/etassia/ir/placement.rb +47 -0
- data/lib/etassia/ir/prepositioned.rb +25 -0
- data/lib/etassia/ir/prepositioned_item.rb +26 -0
- data/lib/etassia/ir/property_set.rb +43 -0
- data/lib/etassia/ir/scalar.rb +25 -0
- data/lib/etassia/ir/series.rb +10 -0
- data/lib/etassia/ir.rb +17 -0
- data/lib/etassia/js_math.rb +511 -0
- data/lib/etassia/js_number.rb +64 -0
- data/lib/etassia/layout/architecture.rb +1472 -0
- data/lib/etassia/layout/base.rb +276 -0
- data/lib/etassia/layout/block.rb +738 -0
- data/lib/etassia/layout/c4.rb +876 -0
- data/lib/etassia/layout/c4_boundary_metrics.rb +35 -0
- data/lib/etassia/layout/c4_bounds.rb +106 -0
- data/lib/etassia/layout/c4_intersection.rb +77 -0
- data/lib/etassia/layout/c4_placement.rb +135 -0
- data/lib/etassia/layout/c4_shape_metrics.rb +97 -0
- data/lib/etassia/layout/c4_shape_outline.rb +67 -0
- data/lib/etassia/layout/c4_stereotype.rb +30 -0
- data/lib/etassia/layout/c4_text.rb +54 -0
- data/lib/etassia/layout/class_cell_placement.rb +148 -0
- data/lib/etassia/layout/class_diagram.rb +1116 -0
- data/lib/etassia/layout/class_diagram_namespaces.rb +26 -0
- data/lib/etassia/layout/class_diagram_notes.rb +26 -0
- data/lib/etassia/layout/class_name_advances.rb +31 -0
- data/lib/etassia/layout/class_namespace_box.rb +21 -0
- data/lib/etassia/layout/class_namespace_nodes.rb +197 -0
- data/lib/etassia/layout/class_namespace_placement.rb +71 -0
- data/lib/etassia/layout/class_note.rb +44 -0
- data/lib/etassia/layout/class_note_nodes.rb +84 -0
- data/lib/etassia/layout/elk_notices.rb +48 -0
- data/lib/etassia/layout/elk_placement.rb +197 -0
- data/lib/etassia/layout/er_diagram.rb +1002 -0
- data/lib/etassia/layout/er_diagram_adjacency.rb +20 -0
- data/lib/etassia/layout/er_diagram_alignment.rb +72 -0
- data/lib/etassia/layout/er_diagram_compaction.rb +85 -0
- data/lib/etassia/layout/er_diagram_conflicts.rb +70 -0
- data/lib/etassia/layout/er_diagram_coordinates.rb +104 -0
- data/lib/etassia/layout/er_diagram_entity_size.rb +82 -0
- data/lib/etassia/layout/er_diagram_layering.rb +109 -0
- data/lib/etassia/layout/er_diagram_ordering.rb +143 -0
- data/lib/etassia/layout/er_diagram_placement.rb +163 -0
- data/lib/etassia/layout/er_diagram_placement_node.rb +22 -0
- data/lib/etassia/layout/error.rb +133 -0
- data/lib/etassia/layout/flowchart/brandes_koepf.rb +208 -0
- data/lib/etassia/layout/flowchart/cluster_reach.rb +70 -0
- data/lib/etassia/layout/flowchart/component_packing.rb +129 -0
- data/lib/etassia/layout/flowchart/directed_placement.rb +428 -0
- data/lib/etassia/layout/flowchart/edge_chains.rb +111 -0
- data/lib/etassia/layout/flowchart/edge_order.rb +34 -0
- data/lib/etassia/layout/flowchart/edge_router.rb +533 -0
- data/lib/etassia/layout/flowchart/label_backdrop_geometry.rb +62 -0
- data/lib/etassia/layout/flowchart/layer_spacing.rb +85 -0
- data/lib/etassia/layout/flowchart/level_edges.rb +74 -0
- data/lib/etassia/layout/flowchart/level_frame.rb +47 -0
- data/lib/etassia/layout/flowchart/minimum_rank_spacing.rb +74 -0
- data/lib/etassia/layout/flowchart/row_centering.rb +229 -0
- data/lib/etassia/layout/flowchart.rb +1290 -0
- data/lib/etassia/layout/gantt.rb +814 -0
- data/lib/etassia/layout/gantt_duration.rb +49 -0
- data/lib/etassia/layout/gantt_exclusions.rb +74 -0
- data/lib/etassia/layout/gantt_ticks.rb +165 -0
- data/lib/etassia/layout/git_graph.rb +1075 -0
- data/lib/etassia/layout/grid.rb +165 -0
- data/lib/etassia/layout/info.rb +113 -0
- data/lib/etassia/layout/kanban.rb +452 -0
- data/lib/etassia/layout/kanban_card_text.rb +95 -0
- data/lib/etassia/layout/mindmap.rb +425 -0
- data/lib/etassia/layout/mindmap_cose.rb +81 -0
- data/lib/etassia/layout/mindmap_cose_body.rb +93 -0
- data/lib/etassia/layout/mindmap_cose_geometry.rb +190 -0
- data/lib/etassia/layout/mindmap_cose_grid.rb +96 -0
- data/lib/etassia/layout/mindmap_cose_link.rb +42 -0
- data/lib/etassia/layout/mindmap_cose_relaxation.rb +166 -0
- data/lib/etassia/layout/mindmap_cose_seed.rb +93 -0
- data/lib/etassia/layout/mindmap_cose_wedge.rb +37 -0
- data/lib/etassia/layout/mindmap_node_size.rb +130 -0
- data/lib/etassia/layout/packet.rb +285 -0
- data/lib/etassia/layout/pie.rb +305 -0
- data/lib/etassia/layout/pie_legend.rb +64 -0
- data/lib/etassia/layout/pie_legend_entry.rb +21 -0
- data/lib/etassia/layout/quadrant.rb +402 -0
- data/lib/etassia/layout/radar.rb +442 -0
- data/lib/etassia/layout/requirement.rb +765 -0
- data/lib/etassia/layout/sankey.rb +501 -0
- data/lib/etassia/layout/scene.rb +18 -0
- data/lib/etassia/layout/sequence/actor_gaps.rb +151 -0
- data/lib/etassia/layout/sequence/box_shape.rb +23 -0
- data/lib/etassia/layout/sequence/creations.rb +73 -0
- data/lib/etassia/layout/sequence/frame_divider.rb +22 -0
- data/lib/etassia/layout/sequence/frame_placement.rb +424 -0
- data/lib/etassia/layout/sequence/frame_reader.rb +75 -0
- data/lib/etassia/layout/sequence/frame_shape.rb +45 -0
- data/lib/etassia/layout/sequence/geometry.rb +24 -0
- data/lib/etassia/layout/sequence/message_rows.rb +165 -0
- data/lib/etassia/layout/sequence/note.rb +16 -0
- data/lib/etassia/layout/sequence/note_box.rb +114 -0
- data/lib/etassia/layout/sequence/note_placement.rb +223 -0
- data/lib/etassia/layout/sequence/text_width.rb +69 -0
- data/lib/etassia/layout/sequence/text_wrap.rb +93 -0
- data/lib/etassia/layout/sequence.rb +936 -0
- data/lib/etassia/layout/state_diagram.rb +1277 -0
- data/lib/etassia/layout/timeline.rb +165 -0
- data/lib/etassia/layout/timeline_card.rb +142 -0
- data/lib/etassia/layout/timeline_flow.rb +164 -0
- data/lib/etassia/layout/timeline_line.rb +33 -0
- data/lib/etassia/layout/timeline_rounding.rb +19 -0
- data/lib/etassia/layout/timeline_text.rb +105 -0
- data/lib/etassia/layout/treemap.rb +303 -0
- data/lib/etassia/layout/treemap_placement.rb +52 -0
- data/lib/etassia/layout/treemap_squarify.rb +108 -0
- data/lib/etassia/layout/user_journey.rb +300 -0
- data/lib/etassia/layout/user_journey_face.rb +33 -0
- data/lib/etassia/layout/user_journey_face_geometry.rb +80 -0
- data/lib/etassia/layout/user_journey_geometry.rb +336 -0
- data/lib/etassia/layout/user_journey_legend.rb +84 -0
- data/lib/etassia/layout/xy_chart.rb +620 -0
- data/lib/etassia/layout.rb +19 -0
- data/lib/etassia/lint_debt_scoreboard.rb +219 -0
- data/lib/etassia/markdown_text/emphasis_simulator.rb +373 -0
- data/lib/etassia/markdown_text.rb +393 -0
- data/lib/etassia/notation/builtin.rb +39 -0
- data/lib/etassia/notation/entry.rb +15 -0
- data/lib/etassia/notation/mermaid/class_diagram_config.rb +42 -0
- data/lib/etassia/notation/mermaid/git_graph_config.rb +46 -0
- data/lib/etassia/notation/mermaid/ir_adapter.rb +27 -0
- data/lib/etassia/notation/mermaid/ir_adapters/architecture.rb +196 -0
- data/lib/etassia/notation/mermaid/ir_adapters/block.rb +138 -0
- data/lib/etassia/notation/mermaid/ir_adapters/c4.rb +258 -0
- data/lib/etassia/notation/mermaid/ir_adapters/class_diagram.rb +257 -0
- data/lib/etassia/notation/mermaid/ir_adapters/er_diagram.rb +220 -0
- data/lib/etassia/notation/mermaid/ir_adapters/error.rb +32 -0
- data/lib/etassia/notation/mermaid/ir_adapters/flowchart.rb +208 -0
- data/lib/etassia/notation/mermaid/ir_adapters/gantt.rb +236 -0
- data/lib/etassia/notation/mermaid/ir_adapters/git_graph.rb +186 -0
- data/lib/etassia/notation/mermaid/ir_adapters/info.rb +34 -0
- data/lib/etassia/notation/mermaid/ir_adapters/kanban.rb +110 -0
- data/lib/etassia/notation/mermaid/ir_adapters/mindmap.rb +76 -0
- data/lib/etassia/notation/mermaid/ir_adapters/packet.rb +51 -0
- data/lib/etassia/notation/mermaid/ir_adapters/pie.rb +71 -0
- data/lib/etassia/notation/mermaid/ir_adapters/quadrant.rb +116 -0
- data/lib/etassia/notation/mermaid/ir_adapters/radar.rb +142 -0
- data/lib/etassia/notation/mermaid/ir_adapters/requirement.rb +237 -0
- data/lib/etassia/notation/mermaid/ir_adapters/sankey.rb +74 -0
- data/lib/etassia/notation/mermaid/ir_adapters/sequence.rb +304 -0
- data/lib/etassia/notation/mermaid/ir_adapters/state_diagram.rb +225 -0
- data/lib/etassia/notation/mermaid/ir_adapters/timeline.rb +93 -0
- data/lib/etassia/notation/mermaid/ir_adapters/treemap.rb +143 -0
- data/lib/etassia/notation/mermaid/ir_adapters/user_journey.rb +127 -0
- data/lib/etassia/notation/mermaid/ir_adapters/xychart.rb +131 -0
- data/lib/etassia/notation/mermaid.rb +399 -0
- data/lib/etassia/notation/parsed.rb +31 -0
- data/lib/etassia/notation/plantuml/activity/arrow_head.rb +45 -0
- data/lib/etassia/notation/plantuml/activity/arrow_style.rb +53 -0
- data/lib/etassia/notation/plantuml/activity/bar_columns.rb +75 -0
- data/lib/etassia/notation/plantuml/activity/box.rb +60 -0
- data/lib/etassia/notation/plantuml/activity/builder.rb +77 -0
- data/lib/etassia/notation/plantuml/activity/canvas.rb +117 -0
- data/lib/etassia/notation/plantuml/activity/column_centres.rb +151 -0
- data/lib/etassia/notation/plantuml/activity/columns.rb +224 -0
- data/lib/etassia/notation/plantuml/activity/diagram.rb +35 -0
- data/lib/etassia/notation/plantuml/activity/edge.rb +35 -0
- data/lib/etassia/notation/plantuml/activity/edge_marks.rb +68 -0
- data/lib/etassia/notation/plantuml/activity/exits.rb +61 -0
- data/lib/etassia/notation/plantuml/activity/frame_marks.rb +116 -0
- data/lib/etassia/notation/plantuml/activity/lane_steps.rb +82 -0
- data/lib/etassia/notation/plantuml/activity/lane_titles.rb +46 -0
- data/lib/etassia/notation/plantuml/activity/layout.rb +50 -0
- data/lib/etassia/notation/plantuml/activity/legacy_parser.rb +181 -0
- data/lib/etassia/notation/plantuml/activity/legacy_row_gaps.rb +65 -0
- data/lib/etassia/notation/plantuml/activity/mark.rb +23 -0
- data/lib/etassia/notation/plantuml/activity/marks.rb +62 -0
- data/lib/etassia/notation/plantuml/activity/metrics.rb +169 -0
- data/lib/etassia/notation/plantuml/activity/new_parser/blocks.rb +166 -0
- data/lib/etassia/notation/plantuml/activity/new_parser.rb +177 -0
- data/lib/etassia/notation/plantuml/activity/node.rb +50 -0
- data/lib/etassia/notation/plantuml/activity/node_marks.rb +174 -0
- data/lib/etassia/notation/plantuml/activity/note.rb +27 -0
- data/lib/etassia/notation/plantuml/activity/parser.rb +51 -0
- data/lib/etassia/notation/plantuml/activity/placement.rb +327 -0
- data/lib/etassia/notation/plantuml/activity/ranking.rb +142 -0
- data/lib/etassia/notation/plantuml/activity/reach.rb +58 -0
- data/lib/etassia/notation/plantuml/activity/renderer.rb +220 -0
- data/lib/etassia/notation/plantuml/activity/route.rb +22 -0
- data/lib/etassia/notation/plantuml/activity/router.rb +308 -0
- data/lib/etassia/notation/plantuml/activity/row_gaps.rb +105 -0
- data/lib/etassia/notation/plantuml/activity/row_spread.rb +59 -0
- data/lib/etassia/notation/plantuml/activity/scene.rb +20 -0
- data/lib/etassia/notation/plantuml/activity/text.rb +36 -0
- data/lib/etassia/notation/plantuml/activity.rb +50 -0
- data/lib/etassia/notation/plantuml/arrow.rb +135 -0
- data/lib/etassia/notation/plantuml/caption.rb +50 -0
- data/lib/etassia/notation/plantuml/caption_layout.rb +97 -0
- data/lib/etassia/notation/plantuml/caption_rows.rb +67 -0
- data/lib/etassia/notation/plantuml/class_header.rb +178 -0
- data/lib/etassia/notation/plantuml/class_name.rb +51 -0
- data/lib/etassia/notation/plantuml/component.rb +37 -0
- data/lib/etassia/notation/plantuml/creole.rb +278 -0
- data/lib/etassia/notation/plantuml/creole_icons.rb +33 -0
- data/lib/etassia/notation/plantuml/diagram.rb +60 -0
- data/lib/etassia/notation/plantuml/diagram_builder.rb +442 -0
- data/lib/etassia/notation/plantuml/diagram_name.rb +51 -0
- data/lib/etassia/notation/plantuml/directives.rb +33 -0
- data/lib/etassia/notation/plantuml/drawing/box.rb +28 -0
- data/lib/etassia/notation/plantuml/drawing/face.rb +39 -0
- data/lib/etassia/notation/plantuml/drawing/pen.rb +105 -0
- data/lib/etassia/notation/plantuml/drawing/renderer.rb +36 -0
- data/lib/etassia/notation/plantuml/drawing/scene.rb +28 -0
- data/lib/etassia/notation/plantuml/drawing.rb +19 -0
- data/lib/etassia/notation/plantuml/ebnf/blocks.rb +272 -0
- data/lib/etassia/notation/plantuml/ebnf/layout.rb +117 -0
- data/lib/etassia/notation/plantuml/ebnf/model.rb +22 -0
- data/lib/etassia/notation/plantuml/ebnf/reader.rb +131 -0
- data/lib/etassia/notation/plantuml/ebnf.rb +34 -0
- data/lib/etassia/notation/plantuml/end_texts.rb +78 -0
- data/lib/etassia/notation/plantuml/entity.rb +54 -0
- data/lib/etassia/notation/plantuml/further.rb +38 -0
- data/lib/etassia/notation/plantuml/gantt/layout.rb +269 -0
- data/lib/etassia/notation/plantuml/gantt/reader.rb +210 -0
- data/lib/etassia/notation/plantuml/gantt/renderer.rb +81 -0
- data/lib/etassia/notation/plantuml/gantt.rb +34 -0
- data/lib/etassia/notation/plantuml/include/blocks.rb +66 -0
- data/lib/etassia/notation/plantuml/include/finder.rb +61 -0
- data/lib/etassia/notation/plantuml/include.rb +78 -0
- data/lib/etassia/notation/plantuml/ir_adapter/annotations.rb +40 -0
- data/lib/etassia/notation/plantuml/ir_adapter/links.rb +91 -0
- data/lib/etassia/notation/plantuml/ir_adapter/sink.rb +49 -0
- data/lib/etassia/notation/plantuml/ir_adapter/structure.rb +86 -0
- data/lib/etassia/notation/plantuml/ir_adapter.rb +32 -0
- data/lib/etassia/notation/plantuml/ir_reader/annotations.rb +51 -0
- data/lib/etassia/notation/plantuml/ir_reader/index.rb +49 -0
- data/lib/etassia/notation/plantuml/ir_reader/links.rb +133 -0
- data/lib/etassia/notation/plantuml/ir_reader/structure.rb +83 -0
- data/lib/etassia/notation/plantuml/ir_reader.rb +42 -0
- data/lib/etassia/notation/plantuml/junction.rb +20 -0
- data/lib/etassia/notation/plantuml/klass.rb +41 -0
- data/lib/etassia/notation/plantuml/label_clearance.rb +67 -0
- data/lib/etassia/notation/plantuml/layout.rb +2806 -0
- data/lib/etassia/notation/plantuml/member.rb +37 -0
- data/lib/etassia/notation/plantuml/member_icon.rb +87 -0
- data/lib/etassia/notation/plantuml/member_icon_elements.rb +91 -0
- data/lib/etassia/notation/plantuml/member_pitch.rb +76 -0
- data/lib/etassia/notation/plantuml/member_rule.rb +48 -0
- data/lib/etassia/notation/plantuml/network/grid.rb +170 -0
- data/lib/etassia/notation/plantuml/network/layout.rb +158 -0
- data/lib/etassia/notation/plantuml/network/model.rb +22 -0
- data/lib/etassia/notation/plantuml/network/placement.rb +64 -0
- data/lib/etassia/notation/plantuml/network/reader.rb +126 -0
- data/lib/etassia/notation/plantuml/network/shapes.rb +109 -0
- data/lib/etassia/notation/plantuml/network.rb +37 -0
- data/lib/etassia/notation/plantuml/node_graph/archimate.rb +49 -0
- data/lib/etassia/notation/plantuml/node_graph/box_reader.rb +86 -0
- data/lib/etassia/notation/plantuml/node_graph/cloud.rb +73 -0
- data/lib/etassia/notation/plantuml/node_graph/crows_foot.rb +85 -0
- data/lib/etassia/notation/plantuml/node_graph/curve.rb +66 -0
- data/lib/etassia/notation/plantuml/node_graph/data_reader.rb +77 -0
- data/lib/etassia/notation/plantuml/node_graph/data_shape.rb +39 -0
- data/lib/etassia/notation/plantuml/node_graph/detour.rb +98 -0
- data/lib/etassia/notation/plantuml/node_graph/edge.rb +26 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_metrics.rb +49 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_reader.rb +65 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_shape.rb +111 -0
- data/lib/etassia/notation/plantuml/node_graph/figures.rb +92 -0
- data/lib/etassia/notation/plantuml/node_graph/frame_ports.rb +73 -0
- data/lib/etassia/notation/plantuml/node_graph/graph.rb +40 -0
- data/lib/etassia/notation/plantuml/node_graph/heads.rb +89 -0
- data/lib/etassia/notation/plantuml/node_graph/label_fan.rb +76 -0
- data/lib/etassia/notation/plantuml/node_graph/label_placer.rb +310 -0
- data/lib/etassia/notation/plantuml/node_graph/label_waypoint.rb +47 -0
- data/lib/etassia/notation/plantuml/node_graph/layout.rb +293 -0
- data/lib/etassia/notation/plantuml/node_graph/link.rb +78 -0
- data/lib/etassia/notation/plantuml/node_graph/macros.rb +39 -0
- data/lib/etassia/notation/plantuml/node_graph/metrics.rb +113 -0
- data/lib/etassia/notation/plantuml/node_graph/node.rb +44 -0
- data/lib/etassia/notation/plantuml/node_graph/note_tail.rb +58 -0
- data/lib/etassia/notation/plantuml/node_graph/packer.rb +126 -0
- data/lib/etassia/notation/plantuml/node_graph/parser.rb +309 -0
- data/lib/etassia/notation/plantuml/node_graph/paths.rb +48 -0
- data/lib/etassia/notation/plantuml/node_graph/ranking.rb +231 -0
- data/lib/etassia/notation/plantuml/node_graph/reader.rb +53 -0
- data/lib/etassia/notation/plantuml/node_graph/references.rb +38 -0
- data/lib/etassia/notation/plantuml/node_graph/renderer.rb +160 -0
- data/lib/etassia/notation/plantuml/node_graph/scene.rb +22 -0
- data/lib/etassia/notation/plantuml/node_graph/shapes.rb +302 -0
- data/lib/etassia/notation/plantuml/node_graph/skipped_ranks.rb +61 -0
- data/lib/etassia/notation/plantuml/node_graph/tab.rb +68 -0
- data/lib/etassia/notation/plantuml/node_graph/usecase_ellipse.rb +100 -0
- data/lib/etassia/notation/plantuml/node_graph.rb +38 -0
- data/lib/etassia/notation/plantuml/note.rb +27 -0
- data/lib/etassia/notation/plantuml/note_layout.rb +257 -0
- data/lib/etassia/notation/plantuml/note_outline.rb +68 -0
- data/lib/etassia/notation/plantuml/objects/map_rows.rb +46 -0
- data/lib/etassia/notation/plantuml/objects/reader.rb +208 -0
- data/lib/etassia/notation/plantuml/objects.rb +39 -0
- data/lib/etassia/notation/plantuml/package.rb +45 -0
- data/lib/etassia/notation/plantuml/package_color.rb +32 -0
- data/lib/etassia/notation/plantuml/package_frames.rb +178 -0
- data/lib/etassia/notation/plantuml/parser.rb +622 -0
- data/lib/etassia/notation/plantuml/portion_visibility.rb +91 -0
- data/lib/etassia/notation/plantuml/qualified_association_layout.rb +332 -0
- data/lib/etassia/notation/plantuml/qualifier_box.rb +78 -0
- data/lib/etassia/notation/plantuml/rank_chain.rb +527 -0
- data/lib/etassia/notation/plantuml/rank_hierarchy.rb +347 -0
- data/lib/etassia/notation/plantuml/relation.rb +103 -0
- data/lib/etassia/notation/plantuml/relation_label_separator.rb +199 -0
- data/lib/etassia/notation/plantuml/relation_path_points.rb +84 -0
- data/lib/etassia/notation/plantuml/renderer.rb +490 -0
- data/lib/etassia/notation/plantuml/scene.rb +134 -0
- data/lib/etassia/notation/plantuml/segment_box.rb +85 -0
- data/lib/etassia/notation/plantuml/sequence/activation.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/appearance.rb +71 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_end.rb +23 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_marks.rb +111 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_style.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_syntax.rb +122 -0
- data/lib/etassia/notation/plantuml/sequence/bar_tracker.rb +59 -0
- data/lib/etassia/notation/plantuml/sequence/box.rb +23 -0
- data/lib/etassia/notation/plantuml/sequence/chrome.rb +60 -0
- data/lib/etassia/notation/plantuml/sequence/chrome_rows.rb +184 -0
- data/lib/etassia/notation/plantuml/sequence/create.rb +34 -0
- data/lib/etassia/notation/plantuml/sequence/delay.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/destroy.rb +20 -0
- data/lib/etassia/notation/plantuml/sequence/diagram.rb +86 -0
- data/lib/etassia/notation/plantuml/sequence/divider.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/edge.rb +53 -0
- data/lib/etassia/notation/plantuml/sequence/embedded.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/fill.rb +56 -0
- data/lib/etassia/notation/plantuml/sequence/fragment.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/fragment_shape.rb +138 -0
- data/lib/etassia/notation/plantuml/sequence/head_style.rb +43 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/blocks.rb +73 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/fills.rb +24 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/items.rb +48 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/messages.rb +62 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/participants.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/settings.rb +54 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter.rb +38 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/blocks.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/fills.rb +27 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/index.rb +36 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/items.rb +35 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/messages.rb +70 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/participants.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/settings.rb +74 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader.rb +38 -0
- data/lib/etassia/notation/plantuml/sequence/keyword_defaults.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/layout.rb +1567 -0
- data/lib/etassia/notation/plantuml/sequence/message.rb +97 -0
- data/lib/etassia/notation/plantuml/sequence/message_wrap.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/note.rb +61 -0
- data/lib/etassia/notation/plantuml/sequence/note_fill.rb +35 -0
- data/lib/etassia/notation/plantuml/sequence/note_geometry.rb +126 -0
- data/lib/etassia/notation/plantuml/sequence/note_shape.rb +51 -0
- data/lib/etassia/notation/plantuml/sequence/numbered_label.rb +57 -0
- data/lib/etassia/notation/plantuml/sequence/numbering.rb +49 -0
- data/lib/etassia/notation/plantuml/sequence/outline.rb +204 -0
- data/lib/etassia/notation/plantuml/sequence/page_break.rb +17 -0
- data/lib/etassia/notation/plantuml/sequence/paint.rb +79 -0
- data/lib/etassia/notation/plantuml/sequence/parallel_message.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/parser.rb +844 -0
- data/lib/etassia/notation/plantuml/sequence/participant.rb +27 -0
- data/lib/etassia/notation/plantuml/sequence/picture.rb +29 -0
- data/lib/etassia/notation/plantuml/sequence/ref.rb +24 -0
- data/lib/etassia/notation/plantuml/sequence/ref_shape.rb +74 -0
- data/lib/etassia/notation/plantuml/sequence/refusals.rb +47 -0
- data/lib/etassia/notation/plantuml/sequence/renderer.rb +501 -0
- data/lib/etassia/notation/plantuml/sequence/scene.rb +200 -0
- data/lib/etassia/notation/plantuml/sequence/skin.rb +76 -0
- data/lib/etassia/notation/plantuml/sequence/spacing.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/style.rb +151 -0
- data/lib/etassia/notation/plantuml/sequence/tab_size.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/walker.rb +1190 -0
- data/lib/etassia/notation/plantuml/sequence.rb +47 -0
- data/lib/etassia/notation/plantuml/source_lines.rb +33 -0
- data/lib/etassia/notation/plantuml/state/axis_solver.rb +272 -0
- data/lib/etassia/notation/plantuml/state/cluster_padding.rb +75 -0
- data/lib/etassia/notation/plantuml/state/curve.rb +73 -0
- data/lib/etassia/notation/plantuml/state/dot_axis.rb +248 -0
- data/lib/etassia/notation/plantuml/state/extent.rb +42 -0
- data/lib/etassia/notation/plantuml/state/hierarchy.rb +355 -0
- data/lib/etassia/notation/plantuml/state/label_clearance.rb +148 -0
- data/lib/etassia/notation/plantuml/state/label_reach.rb +139 -0
- data/lib/etassia/notation/plantuml/state/layout.rb +173 -0
- data/lib/etassia/notation/plantuml/state/level_edges.rb +113 -0
- data/lib/etassia/notation/plantuml/state/look.rb +36 -0
- data/lib/etassia/notation/plantuml/state/note_shape.rb +73 -0
- data/lib/etassia/notation/plantuml/state/plane.rb +85 -0
- data/lib/etassia/notation/plantuml/state/ranking.rb +181 -0
- data/lib/etassia/notation/plantuml/state/reader.rb +310 -0
- data/lib/etassia/notation/plantuml/state/renderer.rb +253 -0
- data/lib/etassia/notation/plantuml/state/route_detour.rb +115 -0
- data/lib/etassia/notation/plantuml/state/route_geometry.rb +186 -0
- data/lib/etassia/notation/plantuml/state/routes.rb +196 -0
- data/lib/etassia/notation/plantuml/state/row.rb +88 -0
- data/lib/etassia/notation/plantuml/state/rows.rb +50 -0
- data/lib/etassia/notation/plantuml/state/stretch.rb +71 -0
- data/lib/etassia/notation/plantuml/state.rb +62 -0
- data/lib/etassia/notation/plantuml/stereotype_head.rb +58 -0
- data/lib/etassia/notation/plantuml/style/bound.rb +34 -0
- data/lib/etassia/notation/plantuml/style/colour.rb +41 -0
- data/lib/etassia/notation/plantuml/style/colour_names.rb +89 -0
- data/lib/etassia/notation/plantuml/style/defaults.rb +33 -0
- data/lib/etassia/notation/plantuml/style/inline.rb +56 -0
- data/lib/etassia/notation/plantuml/style/reader.rb +242 -0
- data/lib/etassia/notation/plantuml/style/sheet.rb +103 -0
- data/lib/etassia/notation/plantuml/style.rb +32 -0
- data/lib/etassia/notation/plantuml/style_reader.rb +160 -0
- data/lib/etassia/notation/plantuml/style_sheet.rb +27 -0
- data/lib/etassia/notation/plantuml/styled_relation_curve.rb +71 -0
- data/lib/etassia/notation/plantuml/timing/arrows.rb +81 -0
- data/lib/etassia/notation/plantuml/timing/axis.rb +100 -0
- data/lib/etassia/notation/plantuml/timing/layout.rb +172 -0
- data/lib/etassia/notation/plantuml/timing/model.rb +34 -0
- data/lib/etassia/notation/plantuml/timing/reader.rb +173 -0
- data/lib/etassia/notation/plantuml/timing/signals.rb +328 -0
- data/lib/etassia/notation/plantuml/timing.rb +38 -0
- data/lib/etassia/notation/plantuml/tree/layout.rb +276 -0
- data/lib/etassia/notation/plantuml/tree/mindmap_layout.rb +157 -0
- data/lib/etassia/notation/plantuml/tree/reader.rb +186 -0
- data/lib/etassia/notation/plantuml/tree/renderer.rb +67 -0
- data/lib/etassia/notation/plantuml/tree/role.rb +57 -0
- data/lib/etassia/notation/plantuml/tree/rules.rb +156 -0
- data/lib/etassia/notation/plantuml/tree/wbs_layout.rb +164 -0
- data/lib/etassia/notation/plantuml/tree.rb +41 -0
- data/lib/etassia/notation/plantuml/unsupported_construct_error.rb +39 -0
- data/lib/etassia/notation/plantuml/unsupported_constructs.rb +103 -0
- data/lib/etassia/notation/plantuml/usecase.rb +36 -0
- data/lib/etassia/notation/plantuml.rb +132 -0
- data/lib/etassia/notation/plantuml_data/boxes/frames.rb +101 -0
- data/lib/etassia/notation/plantuml_data/boxes/graph_layout.rb +348 -0
- data/lib/etassia/notation/plantuml_data/boxes/heads.rb +65 -0
- data/lib/etassia/notation/plantuml_data/boxes/highlights.rb +70 -0
- data/lib/etassia/notation/plantuml_data/boxes/inline_rows.rb +99 -0
- data/lib/etassia/notation/plantuml_data/boxes/json_reader.rb +24 -0
- data/lib/etassia/notation/plantuml_data/boxes/link_text.rb +94 -0
- data/lib/etassia/notation/plantuml_data/boxes/marks.rb +76 -0
- data/lib/etassia/notation/plantuml_data/boxes/ornaments.rb +130 -0
- data/lib/etassia/notation/plantuml_data/boxes/renderer.rb +95 -0
- data/lib/etassia/notation/plantuml_data/boxes/row_alignment.rb +58 -0
- data/lib/etassia/notation/plantuml_data/boxes/row_bend.rb +43 -0
- data/lib/etassia/notation/plantuml_data/boxes/scene.rb +27 -0
- data/lib/etassia/notation/plantuml_data/boxes/table.rb +56 -0
- data/lib/etassia/notation/plantuml_data/boxes/table_box.rb +355 -0
- data/lib/etassia/notation/plantuml_data/boxes/text.rb +101 -0
- data/lib/etassia/notation/plantuml_data/boxes/tree_builder.rb +82 -0
- data/lib/etassia/notation/plantuml_data/boxes/tree_layout.rb +82 -0
- data/lib/etassia/notation/plantuml_data/boxes/yaml_reader.rb +105 -0
- data/lib/etassia/notation/plantuml_data/openiconic.LICENSE +6 -0
- data/lib/etassia/notation/plantuml_data/openiconic.json +1 -0
- data/lib/etassia/notation/plantuml_data.rb +84 -0
- data/lib/etassia/notation/plantuml_salt/block.rb +80 -0
- data/lib/etassia/notation/plantuml_salt/box.rb +30 -0
- data/lib/etassia/notation/plantuml_salt/font_metrics.rb +28 -0
- data/lib/etassia/notation/plantuml_salt/grid_marks.rb +66 -0
- data/lib/etassia/notation/plantuml_salt/group_marks.rb +77 -0
- data/lib/etassia/notation/plantuml_salt/layout.rb +206 -0
- data/lib/etassia/notation/plantuml_salt/mark.rb +36 -0
- data/lib/etassia/notation/plantuml_salt/markup.rb +57 -0
- data/lib/etassia/notation/plantuml_salt/parser.rb +239 -0
- data/lib/etassia/notation/plantuml_salt/renderer.rb +138 -0
- data/lib/etassia/notation/plantuml_salt/row.rb +19 -0
- data/lib/etassia/notation/plantuml_salt/run.rb +34 -0
- data/lib/etassia/notation/plantuml_salt/scene.rb +23 -0
- data/lib/etassia/notation/plantuml_salt/scroll_marks.rb +94 -0
- data/lib/etassia/notation/plantuml_salt/tab_marks.rb +74 -0
- data/lib/etassia/notation/plantuml_salt/tree_marks.rb +127 -0
- data/lib/etassia/notation/plantuml_salt/widget.rb +40 -0
- data/lib/etassia/notation/plantuml_salt/widget_marks.rb +319 -0
- data/lib/etassia/notation/plantuml_salt.rb +66 -0
- data/lib/etassia/notation/plugin_failure.rb +42 -0
- data/lib/etassia/notation.rb +289 -0
- data/lib/etassia/parser/architecture.rb +25 -0
- data/lib/etassia/parser/atoms/delimited_run.rb +82 -0
- data/lib/etassia/parser/atoms/greedy_run.rb +116 -0
- data/lib/etassia/parser/atoms/joined.rb +47 -0
- data/lib/etassia/parser/atoms/trimmed_run.rb +47 -0
- data/lib/etassia/parser/base.rb +258 -0
- data/lib/etassia/parser/block.rb +32 -0
- data/lib/etassia/parser/builders/architecture.rb +135 -0
- data/lib/etassia/parser/builders/block.rb +288 -0
- data/lib/etassia/parser/builders/c4.rb +275 -0
- data/lib/etassia/parser/builders/capture_string.rb +17 -0
- data/lib/etassia/parser/builders/class_diagram.rb +539 -0
- data/lib/etassia/parser/builders/er_diagram.rb +308 -0
- data/lib/etassia/parser/builders/error.rb +51 -0
- data/lib/etassia/parser/builders/flowchart.rb +1150 -0
- data/lib/etassia/parser/builders/gantt.rb +267 -0
- data/lib/etassia/parser/builders/git_graph.rb +301 -0
- data/lib/etassia/parser/builders/info.rb +57 -0
- data/lib/etassia/parser/builders/kanban.rb +411 -0
- data/lib/etassia/parser/builders/mindmap.rb +271 -0
- data/lib/etassia/parser/builders/packet.rb +85 -0
- data/lib/etassia/parser/builders/pie.rb +105 -0
- data/lib/etassia/parser/builders/quadrant.rb +165 -0
- data/lib/etassia/parser/builders/radar.rb +157 -0
- data/lib/etassia/parser/builders/requirement.rb +230 -0
- data/lib/etassia/parser/builders/sankey.rb +142 -0
- data/lib/etassia/parser/builders/sequence.rb +431 -0
- data/lib/etassia/parser/builders/sequence_blocks.rb +117 -0
- data/lib/etassia/parser/builders/sequence_box_title.rb +57 -0
- data/lib/etassia/parser/builders/state_diagram.rb +364 -0
- data/lib/etassia/parser/builders/timeline.rb +133 -0
- data/lib/etassia/parser/builders/treemap.rb +138 -0
- data/lib/etassia/parser/builders/xy_chart.rb +148 -0
- data/lib/etassia/parser/c4.rb +37 -0
- data/lib/etassia/parser/class_diagram.rb +58 -0
- data/lib/etassia/parser/class_namespaces.rb +62 -0
- data/lib/etassia/parser/class_notes.rb +54 -0
- data/lib/etassia/parser/er_diagram.rb +28 -0
- data/lib/etassia/parser/error.rb +30 -0
- data/lib/etassia/parser/flowchart.rb +87 -0
- data/lib/etassia/parser/gantt.rb +43 -0
- data/lib/etassia/parser/git_graph.rb +106 -0
- data/lib/etassia/parser/grammars/architecture.rb +165 -0
- data/lib/etassia/parser/grammars/block.rb +190 -0
- data/lib/etassia/parser/grammars/c4.rb +229 -0
- data/lib/etassia/parser/grammars/class_diagram.rb +606 -0
- data/lib/etassia/parser/grammars/common.rb +107 -0
- data/lib/etassia/parser/grammars/er_diagram.rb +232 -0
- data/lib/etassia/parser/grammars/error.rb +32 -0
- data/lib/etassia/parser/grammars/flowchart.rb +1722 -0
- data/lib/etassia/parser/grammars/gantt.rb +198 -0
- data/lib/etassia/parser/grammars/git_graph.rb +234 -0
- data/lib/etassia/parser/grammars/info.rb +53 -0
- data/lib/etassia/parser/grammars/kanban.rb +417 -0
- data/lib/etassia/parser/grammars/mermaid_unicode_text.rb +108 -0
- data/lib/etassia/parser/grammars/mindmap.rb +220 -0
- data/lib/etassia/parser/grammars/packet.rb +71 -0
- data/lib/etassia/parser/grammars/pie.rb +128 -0
- data/lib/etassia/parser/grammars/quadrant.rb +202 -0
- data/lib/etassia/parser/grammars/radar.rb +158 -0
- data/lib/etassia/parser/grammars/requirement.rb +258 -0
- data/lib/etassia/parser/grammars/sankey.rb +104 -0
- data/lib/etassia/parser/grammars/sequence.rb +940 -0
- data/lib/etassia/parser/grammars/state_diagram.rb +382 -0
- data/lib/etassia/parser/grammars/timeline.rb +153 -0
- data/lib/etassia/parser/grammars/treemap.rb +122 -0
- data/lib/etassia/parser/grammars/xy_chart.rb +119 -0
- data/lib/etassia/parser/info.rb +32 -0
- data/lib/etassia/parser/kanban.rb +131 -0
- data/lib/etassia/parser/mermaid_shapes.rb +106 -0
- data/lib/etassia/parser/metadata_yaml.rb +452 -0
- data/lib/etassia/parser/mindmap.rb +92 -0
- data/lib/etassia/parser/native/builders/architecture.rb +103 -0
- data/lib/etassia/parser/native/builders/block.rb +68 -0
- data/lib/etassia/parser/native/builders/c4.rb +16 -0
- data/lib/etassia/parser/native/builders/class_diagram.rb +63 -0
- data/lib/etassia/parser/native/builders/er_diagram.rb +47 -0
- data/lib/etassia/parser/native/builders/flowchart.rb +58 -0
- data/lib/etassia/parser/native/builders/gantt.rb +35 -0
- data/lib/etassia/parser/native/builders/gitgraph.rb +35 -0
- data/lib/etassia/parser/native/builders/info.rb +30 -0
- data/lib/etassia/parser/native/builders/kanban.rb +37 -0
- data/lib/etassia/parser/native/builders/mindmap.rb +26 -0
- data/lib/etassia/parser/native/builders/packet.rb +63 -0
- data/lib/etassia/parser/native/builders/pie.rb +82 -0
- data/lib/etassia/parser/native/builders/quadrant.rb +27 -0
- data/lib/etassia/parser/native/builders/radar.rb +84 -0
- data/lib/etassia/parser/native/builders/requirement.rb +25 -0
- data/lib/etassia/parser/native/builders/sankey.rb +18 -0
- data/lib/etassia/parser/native/builders/sequence.rb +48 -0
- data/lib/etassia/parser/native/builders/state_diagram.rb +61 -0
- data/lib/etassia/parser/native/builders/timeline.rb +46 -0
- data/lib/etassia/parser/native/builders/treemap.rb +60 -0
- data/lib/etassia/parser/native/builders/user_journey.rb +83 -0
- data/lib/etassia/parser/native/builders/xy_chart.rb +94 -0
- data/lib/etassia/parser/native/declined.rb +12 -0
- data/lib/etassia/parser/native/mermaid.json +1 -0
- data/lib/etassia/parser/native/text.rb +31 -0
- data/lib/etassia/parser/native.rb +99 -0
- data/lib/etassia/parser/packet.rb +56 -0
- data/lib/etassia/parser/pie.rb +32 -0
- data/lib/etassia/parser/quadrant.rb +77 -0
- data/lib/etassia/parser/radar.rb +99 -0
- data/lib/etassia/parser/requirement.rb +32 -0
- data/lib/etassia/parser/sankey.rb +47 -0
- data/lib/etassia/parser/sequence.rb +34 -0
- data/lib/etassia/parser/state_diagram.rb +29 -0
- data/lib/etassia/parser/timeline.rb +40 -0
- data/lib/etassia/parser/treemap.rb +25 -0
- data/lib/etassia/parser/user_journey.rb +253 -0
- data/lib/etassia/parser/xy_chart.rb +98 -0
- data/lib/etassia/parser.rb +18 -0
- data/lib/etassia/renderer/architecture.rb +232 -0
- data/lib/etassia/renderer/architecture_edge_router.rb +379 -0
- data/lib/etassia/renderer/base.rb +295 -0
- data/lib/etassia/renderer/block.rb +157 -0
- data/lib/etassia/renderer/c4.rb +294 -0
- data/lib/etassia/renderer/class_diagram.rb +671 -0
- data/lib/etassia/renderer/er_diagram.rb +842 -0
- data/lib/etassia/renderer/error.rb +131 -0
- data/lib/etassia/renderer/flowchart.rb +315 -0
- data/lib/etassia/renderer/gantt.rb +177 -0
- data/lib/etassia/renderer/git_graph.rb +224 -0
- data/lib/etassia/renderer/info.rb +59 -0
- data/lib/etassia/renderer/kanban.rb +157 -0
- data/lib/etassia/renderer/line_break_text.rb +56 -0
- data/lib/etassia/renderer/markdown_text.rb +106 -0
- data/lib/etassia/renderer/mindmap.rb +290 -0
- data/lib/etassia/renderer/packet.rb +87 -0
- data/lib/etassia/renderer/pie.rb +113 -0
- data/lib/etassia/renderer/quadrant.rb +189 -0
- data/lib/etassia/renderer/radar.rb +191 -0
- data/lib/etassia/renderer/requirement.rb +209 -0
- data/lib/etassia/renderer/sankey.rb +114 -0
- data/lib/etassia/renderer/sequence/frame_drawing.rb +169 -0
- data/lib/etassia/renderer/sequence/note_drawing.rb +69 -0
- data/lib/etassia/renderer/sequence.rb +490 -0
- data/lib/etassia/renderer/state_diagram.rb +202 -0
- data/lib/etassia/renderer/timeline.rb +134 -0
- data/lib/etassia/renderer/timeline_palette.rb +18 -0
- data/lib/etassia/renderer/treemap/section_total.rb +33 -0
- data/lib/etassia/renderer/treemap.rb +128 -0
- data/lib/etassia/renderer/user_journey.rb +209 -0
- data/lib/etassia/renderer/xy_chart.rb +180 -0
- data/lib/etassia/renderer.rb +22 -0
- data/lib/etassia/runtime.rb +125 -0
- data/lib/etassia/source/frontmatter.rb +501 -0
- data/lib/etassia/source.rb +224 -0
- data/lib/etassia/svg/arrowhead.rb +205 -0
- data/lib/etassia/svg/circle.rb +19 -0
- data/lib/etassia/svg/document.rb +106 -0
- data/lib/etassia/svg/element.rb +209 -0
- data/lib/etassia/svg/ellipse.rb +23 -0
- data/lib/etassia/svg/escaping.rb +149 -0
- data/lib/etassia/svg/group.rb +64 -0
- data/lib/etassia/svg/line.rb +21 -0
- data/lib/etassia/svg/numbers.rb +53 -0
- data/lib/etassia/svg/path.rb +67 -0
- data/lib/etassia/svg/path_geometry.rb +378 -0
- data/lib/etassia/svg/polygon.rb +25 -0
- data/lib/etassia/svg/polyline.rb +28 -0
- data/lib/etassia/svg/rect.rb +34 -0
- data/lib/etassia/svg/style.rb +50 -0
- data/lib/etassia/svg/text.rb +181 -0
- data/lib/etassia/svg/tspan.rb +48 -0
- data/lib/etassia/svg.rb +38 -0
- data/lib/etassia/text_measurement/arial_advances.rb +122 -0
- data/lib/etassia/text_measurement/dejavu_advances.rb +111 -0
- data/lib/etassia/text_measurement/times_advances.rb +64 -0
- data/lib/etassia/text_measurement/trebuchet_advances.rb +53 -0
- data/lib/etassia/text_measurement/trebuchet_kerning.rb +29 -0
- data/lib/etassia/text_measurement.rb +198 -0
- data/lib/etassia/theme/builtin/dark.yml +229 -0
- data/lib/etassia/theme/builtin/default.yml +239 -0
- data/lib/etassia/theme/builtin/high_contrast.yml +231 -0
- data/lib/etassia/theme/builtin/light.yml +229 -0
- data/lib/etassia/theme/color_palette.rb +97 -0
- data/lib/etassia/theme/completion.rb +50 -0
- data/lib/etassia/theme/effect_styles.rb +34 -0
- data/lib/etassia/theme/registry.rb +45 -0
- data/lib/etassia/theme/shape_styles.rb +34 -0
- data/lib/etassia/theme/spacing_config.rb +30 -0
- data/lib/etassia/theme/typography.rb +40 -0
- data/lib/etassia/theme.rb +73 -0
- data/lib/etassia/version.rb +5 -0
- data/lib/etassia.rb +40 -0
- metadata +865 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "escaping"
|
|
4
|
+
require "lutaml/model"
|
|
5
|
+
require_relative "numbers"
|
|
6
|
+
require_relative "style"
|
|
7
|
+
|
|
8
|
+
module Etassia
|
|
9
|
+
module Svg
|
|
10
|
+
# Base class for all SVG elements.
|
|
11
|
+
#
|
|
12
|
+
# Provides common attributes and functionality shared by all SVG elements
|
|
13
|
+
# including styling, transformation, and identification.
|
|
14
|
+
class Element < Lutaml::Model::Serializable
|
|
15
|
+
attribute :id, :string
|
|
16
|
+
attribute :class_name, :string
|
|
17
|
+
attribute :style, Svg::Style
|
|
18
|
+
attribute :transform, :string
|
|
19
|
+
attribute :fill, :string
|
|
20
|
+
attribute :fill_opacity, :string
|
|
21
|
+
attribute :stroke, :string
|
|
22
|
+
attribute :stroke_width, :string
|
|
23
|
+
attribute :stroke_opacity, :string
|
|
24
|
+
attribute :opacity, :string
|
|
25
|
+
|
|
26
|
+
# class_name is the only reader whose SVG name is not just its own
|
|
27
|
+
# with underscores hyphenated.
|
|
28
|
+
ATTRIBUTE_NAMES = { class_name: "class" }.freeze
|
|
29
|
+
private_constant :ATTRIBUTE_NAMES
|
|
30
|
+
|
|
31
|
+
# The SVG name for a Ruby attribute reader.
|
|
32
|
+
#
|
|
33
|
+
# @param name [Symbol] the reader
|
|
34
|
+
# @return [String] the attribute name to emit
|
|
35
|
+
def self.svg_name(name)
|
|
36
|
+
ATTRIBUTE_NAMES.fetch(name) { name.to_s.tr("_", "-") }
|
|
37
|
+
end
|
|
38
|
+
private_class_method :svg_name
|
|
39
|
+
|
|
40
|
+
# Emitted by every element, in this order, as [svg name, reader].
|
|
41
|
+
# Named once here rather than on every render.
|
|
42
|
+
#
|
|
43
|
+
# `opacity` is not in the list even though it is an attribute. SVG Tiny
|
|
44
|
+
# 1.2 — the element and attribute table the svg_conform :metanorma
|
|
45
|
+
# profile enforces — has no `opacity` property, only `fill-opacity` and
|
|
46
|
+
# `stroke-opacity`. So the two opacity readers below fold it in rather
|
|
47
|
+
# than emitting it, and every element inherits that by construction.
|
|
48
|
+
BASE_PAIRS = [
|
|
49
|
+
[svg_name(:id), :id],
|
|
50
|
+
[svg_name(:class_name), :class_name],
|
|
51
|
+
[svg_name(:transform), :transform],
|
|
52
|
+
[svg_name(:fill), :fill],
|
|
53
|
+
[svg_name(:fill_opacity), :painted_fill_opacity],
|
|
54
|
+
[svg_name(:stroke), :stroke],
|
|
55
|
+
[svg_name(:stroke_width), :stroke_width],
|
|
56
|
+
[svg_name(:stroke_opacity), :painted_stroke_opacity],
|
|
57
|
+
].map(&:freeze).freeze
|
|
58
|
+
private_constant :BASE_PAIRS
|
|
59
|
+
|
|
60
|
+
# Generate XML representation of this element.
|
|
61
|
+
#
|
|
62
|
+
# A fragment, not a document. An element that draws sibling shapes — a
|
|
63
|
+
# Path with an arrowhead — returns more than one root, and a strict
|
|
64
|
+
# parser will refuse that as having two roots. Group and Document join
|
|
65
|
+
# fragments, so that is the contract they already rely on. Path calls
|
|
66
|
+
# it on each of its own arrowheads too, and a Polygon draws no
|
|
67
|
+
# siblings, so those are always one root.
|
|
68
|
+
#
|
|
69
|
+
# @return [String] one or more sibling elements, newline separated
|
|
70
|
+
def to_xml
|
|
71
|
+
xml_lines.join("\n")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Declares the attributes an element writes, in output order.
|
|
75
|
+
#
|
|
76
|
+
# Several subclasses were each carrying the same shape of method — a
|
|
77
|
+
# list of names paired with the matching reader. Declaring them removes
|
|
78
|
+
# that repetition and, more usefully, removes the chance of one class's
|
|
79
|
+
# version drifting into a different shape.
|
|
80
|
+
#
|
|
81
|
+
# Ruby names map to SVG names by turning underscores into hyphens, which
|
|
82
|
+
# covers every attribute these elements emit (`stroke_dasharray` becomes
|
|
83
|
+
# `stroke-dasharray`). A notation needing anything else should override
|
|
84
|
+
# #element_attributes rather than bend this.
|
|
85
|
+
#
|
|
86
|
+
# @param names [Array<Symbol>] attribute readers, in output order
|
|
87
|
+
# @return [void]
|
|
88
|
+
def self.writes_attributes(*names)
|
|
89
|
+
pairs = names.map { |name| [svg_name(name), name].freeze }.freeze
|
|
90
|
+
define_method(:element_attributes) { attribute_pairs(pairs) }
|
|
91
|
+
|
|
92
|
+
# define_method defines a public method, while the base hook is
|
|
93
|
+
# protected. Without this a declared subclass widened the API for no
|
|
94
|
+
# reason and disagreed with its own parent.
|
|
95
|
+
protected :element_attributes
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
protected
|
|
99
|
+
|
|
100
|
+
# The complete markup for one element.
|
|
101
|
+
#
|
|
102
|
+
# @return [String] XML string
|
|
103
|
+
def element_markup
|
|
104
|
+
tag = self.class.name.split("::").last.downcase
|
|
105
|
+
attrs = build_attributes
|
|
106
|
+
|
|
107
|
+
"<#{tag}#{attrs}/>"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# The markup a parent indents, one entry per structural unit.
|
|
111
|
+
#
|
|
112
|
+
# Separate from #to_xml because a parent may not indent every line of a
|
|
113
|
+
# child's markup: a Text holding a newline would have its content
|
|
114
|
+
# rewritten. Group indents entries instead, and Text#element_markup is
|
|
115
|
+
# the only entry that may carry a newline of its own.
|
|
116
|
+
#
|
|
117
|
+
# @return [Array<String>] this element's markup, then each sibling's
|
|
118
|
+
# markup
|
|
119
|
+
def xml_lines
|
|
120
|
+
[element_markup, *sibling_markup]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Hook for subclasses to draw sibling shapes alongside this element.
|
|
124
|
+
#
|
|
125
|
+
# @return [Array<String>] one entry of markup per sibling
|
|
126
|
+
def sibling_markup
|
|
127
|
+
[]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Build attribute string for XML output
|
|
131
|
+
#
|
|
132
|
+
# @return [String] formatted attribute string
|
|
133
|
+
def build_attributes
|
|
134
|
+
Escaping.attributes(attribute_pairs(BASE_PAIRS) + element_attributes)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Reads the current values for already-named attributes.
|
|
138
|
+
#
|
|
139
|
+
# Shared with .writes_attributes so the base attributes and a
|
|
140
|
+
# subclass's own go through one naming rule. Written out as literal
|
|
141
|
+
# pairs in both places, the hyphenation was typed by hand here and
|
|
142
|
+
# computed there, which is two spellings of one rule.
|
|
143
|
+
#
|
|
144
|
+
# `send`, not `public_send`: some pair-table readers are protected:
|
|
145
|
+
# #painted_fill_opacity and #painted_stroke_opacity here, plus
|
|
146
|
+
# Text#offset_x and Text#baseline_y in the subclass. `public_send`
|
|
147
|
+
# cannot reach them.
|
|
148
|
+
#
|
|
149
|
+
# @param pairs [Array<Array>] [svg name, reader], in output order
|
|
150
|
+
# @return [Array<Array>] name/value pairs
|
|
151
|
+
def attribute_pairs(pairs)
|
|
152
|
+
pairs.map { |svg_name, reader| [svg_name, send(reader)] }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# `fill-opacity` as it should be painted, with any whole-element
|
|
156
|
+
# `opacity` folded in.
|
|
157
|
+
#
|
|
158
|
+
# @return [Object, nil] the attribute value, or nil when unset
|
|
159
|
+
def painted_fill_opacity
|
|
160
|
+
composed_opacity(fill_opacity)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# `stroke-opacity` as it should be painted, with any whole-element
|
|
164
|
+
# `opacity` folded in.
|
|
165
|
+
#
|
|
166
|
+
# @return [Object, nil] the attribute value, or nil when unset
|
|
167
|
+
def painted_stroke_opacity
|
|
168
|
+
composed_opacity(stroke_opacity)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Hook for subclasses to add their specific attributes.
|
|
172
|
+
#
|
|
173
|
+
# Returns name/value PAIRS, not rendered markup. That is deliberate: it
|
|
174
|
+
# leaves Escaping.attributes as the only code that turns an attribute
|
|
175
|
+
# into text, so a subclass cannot emit an unescaped one. Pairs with a
|
|
176
|
+
# nil value are dropped, so callers need no conditionals.
|
|
177
|
+
#
|
|
178
|
+
# @return [Array<Array>] name/value pairs
|
|
179
|
+
def element_attributes
|
|
180
|
+
[]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
# Multiplies a component opacity by the whole-element one.
|
|
186
|
+
#
|
|
187
|
+
# Approximate where fill/stroke overlap (no object opacity in
|
|
188
|
+
# SVG Tiny 1.2) -- accepted deviation, not a bug to fix here.
|
|
189
|
+
# NOT equivalent to Group opacity -- do not reuse this for a
|
|
190
|
+
# container. Non-numeric/non-finite components are left alone,
|
|
191
|
+
# never clamped, to avoid emitting an invented value.
|
|
192
|
+
#
|
|
193
|
+
# @param component [Object] fill-opacity or stroke-opacity as set
|
|
194
|
+
# @return [Object, nil] the value to emit
|
|
195
|
+
def composed_opacity(component)
|
|
196
|
+
whole = Numbers.read(opacity)
|
|
197
|
+
return component if whole.nil?
|
|
198
|
+
|
|
199
|
+
part = Escaping.blank?(component) ? 1.0 : Numbers.read(component)
|
|
200
|
+
return component if part.nil?
|
|
201
|
+
return component unless whole.finite? && part.finite?
|
|
202
|
+
|
|
203
|
+
whole = whole.clamp(0.0, 1.0)
|
|
204
|
+
part = part.clamp(0.0, 1.0)
|
|
205
|
+
Numbers.write(part * whole)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Ellipse element <ellipse>
|
|
9
|
+
#
|
|
10
|
+
# Represents an ellipse shape with center point and radii.
|
|
11
|
+
class Ellipse < Element
|
|
12
|
+
attribute :cx, :float
|
|
13
|
+
attribute :cy, :float
|
|
14
|
+
attribute :rx, :float
|
|
15
|
+
attribute :ry, :float
|
|
16
|
+
|
|
17
|
+
# Emitted nothing before this: an Ellipse rendered as
|
|
18
|
+
# `<ellipse fill="red"/>` with no geometry, and renderer/c4.rb:242 draws
|
|
19
|
+
# boundaries with it.
|
|
20
|
+
writes_attributes :cx, :cy, :rx, :ry
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Etassia
|
|
4
|
+
module Svg
|
|
5
|
+
# XML escaping for everything Etassia writes into an SVG document.
|
|
6
|
+
#
|
|
7
|
+
# Nothing was escaped before this. A diagram label reading
|
|
8
|
+
# `Alice<img src=` was emitted verbatim, which is malformed XML and, since
|
|
9
|
+
# our SVG is embedded directly into Metanorma documents, lets diagram
|
|
10
|
+
# source become markup in a rendered document.
|
|
11
|
+
#
|
|
12
|
+
# Two entry points because the rules differ. Text content only has to
|
|
13
|
+
# protect the three characters that can start markup or an entity.
|
|
14
|
+
# Attribute values additionally sit inside quotes, so both quote
|
|
15
|
+
# characters have to go too.
|
|
16
|
+
#
|
|
17
|
+
# Each is a single pass over a character map rather than a chain of
|
|
18
|
+
# replacements: escaping `&` after `<` would turn `<` into `&lt;`,
|
|
19
|
+
# and a one-pass substitution cannot make that mistake regardless of the
|
|
20
|
+
# order the map is written in.
|
|
21
|
+
module Escaping
|
|
22
|
+
TEXT = {
|
|
23
|
+
"&" => "&",
|
|
24
|
+
"<" => "<",
|
|
25
|
+
">" => ">",
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
ATTRIBUTE = TEXT.merge(
|
|
29
|
+
'"' => """,
|
|
30
|
+
"'" => "'",
|
|
31
|
+
).freeze
|
|
32
|
+
|
|
33
|
+
# Derived from the maps, never written out again. A hand-kept pattern
|
|
34
|
+
# drifts: add a character to a map, forget the regex, and that character
|
|
35
|
+
# silently stops being escaped while every test still passes.
|
|
36
|
+
TEXT_PATTERN = Regexp.union(TEXT.keys).freeze
|
|
37
|
+
ATTRIBUTE_PATTERN = Regexp.union(ATTRIBUTE.keys).freeze
|
|
38
|
+
|
|
39
|
+
# XML 1.0 forbids these code points entirely: they have no escape, so a
|
|
40
|
+
# document containing one is unparseable whatever you do to the rest.
|
|
41
|
+
# Tab, newline and carriage return are the only C0 characters allowed.
|
|
42
|
+
# Characters past U+FFFF (emoji among them) are allowed.
|
|
43
|
+
# A sequence label accepts any non-line-ending character
|
|
44
|
+
# (grammars/sequence.rb:241), so a NUL in a diagram reached the output
|
|
45
|
+
# and xmllint refused the SVG.
|
|
46
|
+
FORBIDDEN = /[^\t\n\r\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/
|
|
47
|
+
|
|
48
|
+
module_function
|
|
49
|
+
|
|
50
|
+
# Removes characters XML cannot represent at all.
|
|
51
|
+
#
|
|
52
|
+
# Dropping rather than substituting: there is no legal escape for them,
|
|
53
|
+
# and inventing a replacement character would put content in the document
|
|
54
|
+
# that the author never wrote.
|
|
55
|
+
def strip_forbidden(text)
|
|
56
|
+
text.gsub(FORBIDDEN, "")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Escapes a value destined for element text content.
|
|
60
|
+
#
|
|
61
|
+
# @param value [Object] the value, stringified first
|
|
62
|
+
# @return [String] the escaped text
|
|
63
|
+
def escape_text(value)
|
|
64
|
+
strip_forbidden(value.to_s).gsub(TEXT_PATTERN, TEXT)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Escapes a value destined for a double-quoted attribute.
|
|
68
|
+
#
|
|
69
|
+
# @param value [Object] the value, stringified first
|
|
70
|
+
# @return [String] the escaped value
|
|
71
|
+
def escape_attribute(value)
|
|
72
|
+
strip_forbidden(value.to_s).gsub(ATTRIBUTE_PATTERN, ATTRIBUTE)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# An XML attribute name: a letter or underscore, then name characters.
|
|
76
|
+
# Deliberately narrow — SVG attribute names are ASCII with hyphens and
|
|
77
|
+
# the occasional colon.
|
|
78
|
+
NAME = /\A[A-Za-z_][\w.:-]*\z/
|
|
79
|
+
|
|
80
|
+
# Renders one name/value pair as a leading-space XML attribute.
|
|
81
|
+
#
|
|
82
|
+
# This is the only place an attribute becomes text. Subclasses hand back
|
|
83
|
+
# pairs rather than markup, so there is no second path to keep in sync.
|
|
84
|
+
#
|
|
85
|
+
# The NAME check is not decoration: a pair whose name was
|
|
86
|
+
# `x="safe" onload` produced a valid document with an extra injected
|
|
87
|
+
# attribute, because only the value was ever escaped.
|
|
88
|
+
#
|
|
89
|
+
# @param name [String] the attribute name
|
|
90
|
+
# @param value [Object] the attribute value
|
|
91
|
+
# @return [String] ` name="escaped"`
|
|
92
|
+
# @raise [ArgumentError] if the name is not a valid XML attribute name
|
|
93
|
+
def attribute(name, value)
|
|
94
|
+
return "" if blank?(value)
|
|
95
|
+
|
|
96
|
+
unless name.to_s.match?(NAME)
|
|
97
|
+
raise ArgumentError, "not a valid attribute name: #{name.inspect}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
%( #{name}="#{escape_attribute(value)}")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Renders name/value pairs, skipping any whose value is nil.
|
|
104
|
+
#
|
|
105
|
+
# @param pairs [Array<Array>] name/value pairs
|
|
106
|
+
# @return [String] the concatenated attributes
|
|
107
|
+
# @raise [ArgumentError] if handed anything but a pair
|
|
108
|
+
def attributes(pairs)
|
|
109
|
+
pairs.filter_map { |pair| render(pair) }.join
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @api private
|
|
113
|
+
def render(pair)
|
|
114
|
+
name, value = as_pair(pair)
|
|
115
|
+
|
|
116
|
+
attribute(name, value) unless blank?(value)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# lutaml-model leaves an unset attribute holding an UninitializedClass
|
|
120
|
+
# sentinel rather than nil, and that object returns ITSELF from both
|
|
121
|
+
# to_s and gsub. So it slipped past a nil check and past escaping, and
|
|
122
|
+
# `Text.from_xml("<text>x</text>").to_xml` emitted
|
|
123
|
+
# `fill-opacity="#<Lutaml::Model::UninitializedClass:0x...>"` — whose raw
|
|
124
|
+
# `<` makes the document unparseable.
|
|
125
|
+
#
|
|
126
|
+
# Tested on to_s rather than on the sentinel's class name: any object
|
|
127
|
+
# whose to_s does not return a String cannot be escaped, and matching a
|
|
128
|
+
# class name by string would break the moment lutaml renames it.
|
|
129
|
+
#
|
|
130
|
+
# @api private
|
|
131
|
+
def blank?(value)
|
|
132
|
+
value.nil? || !value.to_s.is_a?(String)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# The pairs contract is what makes the escaping boundary provable, so a
|
|
136
|
+
# subclass still returning rendered markup has to fail loudly. Dropping
|
|
137
|
+
# it silently would lose every attribute on that element.
|
|
138
|
+
#
|
|
139
|
+
# @api private
|
|
140
|
+
def as_pair(pair)
|
|
141
|
+
return pair if pair.is_a?(Array) && pair.size == 2
|
|
142
|
+
|
|
143
|
+
raise ArgumentError,
|
|
144
|
+
"expected a [name, value] pair, got #{pair.inspect}. " \
|
|
145
|
+
"element_attributes returns pairs, not rendered markup."
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Group element <g>
|
|
9
|
+
#
|
|
10
|
+
# Groups multiple SVG elements together for collective transformation
|
|
11
|
+
# and styling. Implements the Composite pattern for hierarchical
|
|
12
|
+
# SVG structure.
|
|
13
|
+
class Group < Element
|
|
14
|
+
attribute :children, Element, collection: true
|
|
15
|
+
# PlantUML marks a class member's visibility icon with it.
|
|
16
|
+
attribute :data_visibility_modifier, :string
|
|
17
|
+
|
|
18
|
+
writes_attributes :data_visibility_modifier
|
|
19
|
+
|
|
20
|
+
def initialize(**args)
|
|
21
|
+
super
|
|
22
|
+
self.children ||= []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Add a child element to this group
|
|
26
|
+
#
|
|
27
|
+
# @param element [Element] SVG element to add
|
|
28
|
+
# @return [void]
|
|
29
|
+
def add_child(element)
|
|
30
|
+
children << element
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
alias << add_child
|
|
34
|
+
|
|
35
|
+
protected
|
|
36
|
+
|
|
37
|
+
# The open tag, each child's entries indented one level, then the close
|
|
38
|
+
# tag.
|
|
39
|
+
#
|
|
40
|
+
# Indents entries rather than lines: a Text holding a newline would
|
|
41
|
+
# otherwise have its own content indented along with the markup.
|
|
42
|
+
#
|
|
43
|
+
# `children` is a plain Array that enforces no type, so a caller can put
|
|
44
|
+
# anything in one; nothing in the gem does. A foreign object is skipped
|
|
45
|
+
# rather than serialized. That narrows the old test — anything answering
|
|
46
|
+
# to `to_xml` used to be written out — because indenting a child by its
|
|
47
|
+
# entries needs the entries, and only an Element has them.
|
|
48
|
+
#
|
|
49
|
+
# @return [Array<String>] structural lines for this group
|
|
50
|
+
def xml_lines
|
|
51
|
+
attrs = build_attributes
|
|
52
|
+
|
|
53
|
+
return ["<g#{attrs}/>"] if children.empty?
|
|
54
|
+
|
|
55
|
+
child_lines = children.flat_map do |child|
|
|
56
|
+
next [] unless child.is_a?(Element)
|
|
57
|
+
|
|
58
|
+
child.xml_lines.map { |line| " #{line}" }
|
|
59
|
+
end
|
|
60
|
+
["<g#{attrs}>", *child_lines, "</g>"]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Line element <line>
|
|
9
|
+
#
|
|
10
|
+
# Represents a straight line between two points.
|
|
11
|
+
class Line < Element
|
|
12
|
+
attribute :x1, :float
|
|
13
|
+
attribute :y1, :float
|
|
14
|
+
attribute :x2, :float
|
|
15
|
+
attribute :y2, :float
|
|
16
|
+
attribute :stroke_dasharray, :string
|
|
17
|
+
|
|
18
|
+
writes_attributes :x1, :y1, :x2, :y2, :stroke_dasharray
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "escaping"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
module Svg
|
|
7
|
+
# Reading and writing the numbers that end up in SVG attributes.
|
|
8
|
+
#
|
|
9
|
+
# `read` copes with more than Float(): lutaml-model leaves an unset
|
|
10
|
+
# attribute holding a sentinel object rather than nil, renderers
|
|
11
|
+
# assign opacities as strings, and a font size may carry a unit
|
|
12
|
+
# (14px). Anything it can't parse comes back nil -- treat that as
|
|
13
|
+
# "not set", never as zero.
|
|
14
|
+
module Numbers
|
|
15
|
+
# A leading SVG number: optional sign, digits with an optional decimal
|
|
16
|
+
# part, optional exponent. Anything after it (a `px` unit, whitespace)
|
|
17
|
+
# is ignored rather than rejected.
|
|
18
|
+
LEADING = /\A\s*[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/
|
|
19
|
+
|
|
20
|
+
# Computed coordinates are floats, so 12.0 * 1.1 lands on
|
|
21
|
+
# 13.200000000000001 rather than 13.2. Four decimals is finer than
|
|
22
|
+
# any diagram needs and short enough to read in a diff.
|
|
23
|
+
PRECISION = 4
|
|
24
|
+
private_constant :LEADING, :PRECISION
|
|
25
|
+
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
# @param value [Object] an attribute value, or lutaml's unset sentinel
|
|
29
|
+
# @return [Float, nil] the number it holds, or nil if it holds none
|
|
30
|
+
def read(value)
|
|
31
|
+
return nil if Escaping.blank?(value)
|
|
32
|
+
return value.to_f if value.is_a?(Numeric)
|
|
33
|
+
|
|
34
|
+
matched = value.to_s[LEADING]
|
|
35
|
+
matched&.to_f
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Finite only, but nothing here enforces it: Float#round(4) returns
|
|
39
|
+
# Infinity and NaN untouched rather than raising, so a non-finite value
|
|
40
|
+
# would be emitted verbatim as `Infinity`, which is not an SVG number.
|
|
41
|
+
# Every caller refuses a non-finite result before it gets here —
|
|
42
|
+
# Text#offset_x, Text#baseline_y, Element#composed_opacity and
|
|
43
|
+
# Arrowhead#triangle each fall back instead — because the fallback is a
|
|
44
|
+
# different value at each site and none of them is "emit nothing".
|
|
45
|
+
#
|
|
46
|
+
# @param value [Float] a computed, finite number
|
|
47
|
+
# @return [String] the attribute value to emit
|
|
48
|
+
def write(value)
|
|
49
|
+
value.round(PRECISION).to_s
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "arrowhead"
|
|
5
|
+
require_relative "element"
|
|
6
|
+
|
|
7
|
+
module Etassia
|
|
8
|
+
module Svg
|
|
9
|
+
# SVG Path element <path>
|
|
10
|
+
#
|
|
11
|
+
# Represents complex shapes and lines using SVG path data syntax.
|
|
12
|
+
# Commonly used for drawing edges in diagrams with curves and bend points.
|
|
13
|
+
class Path < Element
|
|
14
|
+
COMMAND_FORMATTERS = {
|
|
15
|
+
move: ->(command) { "M #{command[:x]} #{command[:y]}" },
|
|
16
|
+
line: ->(command) { "L #{command[:x]} #{command[:y]}" },
|
|
17
|
+
curve: lambda do |command|
|
|
18
|
+
"Q #{command[:cx]} #{command[:cy]} #{command[:x]} #{command[:y]}"
|
|
19
|
+
end,
|
|
20
|
+
bezier: lambda do |command|
|
|
21
|
+
controls = command.values_at(:c1x, :c1y, :c2x, :c2y).join(" ")
|
|
22
|
+
"C #{controls} #{command[:x]} #{command[:y]}"
|
|
23
|
+
end,
|
|
24
|
+
close: ->(_command) { "Z" },
|
|
25
|
+
}.freeze
|
|
26
|
+
private_constant :COMMAND_FORMATTERS
|
|
27
|
+
|
|
28
|
+
attribute :d, :string
|
|
29
|
+
attribute :stroke_dasharray, :string
|
|
30
|
+
attribute :stroke_linecap, :string
|
|
31
|
+
attribute :stroke_linejoin, :string
|
|
32
|
+
attribute :marker_end, :string
|
|
33
|
+
attribute :marker_start, :string
|
|
34
|
+
|
|
35
|
+
# Four renderers set `marker-end`; `marker-start` is settable directly
|
|
36
|
+
# too. Neither is emitted — Svg::Arrowhead draws them instead. See
|
|
37
|
+
# that class for why.
|
|
38
|
+
writes_attributes :d, :stroke_dasharray, :stroke_linecap, :stroke_linejoin
|
|
39
|
+
|
|
40
|
+
# Helper to build path data from move and line commands
|
|
41
|
+
#
|
|
42
|
+
# @param commands [Array<Hash>] Path commands
|
|
43
|
+
# @return [String] Path data string
|
|
44
|
+
def self.build_path_data(commands)
|
|
45
|
+
commands.map { |command| format_command(command) }.join(" ")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.format_command(command)
|
|
49
|
+
COMMAND_FORMATTERS[command[:type]]&.call(command)
|
|
50
|
+
end
|
|
51
|
+
private_class_method :format_command
|
|
52
|
+
|
|
53
|
+
protected
|
|
54
|
+
|
|
55
|
+
# The arrowheads this path asked for, drawn beside it.
|
|
56
|
+
#
|
|
57
|
+
# A head is a sibling shape rather than a child because `<path>` takes
|
|
58
|
+
# no drawable children. Each is a Polygon — a leaf that draws no
|
|
59
|
+
# siblings of its own — so one head is always one entry.
|
|
60
|
+
#
|
|
61
|
+
# @return [Array<String>] one entry of markup per arrowhead
|
|
62
|
+
def sibling_markup
|
|
63
|
+
Arrowhead.for(self).map(&:to_xml)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|