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,224 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
# Separates a Mermaid source's preamble from its diagram body.
|
|
7
|
+
#
|
|
8
|
+
# Mermaid allows three things before the diagram keyword: a YAML
|
|
9
|
+
# frontmatter block, `%%{init: ...}%%` directives, and `%%` comments.
|
|
10
|
+
# Split them together, not with three separate calls — `%%{` is also a
|
|
11
|
+
# valid `%%` comment opener, so the ordering is part of the lexing.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# Source.split("---\ntitle: T\n---\nflowchart LR\n A-->B\n")
|
|
15
|
+
# # => { frontmatter: "title: T\n", directives: [],
|
|
16
|
+
# body: "flowchart LR\n..." }
|
|
17
|
+
class Source
|
|
18
|
+
# Malformed frontmatter is an error, not an absent title. Collapsing
|
|
19
|
+
# the two meant etassia rendered `title: [` and a duplicated title,
|
|
20
|
+
# both of which mermaid refuses.
|
|
21
|
+
class MalformedFrontmatter < StandardError; end
|
|
22
|
+
|
|
23
|
+
# A frontmatter block: `---` alone on a line, YAML, then `---` alone
|
|
24
|
+
# again. The fences must be indented the SAME amount — mermaid accepts
|
|
25
|
+
# a matching indent and rejects a mismatched one, and 44 corpus cases
|
|
26
|
+
# are damaged in exactly that way (opener at column 0, closer indented).
|
|
27
|
+
# At least one line has to sit between the fences: mermaid rejects an
|
|
28
|
+
# empty block.
|
|
29
|
+
FRONTMATTER = /\A([ \t]*)---[ \t]*\n(.+?)^\1---[ \t]*(?:\n|\z)/m
|
|
30
|
+
|
|
31
|
+
# A byte order mark is a byte like any other to mermaid's frontmatter
|
|
32
|
+
# regex, which is why a BOM in front of a fence costs the title. It is
|
|
33
|
+
# not part of the diagram, though, so it comes off before anything is
|
|
34
|
+
# detected.
|
|
35
|
+
BOM = /\A\uFEFF/
|
|
36
|
+
|
|
37
|
+
# A comment line that is not the start of a directive. A bare `%%` is
|
|
38
|
+
# one too: eight diagram types refuse it and fifteen render it, so the
|
|
39
|
+
# split takes it either way and `Engine` asks the type.
|
|
40
|
+
COMMENT = /\A[ \t]*%%(?!\{)[^\n]*(?:\n|\z)/
|
|
41
|
+
|
|
42
|
+
# A `%%` with NOTHING after it on its line — not even a space. mmdc
|
|
43
|
+
# renders `%% ` and `%%\t` in front of a flowchart and refuses a bare
|
|
44
|
+
# `%%`, so the trailing whitespace is what makes it a comment.
|
|
45
|
+
BARE_COMMENT = /\A[ \t]*%%(?:\n|\z)/
|
|
46
|
+
|
|
47
|
+
# Mermaid's own directive scan: `%%{`, a header word with or without a
|
|
48
|
+
# colon, then a value that is either a bare word or everything up to
|
|
49
|
+
# the first `}%%`.
|
|
50
|
+
#
|
|
51
|
+
# Keep the terminator OPTIONAL: `%%{init: {}` alone on a line must
|
|
52
|
+
# still swallow the diagram with it, matching mmdc's refusal.
|
|
53
|
+
#
|
|
54
|
+
# A value starting with a word character ends where that word ends
|
|
55
|
+
# (`%%{init: x` takes "x"); every other shape (`{`, a quote, a bracket,
|
|
56
|
+
# no value) reaches forward for `}%%` and takes the rest of the file
|
|
57
|
+
# when there is none.
|
|
58
|
+
DIRECTIVE = /\A[ \t]*%%\{\s*(?:\w+\s*:|\w+)
|
|
59
|
+
\s*(?:\w+|(?:(?!\}%%).|\n)*)?\s*(?:\}%%)?/x
|
|
60
|
+
|
|
61
|
+
# A `%%{` that scan will not take — no header word — is not a directive
|
|
62
|
+
# to mermaid at all. It falls through to the comment pass, which eats
|
|
63
|
+
# the whole LINE, `}%%` and all. That is the shape, and the shape
|
|
64
|
+
# decides the verdict: `%%{}%%flowchart LR` loses the keyword with the
|
|
65
|
+
# line, `%%{\n}%%` strands a `}%%` in front of the body, and mmdc
|
|
66
|
+
# refuses both for all 23 types. Only a `%%{}%%` sitting alone on its
|
|
67
|
+
# line costs the body nothing, and that one is type-dependent.
|
|
68
|
+
DEGENERATE_DIRECTIVE = /\A[ \t]*%%\{[^\n]*(?:\n|\z)/
|
|
69
|
+
BLANK_LINE = /\A[ \t]*\n/
|
|
70
|
+
|
|
71
|
+
class << self
|
|
72
|
+
# Splits a source into its preamble parts and its body.
|
|
73
|
+
#
|
|
74
|
+
# @param source [String] raw Mermaid source
|
|
75
|
+
# @return [Hash] :frontmatter (String or nil), :directives (Array),
|
|
76
|
+
# :body (String), and :degenerate — the preamble items only some
|
|
77
|
+
# diagram types tolerate
|
|
78
|
+
# Frontmatter is read before the BOM comes off or comments are consumed;
|
|
79
|
+
# a later fence can be removed from the body but does not provide title.
|
|
80
|
+
def split(source)
|
|
81
|
+
scanner = StringScanner.new(normalize(source))
|
|
82
|
+
frontmatter = take_frontmatter(scanner)
|
|
83
|
+
scanner.skip(BOM)
|
|
84
|
+
directives, degenerate = take_preamble(scanner)
|
|
85
|
+
{ frontmatter: frontmatter, directives: directives,
|
|
86
|
+
body: scanner.rest, degenerate: degenerate }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Reads the `title` out of a frontmatter block.
|
|
90
|
+
#
|
|
91
|
+
# @param frontmatter [String, nil] the YAML block, without its fences
|
|
92
|
+
# @return [String, nil] the title mermaid would draw, or nil when it
|
|
93
|
+
# would draw none
|
|
94
|
+
# @raise [MalformedFrontmatter] when mermaid's loader would refuse
|
|
95
|
+
# the document
|
|
96
|
+
#
|
|
97
|
+
# Never add a `strip.empty?` shortcut here: an empty-or-blank block is
|
|
98
|
+
# `Frontmatter`'s own answer to give, and short-circuiting past it
|
|
99
|
+
# makes this disagree with `Frontmatter.new(x).title` on invalid bytes.
|
|
100
|
+
def title(frontmatter)
|
|
101
|
+
return nil if frontmatter.nil?
|
|
102
|
+
|
|
103
|
+
Frontmatter.new(frontmatter).title
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# Decodes to valid UTF-8 first, since every pattern below and in the
|
|
109
|
+
# parsers raises on invalid bytes. Mermaid treats a lone \r as a line
|
|
110
|
+
# ending too, and leaving them in leaks carriage returns into labels
|
|
111
|
+
# and geometry downstream.
|
|
112
|
+
def normalize(source)
|
|
113
|
+
decode(source).gsub(/\r\n?/, "\n")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# mmdc reads its input as UTF-8 and draws U+FFFD for every invalid
|
|
117
|
+
# run, so that is what every type gets: one valid UTF-8 string, before
|
|
118
|
+
# any regexp or grammar sees it. `String#scrub` makes the same runs
|
|
119
|
+
# as node's decoder.
|
|
120
|
+
#
|
|
121
|
+
# A string tagged BINARY or US-ASCII carries no encoding of its own
|
|
122
|
+
# (`File.binread`, `$stdin.read` under `LANG=C`), so its bytes are read
|
|
123
|
+
# as UTF-8, as mmdc reads a file. A string tagged with a real encoding
|
|
124
|
+
# is transcoded instead; an encoding Ruby has no converter for (EUC-TW,
|
|
125
|
+
# for one) falls back to the byte reading.
|
|
126
|
+
def decode(source)
|
|
127
|
+
case source.encoding
|
|
128
|
+
when Encoding::UTF_8
|
|
129
|
+
source.scrub
|
|
130
|
+
when Encoding::BINARY, Encoding::US_ASCII
|
|
131
|
+
source.dup.force_encoding(Encoding::UTF_8).scrub
|
|
132
|
+
else
|
|
133
|
+
transcode(source)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# CESU-8 and the three UTF8-* carrier encodings come out of `encode`
|
|
138
|
+
# tagged UTF-8 with their bytes unchecked, so the result is retagged
|
|
139
|
+
# through its bytes to make `scrub` look at them.
|
|
140
|
+
def transcode(source)
|
|
141
|
+
source.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
|
142
|
+
.b.force_encoding(Encoding::UTF_8).scrub
|
|
143
|
+
rescue Encoding::ConverterNotFoundError
|
|
144
|
+
source.b.force_encoding(Encoding::UTF_8).scrub
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def take_frontmatter(scanner)
|
|
148
|
+
return nil unless scanner.scan(FRONTMATTER)
|
|
149
|
+
|
|
150
|
+
dedent(scanner[2], scanner[1])
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def dedent(yaml, indent)
|
|
154
|
+
return yaml if indent.empty?
|
|
155
|
+
|
|
156
|
+
yaml.gsub(/^#{Regexp.escape(indent)}/, "")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# A fence met here is never frontmatter — it stays in the text for
|
|
160
|
+
# the diagram's own parser, and `Engine` asks the type whether that
|
|
161
|
+
# is fatal. Exception: once a bare `%%` or headerless `%%{...}%%` has
|
|
162
|
+
# been erased, leave the fence in the body — mermaid deletes those
|
|
163
|
+
# lines whole, which would otherwise leave the fence standing at the
|
|
164
|
+
# front of the file where every type refuses it.
|
|
165
|
+
#
|
|
166
|
+
# Walk with a scanner instead of re-slicing the rest per item, which
|
|
167
|
+
# is quadratic over a long run of comments.
|
|
168
|
+
def take_preamble(scanner)
|
|
169
|
+
directives = []
|
|
170
|
+
degenerate = []
|
|
171
|
+
erased = false
|
|
172
|
+
while (state = consume_preamble_item(
|
|
173
|
+
scanner, directives, degenerate, erased
|
|
174
|
+
))
|
|
175
|
+
erased = state.first
|
|
176
|
+
end
|
|
177
|
+
[directives, degenerate.uniq]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def consume_preamble_item(scanner, directives, degenerate, erased)
|
|
181
|
+
return [erased] if scanner.skip(BLANK_LINE)
|
|
182
|
+
return take_directive(scanner, directives, erased) if
|
|
183
|
+
scanner.match?(DIRECTIVE)
|
|
184
|
+
|
|
185
|
+
return take_degenerate_directive(scanner, degenerate) if
|
|
186
|
+
scanner.skip(DEGENERATE_DIRECTIVE)
|
|
187
|
+
return take_comment(scanner, degenerate, erased) if
|
|
188
|
+
scanner.match?(COMMENT)
|
|
189
|
+
|
|
190
|
+
take_late_frontmatter_unless_erased(scanner, degenerate, erased)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def take_late_frontmatter_unless_erased(scanner, degenerate, erased)
|
|
194
|
+
return if erased || !scanner.skip(FRONTMATTER)
|
|
195
|
+
|
|
196
|
+
take_late_frontmatter(scanner, degenerate)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def take_directive(scanner, directives, erased)
|
|
200
|
+
directives << scanner.scan(DIRECTIVE).strip
|
|
201
|
+
[erased]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def take_degenerate_directive(_scanner, degenerate)
|
|
205
|
+
degenerate << :directive
|
|
206
|
+
[true]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def take_comment(scanner, degenerate, erased)
|
|
210
|
+
bare = scanner.match?(BARE_COMMENT)
|
|
211
|
+
degenerate << :comment if bare
|
|
212
|
+
scanner.skip(COMMENT)
|
|
213
|
+
[erased || bare]
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def take_late_frontmatter(_scanner, degenerate)
|
|
217
|
+
degenerate << :frontmatter
|
|
218
|
+
[false]
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
require_relative "source/frontmatter"
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "escaping"
|
|
4
|
+
require_relative "numbers"
|
|
5
|
+
require_relative "path_geometry"
|
|
6
|
+
require_relative "polygon"
|
|
7
|
+
|
|
8
|
+
module Etassia
|
|
9
|
+
module Svg
|
|
10
|
+
# Draws the arrowheads a path asks for.
|
|
11
|
+
#
|
|
12
|
+
# SVG Tiny 1.2 (:metanorma profile) has no way to reference a
|
|
13
|
+
# <marker>, so marker-end="url(#...)" resolves to nothing -- draw
|
|
14
|
+
# the head directly here rather than adding <marker>/<defs> wiring.
|
|
15
|
+
#
|
|
16
|
+
# A head hidden under its node (centre-to-centre edges) is
|
|
17
|
+
# Engine#layout_graph's bug, not this class's.
|
|
18
|
+
class Arrowhead
|
|
19
|
+
# Chosen by eye as stroke-width multiples so the head scales with the
|
|
20
|
+
# line. These are not derived from mermaid-js's marker proportions.
|
|
21
|
+
LENGTH = 4.0
|
|
22
|
+
HALF_WIDTH = 2.0
|
|
23
|
+
|
|
24
|
+
# An unset stroke-width paints a 1-unit line, per SVG.
|
|
25
|
+
DEFAULT_STROKE_WIDTH = 1.0
|
|
26
|
+
|
|
27
|
+
# SVG's own "no marker here", and its initial `stroke`. A path carrying
|
|
28
|
+
# either is asking for nothing to be drawn, which is not the same as
|
|
29
|
+
# not having asked.
|
|
30
|
+
NONE = "none"
|
|
31
|
+
PAINT_ATTRIBUTES = {
|
|
32
|
+
fill_opacity: :stroke_opacity,
|
|
33
|
+
opacity: :opacity,
|
|
34
|
+
transform: :transform,
|
|
35
|
+
}.freeze
|
|
36
|
+
private_constant :LENGTH, :HALF_WIDTH, :DEFAULT_STROKE_WIDTH, :NONE,
|
|
37
|
+
:PAINT_ATTRIBUTES
|
|
38
|
+
|
|
39
|
+
# @param path [Svg::Path] the path to draw arrowheads for
|
|
40
|
+
# @return [Array<Svg::Polygon>] one per marker the path asked for
|
|
41
|
+
def self.for(path)
|
|
42
|
+
new(path).polygons
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize(path)
|
|
46
|
+
@path = path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Reads the path's data at most once, and not at all when no marker was
|
|
50
|
+
# asked for — which is most paths. Nothing is cached on the instance:
|
|
51
|
+
# the path is mutable, so a remembered geometry would answer for a `d`
|
|
52
|
+
# the caller has since replaced.
|
|
53
|
+
#
|
|
54
|
+
# A head the path gave no heading for is dropped rather than returned as
|
|
55
|
+
# nil, so a position in the result names a head only when both were
|
|
56
|
+
# asked for and both could be drawn.
|
|
57
|
+
#
|
|
58
|
+
# @return [Array<Svg::Polygon>] the end-marker head before the
|
|
59
|
+
# start-marker head, with either absent
|
|
60
|
+
def polygons
|
|
61
|
+
heads = requested_heads
|
|
62
|
+
return [] if heads.empty?
|
|
63
|
+
|
|
64
|
+
# An arrowhead is the end of the line, so a line painting nothing
|
|
65
|
+
# ends in nothing. SVG's initial `stroke` is `none`, and inherited
|
|
66
|
+
# paint is not visible from here, so an unstroked path gets no head
|
|
67
|
+
# rather than a black one floating free of it.
|
|
68
|
+
return [] unless painted?
|
|
69
|
+
|
|
70
|
+
geometry = PathGeometry.new(path.d)
|
|
71
|
+
heads.filter_map { |head| triangle(anchor_for(head, geometry)) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
attr_reader :path
|
|
77
|
+
|
|
78
|
+
def requested_heads
|
|
79
|
+
markers = [[:end, path.marker_end], [:start, path.marker_start]]
|
|
80
|
+
markers.filter_map do |head, marker|
|
|
81
|
+
head if names_something?(marker)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def anchor_for(head, geometry)
|
|
86
|
+
return geometry.terminus if head == :end
|
|
87
|
+
|
|
88
|
+
reversed(geometry.origin)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Asked of a marker and of a stroke alike, because `none` is SVG's own
|
|
92
|
+
# "nothing here" for both. Escaping.blank? catches an unset attribute;
|
|
93
|
+
# an attribute set to `''` or to whitespace is set, and still names
|
|
94
|
+
# nothing.
|
|
95
|
+
#
|
|
96
|
+
# @param value [Object] an attribute value
|
|
97
|
+
# @return [Boolean] whether it names something rather than nothing
|
|
98
|
+
def names_something?(value)
|
|
99
|
+
return false if Escaping.blank?(value)
|
|
100
|
+
|
|
101
|
+
named = value.to_s.strip.downcase
|
|
102
|
+
!named.empty? && named != NONE
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# A line paints only if it names a colour AND has a width to paint it
|
|
106
|
+
# with. SVG Tiny 1.2 gives `stroke-width="0"` no stroke at all, so a
|
|
107
|
+
# head there would be the same free-floating triangle an unset stroke
|
|
108
|
+
# would have left.
|
|
109
|
+
#
|
|
110
|
+
# @return [Boolean] whether the path paints a stroke at all
|
|
111
|
+
def painted?
|
|
112
|
+
names_something?(path.stroke) && stroke_width.positive?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Unlike marker orient="auto", which points along the path, Etassia
|
|
116
|
+
# deliberately reverses a start head to form a bidirectional arrow. No
|
|
117
|
+
# renderer sets marker_start, so this deviation is reached only by a
|
|
118
|
+
# caller assigning `path.marker_start=` directly -- Path.from_xml no
|
|
119
|
+
# longer exists to reach it either.
|
|
120
|
+
def reversed(anchor)
|
|
121
|
+
anchor && PathGeometry::Anchor.new(anchor.x, anchor.y,
|
|
122
|
+
-anchor.dx, -anchor.dy)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @param anchor [PathGeometry::Anchor, nil] tip and heading
|
|
126
|
+
# @return [Svg::Polygon, nil] nil when the path gave no heading to
|
|
127
|
+
# point the arrowhead along or a computed corner is non-finite
|
|
128
|
+
def triangle(anchor)
|
|
129
|
+
return nil if anchor.nil?
|
|
130
|
+
|
|
131
|
+
coordinates = corners(anchor)
|
|
132
|
+
return nil unless coordinates.flatten.all?(&:finite?)
|
|
133
|
+
|
|
134
|
+
Polygon.new.tap do |polygon|
|
|
135
|
+
set_points(polygon, coordinates)
|
|
136
|
+
copy_paint(polygon)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def set_points(polygon, coordinates)
|
|
141
|
+
written = coordinates.map do |x, y|
|
|
142
|
+
[Numbers.write(x), Numbers.write(y)]
|
|
143
|
+
end
|
|
144
|
+
polygon.points = Polygon.build_points(written)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# The head is painted where the line's stroke would have been, so it
|
|
148
|
+
# inherits the line's opacity and sits in its coordinate space.
|
|
149
|
+
def copy_paint(polygon)
|
|
150
|
+
polygon.fill = path.stroke
|
|
151
|
+
PAINT_ATTRIBUTES.each do |target, source|
|
|
152
|
+
value = presence(path.public_send(source))
|
|
153
|
+
polygon.public_send("#{target}=", value)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Tip on the path's end, base one arrow-length back along the heading,
|
|
158
|
+
# squared off either side of it.
|
|
159
|
+
def corners(anchor)
|
|
160
|
+
tip = anchor.to_a.first(2)
|
|
161
|
+
base = arrow_base(anchor)
|
|
162
|
+
offset = corner_offset(anchor)
|
|
163
|
+
[tip, subtract(base, offset), add(base, offset)]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def arrow_base(anchor)
|
|
167
|
+
length = LENGTH * stroke_width
|
|
168
|
+
[anchor.x - (anchor.dx * length),
|
|
169
|
+
anchor.y - (anchor.dy * length)]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def corner_offset(anchor)
|
|
173
|
+
half = HALF_WIDTH * stroke_width
|
|
174
|
+
[anchor.dy * half, -anchor.dx * half]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def add(left, right)
|
|
178
|
+
left.zip(right).map(&:sum)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def subtract(left, right)
|
|
182
|
+
left.zip(right).map { |a, b| a - b }
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# nil rather than lutaml's unset sentinel or an empty attribute value,
|
|
186
|
+
# neither of which should be handed to a new polygon.
|
|
187
|
+
def presence(value)
|
|
188
|
+
value unless Escaping.blank?(value) || value.to_s.strip.empty?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Zero remains zero because it suppresses the stroke. Unset,
|
|
192
|
+
# unreadable, non-finite, and negative widths fall back because SVG
|
|
193
|
+
# ignores those error values and uses the inherited or initial width.
|
|
194
|
+
# Non-finite widths are guarded here before multiplication. A finite
|
|
195
|
+
# width can still overflow as the corners are computed, so #triangle
|
|
196
|
+
# rejects that non-finite result instead of writing it into points.
|
|
197
|
+
def stroke_width
|
|
198
|
+
width = Numbers.read(path.stroke_width)
|
|
199
|
+
return DEFAULT_STROKE_WIDTH unless width&.finite? && !width.negative?
|
|
200
|
+
|
|
201
|
+
width
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Circle element <circle>
|
|
9
|
+
#
|
|
10
|
+
# Represents a circle shape with center point and radius.
|
|
11
|
+
class Circle < Element
|
|
12
|
+
attribute :cx, :float
|
|
13
|
+
attribute :cy, :float
|
|
14
|
+
attribute :r, :float
|
|
15
|
+
|
|
16
|
+
writes_attributes :cx, :cy, :r
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Document root element
|
|
9
|
+
#
|
|
10
|
+
# Represents the top-level <svg> element with namespace declarations,
|
|
11
|
+
# viewBox, and dimension attributes. Contains all other SVG elements
|
|
12
|
+
# as children.
|
|
13
|
+
class Document < Lutaml::Model::Serializable
|
|
14
|
+
SVG_NAMESPACE = "http://www.w3.org/2000/svg"
|
|
15
|
+
XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/"
|
|
16
|
+
SVG_VERSION = "1.2"
|
|
17
|
+
SVG_BASE_PROFILE = "tiny"
|
|
18
|
+
|
|
19
|
+
attribute :width, :float
|
|
20
|
+
attribute :height, :float
|
|
21
|
+
attribute :view_box, :string
|
|
22
|
+
attribute :version, :string
|
|
23
|
+
attribute :base_profile, :string
|
|
24
|
+
attribute :xmlns, :string
|
|
25
|
+
attribute :overflow, :string
|
|
26
|
+
attribute :children, Element, collection: true
|
|
27
|
+
|
|
28
|
+
# Initialize document with calculated viewBox if not provided
|
|
29
|
+
#
|
|
30
|
+
# @param width [Numeric] Document width
|
|
31
|
+
# @param height [Numeric] Document height
|
|
32
|
+
# @param view_box [String] ViewBox specification
|
|
33
|
+
# @param overflow [String, nil] SVG `overflow` presentation attribute,
|
|
34
|
+
# e.g. `'hidden'`. Omitted from the output when nil, which is every
|
|
35
|
+
# renderer but flowchart's today — see `Flowchart#render`.
|
|
36
|
+
def initialize(
|
|
37
|
+
width: nil, height: nil, view_box: nil, overflow: nil, **args
|
|
38
|
+
)
|
|
39
|
+
super(**args)
|
|
40
|
+
self.width = width
|
|
41
|
+
self.height = height
|
|
42
|
+
self.view_box = view_box || calculate_view_box(width, height)
|
|
43
|
+
self.version = SVG_VERSION
|
|
44
|
+
self.base_profile = SVG_BASE_PROFILE
|
|
45
|
+
self.xmlns = SVG_NAMESPACE
|
|
46
|
+
self.overflow = overflow
|
|
47
|
+
self.children = []
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Add an element to the document
|
|
51
|
+
#
|
|
52
|
+
# @param element [Element] SVG element to add
|
|
53
|
+
# @return [void]
|
|
54
|
+
def add_element(element)
|
|
55
|
+
children << element
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
alias << add_element
|
|
59
|
+
|
|
60
|
+
# Generate SVG XML string
|
|
61
|
+
#
|
|
62
|
+
# @return [String] XML representation of the SVG document
|
|
63
|
+
def to_xml
|
|
64
|
+
parts = ["<svg"]
|
|
65
|
+
parts.concat(document_xml_attributes)
|
|
66
|
+
parts << ">"
|
|
67
|
+
|
|
68
|
+
append_xml_children(parts)
|
|
69
|
+
|
|
70
|
+
parts << "</svg>"
|
|
71
|
+
parts.join("\n")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# String representation returns XML
|
|
75
|
+
alias to_s to_xml
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def document_xml_attributes
|
|
80
|
+
document_attribute_pairs.each_with_object([]) do |(name, value), pairs|
|
|
81
|
+
pairs << Escaping.attribute(name, value) unless value.nil?
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def document_attribute_pairs
|
|
86
|
+
[
|
|
87
|
+
["width", width], ["height", height], ["viewBox", view_box],
|
|
88
|
+
["version", version], ["baseProfile", base_profile],
|
|
89
|
+
["xmlns", xmlns], ["overflow", overflow]
|
|
90
|
+
]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def append_xml_children(parts)
|
|
94
|
+
children.each do |child|
|
|
95
|
+
parts << child.to_xml if child.respond_to?(:to_xml)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def calculate_view_box(width, height)
|
|
100
|
+
return nil unless width && height
|
|
101
|
+
|
|
102
|
+
"0 0 #{width} #{height}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|