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,289 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "error/notation_registration_error"
|
|
4
|
+
require_relative "error/pipeline_error"
|
|
5
|
+
require_relative "notation/entry"
|
|
6
|
+
require_relative "notation/parsed"
|
|
7
|
+
require_relative "notation/plugin_failure"
|
|
8
|
+
|
|
9
|
+
module Etassia
|
|
10
|
+
# The registry of diagram notations. A notation is any object answering:
|
|
11
|
+
#
|
|
12
|
+
# - `id`: a lowercase Symbol, `/\A[a-z][a-z0-9_]*\z/`
|
|
13
|
+
# - `extensions`: a frozen Array of lowercase dotted Strings, may be empty
|
|
14
|
+
# - `claims?(source)`: true or false; never raises for any String
|
|
15
|
+
# - `parse(source)`: returns a {Parsed}; an optional `logger:` keyword,
|
|
16
|
+
# declared by that name (`**options` does not count), receives the
|
|
17
|
+
# engine's progress lines under `verbose`
|
|
18
|
+
# - `types`: an Array of Symbols
|
|
19
|
+
#
|
|
20
|
+
# Loading a file that calls {register} is all a consumer does to add one.
|
|
21
|
+
module Notation
|
|
22
|
+
ID_PATTERN = /\A[a-z][a-z0-9_]*\z/
|
|
23
|
+
EXTENSION_PATTERN = /\A\.[a-z0-9_+-]+\z/
|
|
24
|
+
DEFAULT_ID = :mermaid
|
|
25
|
+
# The members `register` checks after `id`, in order, each by the
|
|
26
|
+
# private method named here. `register` has no other plugin access.
|
|
27
|
+
MEMBER_CHECKS = {
|
|
28
|
+
extensions: :validated_extensions,
|
|
29
|
+
claims?: :validated_claims,
|
|
30
|
+
parse: :validated_parse,
|
|
31
|
+
types: :validate_types,
|
|
32
|
+
}.freeze
|
|
33
|
+
private_constant :EXTENSION_PATTERN, :DEFAULT_ID, :MEMBER_CHECKS,
|
|
34
|
+
:Entry
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
# Registers a notation, validating everything before recording
|
|
38
|
+
# anything. `claims?` and `parse` take exactly one positional argument.
|
|
39
|
+
# Register at load time: the registry is not thread-safe.
|
|
40
|
+
#
|
|
41
|
+
# A plugin is trusted code: this refuses honest mistakes, not one that
|
|
42
|
+
# overrides core methods (`method`, `is_a?`) to misreport itself.
|
|
43
|
+
#
|
|
44
|
+
# @param plugin [#id, #extensions, #claims?, #parse, #types]
|
|
45
|
+
# @return [void]
|
|
46
|
+
# @raise [NotationRegistrationError] naming the first broken member,
|
|
47
|
+
# including one whose reader raises
|
|
48
|
+
def register(plugin)
|
|
49
|
+
member = :id
|
|
50
|
+
id = validated_id(plugin)
|
|
51
|
+
checked = MEMBER_CHECKS.to_h do |name, check|
|
|
52
|
+
member = name
|
|
53
|
+
[name, send(check, plugin, id)]
|
|
54
|
+
end
|
|
55
|
+
record(plugin, id, checked[:extensions])
|
|
56
|
+
rescue NotationRegistrationError then raise
|
|
57
|
+
rescue PluginFailure
|
|
58
|
+
raise malformed(member, id)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @param id [Symbol, String]
|
|
62
|
+
# @return [#parse] the registered notation
|
|
63
|
+
# @raise [Engine::PipelineError] when `id` is not a Symbol or String,
|
|
64
|
+
# or names no registered notation
|
|
65
|
+
def fetch(id)
|
|
66
|
+
entry = lookup(id)
|
|
67
|
+
return entry.plugin if entry
|
|
68
|
+
|
|
69
|
+
raise Engine::PipelineError,
|
|
70
|
+
"Unknown notation: #{printable(id)}. " \
|
|
71
|
+
"Valid notations: #{ids.sort.join(', ')}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [Array<Symbol>] registered ids, in registration order
|
|
75
|
+
def ids
|
|
76
|
+
entries.keys
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @return [Array] registered notations, in registration order
|
|
80
|
+
def plugins
|
|
81
|
+
entries.values.map(&:plugin)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @return [Array<String>] every registered extension
|
|
85
|
+
def extensions
|
|
86
|
+
entries.values.flat_map(&:extensions)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @param extension [String] lowercase, dotted
|
|
90
|
+
# @return [Object, nil] the notation that claims it
|
|
91
|
+
def for_extension(extension)
|
|
92
|
+
entries.each_value do |entry|
|
|
93
|
+
return entry.plugin if entry.extensions.include?(extension)
|
|
94
|
+
end
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Picks the notation for one render. The first signal that yields one
|
|
99
|
+
# wins: the explicit id, then the path's extension, then the first
|
|
100
|
+
# notation (in registration order) that claims the source, then Mermaid.
|
|
101
|
+
#
|
|
102
|
+
# @param explicit [Symbol, String, nil]
|
|
103
|
+
# @param path [String, nil]
|
|
104
|
+
# @param source [String]
|
|
105
|
+
# @return [#parse]
|
|
106
|
+
# @raise [Engine::PipelineError] for an invalid or unknown explicit id
|
|
107
|
+
def resolve(explicit:, path:, source:)
|
|
108
|
+
case explicit
|
|
109
|
+
when nil
|
|
110
|
+
for_extension(extension_of(path)) ||
|
|
111
|
+
plugins.find { |plugin| plugin.claims?(source) } ||
|
|
112
|
+
fetch(DEFAULT_ID)
|
|
113
|
+
else
|
|
114
|
+
fetch(explicit)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def entries
|
|
121
|
+
@entries ||= {}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def record(plugin, id, declared)
|
|
125
|
+
entries[id] = Entry.new(plugin, declared)
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def malformed(member, id)
|
|
130
|
+
owner = id ? "Notation #{id}" : "Notation"
|
|
131
|
+
NotationRegistrationError.new("#{owner}: #{member} is malformed")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# A path is a hint, never a reason to fail: one that cannot name a
|
|
135
|
+
# file (NUL byte, invalid or non-ASCII-compatible encoding) has no
|
|
136
|
+
# extension, and the source decides.
|
|
137
|
+
def extension_of(path)
|
|
138
|
+
name = String === path ? String.new(path) : path.to_s
|
|
139
|
+
return "" unless name.encoding.ascii_compatible? && name.valid_encoding?
|
|
140
|
+
return "" if name.include?("\0")
|
|
141
|
+
|
|
142
|
+
File.extname(name).downcase(:ascii)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def takes_no_arguments?(plugin, name)
|
|
146
|
+
parameter_kinds(plugin, name).slice(:req, :keyreq).empty?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Exactly one positional parameter; optional keywords are fine.
|
|
150
|
+
def one_positional?(plugin, name)
|
|
151
|
+
parameter_kinds(plugin, name)
|
|
152
|
+
.slice(:req, :opt, :rest, :keyreq) == { req: 1 }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def parameter_kinds(plugin, name)
|
|
156
|
+
plugin.method(name).parameters.map(&:first).tally
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def printable(id)
|
|
160
|
+
utf8(String === id ? String.new(id) : id.to_s)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def utf8(string)
|
|
164
|
+
string.encode("UTF-8", invalid: :replace, undef: :replace).scrub
|
|
165
|
+
rescue Encoding::ConverterNotFoundError
|
|
166
|
+
string.b.force_encoding(Encoding::UTF_8).scrub
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def lookup(id)
|
|
170
|
+
case id
|
|
171
|
+
when Symbol then entries[id]
|
|
172
|
+
when String then entries[string_id(id)]
|
|
173
|
+
else
|
|
174
|
+
raise Engine::PipelineError,
|
|
175
|
+
"Invalid notation: #{safe_inspect(id)}. " \
|
|
176
|
+
"Notation must be a Symbol or String"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def string_id(id)
|
|
181
|
+
return unless String.instance_method(:valid_encoding?).bind_call(id)
|
|
182
|
+
|
|
183
|
+
String.instance_method(:to_sym).bind_call(id)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def safe_inspect(value)
|
|
187
|
+
utf8(String.new(value.inspect))
|
|
188
|
+
rescue PluginFailure
|
|
189
|
+
"<uninspectable>"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def validated_id(plugin)
|
|
193
|
+
id = member(plugin, :id)
|
|
194
|
+
unless Symbol === id && matches?(id.to_s, ID_PATTERN)
|
|
195
|
+
raise NotationRegistrationError,
|
|
196
|
+
"Notation id must be a lowercase Symbol matching " \
|
|
197
|
+
"#{ID_PATTERN.inspect}, got #{id.inspect}"
|
|
198
|
+
end
|
|
199
|
+
return id unless entries.key?(id)
|
|
200
|
+
|
|
201
|
+
raise NotationRegistrationError, "Notation #{id} is already registered"
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def validated_extensions(plugin, id)
|
|
205
|
+
declared = member(plugin, :extensions, id)
|
|
206
|
+
check_extension_shape!(declared, id)
|
|
207
|
+
snapshot = declared.map { |ext| String.new(ext).freeze }.freeze
|
|
208
|
+
check_extensions_free!(snapshot, id)
|
|
209
|
+
snapshot
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def check_extension_shape!(declared, id)
|
|
213
|
+
return if Array === declared && declared.frozen? &&
|
|
214
|
+
declared.all? { |ext| extension?(ext) }
|
|
215
|
+
|
|
216
|
+
raise NotationRegistrationError,
|
|
217
|
+
"Notation #{id}: extensions must be a frozen Array of " \
|
|
218
|
+
"lowercase dotted Strings, got #{declared.inspect}"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def extension?(ext)
|
|
222
|
+
String === ext && matches?(String.new(ext), EXTENSION_PATTERN)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Matching raises on a broken or non-ASCII-compatible string; both are
|
|
226
|
+
# plain mismatches here.
|
|
227
|
+
def matches?(string, pattern)
|
|
228
|
+
string.encoding.ascii_compatible? && string.valid_encoding? &&
|
|
229
|
+
string.match?(pattern)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def check_extensions_free!(declared, id)
|
|
233
|
+
taken = declared.find do |ext|
|
|
234
|
+
extensions.include?(ext) || declared.count(ext) > 1
|
|
235
|
+
end
|
|
236
|
+
return unless taken
|
|
237
|
+
|
|
238
|
+
raise NotationRegistrationError,
|
|
239
|
+
"Notation #{id}: extension #{taken} is already claimed"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def validated_claims(plugin, id)
|
|
243
|
+
require_one_positional(plugin, :claims?, id)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def validated_parse(plugin, id)
|
|
247
|
+
require_one_positional(plugin, :parse, id)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def validate_types(plugin, id)
|
|
251
|
+
types = member(plugin, :types, id)
|
|
252
|
+
return if Array === types && types.all?(Symbol)
|
|
253
|
+
|
|
254
|
+
raise NotationRegistrationError,
|
|
255
|
+
"Notation #{id}: types must be an Array of Symbols, " \
|
|
256
|
+
"got #{types.inspect}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def member(plugin, name, id = nil)
|
|
260
|
+
owner = id ? "Notation #{id}" : "Notation"
|
|
261
|
+
unless public_member?(plugin, name)
|
|
262
|
+
raise NotationRegistrationError, "#{owner} must respond to #{name}"
|
|
263
|
+
end
|
|
264
|
+
return plugin.public_send(name) if takes_no_arguments?(plugin, name)
|
|
265
|
+
|
|
266
|
+
raise NotationRegistrationError,
|
|
267
|
+
"#{owner}: #{name} must take no arguments"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def require_one_positional(plugin, name, id)
|
|
271
|
+
unless public_member?(plugin, name)
|
|
272
|
+
raise NotationRegistrationError,
|
|
273
|
+
"Notation #{id} must respond to #{name}"
|
|
274
|
+
end
|
|
275
|
+
return if one_positional?(plugin, name)
|
|
276
|
+
|
|
277
|
+
raise NotationRegistrationError,
|
|
278
|
+
"Notation #{id}: #{name} must take one positional argument"
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Object's own respond_to?, so a plugin cannot answer for itself; a
|
|
282
|
+
# BasicObject or a raising respond_to_missing? counts as "no".
|
|
283
|
+
def public_member?(plugin, name)
|
|
284
|
+
Object.instance_method(:respond_to?).bind_call(plugin, name)
|
|
285
|
+
rescue StandardError then false
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "grammars/architecture"
|
|
5
|
+
require_relative "builders/architecture"
|
|
6
|
+
require_relative "native/builders/architecture"
|
|
7
|
+
|
|
8
|
+
module Etassia
|
|
9
|
+
module Parser
|
|
10
|
+
# Parser for architecture diagrams
|
|
11
|
+
class Architecture < Base
|
|
12
|
+
grammar Grammars::Architecture
|
|
13
|
+
builder Builders::Architecture
|
|
14
|
+
native :architecture, builder: Native::Builders::Architecture
|
|
15
|
+
|
|
16
|
+
# Stripped before parsing. The grammar tolerates leading and trailing
|
|
17
|
+
# whitespace, but String#strip also removes , and
|
|
18
|
+
# grammar does not, so dropping it changes which inputs parse. Error
|
|
19
|
+
# positions are therefore relative to the stripped source.
|
|
20
|
+
def parse(input)
|
|
21
|
+
super(input.strip)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parslet"
|
|
4
|
+
require_relative "greedy_run"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Parser
|
|
8
|
+
module Atoms
|
|
9
|
+
# Matches `delimiter` once, then one-or-more repetitions of (a run
|
|
10
|
+
# of `segment_class`, then `delimiter` again) -- e.g. Mermaid's ER
|
|
11
|
+
# `~T~` core, `~(?:[^~<terminator>]*~)+`. JS's `.*` is greedy, so
|
|
12
|
+
# this matches through to the LAST delimiter reachable, not the
|
|
13
|
+
# first. Accumulate segments with `<<`, never `.repeat`/`Slice#+`
|
|
14
|
+
# (O(n^2)); call `GreedyRun.scan` per segment. Every call restarts
|
|
15
|
+
# its doubling probe at the small initial size, so a short segment
|
|
16
|
+
# costs about its own length -- that reset is what keeps the whole
|
|
17
|
+
# match linear.
|
|
18
|
+
class DelimitedRun < Parslet::Atoms::Base
|
|
19
|
+
def initialize(delimiter, segment_class)
|
|
20
|
+
super()
|
|
21
|
+
if delimiter.length != 1
|
|
22
|
+
message = "delimiter must be one character, got "
|
|
23
|
+
message += delimiter.inspect
|
|
24
|
+
raise ArgumentError, message
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@delimiter = delimiter
|
|
28
|
+
@segment_re = GreedyRun.anchored(segment_class)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def try(source, context, _consume_all)
|
|
32
|
+
start = source.bytepos
|
|
33
|
+
anchor = source.consume(0)
|
|
34
|
+
return opening_error(source, context, start) unless opening?(source)
|
|
35
|
+
|
|
36
|
+
buffer, segments = consume_segments(source)
|
|
37
|
+
return segment_error(source, context, start) if segments.zero?
|
|
38
|
+
|
|
39
|
+
succ(Parslet::Slice.new(anchor.position, buffer, anchor.line_cache))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def opening?(source)
|
|
43
|
+
source.consume(1).to_s == @delimiter
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def opening_error(source, context, start)
|
|
47
|
+
source.bytepos = start
|
|
48
|
+
context.err(self, source, "Expected #{@delimiter.inspect}")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def consume_segments(source)
|
|
52
|
+
buffer = +@delimiter
|
|
53
|
+
segments = 0
|
|
54
|
+
while (run = consume_segment(source))
|
|
55
|
+
buffer << run << @delimiter
|
|
56
|
+
segments += 1
|
|
57
|
+
end
|
|
58
|
+
[buffer, segments]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def consume_segment(source)
|
|
62
|
+
before = source.bytepos
|
|
63
|
+
run = GreedyRun.scan(source, @segment_re)
|
|
64
|
+
return run if source.consume(1).to_s == @delimiter
|
|
65
|
+
|
|
66
|
+
source.bytepos = before
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def segment_error(source, context, start)
|
|
71
|
+
source.bytepos = start
|
|
72
|
+
message = "Expected at least one #{@delimiter.inspect}-closed run"
|
|
73
|
+
context.err(self, source, message)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def to_s_inner(_prec)
|
|
77
|
+
"#{@delimiter}(?:#{@segment_re.inspect}#{@delimiter})+"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parslet"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
module Parser
|
|
7
|
+
module Atoms
|
|
8
|
+
# Matches a run of `char_class` (e.g. `[^\]]`) in bounded native
|
|
9
|
+
# regex scans, avoiding Parslet's default `match(char_class).repeat`
|
|
10
|
+
# (applies its atom once per character -- DoS shape on a long run).
|
|
11
|
+
#
|
|
12
|
+
# Consumes CHARACTER-count chunks and matches each with Ruby's own
|
|
13
|
+
# (character-correct) `Regexp`, never `Parslet::Source#matches?`
|
|
14
|
+
# (returns the match length in BYTES; `Source#consume(n)` takes a
|
|
15
|
+
# CHARACTER count - mixing the two over-consumes on a multibyte body,
|
|
16
|
+
# e.g. the text of kanban's `root[café]`).
|
|
17
|
+
class GreedyRun < Parslet::Atoms::Base
|
|
18
|
+
# First chunk size tried; doubles each round up to CHUNK. A short
|
|
19
|
+
# run (the common case) then costs about its own length instead of
|
|
20
|
+
# a fixed CHUNK per call.
|
|
21
|
+
INITIAL_PROBE = 64
|
|
22
|
+
private_constant :INITIAL_PROBE
|
|
23
|
+
|
|
24
|
+
# `Parslet::Source#consume(n)` builds a `/(.|$){n}/` regexp to pull
|
|
25
|
+
# n characters at once, and Ruby's regexp engine refuses a repeat
|
|
26
|
+
# count above 100_000 (`RegexpError: too big number for repeat
|
|
27
|
+
# range`). Chunks stay well under that ceiling.
|
|
28
|
+
CHUNK = 50_000
|
|
29
|
+
private_constant :CHUNK
|
|
30
|
+
|
|
31
|
+
# `min: 1` (default) requires at least one matching character
|
|
32
|
+
# (`char_class+`); `min: 0` allows an empty match (`char_class*`).
|
|
33
|
+
def initialize(char_class, min: 1)
|
|
34
|
+
super()
|
|
35
|
+
@char_class = char_class
|
|
36
|
+
@min = min
|
|
37
|
+
@anchored = self.class.anchored(char_class)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def try(source, context, _consume_all)
|
|
41
|
+
origin = source.consume(0)
|
|
42
|
+
matched = self.class.scan(source, @anchored)
|
|
43
|
+
|
|
44
|
+
message = "Expected at least one matching character"
|
|
45
|
+
empty = @min.positive? && matched.empty?
|
|
46
|
+
return context.err(self, source, message) if empty
|
|
47
|
+
|
|
48
|
+
succ(Parslet::Slice.new(origin.position, matched, origin.line_cache))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The `\A(?:class)*` regexp that `scan` expects, for a Parslet-style
|
|
52
|
+
# character class string such as `[^~\n]`.
|
|
53
|
+
def self.anchored(char_class)
|
|
54
|
+
Regexp.new("\\A(?:#{char_class})*", Regexp::MULTILINE)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Scans `anchored` (an `\A(?:...)* ` regex) against `source` from
|
|
58
|
+
# its current position, joining the parts ONCE at the end (never
|
|
59
|
+
# per chunk -- that would make an attacker-sized body quadratic
|
|
60
|
+
# again). Shared with `DelimitedRun`, which calls this once per
|
|
61
|
+
# delimited segment with its own segment regex.
|
|
62
|
+
def self.scan(source, anchored)
|
|
63
|
+
buffer = +""
|
|
64
|
+
probe = INITIAL_PROBE
|
|
65
|
+
|
|
66
|
+
loop do
|
|
67
|
+
break if source.chars_left.zero?
|
|
68
|
+
|
|
69
|
+
matched, complete = scan_chunk(source, anchored, probe)
|
|
70
|
+
buffer << matched
|
|
71
|
+
break unless complete
|
|
72
|
+
|
|
73
|
+
probe = [probe * 2, CHUNK].min
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
buffer
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# A fixed-UTF-8 regex can reject a binary chunk even when its leading
|
|
80
|
+
# ASCII run matches. Retry against that prefix, then restore any bytes
|
|
81
|
+
# consumed beyond the match.
|
|
82
|
+
def self.scan_chunk(source, anchored, probe)
|
|
83
|
+
size = [source.chars_left, probe].min
|
|
84
|
+
chunk = source.consume(size).to_s
|
|
85
|
+
matched = anchored_match(anchored, chunk)
|
|
86
|
+
excess = chunk.bytesize - matched.bytesize
|
|
87
|
+
source.bytepos -= excess
|
|
88
|
+
[matched, excess.zero?]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.anchored_match(anchored, chunk)
|
|
92
|
+
anchored.match(chunk)[0]
|
|
93
|
+
rescue Encoding::CompatibilityError
|
|
94
|
+
anchored.match(ascii_prefix(chunk))[0]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The bytes of `chunk_str` before its first byte >= 0x80, safe to
|
|
98
|
+
# match against a fixed-UTF-8 `anchored` because every one of them
|
|
99
|
+
# is also valid UTF-8. `chunk_str` always carries an ASCII-compatible
|
|
100
|
+
# encoding here: it comes from a `Parslet::Source`, and
|
|
101
|
+
# `Source#initialize` itself already rejects any encoding that
|
|
102
|
+
# isn't (`LineCache#scan_for_line_endings` matching a `US-ASCII`
|
|
103
|
+
# `/\n/` against it) before this method ever runs.
|
|
104
|
+
def self.ascii_prefix(chunk_str)
|
|
105
|
+
high_byte = chunk_str.each_byte.find_index { |byte| byte >= 0x80 }
|
|
106
|
+
high_byte ? chunk_str.byteslice(0, high_byte) : chunk_str
|
|
107
|
+
end
|
|
108
|
+
private_class_method :ascii_prefix
|
|
109
|
+
|
|
110
|
+
def to_s_inner(_prec)
|
|
111
|
+
@anchored.inspect
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parslet"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
module Parser
|
|
7
|
+
module Atoms
|
|
8
|
+
# Matches `inner` and returns everything it consumed as ONE slice.
|
|
9
|
+
# Parslet joins a repetition of plain slices with `Slice#+`, which
|
|
10
|
+
# copies the whole string built so far on every step: a body of
|
|
11
|
+
# n short lines costs O(n^2). Here the pieces are appended to one
|
|
12
|
+
# buffer instead. `inner` must not capture (`.as`): a named result has
|
|
13
|
+
# no text to join, so it raises rather than return a shorter string.
|
|
14
|
+
class Joined < Parslet::Atoms::Base
|
|
15
|
+
def initialize(inner)
|
|
16
|
+
super()
|
|
17
|
+
@inner = inner
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def try(source, context, consume_all)
|
|
21
|
+
anchor = source.consume(0)
|
|
22
|
+
success, value = @inner.apply(source, context, consume_all)
|
|
23
|
+
return [success, value] unless success
|
|
24
|
+
|
|
25
|
+
buffer = +""
|
|
26
|
+
append(value, buffer)
|
|
27
|
+
succ(Parslet::Slice.new(anchor.position, buffer, anchor.line_cache))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_s_inner(prec)
|
|
31
|
+
@inner.to_s(prec)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def append(value, buffer)
|
|
37
|
+
case value
|
|
38
|
+
when Array then value.each { |piece| append(piece, buffer) }
|
|
39
|
+
when Parslet::Slice, String then buffer << value.to_s
|
|
40
|
+
when Hash
|
|
41
|
+
raise ArgumentError, "cannot join a captured #{value.class}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "greedy_run"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
module Parser
|
|
7
|
+
module Atoms
|
|
8
|
+
# Matches a run of `broad_class` (Kleene star, via `GreedyRun` --
|
|
9
|
+
# exact across chunk boundaries because a pure character-class-star
|
|
10
|
+
# is position-independent), then un-consumes trailing characters
|
|
11
|
+
# matching `trim_class`, giving them back to the source.
|
|
12
|
+
#
|
|
13
|
+
# This reproduces a backreference-free version of Ruby/JS's own
|
|
14
|
+
# backtracking for `\w([-.\/\w]*[-\w])?`: matching the whole greedy
|
|
15
|
+
# run and then trimming trailing non-`trim_class` characters off
|
|
16
|
+
# the end is equivalent to backtracking the greedy run one
|
|
17
|
+
# character at a time until the required trailing char matches.
|
|
18
|
+
class TrimmedRun < Parslet::Atoms::Base
|
|
19
|
+
def initialize(broad_class, trim_class)
|
|
20
|
+
super()
|
|
21
|
+
@run = GreedyRun.new(broad_class, min: 0)
|
|
22
|
+
@trim_re = /(?:#{trim_class})*\z/
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def try(source, context, _consume_all)
|
|
26
|
+
# `@run` is `GreedyRun.new(broad_class, min: 0)` -- a Kleene star
|
|
27
|
+
# matches zero or more, so it can never fail; there is no
|
|
28
|
+
# failure branch to handle here.
|
|
29
|
+
result = @run.apply(source, context, false).last
|
|
30
|
+
kept, trimmed = trim_match(result.to_s)
|
|
31
|
+
source.bytepos -= trimmed.bytesize
|
|
32
|
+
succ(Parslet::Slice.new(result.position, kept, result.line_cache))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def trim_match(matched)
|
|
36
|
+
trimmed = matched[@trim_re]
|
|
37
|
+
kept = matched[0...(matched.length - trimmed.length)]
|
|
38
|
+
[kept, trimmed]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s_inner(_prec)
|
|
42
|
+
"#{@run.inspect}(trim: #{@trim_re.inspect})"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|