Operand

da ploy? ed.

gram: op

> ./lib/source.ex

Lenses
(coming soon!)


# A generic module able to read change-logged sources;
# can be rendered as machine-compilable code,
# essay pages, or in numerous unique schemas.

defmodule Source do
  def any(base) do
    base |> Path.absname |> File.ls!
    |> Enum.filter(& File.exists?(base <> &1 <> "/.git"))
  end

  def nodes(base, address \\ ~r/.*/) do
    index =
      Git.new(base)
      |> Git.ls_files()
      |> elem(1)
      |> String.trim
      |> String.split("\n")
      |> Enum.filter(& &1 =~ address)
      |> Enum.map(& %Source.Node{
        base: base, label: "main", address: &1,
      })
  end

  def changes(base) do
    log = Git.new(base) |> Git.log([
      "--format=format:%h (%ai) %aN: %s %d",
    ]) |> elem(1) |> String.trim |> String.split("\n")

    # parse!
    log |> Enum.map(fn ln ->
      [hash, "("<>day, clock, zone, composer | message ] = ln |> String.split(" ")
      zone = zone |> String.replace(~r/\)$/, "")
      composer = composer |> String.replace(~r/:$/, "")
      message = message |> Enum.join(" ")
      labels = []

      [message, labels] = if (message |> String.ends_with?(")")) do
        [ message | [labels] ] = message |> String.split("(")
        [message, labels |> String.trim_trailing(")") |> String.split(",") |> Enum.map(&String.trim/1) ]
        else [message, labels] end

      [ hash, day, clock, zone, labels, message ]
    end)
  end

  def changes_by_day(base) do
    changes(base)
    |> Enum.group_by(fn [_, day | _] -> day end)
    |> Enum.sort(:desc)
  end

  def measure(base, address, branch \\ "main") do
    case Git.new(base) |> Git.cat_file(["blob", "#{branch}:#{address}"]) do
      {:error, response } -> response.message |> IO.inspect(label: "Error reading node")
      {:ok, blob } -> blob
    end
  end

end

# more graph flags:
  # https://mermaid.js.org/syntax/gitgraph.html
    # "--graph",
  # colors:
    # "--format=format:%C(red)%h %G?%C(reset) %C(cyan)(%ai)%C(reset) %C(yellow)%aN:%C(reset) %s %C(blue)%d%C(reset)",
      # "--all",
  # def graph(base) do
  # end