lib/mix/tasks/philtre/convert.ex

defmodule Mix.Tasks.Philtre.Convert do
  @moduledoc """
  Handles conversion of old block formats to newer
  """
  use Mix.Task

  alias Philtre.Block.Code
  alias Philtre.Block.ContentEditable
  alias Philtre.Block.Table
  alias Philtre.Editor
  alias Philtre.Editor.Serializer

  def run([path]) do
    path = Path.join(File.cwd!(), path)
    files = File.ls!(path)

    paths = Enum.map(files, &Path.join(path, &1))

    paths
    |> Enum.filter(&String.ends_with?(&1, ".json"))
    |> Enum.each(fn file ->
      converted =
        file
        |> File.read!()
        |> Jason.decode!()
        |> normalize()
        |> Serializer.serialize()
        |> Jason.encode!(pretty: true)

      File.write!(file, converted)
    end)
  end

  @types [
    "p",
    "h1",
    "h2",
    "h3",
    "blockquote",
    "pre",
    "li"
  ]

  def normalize(%{"id" => id, "blocks" => blocks}) when is_binary(id) and is_list(blocks) do
    %Editor{id: id, blocks: Enum.map(blocks, &normalize/1)}
  end

  def normalize(%{"blocks" => blocks} = params) when is_list(blocks) do
    params |> Map.put("id", Editor.Utils.new_id()) |> normalize()
  end

  def normalize(%{"id" => id, "type" => kind, "content" => content})
      when kind in @types and is_list(content) do
    %ContentEditable{id: id, kind: kind, cells: Enum.map(content, &normalize/1)}
  end

  def normalize(%{"id" => id, "modifiers" => modifiers, "text" => text}) do
    %ContentEditable.Cell{id: id, modifiers: modifiers, text: text}
  end

  def normalize(%{"id" => id, "type" => "table"} = data) do
    %Table{
      id: id,
      rows: Map.get(data, "rows", []),
      header_rows: Map.get(data, "header_rows", [])
    }
  end

  def normalize(%{"id" => id, "content" => content, "language" => language, "type" => "code"}) do
    %Code{id: id, content: content, language: language}
  end

  def normalize(content) do
    Serializer.normalize(content)
  end
end