# `Envious`
[🔗](https://github.com/jax-ex/envious/blob/main/lib/envious.ex#L1)

Parser for .env files.

Envious provides a simple, functional parser for .env files.
It does not mutate the environment or have any side effects.

## Example

    iex> Envious.parse("KEY=value")
    {:ok, %{"KEY" => "value"}}

    iex> Envious.parse("""
    ...> export FOO=bar
    ...> # This is a comment
    ...> BAZ=qux
    ...> """)
    {:ok, %{"FOO" => "bar", "BAZ" => "qux"}}

## Variable Interpolation

Enable shell-style variable interpolation with the `:interpolate` option:

    iex> Envious.parse("BASE=/app\nPATH=$BASE/bin", interpolate: true)
    {:ok, %{"BASE" => "/app", "PATH" => "/app/bin"}}

See `parse/2` for all available options.

## Using Envious

You can `use Envious` to import both the parser functions and the environment
variable helpers:

    use Envious

    # Now you have access to:
    parse!/1, parse!/2        # from Envious
    optional/1, optional/2    # from Envious.Env
    required!/1               # from Envious.Env
    integer!/1, float!/1, etc.  # from Envious.Env

# `interpolation_opt`

```elixir
@type interpolation_opt() :: {:interpolate, boolean()}
```

# `parse_opt`

```elixir
@type parse_opt() :: interpolation_opt() | undefined_vars_opt()
```

# `undefined_vars_opt`

```elixir
@type undefined_vars_opt() :: {:undefined_vars, :keep | :empty | :error}
```

# `parse`

```elixir
@spec parse(String.t(), [parse_opt()]) :: {:ok, map()} | {:error, String.t()}
```

Parse a .env file string into a map.

## Options

- `:interpolate` - Enable variable interpolation with `$VAR` or `${VAR}` syntax.
  Defaults to `false`.
- `:undefined_vars` - How to handle undefined variables when interpolation is enabled:
  - `:keep` - Keep the literal `$VAR` text (default, safest)
  - `:empty` - Replace with empty string (shell-compatible)
  - `:error` - Return an error for undefined variables

## Examples

    iex> Envious.parse("PORT=3000")
    {:ok, %{"PORT" => "3000"}}

    iex> Envious.parse("export API_KEY=secret\nDATABASE_URL=postgres://localhost")
    {:ok, %{"API_KEY" => "secret", "DATABASE_URL" => "postgres://localhost"}}

    # Interpolation disabled by default
    iex> Envious.parse("A=foo\nB=$A")
    {:ok, %{"A" => "foo", "B" => "$A"}}

    # Enable interpolation
    iex> Envious.parse("A=foo\nB=$A", interpolate: true)
    {:ok, %{"A" => "foo", "B" => "foo"}}

    # Undefined variables with :keep (default)
    iex> Envious.parse("B=$UNDEFINED", interpolate: true)
    {:ok, %{"B" => "$UNDEFINED"}}

    # Undefined variables with :empty
    iex> Envious.parse("B=$UNDEFINED", interpolate: true, undefined_vars: :empty)
    {:ok, %{"B" => ""}}

    iex> Envious.parse("KEY=value\n!INVALID")
    {:error, ~s(Parse error at line 2, column 1: could not parse remaining input starting with: "!INVALID")}

# `parse!`

```elixir
@spec parse!(String.t(), [parse_opt()]) :: map()
```

Parse a .env file string into a map, raising on error.

Same as `parse/2` but raises a `RuntimeError` if the input cannot be parsed
or if an undefined variable error occurs.

## Examples

    iex> Envious.parse!("PORT=3000")
    %{"PORT" => "3000"}

    iex> Envious.parse!("export API_KEY=secret\nDATABASE_URL=postgres://localhost")
    %{"API_KEY" => "secret", "DATABASE_URL" => "postgres://localhost"}

    iex> Envious.parse!("A=foo\nB=$A", interpolate: true)
    %{"A" => "foo", "B" => "foo"}

    iex> Envious.parse!("INVALID")
    ** (RuntimeError) Parse error at line 1, column 1: could not parse remaining input starting with: "INVALID"

---

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