Skip to content

improvement: Add the ability to render Mermaid flowcharts.#175

Merged
jimsynz merged 2 commits intomainfrom
improvement/mermaid
Mar 2, 2025
Merged

improvement: Add the ability to render Mermaid flowcharts.#175
jimsynz merged 2 commits intomainfrom
improvement/mermaid

Conversation

@jimsynz
Copy link
Copy Markdown
Contributor

@jimsynz jimsynz commented Feb 24, 2025

Hi folks 👋

This PR adds the ability to convert Reactors into Mermaid. It's not particularly pretty yet, but it works well enough to ship it as a first version and can be improved if required.

flowchart LR
        start{"Start"}
        start==>reactor_Reactor.MermaidTest.BasicReactor
        subgraph reactor_Reactor.MermaidTest.BasicReactor["Reactor.MermaidTest.BasicReactor"]
            direction LR
            input_105483575>"Input whom"]
            input_105483575 -->|whom|step_19254403
            step_19254403["greet(Example.Step.Greeter)"]
            return_Reactor.MermaidTest.BasicReactor{"Return"}
            step_19254403==>return_Reactor.MermaidTest.BasicReactor
        end
Loading

@jimsynz jimsynz force-pushed the improvement/mermaid branch 2 times, most recently from 4dffc97 to b0e2d1e Compare February 28, 2025 01:53
@jimsynz jimsynz marked this pull request as ready for review February 28, 2025 01:55
@jimsynz jimsynz force-pushed the improvement/mermaid branch from b0e2d1e to 8ade2c4 Compare February 28, 2025 01:56
@jimsynz jimsynz requested a review from a team February 28, 2025 01:56
@jimsynz jimsynz force-pushed the improvement/mermaid branch from 8ade2c4 to e9eadf1 Compare February 28, 2025 01:59
@jimsynz
Copy link
Copy Markdown
Contributor Author

jimsynz commented Feb 28, 2025

Here's a more pathological example as requested by @zachdaniel

flowchart LR
    start{"Start"}
    start==>reactor_Neon.Reactor.StartupReactor
    subgraph reactor_Neon.Reactor.StartupReactor["Neon.Reactor.StartupReactor"]
        direction LR
        input_9198890>"Input supervisor"]
        step_44774040["secrets(Reactor.Step.Compose)"]
        subgraph reactor_66969717["{Neon.Reactor.EnsureAllSecretsReactor, :secrets}"]
            direction LR
            step_14043928 -->|value|step_33852712
            step_33852712[Transform argument path]
            step_14043928 -->|value|step_127867733
            step_127867733[Transform argument path]
            step_14043928 -->|value|step_61719474
            step_61719474[Transform argument path]
            step_33852712 -->|path|step_52616830
            value_72326164{{"`64`"}}
            value_72326164 -->|secret_length|step_52616830
            value_93482233{{"`\[NeonWeb\.Endpoint, :secret\_key\_base\]`"}}
            value_93482233 -->|app_path|step_52616830
            step_52616830["phx_secret_key_base(Reactor.Step.Compose)"]
            subgraph reactor_124429572["{Neon.Reactor.EnsureSecretReactor, :phx_secret_key_base}"]
                direction LR
                input_30549490>"Input path"]
                input_30349613>"Input secret_length"]
                input_27225100>"Input app_path"]
                value_neon_core{{"`:neon\_core`"}}
                value_neon_core -->|otp_app|step_92232422
                input_27225100 -->|path|step_92232422
                step_115529526 -->|value|step_92232422
                step_92232422["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
                step_74828596 -->|secret|step_115529526
                input_30349613 -->|secret_length|step_115529526
                step_115529526["secret_content(Reactor.Step.AnonFn)"]
                input_30549490 -->|path|step_74828596
                step_74828596["original_content(Reactor.File.Step.ReadFile)"]
                step_7420378 -->|value|step_100565385
                step_100565385["maybe_write_file(Reactor.Step.Switch)"]
                step_100565385_decision@{shape: diamond, label: "Decision for maybe_write_file"}
                step_100565385-->step_100565385_decision
                step_100565385_decision-->step_96566794
                subgraph step_96566794["match branch of maybe_write_file"]
                    input_30549490 -->|path|step_49914735
                    step_115529526 -->|content|step_49914735
                    step_49914735["secret_file(Reactor.File.Step.WriteFile)"]
                    direction LR
                end
                step_74828596 -->|original|step_7420378
                step_115529526 -->|new|step_7420378
                step_7420378["content_changed?(Reactor.Step.AnonFn)"]
                return_124429572{"Return"}
                step_115529526==>return_124429572
            end
            step_52616830-->input_27225100
            step_52616830-->input_30349613
            step_52616830-->input_30549490
            return_124429572-->step_52616830
            step_127867733 -->|path|step_7866072
            value_67142174{{"`16`"}}
            value_67142174 -->|secret_length|step_7866072
            value_59888801{{"`\[NeonWeb\.Endpoint, :live\_view, :signing\_salt\]`"}}
            value_59888801 -->|app_path|step_7866072
            step_7866072["phx_live_view_signing_salt(Reactor.Step.Compose)"]
            subgraph reactor_71196029["{Neon.Reactor.EnsureSecretReactor, :phx_live_view_signing_salt}"]
                direction LR
                input_11139820>"Input path"]
                input_45448196>"Input secret_length"]
                input_112027663>"Input app_path"]
                value_neon_core{{"`:neon\_core`"}}
                value_neon_core -->|otp_app|step_111503509
                input_112027663 -->|path|step_111503509
                step_73727431 -->|value|step_111503509
                step_111503509["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
                step_102532192 -->|secret|step_73727431
                input_45448196 -->|secret_length|step_73727431
                step_73727431["secret_content(Reactor.Step.AnonFn)"]
                input_11139820 -->|path|step_102532192
                step_102532192["original_content(Reactor.File.Step.ReadFile)"]
                step_92208032 -->|value|step_2235755
                step_2235755["maybe_write_file(Reactor.Step.Switch)"]
                step_2235755_decision@{shape: diamond, label: "Decision for maybe_write_file"}
                step_2235755-->step_2235755_decision
                step_2235755_decision-->step_33123163
                subgraph step_33123163["match branch of maybe_write_file"]
                    input_11139820 -->|path|step_130111125
                    step_73727431 -->|content|step_130111125
                    step_130111125["secret_file(Reactor.File.Step.WriteFile)"]
                    direction LR
                end
                step_102532192 -->|original|step_92208032
                step_73727431 -->|new|step_92208032
                step_92208032["content_changed?(Reactor.Step.AnonFn)"]
                return_71196029{"Return"}
                step_73727431==>return_71196029
            end
            step_7866072-->input_112027663
            step_7866072-->input_45448196
            step_7866072-->input_11139820
            return_71196029-->step_7866072
            step_61719474 -->|path|step_50144077
            value_72326164{{"`64`"}}
            value_72326164 -->|secret_length|step_50144077
            value_87125564{{"`\[Neon\.Accounts, :token\_signing\_secret\]`"}}
            value_87125564 -->|app_path|step_50144077
            step_50144077["aa_token_signing_secret(Reactor.Step.Compose)"]
            subgraph reactor_59877050["{Neon.Reactor.EnsureSecretReactor, :aa_token_signing_secret}"]
                direction LR
                input_81702250>"Input path"]
                input_127553628>"Input secret_length"]
                input_113275556>"Input app_path"]
                value_neon_core{{"`:neon\_core`"}}
                value_neon_core -->|otp_app|step_101178976
                input_113275556 -->|path|step_101178976
                step_118903631 -->|value|step_101178976
                step_101178976["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
                step_19143458 -->|secret|step_118903631
                input_127553628 -->|secret_length|step_118903631
                step_118903631["secret_content(Reactor.Step.AnonFn)"]
                input_81702250 -->|path|step_19143458
                step_19143458["original_content(Reactor.File.Step.ReadFile)"]
                step_42402661 -->|value|step_52346503
                step_52346503["maybe_write_file(Reactor.Step.Switch)"]
                step_52346503_decision@{shape: diamond, label: "Decision for maybe_write_file"}
                step_52346503-->step_52346503_decision
                step_52346503_decision-->step_52319625
                subgraph step_52319625["match branch of maybe_write_file"]
                    input_81702250 -->|path|step_32774053
                    step_118903631 -->|content|step_32774053
                    step_32774053["secret_file(Reactor.File.Step.WriteFile)"]
                    direction LR
                end
                step_19143458 -->|original|step_42402661
                step_118903631 -->|new|step_42402661
                step_42402661["content_changed?(Reactor.Step.AnonFn)"]
                return_59877050{"Return"}
                step_118903631==>return_59877050
            end
            step_50144077-->input_113275556
            step_50144077-->input_127553628
            step_50144077-->input_81702250
            return_59877050-->step_50144077
            value_123381424{{"`"config/secrets"`"}}
            value_123381424 -->|sub_path|step_14043928
            step_14043928["secrets_path(Reactor.Step.Compose)"]
            subgraph reactor_105441487["{Neon.Reactor.EnsureStoragePathReactor, :secrets_path}"]
                direction LR
                input_35399639>"Input sub_path"]
                step_65352851 -->|path|step_23566636
                step_23566636["mkdir(Reactor.File.Step.MkdirP)"]
                input_35399639 -->|sub_path|step_65352851
                step_65352851["path(Reactor.Step.AnonFn)"]
                return_105441487{"Return"}
                step_65352851==>return_105441487
            end
            step_14043928-->input_35399639
            return_105441487-->step_14043928
            return_66969717{"Return"}
            step_50144077==>return_66969717
        end
        return_66969717-->step_44774040
        input_9198890 -->|supervisor|step_2670933
        value_NeonWeb.Endpoint{{"`NeonWeb\.Endpoint`"}}
        value_NeonWeb.Endpoint -->|child_spec|step_2670933
        step_100673197 -->|_|step_2670933
        step_44774040 -->|_|step_2670933
        step_2670933["endpoint(Reactor.Process.Step.StartChild)"]
        step_120864991 -->|_|step_100673197
        step_100673197["settings(Reactor.Step.Compose)"]
        subgraph reactor_122041945["{Neon.Reactor.ApplySettingsReactor, :settings}"]
            direction LR
            step_92922204 -->|value|step_117256111
            step_117256111[Transform argument value]
            step_101217954 -->|value|step_83362370
            step_83362370[Transform argument arguments]
            value_vintage_net{{"`:vintage\_net`"}}
            value_vintage_net -->|otp_app|step_26270303
            value_49508896{{"`\[:regulatory\_domain\]`"}}
            value_49508896 -->|path|step_26270303
            step_117256111 -->|value|step_26270303
            step_26270303["set_wifi_country(Neon.Reactor.Steps.SetAppEnvStep)"]
            value_neon_core{{"`:neon\_core`"}}
            value_neon_core -->|otp_app|step_126882274
            value_133893407{{"`\[:timezone\]`"}}
            value_133893407 -->|path|step_126882274
            step_92922204 -->|value|step_126882274
            step_126882274["set_system_timezone(Neon.Reactor.Steps.SetAppEnvStep)"]
            value_39679005{{"`%\{\}`"}}
            value_39679005 -->|input|step_125575241
            step_125575241["get_settings(Ash.Reactor.ReadOneStep)"]
            value_41978982{{"`"/usr/bin/hostname"`"}}
            value_41978982 -->|command|step_121158215
            step_83362370 -->|arguments|step_121158215
            step_44347617 -->|_|step_121158215
            step_121158215["set_system_hostname(Neon.Reactor.Steps.RunCommandStep)"]
            value_123524932{{"`"config/etc"`"}}
            value_123524932 -->|sub_path|step_101217954
            step_101217954["etc_path(Reactor.Step.Compose)"]
            subgraph reactor_103570142["{Neon.Reactor.EnsureStoragePathReactor, :etc_path}"]
                direction LR
                input_39732180>"Input sub_path"]
                step_113242578 -->|path|step_1594212
                step_1594212["mkdir(Reactor.File.Step.MkdirP)"]
                input_39732180 -->|sub_path|step_113242578
                step_113242578["path(Reactor.Step.AnonFn)"]
                return_103570142{"Return"}
                step_113242578==>return_103570142
            end
            step_101217954-->input_39732180
            return_103570142-->step_101217954
            step_101217954 -->|base|step_108132378
            step_108132378["etc_hosts_path(Reactor.Step.AnonFn)"]
            step_108132378 -->|path|step_13234098
            step_110135308 -->|content|step_13234098
            step_13234098["write_etc_hosts(Reactor.File.Step.WriteFile)"]
            step_92922204 -->|settings|step_110135308
            step_110135308["etc_hosts_content(Reactor.Step.Template)"]
            step_101217954 -->|base|step_20541118
            step_20541118["etc_hostname_path(Reactor.Step.AnonFn)"]
            step_20541118 -->|path|step_44347617
            step_46004921 -->|content|step_44347617
            step_44347617["write_etc_hostname(Reactor.File.Step.WriteFile)"]
            step_92922204 -->|settings|step_46004921
            step_46004921["etc_hostname_content(Reactor.Step.Template)"]
            step_125575241 -->|settings|step_92922204
            step_92922204["settings(Reactor.Step.AnonFn)"]
            return_122041945{"Return"}
            step_126882274==>return_122041945
        end
        return_122041945-->step_100673197
        step_120864991 -->|_|step_68426946
        step_100673197 -->|_|step_68426946
        input_9198890 -->|supervisor|step_68426946
        value_Oban{{"`Oban`"}}
        value_Oban -->|module|step_68426946
        step_68426946["oban(Reactor.Step.Compose)"]
        subgraph reactor_29023697["{Neon.Reactor.StartObanReactor, :oban}"]
            direction LR
            input_121044242>"Input supervisor"]
            input_99777965>"Input module"]
            value_neon_core{{"`:neon\_core`"}}
            value_neon_core -->|otp_app|step_130005066
            value_67693049{{"`\[Oban\]`"}}
            value_67693049 -->|path|step_130005066
            step_130005066["oban_config(Neon.Reactor.Steps.GetAppEnvStep)"]
            value_neon_core{{"`:neon\_core`"}}
            value_neon_core -->|otp_app|step_64783539
            value_59181804{{"`\[:ash\_domains\]`"}}
            value_59181804 -->|path|step_64783539
            step_64783539["all_domains(Neon.Reactor.Steps.GetAppEnvStep)"]
            input_121044242 -->|supervisor|step_80577418
            step_127596499 -->|child_spec|step_80577418
            step_80577418["oban(Reactor.Process.Step.StartChild)"]
            input_99777965 -->|module|step_127596499
            step_64783539 -->|all_domains|step_127596499
            step_130005066 -->|oban_config|step_127596499
            step_127596499["child_spec(Reactor.Step.AnonFn)"]
            return_29023697{"Return"}
            step_80577418==>return_29023697
        end
        step_68426946-->input_99777965
        step_68426946-->input_121044242
        return_29023697-->step_68426946
        input_9198890 -->|supervisor|step_120864991
        step_120864991["repos(Reactor.Step.Compose)"]
        subgraph reactor_133882914["{Neon.Reactor.StartAllReposReactor, :repos}"]
            direction LR
            input_15973844>"Input supervisor"]
            step_89289127 -->|source|step_58628162
            step_58628162["migrate_and_start_all_repos(Reactor.Step.Map)"]
            subgraph reactor_83839479["{Reactor.Step.Map.Mermaid, :migrate_and_start_all_repos}"]
                direction LR
                input_36536047>"Input source"]
                input_119846339 -->|supervisor|step_74432928
                input_36536047 -->|child_spec|step_74432928
                step_84659762 -->|_|step_74432928
                step_74432928["repo(Reactor.Process.Step.StartChild)"]
                input_36536047 -->|repo|step_84659762
                step_84659762["migrate(Reactor.Step.AnonFn)"]
                return_83839479{"Return"}
                step_74432928==>return_83839479
            end
            step_58628162-->input_36536047
            return_83839479-->step_58628162
            value_neon_core{{"`:neon\_core`"}}
            value_neon_core -->|otp_app|step_89289127
            value_38559143{{"`\[:ecto\_repos\]`"}}
            value_38559143 -->|path|step_89289127
            step_89289127["all_repos(Neon.Reactor.Steps.GetAppEnvStep)"]
            return_133882914{"Return"}
            step_89289127==>return_133882914
        end
        step_120864991-->input_15973844
        return_133882914-->step_120864991
        input_9198890 -->|supervisor|step_125716691
        value_Neon.Services.Supervisor{{"`Neon\.Services\.Supervisor`"}}
        value_Neon.Services.Supervisor -->|child_spec|step_125716691
        step_100673197 -->|_|step_125716691
        step_125716691["services(Reactor.Process.Step.StartChild)"]
        return_Neon.Reactor.StartupReactor{"Return"}
        step_68426946==>return_Neon.Reactor.StartupReactor
    end
Loading

@jimsynz jimsynz merged commit d21c842 into main Mar 2, 2025
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants