sirena 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/.github/workflows/build_deploy.yml +59 -0
- data/.github/workflows/links.yml +85 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +27 -0
- data/.gitignore +68 -0
- data/.rspec +3 -0
- data/.rubocop.yml +14 -0
- data/.rubocop_todo.yml +70 -0
- data/ARCHITECTURE.md +744 -0
- data/Gemfile +12 -0
- data/LICENSE +25 -0
- data/README.adoc +357 -0
- data/Rakefile +11 -0
- data/docs/.gitignore +1 -0
- data/docs/Gemfile +13 -0
- data/docs/_config.yml +182 -0
- data/docs/_diagram_types/architecture-diagram.adoc +314 -0
- data/docs/_diagram_types/block-diagram.adoc +345 -0
- data/docs/_diagram_types/c4-diagram.adoc +559 -0
- data/docs/_diagram_types/class-diagram.adoc +816 -0
- data/docs/_diagram_types/er-diagram.adoc +719 -0
- data/docs/_diagram_types/error-diagram.adoc +114 -0
- data/docs/_diagram_types/examples/flowchart-examples.adoc +29 -0
- data/docs/_diagram_types/flowchart.adoc +488 -0
- data/docs/_diagram_types/gantt-chart.adoc +502 -0
- data/docs/_diagram_types/git-graph.adoc +600 -0
- data/docs/_diagram_types/index.adoc +192 -0
- data/docs/_diagram_types/info-diagram.adoc +103 -0
- data/docs/_diagram_types/kanban-diagram.adoc +262 -0
- data/docs/_diagram_types/mindmap.adoc +603 -0
- data/docs/_diagram_types/packet-diagram.adoc +378 -0
- data/docs/_diagram_types/pie-chart.adoc +335 -0
- data/docs/_diagram_types/quadrant-chart.adoc +406 -0
- data/docs/_diagram_types/radar-chart.adoc +528 -0
- data/docs/_diagram_types/requirement-diagram.adoc +416 -0
- data/docs/_diagram_types/sankey-diagram.adoc +357 -0
- data/docs/_diagram_types/sequence-diagram.adoc +664 -0
- data/docs/_diagram_types/state-diagram.adoc +658 -0
- data/docs/_diagram_types/timeline.adoc +352 -0
- data/docs/_diagram_types/treemap-diagram.adoc +462 -0
- data/docs/_diagram_types/user-journey.adoc +602 -0
- data/docs/_features/index.adoc +129 -0
- data/docs/_guides/cli-reference.adoc +203 -0
- data/docs/_guides/index.adoc +56 -0
- data/docs/_guides/installation.adoc +100 -0
- data/docs/_guides/quick-start.adoc +132 -0
- data/docs/_pages/comparison.adoc +441 -0
- data/docs/_pages/compatibility.adoc +300 -0
- data/docs/_pages/index.adoc +39 -0
- data/docs/_references/index.adoc +103 -0
- data/docs/_tutorials/index.adoc +57 -0
- data/docs/index.adoc +166 -0
- data/docs/lychee.toml +54 -0
- data/examples/.gitignore +10 -0
- data/examples/README.adoc +196 -0
- data/examples/README.md +64 -0
- data/examples/architecture/01-basic-services.mmd +9 -0
- data/examples/architecture/01-basic-services.svg +37 -0
- data/examples/architecture/02-service-groups.mmd +16 -0
- data/examples/architecture/02-service-groups.svg +55 -0
- data/examples/architecture/README.adoc +79 -0
- data/examples/block/01-basic-blocks.mmd +13 -0
- data/examples/block/01-basic-blocks.svg +44 -0
- data/examples/block/02-block-shapes.mmd +13 -0
- data/examples/block/02-block-shapes.svg +47 -0
- data/examples/block/README.adoc +85 -0
- data/examples/c4/01-context-diagram.mmd +10 -0
- data/examples/c4/01-context-diagram.svg +45 -0
- data/examples/c4/02-container-diagram.mmd +24 -0
- data/examples/c4/02-container-diagram.svg +105 -0
- data/examples/c4/README.adoc +92 -0
- data/examples/class_diagram/01-basic-classes.mmd +61 -0
- data/examples/class_diagram/01-basic-classes.svg +117 -0
- data/examples/class_diagram/02-relationships.mmd +61 -0
- data/examples/class_diagram/02-relationships.svg +129 -0
- data/examples/class_diagram/README.adoc +93 -0
- data/examples/er_diagram/01-basic-entities.mmd +64 -0
- data/examples/er_diagram/01-basic-entities.svg +5 -0
- data/examples/er_diagram/02-cardinality.mmd +57 -0
- data/examples/er_diagram/02-cardinality.svg +125 -0
- data/examples/er_diagram/README.adoc +88 -0
- data/examples/error/01-basic-error.mmd +1 -0
- data/examples/error/01-basic-error.svg +13 -0
- data/examples/error/02-error-display.mmd +1 -0
- data/examples/error/02-error-display.svg +13 -0
- data/examples/error/README.adoc +71 -0
- data/examples/error_message_example.svg +13 -0
- data/examples/flowchart/00-original.mmd +13 -0
- data/examples/flowchart/00-original.svg +5 -0
- data/examples/flowchart/01-basic-flow.mmd +7 -0
- data/examples/flowchart/01-basic-flow.svg +52 -0
- data/examples/flowchart/01-basic-flow.yml +13 -0
- data/examples/flowchart/02*.svg +87 -0
- data/examples/flowchart/02-node-shapes.mmd +9 -0
- data/examples/flowchart/02-node-shapes.svg +33 -0
- data/examples/flowchart/03-edge-types.mmd +7 -0
- data/examples/flowchart/03-edge-types.svg +53 -0
- data/examples/flowchart/04-subgraphs.mmd +9 -0
- data/examples/flowchart/04-subgraphs.svg +33 -0
- data/examples/flowchart/05-styling.mmd +9 -0
- data/examples/flowchart/05-styling.svg +33 -0
- data/examples/flowchart/06-complex-flow.mmd +8 -0
- data/examples/flowchart/06-complex-flow.svg +59 -0
- data/examples/flowchart/README.adoc +167 -0
- data/examples/gantt/01-simple-timeline.* +14 -0
- data/examples/gantt/01-simple-timeline.mmd +6 -0
- data/examples/gantt/01-simple-timeline.svg +26 -0
- data/examples/gantt/02-task-dependencies.mmd +6 -0
- data/examples/gantt/02-task-dependencies.svg +26 -0
- data/examples/gantt/README.adoc +86 -0
- data/examples/git_graph/01-linear-history.mmd +12 -0
- data/examples/git_graph/01-linear-history.svg +26 -0
- data/examples/git_graph/02-branching.mmd +12 -0
- data/examples/git_graph/02-branching.svg +26 -0
- data/examples/git_graph/README.adoc +73 -0
- data/examples/info/02-showinfo.mmd +1 -0
- data/examples/info/02-showinfo.svg +10 -0
- data/examples/info/README.adoc +58 -0
- data/examples/info_showinfo_example.svg +10 -0
- data/examples/kanban/01-simple-board.mmd +8 -0
- data/examples/kanban/01-simple-board.svg +43 -0
- data/examples/kanban/02-workflow.mmd +8 -0
- data/examples/kanban/02-workflow.svg +43 -0
- data/examples/kanban/README.adoc +79 -0
- data/examples/mindmap/01-simple-tree.mmd +19 -0
- data/examples/mindmap/01-simple-tree.svg +61 -0
- data/examples/mindmap/02-knowledge-map.mmd +19 -0
- data/examples/mindmap/02-knowledge-map.svg +61 -0
- data/examples/mindmap/README.adoc +77 -0
- data/examples/packet/01-basic-packet.* +17 -0
- data/examples/packet/01-basic-packet.mmd +4 -0
- data/examples/packet/01-basic-packet.svg +82 -0
- data/examples/packet/README.adoc +58 -0
- data/examples/pie/01-simple-chart.mmd +5 -0
- data/examples/pie/01-simple-chart.svg +17 -0
- data/examples/pie/02-labeled-slices.mmd +6 -0
- data/examples/pie/02-labeled-slices.svg +19 -0
- data/examples/pie/README.adoc +75 -0
- data/examples/quadrant/01-basic-quadrant.mmd +13 -0
- data/examples/quadrant/01-basic-quadrant.svg +33 -0
- data/examples/quadrant/02-positioned-items.mmd +14 -0
- data/examples/quadrant/02-positioned-items.svg +35 -0
- data/examples/quadrant/README.adoc +84 -0
- data/examples/radar/01-simple-radar.* +5 -0
- data/examples/radar/01-simple-radar.mmd +3 -0
- data/examples/radar/01-simple-radar.svg +25 -0
- data/examples/radar/02-multiple-curves.mmd +4 -0
- data/examples/radar/02-multiple-curves.svg +43 -0
- data/examples/radar/README.adoc +75 -0
- data/examples/requirement/01-basic-requirements.mmd +23 -0
- data/examples/requirement/01-basic-requirements.svg +49 -0
- data/examples/requirement/02-risk-levels.mmd +23 -0
- data/examples/requirement/02-risk-levels.svg +49 -0
- data/examples/requirement/README.adoc +85 -0
- data/examples/sankey/01-simple-flow.mmd +7 -0
- data/examples/sankey/01-simple-flow.svg +34 -0
- data/examples/sankey/02-multi-stage.mmd +11 -0
- data/examples/sankey/02-multi-stage.svg +44 -0
- data/examples/sankey/README.adoc +74 -0
- data/examples/sequence/01-basic-sequence.mmd +27 -0
- data/examples/sequence/01-basic-sequence.svg +5 -0
- data/examples/sequence/02-activations.mmd +17 -0
- data/examples/sequence/02-activations.svg +78 -0
- data/examples/sequence/README.adoc +86 -0
- data/examples/state_diagram/01-simple-states.mmd +29 -0
- data/examples/state_diagram/01-simple-states.svg +5 -0
- data/examples/state_diagram/02-composite.mmd +19 -0
- data/examples/state_diagram/02-composite.svg +81 -0
- data/examples/state_diagram/README.adoc +90 -0
- data/examples/timeline/01-simple-timeline.mmd +11 -0
- data/examples/timeline/01-simple-timeline.svg +36 -0
- data/examples/timeline/02-periods.mmd +15 -0
- data/examples/timeline/02-periods.svg +47 -0
- data/examples/timeline/README.adoc +78 -0
- data/examples/treemap/01-basic-treemap.mmd +12 -0
- data/examples/treemap/01-basic-treemap.svg +59 -0
- data/examples/treemap/README.adoc +59 -0
- data/examples/user_journey/01-simple-journey.mmd +23 -0
- data/examples/user_journey/01-simple-journey.svg +5 -0
- data/examples/user_journey/02-multi-actor.mmd +18 -0
- data/examples/user_journey/02-multi-actor.svg +129 -0
- data/examples/user_journey/README.adoc +81 -0
- data/examples/xychart/01-line-chart.mmd +5 -0
- data/examples/xychart/01-line-chart.svg +43 -0
- data/examples/xychart/02-bar-chart.mmd +7 -0
- data/examples/xychart/02-bar-chart.svg +48 -0
- data/examples/xychart/README.adoc +80 -0
- data/exe/sirena +7 -0
- data/lib/sirena/cli.rb +138 -0
- data/lib/sirena/commands/batch.rb +117 -0
- data/lib/sirena/commands/render.rb +80 -0
- data/lib/sirena/commands/types.rb +29 -0
- data/lib/sirena/commands/version.rb +24 -0
- data/lib/sirena/diagram/architecture.rb +46 -0
- data/lib/sirena/diagram/base.rb +61 -0
- data/lib/sirena/diagram/block.rb +81 -0
- data/lib/sirena/diagram/c4.rb +328 -0
- data/lib/sirena/diagram/class_diagram.rb +385 -0
- data/lib/sirena/diagram/er_diagram.rb +238 -0
- data/lib/sirena/diagram/error.rb +38 -0
- data/lib/sirena/diagram/flowchart.rb +160 -0
- data/lib/sirena/diagram/gantt.rb +71 -0
- data/lib/sirena/diagram/git_graph.rb +36 -0
- data/lib/sirena/diagram/info.rb +38 -0
- data/lib/sirena/diagram/kanban.rb +178 -0
- data/lib/sirena/diagram/mindmap.rb +54 -0
- data/lib/sirena/diagram/packet.rb +79 -0
- data/lib/sirena/diagram/pie.rb +115 -0
- data/lib/sirena/diagram/quadrant.rb +138 -0
- data/lib/sirena/diagram/radar.rb +52 -0
- data/lib/sirena/diagram/requirement.rb +133 -0
- data/lib/sirena/diagram/sankey.rb +217 -0
- data/lib/sirena/diagram/sequence.rb +242 -0
- data/lib/sirena/diagram/state_diagram.rb +237 -0
- data/lib/sirena/diagram/timeline.rb +171 -0
- data/lib/sirena/diagram/treemap.rb +84 -0
- data/lib/sirena/diagram/user_journey.rb +149 -0
- data/lib/sirena/diagram/xy_chart.rb +76 -0
- data/lib/sirena/diagram.rb +8 -0
- data/lib/sirena/diagram_registry.rb +101 -0
- data/lib/sirena/engine.rb +292 -0
- data/lib/sirena/parser/architecture.rb +41 -0
- data/lib/sirena/parser/base.rb +41 -0
- data/lib/sirena/parser/block.rb +72 -0
- data/lib/sirena/parser/c4.rb +53 -0
- data/lib/sirena/parser/class_diagram.rb +63 -0
- data/lib/sirena/parser/er_diagram.rb +40 -0
- data/lib/sirena/parser/error.rb +49 -0
- data/lib/sirena/parser/flowchart.rb +71 -0
- data/lib/sirena/parser/gantt.rb +60 -0
- data/lib/sirena/parser/git_graph.rb +95 -0
- data/lib/sirena/parser/grammars/architecture.rb +145 -0
- data/lib/sirena/parser/grammars/block.rb +190 -0
- data/lib/sirena/parser/grammars/c4.rb +226 -0
- data/lib/sirena/parser/grammars/class_diagram.rb +284 -0
- data/lib/sirena/parser/grammars/common.rb +84 -0
- data/lib/sirena/parser/grammars/er_diagram.rb +114 -0
- data/lib/sirena/parser/grammars/error.rb +40 -0
- data/lib/sirena/parser/grammars/flowchart.rb +298 -0
- data/lib/sirena/parser/grammars/gantt.rb +252 -0
- data/lib/sirena/parser/grammars/git_graph.rb +167 -0
- data/lib/sirena/parser/grammars/info.rb +58 -0
- data/lib/sirena/parser/grammars/kanban.rb +83 -0
- data/lib/sirena/parser/grammars/mindmap.rb +115 -0
- data/lib/sirena/parser/grammars/packet.rb +73 -0
- data/lib/sirena/parser/grammars/pie.rb +128 -0
- data/lib/sirena/parser/grammars/quadrant.rb +199 -0
- data/lib/sirena/parser/grammars/radar.rb +150 -0
- data/lib/sirena/parser/grammars/requirement.rb +188 -0
- data/lib/sirena/parser/grammars/sankey.rb +104 -0
- data/lib/sirena/parser/grammars/sequence.rb +247 -0
- data/lib/sirena/parser/grammars/state_diagram.rb +172 -0
- data/lib/sirena/parser/grammars/timeline.rb +142 -0
- data/lib/sirena/parser/grammars/treemap.rb +120 -0
- data/lib/sirena/parser/grammars/xy_chart.rb +120 -0
- data/lib/sirena/parser/info.rb +49 -0
- data/lib/sirena/parser/kanban.rb +97 -0
- data/lib/sirena/parser/mindmap.rb +106 -0
- data/lib/sirena/parser/packet.rb +76 -0
- data/lib/sirena/parser/pie.rb +49 -0
- data/lib/sirena/parser/quadrant.rb +57 -0
- data/lib/sirena/parser/radar.rb +104 -0
- data/lib/sirena/parser/requirement.rb +70 -0
- data/lib/sirena/parser/sankey.rb +64 -0
- data/lib/sirena/parser/sequence.rb +51 -0
- data/lib/sirena/parser/state_diagram.rb +69 -0
- data/lib/sirena/parser/timeline.rb +57 -0
- data/lib/sirena/parser/transforms/architecture.rb +97 -0
- data/lib/sirena/parser/transforms/block.rb +254 -0
- data/lib/sirena/parser/transforms/c4.rb +347 -0
- data/lib/sirena/parser/transforms/class_diagram.rb +352 -0
- data/lib/sirena/parser/transforms/er_diagram.rb +169 -0
- data/lib/sirena/parser/transforms/error.rb +58 -0
- data/lib/sirena/parser/transforms/flowchart.rb +293 -0
- data/lib/sirena/parser/transforms/gantt.rb +215 -0
- data/lib/sirena/parser/transforms/git_graph.rb +160 -0
- data/lib/sirena/parser/transforms/info.rb +58 -0
- data/lib/sirena/parser/transforms/kanban.rb +176 -0
- data/lib/sirena/parser/transforms/mindmap.rb +227 -0
- data/lib/sirena/parser/transforms/packet.rb +63 -0
- data/lib/sirena/parser/transforms/pie.rb +143 -0
- data/lib/sirena/parser/transforms/quadrant.rb +177 -0
- data/lib/sirena/parser/transforms/radar.rb +126 -0
- data/lib/sirena/parser/transforms/requirement.rb +272 -0
- data/lib/sirena/parser/transforms/sankey.rb +122 -0
- data/lib/sirena/parser/transforms/sequence.rb +342 -0
- data/lib/sirena/parser/transforms/state_diagram.rb +292 -0
- data/lib/sirena/parser/transforms/timeline.rb +177 -0
- data/lib/sirena/parser/transforms/treemap.rb +81 -0
- data/lib/sirena/parser/transforms/xy_chart.rb +132 -0
- data/lib/sirena/parser/treemap.rb +98 -0
- data/lib/sirena/parser/user_journey.rb +120 -0
- data/lib/sirena/parser/xy_chart.rb +114 -0
- data/lib/sirena/parser.rb +8 -0
- data/lib/sirena/renderer/architecture.rb +251 -0
- data/lib/sirena/renderer/base.rb +251 -0
- data/lib/sirena/renderer/block.rb +286 -0
- data/lib/sirena/renderer/c4.rb +490 -0
- data/lib/sirena/renderer/class_diagram.rb +499 -0
- data/lib/sirena/renderer/er_diagram.rb +417 -0
- data/lib/sirena/renderer/error.rb +131 -0
- data/lib/sirena/renderer/flowchart.rb +301 -0
- data/lib/sirena/renderer/gantt.rb +331 -0
- data/lib/sirena/renderer/git_graph.rb +368 -0
- data/lib/sirena/renderer/info.rb +93 -0
- data/lib/sirena/renderer/kanban.rb +295 -0
- data/lib/sirena/renderer/mindmap.rb +396 -0
- data/lib/sirena/renderer/packet.rb +239 -0
- data/lib/sirena/renderer/pie.rb +235 -0
- data/lib/sirena/renderer/quadrant.rb +292 -0
- data/lib/sirena/renderer/radar.rb +323 -0
- data/lib/sirena/renderer/requirement.rb +371 -0
- data/lib/sirena/renderer/sankey.rb +255 -0
- data/lib/sirena/renderer/sequence.rb +424 -0
- data/lib/sirena/renderer/state_diagram.rb +328 -0
- data/lib/sirena/renderer/timeline.rb +304 -0
- data/lib/sirena/renderer/treemap.rb +152 -0
- data/lib/sirena/renderer/user_journey.rb +331 -0
- data/lib/sirena/renderer/xy_chart.rb +452 -0
- data/lib/sirena/renderer.rb +8 -0
- data/lib/sirena/svg/circle.rb +41 -0
- data/lib/sirena/svg/document.rb +103 -0
- data/lib/sirena/svg/element.rb +65 -0
- data/lib/sirena/svg/ellipse.rb +33 -0
- data/lib/sirena/svg/group.rb +71 -0
- data/lib/sirena/svg/line.rb +49 -0
- data/lib/sirena/svg/path.rb +76 -0
- data/lib/sirena/svg/polygon.rb +43 -0
- data/lib/sirena/svg/polyline.rb +35 -0
- data/lib/sirena/svg/rect.rb +57 -0
- data/lib/sirena/svg/style.rb +44 -0
- data/lib/sirena/svg/text.rb +72 -0
- data/lib/sirena/svg.rb +19 -0
- data/lib/sirena/text_measurement.rb +71 -0
- data/lib/sirena/theme/builtin/dark.yml +70 -0
- data/lib/sirena/theme/builtin/default.yml +80 -0
- data/lib/sirena/theme/builtin/high_contrast.yml +70 -0
- data/lib/sirena/theme/builtin/light.yml +70 -0
- data/lib/sirena/theme/color_palette.rb +48 -0
- data/lib/sirena/theme/effect_styles.rb +28 -0
- data/lib/sirena/theme/registry.rb +41 -0
- data/lib/sirena/theme/shape_styles.rb +28 -0
- data/lib/sirena/theme/spacing_config.rb +24 -0
- data/lib/sirena/theme/typography.rb +30 -0
- data/lib/sirena/theme.rb +69 -0
- data/lib/sirena/transform/architecture.rb +273 -0
- data/lib/sirena/transform/base.rb +199 -0
- data/lib/sirena/transform/block.rb +215 -0
- data/lib/sirena/transform/c4.rb +288 -0
- data/lib/sirena/transform/class_diagram.rb +296 -0
- data/lib/sirena/transform/er_diagram.rb +204 -0
- data/lib/sirena/transform/error.rb +39 -0
- data/lib/sirena/transform/flowchart.rb +161 -0
- data/lib/sirena/transform/gantt.rb +253 -0
- data/lib/sirena/transform/git_graph.rb +283 -0
- data/lib/sirena/transform/info.rb +39 -0
- data/lib/sirena/transform/kanban.rb +180 -0
- data/lib/sirena/transform/mindmap.rb +251 -0
- data/lib/sirena/transform/packet.rb +185 -0
- data/lib/sirena/transform/pie.rb +62 -0
- data/lib/sirena/transform/quadrant.rb +167 -0
- data/lib/sirena/transform/radar.rb +227 -0
- data/lib/sirena/transform/requirement.rb +233 -0
- data/lib/sirena/transform/sankey.rb +212 -0
- data/lib/sirena/transform/sequence.rb +143 -0
- data/lib/sirena/transform/state_diagram.rb +228 -0
- data/lib/sirena/transform/timeline.rb +139 -0
- data/lib/sirena/transform/treemap.rb +120 -0
- data/lib/sirena/transform/user_journey.rb +207 -0
- data/lib/sirena/transform/xy_chart.rb +273 -0
- data/lib/sirena/transform.rb +8 -0
- data/lib/sirena/version.rb +5 -0
- data/lib/sirena.rb +328 -0
- data/lib/tasks/benchmark.rake +532 -0
- data/lib/tasks/examples.rake +468 -0
- data/lib/tasks/generate_mermaid_fixtures.rake +363 -0
- data/lib/tasks/mermaid_fixtures.rake +46 -0
- data/scripts/extract_mermaid_tests.rb +493 -0
- data/scripts/rename_to_sirena.rb +73 -0
- data/sirena.gemspec +47 -0
- metadata +529 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "grammars/architecture"
|
|
5
|
+
require_relative "transforms/architecture"
|
|
6
|
+
|
|
7
|
+
module Sirena
|
|
8
|
+
module Parser
|
|
9
|
+
# Parser for architecture diagrams
|
|
10
|
+
class Architecture < Base
|
|
11
|
+
def parse(input)
|
|
12
|
+
input = input.strip
|
|
13
|
+
|
|
14
|
+
grammar = Grammars::Architecture.new
|
|
15
|
+
tree = grammar.parse(input)
|
|
16
|
+
|
|
17
|
+
transform = Transforms::Architecture.new
|
|
18
|
+
transform.apply(tree)
|
|
19
|
+
rescue Parslet::ParseFailed => e
|
|
20
|
+
raise ParseError, format_error(e, input)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def format_error(error, input)
|
|
26
|
+
lines = input.split("\n")
|
|
27
|
+
line_no = error.parse_failure_cause.source.line_and_column[0]
|
|
28
|
+
column = error.parse_failure_cause.source.line_and_column[1]
|
|
29
|
+
|
|
30
|
+
context = []
|
|
31
|
+
context << lines[line_no - 2] if line_no > 1
|
|
32
|
+
context << lines[line_no - 1] if line_no > 0
|
|
33
|
+
context << " " * (column - 1) + "^"
|
|
34
|
+
|
|
35
|
+
"Parse error at line #{line_no}, column #{column}:\n" \
|
|
36
|
+
"#{context.join("\n")}\n" \
|
|
37
|
+
"#{error.parse_failure_cause.message}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sirena
|
|
4
|
+
module Parser
|
|
5
|
+
# Abstract base class for diagram parsers.
|
|
6
|
+
#
|
|
7
|
+
# This class defines the interface that all diagram-specific parsers
|
|
8
|
+
# must implement. Parsers are responsible for converting source code
|
|
9
|
+
# into a typed diagram model using Parslet grammars.
|
|
10
|
+
#
|
|
11
|
+
# @example Define a custom parser
|
|
12
|
+
# class FlowchartParser < Parser::Base
|
|
13
|
+
# def parse(source)
|
|
14
|
+
# grammar = Grammars::Flowchart.new
|
|
15
|
+
# tree = grammar.parse(source)
|
|
16
|
+
# transform = Transforms::Flowchart.new
|
|
17
|
+
# transform.apply(tree)
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# @abstract Subclass and implement #parse
|
|
22
|
+
class Base
|
|
23
|
+
|
|
24
|
+
# Parses Mermaid source code into a diagram model.
|
|
25
|
+
#
|
|
26
|
+
# This method should be overridden by subclasses to implement
|
|
27
|
+
# diagram-specific parsing logic using Parslet grammars.
|
|
28
|
+
#
|
|
29
|
+
# @param source [String] the Mermaid source code to parse
|
|
30
|
+
# @return [Diagram::Base] the parsed diagram model
|
|
31
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
32
|
+
def parse(source)
|
|
33
|
+
raise NotImplementedError,
|
|
34
|
+
"#{self.class} must implement #parse(source)"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Error raised during parsing.
|
|
39
|
+
class ParseError < StandardError; end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'grammars/block'
|
|
5
|
+
require_relative 'transforms/block'
|
|
6
|
+
require_relative '../diagram/block'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Block diagram parser for Mermaid block diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Parses block diagrams with support for:
|
|
13
|
+
# - Column-based layouts
|
|
14
|
+
# - Blocks with various shapes (rectangle, circle)
|
|
15
|
+
# - Block width specifications
|
|
16
|
+
# - Compound/nested blocks
|
|
17
|
+
# - Space placeholders
|
|
18
|
+
# - Arrow blocks with directions
|
|
19
|
+
# - Connections between blocks
|
|
20
|
+
# - Styling directives
|
|
21
|
+
#
|
|
22
|
+
# @example Parse a simple block diagram
|
|
23
|
+
# parser = BlockParser.new
|
|
24
|
+
# diagram = parser.parse("block-beta\n columns 2\n A\n B")
|
|
25
|
+
class BlockParser < Base
|
|
26
|
+
# Parses block diagram source into a BlockDiagram model.
|
|
27
|
+
#
|
|
28
|
+
# @param source [String] the Mermaid block diagram source
|
|
29
|
+
# @return [Diagram::BlockDiagram] the parsed block diagram
|
|
30
|
+
# @raise [ParseError] if syntax is invalid
|
|
31
|
+
def parse(source)
|
|
32
|
+
grammar = Grammars::Block.new
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
tree = grammar.parse(source)
|
|
36
|
+
diagram = Transforms::Block.apply(tree)
|
|
37
|
+
diagram
|
|
38
|
+
rescue Parslet::ParseFailed => e
|
|
39
|
+
raise ParseError, format_parse_error(e, source)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# Formats a Parslet parse error with context.
|
|
46
|
+
#
|
|
47
|
+
# @param error [Parslet::ParseFailed] the parse error
|
|
48
|
+
# @param source [String] the source that failed to parse
|
|
49
|
+
# @return [String] formatted error message
|
|
50
|
+
def format_parse_error(error, source)
|
|
51
|
+
lines = source.lines
|
|
52
|
+
line_num = error.parse_failure_cause.source.line_and_column[0]
|
|
53
|
+
col_num = error.parse_failure_cause.source.line_and_column[1]
|
|
54
|
+
|
|
55
|
+
context = []
|
|
56
|
+
context << "Parse error at line #{line_num}, column #{col_num}:"
|
|
57
|
+
|
|
58
|
+
# Show the problematic line
|
|
59
|
+
if line_num > 0 && line_num <= lines.length
|
|
60
|
+
context << lines[line_num - 1].chomp
|
|
61
|
+
context << (' ' * (col_num - 1)) + '^'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context << error.parse_failure_cause.to_s
|
|
65
|
+
context.join("\n")
|
|
66
|
+
rescue StandardError
|
|
67
|
+
# Fallback to simple error message
|
|
68
|
+
"Parse error: #{error.message}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'grammars/c4'
|
|
5
|
+
require_relative 'transforms/c4'
|
|
6
|
+
require_relative '../diagram/c4'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# C4 parser for Mermaid C4 diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Uses Parslet grammar-based parsing to handle C4 diagram syntax including
|
|
13
|
+
# elements, relationships, and boundaries.
|
|
14
|
+
#
|
|
15
|
+
# Parses C4 diagrams with support for:
|
|
16
|
+
# - Multiple C4 levels (Context, Container, Component, Dynamic, Deployment)
|
|
17
|
+
# - Person, System, Container, Component elements
|
|
18
|
+
# - External variants (_Ext suffix)
|
|
19
|
+
# - Database and Queue variants (SystemDb, ContainerQueue, etc.)
|
|
20
|
+
# - Relationships (Rel, BiRel)
|
|
21
|
+
# - Boundaries (Enterprise_Boundary, System_Boundary, Boundary)
|
|
22
|
+
# - Nested boundaries
|
|
23
|
+
# - Element attributes (sprite, link, tags)
|
|
24
|
+
# - Layout configuration
|
|
25
|
+
#
|
|
26
|
+
# @example Parse a simple C4 Context diagram
|
|
27
|
+
# parser = C4Parser.new
|
|
28
|
+
# diagram = parser.parse("C4Context\ntitle My System\nPerson(user, \"User\")")
|
|
29
|
+
class C4Parser < Base
|
|
30
|
+
# Parses C4 diagram source into a C4 diagram model.
|
|
31
|
+
#
|
|
32
|
+
# @param source [String] the Mermaid C4 diagram source
|
|
33
|
+
# @return [Diagram::C4] the parsed C4 diagram
|
|
34
|
+
# @raise [ParseError] if syntax is invalid
|
|
35
|
+
def parse(source)
|
|
36
|
+
grammar = Grammars::C4.new
|
|
37
|
+
|
|
38
|
+
begin
|
|
39
|
+
parse_tree = grammar.parse(source)
|
|
40
|
+
rescue Parslet::ParseFailed => e
|
|
41
|
+
raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
|
|
42
|
+
"#{e.parse_failure_cause}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Transform parse tree to diagram model
|
|
46
|
+
transform = Transforms::C4.new
|
|
47
|
+
diagram = transform.apply(parse_tree)
|
|
48
|
+
|
|
49
|
+
diagram
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'grammars/class_diagram'
|
|
5
|
+
require_relative 'transforms/class_diagram'
|
|
6
|
+
require_relative '../diagram/class_diagram'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Class diagram parser for Mermaid class diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Parses class diagrams with support for:
|
|
13
|
+
# - Class declarations with stereotypes
|
|
14
|
+
# - Attributes with visibility modifiers
|
|
15
|
+
# - Methods with parameters and return types
|
|
16
|
+
# - Relationships (inheritance, composition, aggregation, association)
|
|
17
|
+
# - Generic types (e.g., List~String~)
|
|
18
|
+
# - Namespaces
|
|
19
|
+
# - Cardinality labels
|
|
20
|
+
#
|
|
21
|
+
# @example Parse a simple class diagram
|
|
22
|
+
# parser = ClassDiagramParser.new
|
|
23
|
+
# diagram = parser.parse("classDiagram\nAnimal <|-- Dog")
|
|
24
|
+
class ClassDiagramParser < Base
|
|
25
|
+
# Parses class diagram source into a ClassDiagram model.
|
|
26
|
+
#
|
|
27
|
+
# @param source [String] the Mermaid class diagram source
|
|
28
|
+
# @return [Diagram::ClassDiagram] the parsed class diagram
|
|
29
|
+
# @raise [ParseError] if syntax is invalid
|
|
30
|
+
def parse(source)
|
|
31
|
+
grammar = Grammars::ClassDiagram.new
|
|
32
|
+
transform = Transforms::ClassDiagram.new
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
parse_tree = grammar.parse(source)
|
|
36
|
+
diagram = transform.apply(parse_tree)
|
|
37
|
+
diagram
|
|
38
|
+
rescue Parslet::ParseFailed => e
|
|
39
|
+
raise ParseError, format_parse_error(e, source)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def format_parse_error(error, source)
|
|
46
|
+
lines = source.lines
|
|
47
|
+
line_num = error.parse_failure_cause.source.line_and_column[0]
|
|
48
|
+
col_num = error.parse_failure_cause.source.line_and_column[1]
|
|
49
|
+
|
|
50
|
+
context = if line_num <= lines.length
|
|
51
|
+
lines[line_num - 1].chomp
|
|
52
|
+
else
|
|
53
|
+
'(end of input)'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
"Parse error at line #{line_num}, column #{col_num}:\n" \
|
|
57
|
+
"#{context}\n" \
|
|
58
|
+
"#{' ' * (col_num - 1)}^\n" \
|
|
59
|
+
"Expected: #{error.parse_failure_cause.message}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../diagram/er_diagram'
|
|
5
|
+
require_relative 'grammars/er_diagram'
|
|
6
|
+
require_relative 'transforms/er_diagram'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# ER diagram parser for Mermaid ER diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Parses ER diagrams with support for:
|
|
13
|
+
# - Entity declarations with attributes
|
|
14
|
+
# - Attribute types and key markers (PK, FK, UK)
|
|
15
|
+
# - Relationships with cardinality notation
|
|
16
|
+
# - Identifying and non-identifying relationships
|
|
17
|
+
#
|
|
18
|
+
# @example Parse a simple ER diagram
|
|
19
|
+
# parser = ErDiagramParser.new
|
|
20
|
+
# diagram = parser.parse("erDiagram\nCUSTOMER ||--o{ ORDER : places")
|
|
21
|
+
class ErDiagramParser < Base
|
|
22
|
+
# Parses ER diagram source into an ErDiagram model.
|
|
23
|
+
#
|
|
24
|
+
# @param source [String] the Mermaid ER diagram source
|
|
25
|
+
# @return [Diagram::ErDiagram] the parsed ER diagram
|
|
26
|
+
# @raise [ParseError] if syntax is invalid
|
|
27
|
+
def parse(source)
|
|
28
|
+
grammar = Grammars::ErDiagram.new
|
|
29
|
+
transform = Transforms::ErDiagram.new
|
|
30
|
+
|
|
31
|
+
tree = grammar.parse(source)
|
|
32
|
+
diagram = transform.apply(tree)
|
|
33
|
+
|
|
34
|
+
diagram
|
|
35
|
+
rescue Parslet::ParseFailed => e
|
|
36
|
+
raise ParseError, e.parse_failure_cause.ascii_tree
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'grammars/error'
|
|
5
|
+
require_relative 'transforms/error'
|
|
6
|
+
require_relative '../diagram/error'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Error diagram parser for Mermaid error diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Uses Parslet grammar-based parsing to handle simple error diagrams.
|
|
13
|
+
#
|
|
14
|
+
# Parses error diagrams with support for:
|
|
15
|
+
# - Basic error keyword
|
|
16
|
+
# - Optional error message text
|
|
17
|
+
#
|
|
18
|
+
# @example Parse a simple error diagram
|
|
19
|
+
# parser = ErrorParser.new
|
|
20
|
+
# diagram = parser.parse("error")
|
|
21
|
+
#
|
|
22
|
+
# @example Parse error diagram with message
|
|
23
|
+
# parser = ErrorParser.new
|
|
24
|
+
# diagram = parser.parse("Error Diagrams")
|
|
25
|
+
class ErrorParser < Base
|
|
26
|
+
# Parses error diagram source into an Error diagram model.
|
|
27
|
+
#
|
|
28
|
+
# @param source [String] the Mermaid error diagram source
|
|
29
|
+
# @return [Diagram::Error] the parsed error diagram
|
|
30
|
+
# @raise [ParseError] if syntax is invalid
|
|
31
|
+
def parse(source)
|
|
32
|
+
grammar = Grammars::Error.new
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
parse_tree = grammar.parse(source)
|
|
36
|
+
rescue Parslet::ParseFailed => e
|
|
37
|
+
raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
|
|
38
|
+
"#{e.parse_failure_cause}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Transform parse tree to diagram model
|
|
42
|
+
transform = Transforms::Error.new
|
|
43
|
+
diagram = transform.apply(parse_tree)
|
|
44
|
+
|
|
45
|
+
diagram
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'grammars/flowchart'
|
|
5
|
+
require_relative 'transforms/flowchart'
|
|
6
|
+
require_relative '../diagram/flowchart'
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Flowchart parser for Mermaid flowchart syntax.
|
|
11
|
+
#
|
|
12
|
+
# Parses flowchart diagrams with support for:
|
|
13
|
+
# - Multiple node shapes (rectangle, rounded, rhombus, circle, etc.)
|
|
14
|
+
# - Multiple edge types (arrow, line, dotted, etc.)
|
|
15
|
+
# - Node labels with special characters
|
|
16
|
+
# - Edge chaining (A --> B --> C)
|
|
17
|
+
# - Subgraphs
|
|
18
|
+
# - Styling directives
|
|
19
|
+
# - Direction specification (TD, LR, etc.)
|
|
20
|
+
#
|
|
21
|
+
# @example Parse a simple flowchart
|
|
22
|
+
# parser = FlowchartParser.new
|
|
23
|
+
# diagram = parser.parse("graph TD\nA[Start]-->B[End]")
|
|
24
|
+
class FlowchartParser < Base
|
|
25
|
+
# Parses flowchart source into a Flowchart diagram model.
|
|
26
|
+
#
|
|
27
|
+
# @param source [String] the Mermaid flowchart source
|
|
28
|
+
# @return [Diagram::Flowchart] the parsed flowchart
|
|
29
|
+
# @raise [ParseError] if syntax is invalid
|
|
30
|
+
def parse(source)
|
|
31
|
+
grammar = Grammars::Flowchart.new
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
tree = grammar.parse(source)
|
|
35
|
+
diagram = Transforms::Flowchart.apply(tree)
|
|
36
|
+
diagram
|
|
37
|
+
rescue Parslet::ParseFailed => e
|
|
38
|
+
raise ParseError, format_parse_error(e, source)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Formats a Parslet parse error with context.
|
|
45
|
+
#
|
|
46
|
+
# @param error [Parslet::ParseFailed] the parse error
|
|
47
|
+
# @param source [String] the source that failed to parse
|
|
48
|
+
# @return [String] formatted error message
|
|
49
|
+
def format_parse_error(error, source)
|
|
50
|
+
lines = source.lines
|
|
51
|
+
line_num = error.parse_failure_cause.source.line_and_column[0]
|
|
52
|
+
col_num = error.parse_failure_cause.source.line_and_column[1]
|
|
53
|
+
|
|
54
|
+
context = []
|
|
55
|
+
context << "Parse error at line #{line_num}, column #{col_num}:"
|
|
56
|
+
|
|
57
|
+
# Show the problematic line
|
|
58
|
+
if line_num > 0 && line_num <= lines.length
|
|
59
|
+
context << lines[line_num - 1].chomp
|
|
60
|
+
context << (' ' * (col_num - 1)) + '^'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context << error.parse_failure_cause.to_s
|
|
64
|
+
context.join("\n")
|
|
65
|
+
rescue StandardError
|
|
66
|
+
# Fallback to simple error message
|
|
67
|
+
"Parse error: #{error.message}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "grammars/gantt"
|
|
5
|
+
require_relative "transforms/gantt"
|
|
6
|
+
require_relative "../diagram/gantt"
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Gantt chart parser for Mermaid gantt diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Uses Parslet grammar-based parsing to handle Gantt chart syntax
|
|
13
|
+
# with sections, tasks, dependencies, and timeline configuration.
|
|
14
|
+
#
|
|
15
|
+
# Parses Gantt charts with support for:
|
|
16
|
+
# - Title and date format declarations
|
|
17
|
+
# - Axis formatting and tick intervals
|
|
18
|
+
# - Excludes (weekends, weekdays, specific dates)
|
|
19
|
+
# - Section grouping
|
|
20
|
+
# - Tasks with dates, durations, and dependencies
|
|
21
|
+
# - Task status tags (done, active, crit, milestone)
|
|
22
|
+
# - Click handlers for interactivity
|
|
23
|
+
# - Accessibility features (accTitle, accDescr)
|
|
24
|
+
# - Comments
|
|
25
|
+
#
|
|
26
|
+
# @example Parse a simple Gantt chart
|
|
27
|
+
# parser = GanttParser.new
|
|
28
|
+
# diagram = parser.parse(<<~GANTT)
|
|
29
|
+
# gantt
|
|
30
|
+
# title Project Timeline
|
|
31
|
+
# dateFormat YYYY-MM-DD
|
|
32
|
+
# section Planning
|
|
33
|
+
# Task 1 :a1, 2024-01-01, 30d
|
|
34
|
+
# Task 2 :after a1, 20d
|
|
35
|
+
# GANTT
|
|
36
|
+
class GanttParser < Base
|
|
37
|
+
# Parses Gantt chart diagram source into a GanttChart diagram model.
|
|
38
|
+
#
|
|
39
|
+
# @param source [String] the Mermaid Gantt chart diagram source
|
|
40
|
+
# @return [Diagram::GanttChart] the parsed Gantt chart diagram
|
|
41
|
+
# @raise [ParseError] if syntax is invalid
|
|
42
|
+
def parse(source)
|
|
43
|
+
grammar = Grammars::Gantt.new
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
parse_tree = grammar.parse(source)
|
|
47
|
+
rescue Parslet::ParseFailed => e
|
|
48
|
+
raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
|
|
49
|
+
"#{e.parse_failure_cause}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Transform parse tree to diagram model
|
|
53
|
+
transform = Transforms::Gantt.new
|
|
54
|
+
diagram = transform.apply(parse_tree)
|
|
55
|
+
|
|
56
|
+
diagram
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "grammars/git_graph"
|
|
5
|
+
require_relative "transforms/git_graph"
|
|
6
|
+
require_relative "../diagram/git_graph"
|
|
7
|
+
|
|
8
|
+
module Sirena
|
|
9
|
+
module Parser
|
|
10
|
+
# Git Graph parser for Mermaid gitGraph diagram syntax.
|
|
11
|
+
#
|
|
12
|
+
# Uses Parslet grammar-based parsing to handle git graph syntax
|
|
13
|
+
# with commits, branches, merges, and cherry-picks.
|
|
14
|
+
#
|
|
15
|
+
# Parses git graphs with support for:
|
|
16
|
+
# - Commit declarations with id, type, and tag
|
|
17
|
+
# - Branch creation with optional order
|
|
18
|
+
# - Checkout/switch operations
|
|
19
|
+
# - Merge operations
|
|
20
|
+
# - Cherry-pick operations
|
|
21
|
+
# - Commit types (NORMAL, REVERSE, HIGHLIGHT)
|
|
22
|
+
#
|
|
23
|
+
# @example Parse a simple git graph
|
|
24
|
+
# parser = GitGraphParser.new
|
|
25
|
+
# source = <<~MERMAID
|
|
26
|
+
# gitGraph
|
|
27
|
+
# commit id: "Initial"
|
|
28
|
+
# branch develop
|
|
29
|
+
# checkout develop
|
|
30
|
+
# commit id: "Feature"
|
|
31
|
+
# checkout main
|
|
32
|
+
# merge develop
|
|
33
|
+
# MERMAID
|
|
34
|
+
# diagram = parser.parse(source)
|
|
35
|
+
class GitGraphParser < Base
|
|
36
|
+
# Parses git graph diagram source into a GitGraph model.
|
|
37
|
+
#
|
|
38
|
+
# @param source [String] the Mermaid git graph diagram source
|
|
39
|
+
# @return [Diagram::GitGraph] the parsed git graph diagram
|
|
40
|
+
# @raise [ParseError] if syntax is invalid
|
|
41
|
+
def parse(source)
|
|
42
|
+
grammar = Grammars::GitGraph.new
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
parse_tree = grammar.parse(source)
|
|
46
|
+
rescue Parslet::ParseFailed => e
|
|
47
|
+
raise ParseError, "Syntax error at #{e.parse_failure_cause.pos}: " \
|
|
48
|
+
"#{e.parse_failure_cause}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Transform parse tree to diagram model
|
|
52
|
+
transform = Transforms::GitGraph.new
|
|
53
|
+
result = transform.apply(parse_tree)
|
|
54
|
+
|
|
55
|
+
# Create the diagram model
|
|
56
|
+
create_diagram(result)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def create_diagram(result)
|
|
62
|
+
diagram = Diagram::GitGraph.new
|
|
63
|
+
|
|
64
|
+
# Add commits
|
|
65
|
+
result[:commits].each do |commit_data|
|
|
66
|
+
commit = Diagram::GitGraph::Commit.new(
|
|
67
|
+
id: commit_data[:id],
|
|
68
|
+
type: commit_data[:type],
|
|
69
|
+
tag: commit_data[:tag],
|
|
70
|
+
branch_name: commit_data[:branch_name],
|
|
71
|
+
parent_ids: commit_data[:parent_ids],
|
|
72
|
+
is_merge: commit_data[:is_merge],
|
|
73
|
+
merge_branch: commit_data[:merge_branch],
|
|
74
|
+
is_cherry_pick: commit_data[:is_cherry_pick],
|
|
75
|
+
cherry_pick_parent: commit_data[:cherry_pick_parent]
|
|
76
|
+
)
|
|
77
|
+
diagram.commits << commit
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Add branches
|
|
81
|
+
result[:branches].each do |branch_data|
|
|
82
|
+
branch = Diagram::GitGraph::Branch.new(
|
|
83
|
+
name: branch_data[:name],
|
|
84
|
+
order: branch_data[:order],
|
|
85
|
+
parent_branch: branch_data[:parent_branch],
|
|
86
|
+
created_at_commit: branch_data[:created_at_commit]
|
|
87
|
+
)
|
|
88
|
+
diagram.branches << branch
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
diagram
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|