# `JSONAPI.Utils.String`
[🔗](https://github.com/beam-community/jsonapi/blob/main/lib/jsonapi/utils/string.ex#L1)

String manipulation helpers.

# `camelize`

```elixir
@spec camelize(atom()) :: String.t()
@spec camelize(String.t()) :: String.t()
```

Replace underscores or dashes between words in `value` with camelCasing

Ignores underscores or dashes that are not between letters/numbers

## Examples

    iex> camelize("top_posts")
    "topPosts"

    iex> camelize(:top_posts)
    "topPosts"

    iex> camelize("_top_posts")
    "_topPosts"

    iex> camelize("_top__posts_")
    "_top__posts_"

    iex> camelize("")
    ""

    iex> camelize("alreadyCamelized")
    "alreadyCamelized"

    iex> camelize("alreadyCamelized-id")
    "alreadyCamelizedId"

    iex> camelize("alreadyCamelized_id")
    "alreadyCamelizedId"

    iex> camelize("PascalLambda_id")
    "pascalLambdaId"

# `dasherize`

```elixir
@spec dasherize(atom()) :: String.t()
@spec dasherize(String.t()) :: String.t()
```

Replace underscores between words in `value` with dashes

Ignores underscores that are not between letters/numbers

## Examples

    iex> dasherize("top_posts")
    "top-posts"

    iex> dasherize("_top_posts")
    "_top-posts"

    iex> dasherize("_top__posts_")
    "_top__posts_"

    iex> dasherize("ages_0_17")
    "ages-0-17"

# `expand_fields`

```elixir
@spec expand_fields(map(), function()) :: map()
@spec expand_fields(list(), function()) :: list()
@spec expand_fields(tuple(), function()) :: tuple()
@spec expand_fields(String.t() | atom(), function()) :: String.t()
```

## Examples

    iex> expand_fields(%{"foo-bar" => "baz"}, &underscore/1)
    %{"foo_bar" => "baz"}

    iex> expand_fields(%{"foo_bar" => "baz"}, &dasherize/1)
    %{"foo-bar" => "baz"}

    iex> expand_fields(%{"foo-bar" => "baz"}, &camelize/1)
    %{"fooBar" => "baz"}

    iex> expand_fields({"foo-bar", "dollar-sol"}, &underscore/1)
    {"foo_bar", "dollar-sol"}

    iex> expand_fields({"foo-bar", %{"a-d" => "z-8"}}, &underscore/1)
    {"foo_bar", %{"a_d" => "z-8"}}

    iex> expand_fields(%{"f-b" => %{"a-d" => "z"}, "c-d" => "e"}, &underscore/1)
    %{"f_b" => %{"a_d" => "z"}, "c_d" => "e"}

    iex> expand_fields(%{"f-b" => %{"a-d" => %{"z-w" => "z"}}, "c-d" => "e"}, &underscore/1)
    %{"f_b" => %{"a_d" => %{"z_w" => "z"}}, "c_d" => "e"}

    iex> expand_fields(:"foo-bar", &underscore/1)
    "foo_bar"

    iex> expand_fields(:foo_bar, &dasherize/1)
    "foo-bar"

    iex> expand_fields(:"foo-bar", &camelize/1)
    "fooBar"

    iex> expand_fields(%{"f-b" => "a-d"}, &underscore/1)
    %{"f_b" => "a-d"}

    iex> expand_fields(%{"inserted-at" => ~N[2019-01-17 03:27:24.776957]}, &underscore/1)
    %{"inserted_at" => ~N[2019-01-17 03:27:24.776957]}

    iex> expand_fields(%{"xValue" => 123}, &underscore/1)
    %{"x_value" => 123}

    iex> expand_fields(%{"attributes" => %{"corgiName" => "Wardel"}}, &underscore/1)
    %{"attributes" => %{"corgi_name" => "Wardel"}}

    iex> expand_fields(%{"attributes" => %{"corgiName" => ["Wardel"]}}, &underscore/1)
    %{"attributes" => %{"corgi_name" => ["Wardel"]}}

    iex> expand_fields(%{"attributes" => %{"someField" => ["SomeValue", %{"nestedField" => "Value"}]}}, &underscore/1)
    %{"attributes" => %{"some_field" => ["SomeValue", %{"nested_field" => "Value"}]}}

    iex> expand_fields([%{"fooBar" => "a"}, %{"fooBar" => "b"}], &underscore/1)
    [%{"foo_bar" => "a"}, %{"foo_bar" => "b"}]

    iex> expand_fields([%{"foo_bar" => "a"}, %{"foo_bar" => "b"}], &camelize/1)
    [%{"fooBar" => "a"}, %{"fooBar" => "b"}]

    iex> expand_fields(%{"fooAttributes" => [%{"fooBar" => "a"}, %{"fooBar" => "b"}]}, &underscore/1)
    %{"foo_attributes" => [%{"foo_bar" => "a"}, %{"foo_bar" => "b"}]}

    iex> expand_fields(%{"foo_attributes" => [%{"foo_bar" => "a"}, %{"foo_bar" => "b"}]}, &camelize/1)
    %{"fooAttributes" => [%{"fooBar" => "a"}, %{"fooBar" => "b"}]}

    iex> expand_fields(%{"foo_attributes" => [%{"foo_bar" => [1, 2]}]}, &camelize/1)
    %{"fooAttributes" => [%{"fooBar" => [1, 2]}]}

# `expand_root_keys`

Like `JSONAPI.Utils.String.expand_fields/2`, but only uses the given function to transform the
keys of a top-level map. Other values are transformed with `to_string/1`.

## Examples

    iex> expand_root_keys(%{"foo-bar" => %{"bar-baz" => "x"}}, &underscore/1)
    %{"foo_bar" => %{"bar-baz" => "x"}}

    iex> expand_root_keys(%{"foo-bar" => [:x, %{"bar-baz" => "y"}]}, &underscore/1)
    %{"foo_bar" => ["x", %{"bar-baz" => "y"}]}

# `field_transformation`

The configured transformation for the API's fields. JSON:API v1.1 recommends
using camlized fields (e.g. "goodDog", versus "good_dog").  However, we don't hold a strong
opinion, so feel free to customize it how you would like (e.g. "good-dog", versus "good_dog").

This library currently supports camelized, dashed and underscored fields. Shallow variants
exist that only transform top-level field keys.

## Configuration examples

camelCase fields:

```
config :jsonapi, field_transformation: :camelize
```

```
config :jsonapi, field_transformation: :camelize_shallow
```

Dashed fields:

```
config :jsonapi, field_transformation: :dasherize
```

```
config :jsonapi, field_transformation: :dasherize_shallow
```

Underscored fields:

```
config :jsonapi, field_transformation: :underscore
```

# `underscore`

```elixir
@spec underscore(String.t()) :: String.t()
@spec underscore(atom()) :: String.t()
```

Replace dashes between words in `value` with underscores

Ignores dashes that are not between letters/numbers

## Examples

    iex> underscore("top-posts")
    "top_posts"

    iex> underscore(:top_posts)
    "top_posts"

    iex> underscore("-top-posts")
    "-top_posts"

    iex> underscore("-top--posts-")
    "-top--posts-"

    iex> underscore("corgiAge")
    "corgi_age"

    iex> underscore("ages-0-17")
    "ages_0_17"

---

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