diff --git a/documentation/tutorials/get-started-with-state-machines.md b/documentation/tutorials/get-started-with-state-machines.md index 0fa313b..5ec2169 100644 --- a/documentation/tutorials/get-started-with-state-machines.md +++ b/documentation/tutorials/get-started-with-state-machines.md @@ -107,13 +107,13 @@ end run `mix ash_state_machine.generate_flow_charts` to generate flow charts for your resources. See the task documentation for more. Here is a chart generated from the example above: ```mermaid -flowchart TD -pending --> |confirm| confirmed -confirmed --> |begin_delivery| on_its_way -on_its_way --> |package_arrived| arrived -on_its_way --> |error| error -confirmed --> |error| error -pending --> |error| error +stateDiagram-v2 +pending --> confirmed: confirm +confirmed --> on_its_way: begin_delivery +on_its_way --> arrived: package_arrived +on_its_way --> error: error +confirmed --> error: error +pending --> error: error ``` ## Learning more diff --git a/lib/charts.ex b/lib/charts.ex index 00d0fa9..01ce9b6 100644 --- a/lib/charts.ex +++ b/lib/charts.ex @@ -3,18 +3,29 @@ defmodule AshStateMachine.Charts do Returns a mermaid flow chart of a given state machine resource. """ + @spec mermaid_state_diagram(Ash.Resource.t()) :: String.t() + def mermaid_state_diagram(resource) do + resource + |> AshStateMachine.Info.state_machine_initial_states!() + |> Enum.reduce({["stateDiagram-v2"], MapSet.new()}, fn state, {lines, checked} -> + add_to_chart(resource, state, lines ++ [], checked, :state_diagram) + end) + |> elem(0) + |> Enum.join("\n") + end + @spec mermaid_flowchart(Ash.Resource.t()) :: String.t() def mermaid_flowchart(resource) do resource |> AshStateMachine.Info.state_machine_initial_states!() |> Enum.reduce({["flowchart TD"], MapSet.new()}, fn state, {lines, checked} -> - add_to_chart(resource, state, lines ++ [], checked) + add_to_chart(resource, state, lines ++ [], checked, :flow_chart) end) |> elem(0) |> Enum.join("\n") end - defp add_to_chart(resource, state, lines, checked) do + defp add_to_chart(resource, state, lines, checked, type) do if state in checked do {lines, checked} else @@ -24,14 +35,28 @@ defmodule AshStateMachine.Charts do |> transitions_from(resource) |> Enum.reduce({lines, checked}, fn event, {lines, checked} -> Enum.reduce(List.wrap(event.to), {lines, checked}, fn to, {lines, checked} -> - name = - case event.action do - :* -> "" - action -> "|#{action}|" + lines = + case type do + :flow_chart -> + name = + case event.action do + :* -> "" + action -> "|#{action}|" + end + + lines ++ ["#{state} --> #{name} #{to}"] + + :state_diagram -> + name = + case event.action do + :* -> "" + action -> ": #{action}" + end + + lines ++ ["#{state} --> #{to}#{name}"] end - lines = lines ++ ["#{state} --> #{name} #{to}"] - add_to_chart(resource, to, lines, checked) + add_to_chart(resource, to, lines, checked, type) end) end) end diff --git a/lib/mix/generate_flow_charts.ex b/lib/mix/generate_flow_charts.ex index 7bd49f3..bd951f7 100644 --- a/lib/mix/generate_flow_charts.ex +++ b/lib/mix/generate_flow_charts.ex @@ -11,6 +11,7 @@ defmodule Mix.Tasks.AshStateMachine.GenerateFlowCharts do ## Command line options + * `--type` - generates a given type. Valid values are `"state_diagram"` and `"flow_chart"`. Defaults to `"state_diagram"`. * `--only` - only generates the given Flow file * `--format` - Can be set to one of either: * `plain` - Prints just the mermaid output as text. This is the default. @@ -30,8 +31,8 @@ defmodule Mix.Tasks.AshStateMachine.GenerateFlowCharts do {opts, _} = OptionParser.parse!(argv, - strict: [only: :keep, format: :string], - aliases: [o: :only, f: :format] + strict: [only: :keep, format: :string, type: :string], + aliases: [o: :only, f: :format, t: :type] ) only = @@ -47,11 +48,20 @@ defmodule Mix.Tasks.AshStateMachine.GenerateFlowCharts do source = state_machine.module_info(:compile)[:source] if is_nil(only) || Path.expand(source) in only do + diagram = + case opts[:type] || "state_diagram" do + "state_diagram" -> + AshStateMachine.Charts.mermaid_state_diagram(state_machine) + + "flow_chart" -> + AshStateMachine.Charts.mermaid_flowchart(state_machine) + end + Mix.Mermaid.generate_diagram( source, "mermaid-flowchart", format, - AshStateMachine.Charts.mermaid_flowchart(state_machine), + diagram, "Generated Mermaid flowchart for #{inspect(state_machine)}" ) end diff --git a/test/ash_state_machine_test.exs b/test/ash_state_machine_test.exs index dcfed00..7922274 100644 --- a/test/ash_state_machine_test.exs +++ b/test/ash_state_machine_test.exs @@ -154,7 +154,7 @@ defmodule AshStateMachineTest do describe "charts" do test "it generates the appropriate chart" do - AshStateMachine.Charts.mermaid_flowchart(Order) |> IO.puts() + AshStateMachine.Charts.mermaid_state_diagram(Order) |> IO.puts() assert AshStateMachine.Charts.mermaid_flowchart(ThreeStates) == """