defmodule Mix.Tasks.SlackApiDocs.Gen.Json do use Mix.Task @default_output_path "tmp/slack/docs" @tmp_dir String.trim_trailing(System.tmp_dir(), "/") <> "/slack_api_docs" @shortdoc "Generates Slack Web API docs in JSON format" @moduledoc """ Generates Slack API docs in JSON format ## Usage $ mix slack_api_docs.gen.json $ mix slack_api_docs.gen.json tmp/slack/docs ## Command line options * `--concurrency 75` - default: 50, the amount of requests running in parallel * `--quiet` - suppress all informational messages. """ alias Mix.SlackApiDocs.{HomePage, MethodPage, Request, Helpers} @command_options [ concurrency: :integer, quiet: :boolean ] @default_opts [concurrency: 50, quiet: false] @impl Mix.Task def run(all_args) do {original_opts, args, _} = OptionParser.parse(all_args, switches: @command_options) opts = Keyword.merge(@default_opts, original_opts) output_path = List.first(args) || @default_output_path concurrency = opts[:concurrency] original_shell = Mix.shell() if opts[:quiet], do: Mix.shell(Mix.Shell.Quiet) try do # Setup HTTPoison.start() File.mkdir_p!(@tmp_dir) # Generate files Mix.shell().info("Gathering API methods, concurrency: #{concurrency}") Request.get!("/methods") |> HomePage.gather_methods!() |> Helpers.partition_list(concurrency) |> Enum.map(&enqueue_group/1) |> Task.await_many(:infinity) # Copy the files over to the target location Mix.shell().info("Copying files to: #{output_path}") copy_to_target!(output_path) after System.cmd("rm", ["-rf", @tmp_dir]) end Mix.shell(original_shell) end defp write_json_for_endpoint!(%{"name" => name} = item) do Mix.shell().info("Generating: #{name}") contents = MethodPage.gather!(item) |> Jason.encode!(pretty: true) File.write!("#{@tmp_dir}/#{name}.json", contents) end defp enqueue_group(group) do Task.async(fn -> Enum.map(group, fn item -> write_json_for_endpoint!(item) end) end) end defp copy_to_target!(output_path) do File.mkdir_p!(output_path) File.ls!(@tmp_dir) |> Enum.filter(fn file -> String.ends_with?(file, "json") end) |> Enum.map(fn file -> origin = "#{@tmp_dir}/#{file}" dest = "#{String.trim_trailing(output_path, "/")}/#{file}" File.cp!(origin, dest) end) end end