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,501 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "psych"
|
|
4
|
+
require_relative "../js_number"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
class Source
|
|
8
|
+
# Reads a frontmatter block the way mermaid reads it.
|
|
9
|
+
#
|
|
10
|
+
# Both the loader's refusal and JS's stringification matter: the WHOLE
|
|
11
|
+
# document is refused over a repeated key or an unresolvable tag
|
|
12
|
+
# wherever it sits (`x: !!float nope` rejects even a fine title), and
|
|
13
|
+
# `title: 0` draws nothing while `title: [0, false, null]` draws
|
|
14
|
+
# "0,false,".
|
|
15
|
+
#
|
|
16
|
+
# Parse to an AST rather than loading so alias resolution stays under
|
|
17
|
+
# Etassia's control — loading would expand aliases before the depth and
|
|
18
|
+
# work bounds below could reject them.
|
|
19
|
+
class Frontmatter
|
|
20
|
+
# A plain scalar is resolved against these in order before falling
|
|
21
|
+
# back to its own text. `title: True` draws "true" because of the
|
|
22
|
+
# boolean row, and `title: 0x0` draws nothing because of the radix
|
|
23
|
+
# one. Leading zeros stay decimal: mmdc draws `title: 017` as "17".
|
|
24
|
+
NULL = /\A(?:~|null|Null|NULL)?\z/
|
|
25
|
+
TRUE_TEXT = /\A(?:true|True|TRUE)\z/
|
|
26
|
+
FALSE_TEXT = /\A(?:false|False|FALSE)\z/
|
|
27
|
+
NAN = /\A\.(?:nan|NaN|NAN)\z/
|
|
28
|
+
INFINITY = /\A([-+])?\.(?:inf|Inf|INF)\z/
|
|
29
|
+
DECIMAL = /\A[-+]?[0-9][0-9_]*\z/
|
|
30
|
+
|
|
31
|
+
# A radix prefix takes only the digits its base allows, so `0o9` and
|
|
32
|
+
# `0b2` stay text — mmdc draws them as written. So does `0x_`:
|
|
33
|
+
# grouping marks on their own are not a number.
|
|
34
|
+
RADIX = /\A(?<sign>[-+])?0(?:
|
|
35
|
+
x(?<hex>[0-9a-fA-F_]*[0-9a-fA-F][0-9a-fA-F_]*)
|
|
36
|
+
| o(?<octal>[0-7_]*[0-7][0-7_]*)
|
|
37
|
+
| b(?<binary>[01_]*[01][01_]*)
|
|
38
|
+
)\z/x
|
|
39
|
+
|
|
40
|
+
# A sign is allowed only when digits come before the point: mmdc
|
|
41
|
+
# draws `.5` as 0.5 and leaves `+.5` and `-.5` as text.
|
|
42
|
+
FLOAT = /\A(?:[-+]?[0-9][0-9_]*(?:\.[0-9_]*)?|\.[0-9_]+)
|
|
43
|
+
(?:[eE][-+]?[0-9]+)?\z/x
|
|
44
|
+
|
|
45
|
+
RADICES = { hex: 16, octal: 8, binary: 2 }.freeze
|
|
46
|
+
|
|
47
|
+
# The tags the loader knows. Anything else — `!!timestamp`,
|
|
48
|
+
# `!!binary`, `!custom` — is a rejection, and so is a value that
|
|
49
|
+
# will not resolve under the tag it carries.
|
|
50
|
+
TAG = %r{\Atag:yaml\.org,2002:(null|bool|int|float|str|seq|map)\z}
|
|
51
|
+
|
|
52
|
+
# What each scalar tag will hold, once the text has been resolved
|
|
53
|
+
# the ordinary way. `!!float 1` is fine and draws "1"; `!!int 1.5`
|
|
54
|
+
# is not. `!!str` is missing on purpose — it takes any text at all.
|
|
55
|
+
SCALAR_TAGS = {
|
|
56
|
+
"null" => [NilClass],
|
|
57
|
+
"bool" => [TrueClass, FalseClass],
|
|
58
|
+
"int" => [Integer],
|
|
59
|
+
"float" => [Numeric],
|
|
60
|
+
}.freeze
|
|
61
|
+
|
|
62
|
+
# What a mapping stringifies to in JS, whatever it holds. Two
|
|
63
|
+
# different mappings used as keys therefore collide.
|
|
64
|
+
OBJECT = "[object Object]"
|
|
65
|
+
|
|
66
|
+
# A block holding only whitespace sets no title, and mermaid renders
|
|
67
|
+
# the diagram under it. Only space, tab, tab+space, newline and CR
|
|
68
|
+
# render for mmdc; NUL, a vertical tab and a form feed reach the
|
|
69
|
+
# loader and are refused there — this covers exactly the render set.
|
|
70
|
+
# Psych disagrees on tab: it cannot indent in YAML, so
|
|
71
|
+
# `parse_stream("\t")` raises where mermaid's loader returns nothing.
|
|
72
|
+
BLANK = /\A[ \t\r\n]*\z/
|
|
73
|
+
|
|
74
|
+
# Both walks recurse and must stop before the machine stack does — a
|
|
75
|
+
# SystemStackError is not a StandardError, so it escapes every rescue
|
|
76
|
+
# in the pipeline and takes the host down with it. The bound is set
|
|
77
|
+
# for the SMALLEST stack a caller might run on (a Fiber's VM stack is
|
|
78
|
+
# an eighth of a Thread's), not for mermaid's own ~1,400-level limit.
|
|
79
|
+
# A depth bound alone is not enough — a MAPPING level costs more
|
|
80
|
+
# frames than a sequence one, so `title` also catches the overflow
|
|
81
|
+
# directly; this bound only keeps the ORDINARY refusal precise.
|
|
82
|
+
MAX_NESTING = 256
|
|
83
|
+
|
|
84
|
+
# Following an alias recurses twice per link, so the same reach
|
|
85
|
+
# costs twice the frames.
|
|
86
|
+
MAX_WALK = 512
|
|
87
|
+
|
|
88
|
+
# Etassia is embedded in Metanorma, so a few hundred bytes must not buy
|
|
89
|
+
# hundreds of thousands of allocations in its host process. Ten thousand
|
|
90
|
+
# value-walk steps still permits unusually large human-written titles but
|
|
91
|
+
# deliberately refuses some machine-generated titles mmdc renders, such
|
|
92
|
+
# as its 531,441-element, roughly 1 MB alias expansion.
|
|
93
|
+
MAX_VALUES = 10_000
|
|
94
|
+
|
|
95
|
+
# MAX_VALUES bounds how many scalars a document holds, not how long
|
|
96
|
+
# any ONE of them is: a single all-digit scalar costs nothing against
|
|
97
|
+
# that budget but `String#to_i` on a bare-integer literal is
|
|
98
|
+
# superlinear in Ruby (~0.5s at a million digits, worse beyond), and
|
|
99
|
+
# every double is already Infinity or 0 well before 1000 significant
|
|
100
|
+
# digits. Refuse rather than parse past that, the same way the other
|
|
101
|
+
# bounds do.
|
|
102
|
+
MAX_NUMBER_LENGTH = 1_000
|
|
103
|
+
|
|
104
|
+
# @param yaml [String] the frontmatter block, without its fences
|
|
105
|
+
def initialize(yaml)
|
|
106
|
+
@yaml = yaml
|
|
107
|
+
@anchors = {}
|
|
108
|
+
@bindings = {}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# The title mermaid would draw for this block.
|
|
112
|
+
#
|
|
113
|
+
# @return [String, nil] the title, or nil when the block sets none
|
|
114
|
+
# and when mermaid would draw none
|
|
115
|
+
# @raise [MalformedFrontmatter] when the document is malformed or
|
|
116
|
+
# exceeds Etassia's safety bounds
|
|
117
|
+
def title
|
|
118
|
+
load_document
|
|
119
|
+
return nil unless @title_node
|
|
120
|
+
|
|
121
|
+
budget = value_budget
|
|
122
|
+
drawn(value_of(@title_node, budget))
|
|
123
|
+
rescue SystemStackError
|
|
124
|
+
raise MalformedFrontmatter, "Frontmatter is nested too deeply."
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# The optional Mermaid layout engine named at `config.layout`.
|
|
128
|
+
# The complete document is validated by the same bounded walk as
|
|
129
|
+
# {#title}; mappings, aliases and scalar resolution therefore cannot
|
|
130
|
+
# bypass the frontmatter safety contract.
|
|
131
|
+
#
|
|
132
|
+
# @return [String, nil]
|
|
133
|
+
def config_layout
|
|
134
|
+
load_document
|
|
135
|
+
return nil unless @config_node
|
|
136
|
+
|
|
137
|
+
value = mapping_value(@config_node, "layout", value_budget)
|
|
138
|
+
value if value.is_a?(String)
|
|
139
|
+
rescue SystemStackError
|
|
140
|
+
raise MalformedFrontmatter, "Frontmatter is nested too deeply."
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def load_document
|
|
146
|
+
return if @document_loaded
|
|
147
|
+
|
|
148
|
+
@root = parse
|
|
149
|
+
budget = { remaining: MAX_VALUES }
|
|
150
|
+
check(@root, budget) if @root
|
|
151
|
+
@remaining_values = budget.fetch(:remaining)
|
|
152
|
+
@document_loaded = true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def value_budget
|
|
156
|
+
{ remaining: @remaining_values }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# parse_stream rather than parse: `parse` hands back the FIRST
|
|
160
|
+
# document and says nothing about the rest, so `title: T` followed
|
|
161
|
+
# by `...` and a second document read as a plain title here while
|
|
162
|
+
# mmdc exited nonzero.
|
|
163
|
+
def parse
|
|
164
|
+
return nil if blank?
|
|
165
|
+
|
|
166
|
+
stream = Psych.parse_stream(@yaml)
|
|
167
|
+
reject_multiple if stream.children.length > 1
|
|
168
|
+
|
|
169
|
+
stream.children.first&.children&.first
|
|
170
|
+
rescue Psych::Exception, ArgumentError
|
|
171
|
+
raise MalformedFrontmatter, "Malformed frontmatter."
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Bytes that are not valid text are not whitespace, and asking the
|
|
175
|
+
# regex would raise ArgumentError out of a method that documents
|
|
176
|
+
# only MalformedFrontmatter.
|
|
177
|
+
def blank?
|
|
178
|
+
@yaml.valid_encoding? && BLANK.match?(@yaml)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def reject_multiple
|
|
182
|
+
raise MalformedFrontmatter,
|
|
183
|
+
"Frontmatter holds more than one YAML document."
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# The loader walks the document once, in order, and throws at the
|
|
187
|
+
# first thing it cannot make sense of. An anchor registers as it
|
|
188
|
+
# enters the node, which is why `a: &x [*x]` is allowed while an
|
|
189
|
+
# alias that runs ahead of its anchor is not.
|
|
190
|
+
def check(node, budget, depth = 0)
|
|
191
|
+
reject_depth if depth > MAX_NESTING
|
|
192
|
+
return check_alias(node) if node.is_a?(Psych::Nodes::Alias)
|
|
193
|
+
|
|
194
|
+
register_anchor(node)
|
|
195
|
+
check_tag(node)
|
|
196
|
+
return check_mapping(node, budget, depth) if mapping?(node)
|
|
197
|
+
|
|
198
|
+
check_children(node, budget, depth)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def register_anchor(node)
|
|
202
|
+
@anchors[node.anchor] = node if node.anchor
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def mapping?(node)
|
|
206
|
+
node.is_a?(Psych::Nodes::Mapping)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def check_children(node, budget, depth)
|
|
210
|
+
node.children.to_a.each { |child| check(child, budget, depth + 1) }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# An alias binds to the anchor standing where the alias sits, and
|
|
214
|
+
# keeps that binding for good. The loader builds the value right
|
|
215
|
+
# there, so a later `&x` cannot reach back into a list built
|
|
216
|
+
# earlier: mmdc draws "one" for `a: &x one`, `b: &y [*x]`,
|
|
217
|
+
# `c: &x two`, `title: *y`, where resolving `*x` at the end draws
|
|
218
|
+
# "two".
|
|
219
|
+
def check_alias(node)
|
|
220
|
+
@bindings[node] = @anchors.fetch(node.anchor) do
|
|
221
|
+
raise MalformedFrontmatter,
|
|
222
|
+
"Frontmatter refers to an undefined anchor: #{node.anchor}."
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def reject_depth
|
|
227
|
+
raise MalformedFrontmatter, "Frontmatter is nested too deeply."
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Keys collide when they spell the same JS property name. A
|
|
231
|
+
# sequence key and the string that spells it are one key, and any
|
|
232
|
+
# two mapping keys are.
|
|
233
|
+
def check_mapping(mapping, budget, depth)
|
|
234
|
+
seen = {}
|
|
235
|
+
mapping.children.each_slice(2) do |key, value|
|
|
236
|
+
pair = [key, value]
|
|
237
|
+
check_mapping_pair(pair, seen, budget, depth, mapping.equal?(@root))
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def check_mapping_pair(pair, seen, budget, depth, root_mapping)
|
|
242
|
+
key, value = pair
|
|
243
|
+
check(key, budget, depth + 1)
|
|
244
|
+
reject_nested_key if nested_sequence_key?(key)
|
|
245
|
+
name = js_string(value_of(key, budget))
|
|
246
|
+
reject_duplicate(name) if seen.key?(name)
|
|
247
|
+
seen[name] = true
|
|
248
|
+
check(value, budget, depth + 1)
|
|
249
|
+
note_root_value(name, value) if root_mapping
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Only the node is kept. Everything under it was bound as the walk
|
|
253
|
+
# passed it, so the value can be built once the walk is over and
|
|
254
|
+
# still read the anchors that stood where each alias sat.
|
|
255
|
+
def note_root_value(name, value)
|
|
256
|
+
@title_node = value if name == "title"
|
|
257
|
+
@config_node = value if name == "config"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def mapping_value(node, name, budget)
|
|
261
|
+
mapping = resolved(node)
|
|
262
|
+
return unless mapping?(mapping)
|
|
263
|
+
|
|
264
|
+
mapping.children.each_slice(2) do |key, value|
|
|
265
|
+
return value_of(value, budget) if
|
|
266
|
+
js_string(value_of(key, budget)) == name
|
|
267
|
+
end
|
|
268
|
+
nil
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def reject_duplicate(name)
|
|
272
|
+
raise MalformedFrontmatter,
|
|
273
|
+
"Duplicate key in frontmatter: #{name}."
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# A sequence inside a key is the one shape the loader refuses
|
|
277
|
+
# outright — "nested arrays are not supported inside keys". It looks
|
|
278
|
+
# only at the key's own elements, so `? [{a: 1}]` and `? [~]` pass
|
|
279
|
+
# and `? [[a]]` and `? [[]]` do not. The question is about the node,
|
|
280
|
+
# not the value: `a: &x [*x]` then `? [*x]` holds a list that holds
|
|
281
|
+
# itself, and the loader refuses that too.
|
|
282
|
+
def nested_sequence_key?(key)
|
|
283
|
+
node = resolved(key)
|
|
284
|
+
return false unless node.is_a?(Psych::Nodes::Sequence)
|
|
285
|
+
|
|
286
|
+
node.children.any? { |child| resolved(child).is_a?(Psych::Nodes::Sequence) }
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# The node an alias stands for. An anchor never names an alias, so
|
|
290
|
+
# one step is the whole chain.
|
|
291
|
+
def resolved(node)
|
|
292
|
+
node.is_a?(Psych::Nodes::Alias) ? bound(node) : node
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# A key is checked and named while the walk is still inside it, so
|
|
296
|
+
# both the nested-key guard and the key's JS name can follow an
|
|
297
|
+
# anchor out to an alias standing LATER in the document that nothing
|
|
298
|
+
# has bound yet. `&a [ { ? *a : x }, *a ]` does exactly that, and it
|
|
299
|
+
# leaked a KeyError out of both title entry points.
|
|
300
|
+
#
|
|
301
|
+
# The anchor standing right now is the one that alias will bind to,
|
|
302
|
+
# so it answers the question. When no anchor stands at all the alias
|
|
303
|
+
# is undefined, and `check` reaches it moments later and refuses it
|
|
304
|
+
# by name — every alias in the document is walked, so that is not a
|
|
305
|
+
# verdict this can swallow.
|
|
306
|
+
def bound(node)
|
|
307
|
+
@bindings.fetch(node) { @anchors[node.anchor] }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def reject_nested_key
|
|
311
|
+
raise MalformedFrontmatter,
|
|
312
|
+
"Frontmatter nests a sequence inside a key."
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Psych does not validate a decoded tag URI's encoding, so reject an
|
|
316
|
+
# invalid tag by name before applying TAG to it.
|
|
317
|
+
def check_tag(node)
|
|
318
|
+
return if node.tag.nil?
|
|
319
|
+
unless node.tag.valid_encoding?
|
|
320
|
+
raise MalformedFrontmatter, "Frontmatter carries an unknown tag."
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
kind = node.tag[TAG, 1]
|
|
324
|
+
return check_tag_fits(node, kind) if kind
|
|
325
|
+
|
|
326
|
+
raise MalformedFrontmatter,
|
|
327
|
+
"Frontmatter carries an unknown tag: #{node.tag}."
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# A `!!seq` on a mapping is as wrong as a `!custom` anywhere, and a
|
|
331
|
+
# scalar tag has to accept the text it sits on.
|
|
332
|
+
def check_tag_fits(node, kind)
|
|
333
|
+
return if fits?(node, kind)
|
|
334
|
+
|
|
335
|
+
raise MalformedFrontmatter,
|
|
336
|
+
"Frontmatter value does not fit #{node.tag}."
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def fits?(node, kind)
|
|
340
|
+
case node
|
|
341
|
+
when Psych::Nodes::Sequence then kind == "seq"
|
|
342
|
+
when Psych::Nodes::Mapping then kind == "map"
|
|
343
|
+
else scalar_fits?(node, kind)
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# A collection tag on a scalar fits nothing, which is why
|
|
348
|
+
# `title: !!seq x` is refused the same way `!!int nope` is.
|
|
349
|
+
#
|
|
350
|
+
# `!!float` has its own idea of a number and a radix prefix is not
|
|
351
|
+
# in it: the loader takes `!!int 0x10` and refuses `!!float 0x10`,
|
|
352
|
+
# though both resolve to 16 with no tag at all.
|
|
353
|
+
def scalar_fits?(node, kind)
|
|
354
|
+
return true if kind == "str"
|
|
355
|
+
return false if kind == "float" && RADIX.match?(node.value)
|
|
356
|
+
|
|
357
|
+
held = SCALAR_TAGS[kind]
|
|
358
|
+
held&.any? { |type| resolve(node.value).is_a?(type) }
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# The JS value the loader would build. A cycle comes back as null:
|
|
362
|
+
# `a: &x [*x]` builds an array holding itself, and JS prints
|
|
363
|
+
# nothing for the element that loops.
|
|
364
|
+
#
|
|
365
|
+
# `open` holds the sequences this walk is inside, and a sequence
|
|
366
|
+
# joins it as the walk ENTERS it rather than when an alias reaches
|
|
367
|
+
# it. Registering on the alias instead made the bound depend on how
|
|
368
|
+
# the title got to the cycle: `title: &a [x, *a]` drew "x,x," where
|
|
369
|
+
# `a: &a [x, *a]` then `title: *a` drew "x,". Both name the same
|
|
370
|
+
# array, and node prints "x," for it.
|
|
371
|
+
def value_of(node, budget, open = [], depth = 0)
|
|
372
|
+
reject_depth if depth > MAX_WALK
|
|
373
|
+
consume_value(budget)
|
|
374
|
+
|
|
375
|
+
case node
|
|
376
|
+
when Psych::Nodes::Alias
|
|
377
|
+
alias_value(node, budget, open, depth)
|
|
378
|
+
when Psych::Nodes::Scalar then scalar_value(node)
|
|
379
|
+
when Psych::Nodes::Sequence
|
|
380
|
+
sequence_value(node, budget, open, depth)
|
|
381
|
+
else OBJECT
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def alias_value(node, budget, open, depth)
|
|
386
|
+
target = bound(node)
|
|
387
|
+
return nil if target.nil? || open.include?(target)
|
|
388
|
+
|
|
389
|
+
value_of(target, budget, open, depth + 1)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def sequence_value(node, budget, open, depth)
|
|
393
|
+
inside = open + [node]
|
|
394
|
+
node.children.map do |child|
|
|
395
|
+
value_of(child, budget, inside, depth + 1)
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def consume_value(budget)
|
|
400
|
+
reject_expansion unless budget[:remaining].positive?
|
|
401
|
+
|
|
402
|
+
budget[:remaining] -= 1
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def reject_expansion
|
|
406
|
+
raise MalformedFrontmatter, "Frontmatter expands to too many values."
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def scalar_value(node)
|
|
410
|
+
return node.value if node.quoted
|
|
411
|
+
return tagged_value(node) if node.tag
|
|
412
|
+
|
|
413
|
+
resolve(node.value)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# `!!str` takes the text as it stands. Every other tag has already
|
|
417
|
+
# been checked against what it can hold, so the ordinary resolution
|
|
418
|
+
# is the value — `!!float 1` resolves to 1 and draws "1", which is
|
|
419
|
+
# what mmdc draws.
|
|
420
|
+
def tagged_value(node)
|
|
421
|
+
return node.value if node.tag[TAG, 1] == "str"
|
|
422
|
+
|
|
423
|
+
resolve(node.value)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def resolve(text)
|
|
427
|
+
return nil if NULL.match?(text)
|
|
428
|
+
return true if TRUE_TEXT.match?(text)
|
|
429
|
+
return false if FALSE_TEXT.match?(text)
|
|
430
|
+
|
|
431
|
+
# Underscores are grouping marks, and a number cannot end on one.
|
|
432
|
+
# That is the whole difference between `1_0`, which is ten, and
|
|
433
|
+
# `1_`, which mmdc draws as the text "1_".
|
|
434
|
+
return text if text.end_with?("_")
|
|
435
|
+
|
|
436
|
+
number(text) || text
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def number(text)
|
|
440
|
+
return Float::NAN if NAN.match?(text)
|
|
441
|
+
return infinity(text) if INFINITY.match?(text)
|
|
442
|
+
return radix(text) if RADIX.match?(text)
|
|
443
|
+
return decimal(text) if DECIMAL.match?(text)
|
|
444
|
+
return text.delete("_").to_f if FLOAT.match?(text)
|
|
445
|
+
|
|
446
|
+
nil
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def decimal(text)
|
|
450
|
+
reject_number_length if text.length > MAX_NUMBER_LENGTH
|
|
451
|
+
|
|
452
|
+
text.delete("_").to_i
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def reject_number_length
|
|
456
|
+
raise MalformedFrontmatter, "Frontmatter carries too long a number."
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def infinity(text)
|
|
460
|
+
text[INFINITY, 1] == "-" ? -Float::INFINITY : Float::INFINITY
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def radix(text)
|
|
464
|
+
found = text.match(RADIX)
|
|
465
|
+
name, base = RADICES.detect { |key, _| found[key] }
|
|
466
|
+
magnitude = Integer(found[name].delete("_"), base)
|
|
467
|
+
found[:sign] == "-" ? -magnitude : magnitude
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Mermaid draws the title only when the value is truthy AND its
|
|
471
|
+
# string is not empty. `title: 0` fails the first test, `title: []`
|
|
472
|
+
# the second.
|
|
473
|
+
def drawn(value)
|
|
474
|
+
return nil unless truthy?(value)
|
|
475
|
+
|
|
476
|
+
text = js_string(value)
|
|
477
|
+
text.empty? ? nil : text
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def truthy?(value)
|
|
481
|
+
case value
|
|
482
|
+
when nil, false then false
|
|
483
|
+
when Float then !value.zero? && !value.nan?
|
|
484
|
+
when Numeric then !value.zero?
|
|
485
|
+
when String then !value.empty?
|
|
486
|
+
else true
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def js_string(value)
|
|
491
|
+
case value
|
|
492
|
+
when nil then "null"
|
|
493
|
+
when Numeric then Etassia::JsNumber.stringify(value)
|
|
494
|
+
when Array
|
|
495
|
+
value.map { |item| item.nil? ? "" : js_string(item) }.join(",")
|
|
496
|
+
else value.to_s
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
end
|