View Source Igniter.Project.MixProject (igniter v0.5.0)

Codemods and utilities for updating project configuration in mix.exs.

Summary

Functions

Updates the project configuration AST at the given path.

Functions

update(igniter, function_name, path, update_fun)

@spec update(
  Igniter.t(),
  function_name :: atom(),
  path :: [atom(), ...],
  update_fun :: (Sourceror.Zipper.t() | nil ->
                   {:ok,
                    Sourceror.Zipper.t() | nil | {:code, quoted :: Macro.t()}}
                   | {:error | :warning, term()}
                   | :error)
) :: Igniter.t()

Updates the project configuration AST at the given path.

This function accepts a function_name atom corresponding to a function like project/0, application/0, or cli/0 and navigates to the given path, jumping to private functions if necessary and creating nested keyword lists if they don't already exist. It then calls the given update_fun, using the return value to update the AST.

update_fun must be a function that accepts one argument, a zipper targeting the current AST at the given configuration path or nil if there was no value at that path. It then must return one of the following:

  • {:ok, zipper} - the updated zipper
  • {:ok, {:code, quoted}} - a quoted expression that should be inserted as the new value at path
  • {:ok, nil} - indicates that the last key in path should be removed
  • {:error, message} or {:warning, message} - an error or warning that should be added to igniter
  • :error - indicates igniter should be returned without change

Examples

Assuming a newly-generated Mix project that looks like:

defmodule Example.MixProject do
  use Mix.Project

  def project do
    [
      app: :example,
      version: "0.1.0",
      elixir: "~> 1.17",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger]
    ]
  end

  defp deps do
    []
  end
end

Increment the project version by one patch level

Igniter.Project.MixProject.update(igniter, :project, [:version], fn zipper ->
  new_version =
    zipper.node
    |> Version.parse!()
    |> Map.update!(:patch, &(&1 + 1))
    |> to_string()

  {:ok, {:code, new_version}}
end)

# would result in
def project do
  [
    ...,
    version: "0.1.1",
    ...
  ]
end

Set the preferred env for a task to :test

Igniter.Project.MixProject.update(
  igniter,
  :cli,
  [:preferred_envs, :"some.task"],
  fn _ -> {:ok, {:code, :test}} end
)

# would create `cli/0` and set the env:
def cli do
  [
    preferred_envs: [
      "some.task": :test
    ]
  ]
end

Add :some_application to :extra_applications

Igniter.Project.MixProject.update(igniter, :application, [:extra_applications], fn
  nil -> {:ok, {:code, [:some_application]}}
  zipper -> Igniter.Code.List.append_to_list(zipper, :some_application)
end)

# would result in
def application do
  [
    extra_applications: [:logger, :some_application]
  ]
end

Remove :extra_applications altogether

Igniter.Project.MixProject.update(
  igniter,
  :application,
  [:extra_applications],
  fn _ -> {:ok, nil} end
)

# would result in
def application do
  []
end