# `Igniter.Project.MixProject`
[🔗](https://github.com/ash-project/igniter/blob/v0.8.2/lib/igniter/project/mix_project.ex#L5)

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

# `update`

```elixir
@spec update(
  Igniter.t(),
  function_name :: atom(),
  path :: [atom(), ...],
  update_fun :: (Sourceror.Zipper.t() | nil -&gt;
                   {: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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
