From ac0355f68f74a6c50f581dd8b988357196e3b2ce Mon Sep 17 00:00:00 2001 From: Kip Cole Date: Tue, 5 Mar 2024 09:57:35 +1100 Subject: [PATCH] Use github CI and improve docs --- .github/workflows/ci.yml | 106 +++++++++++++++++++++++++++++++++++++++ README.md | 12 ++--- lib/cldr_trans.ex | 85 +++++++++++-------------------- mix.lock | 32 ++++++------ 4 files changed, 158 insertions(+), 77 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b5b4a83 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,106 @@ +name: Elixir CI + +# Define workflow that runs when changes are pushed to the +# `main` branch or pushed to a PR branch that targets the `main` +# branch. Change the branch name if your project uses a +# different name for the main branch like "master" or "production". +on: + push: + branches: [ "main" ] # adapt branch for project + pull_request: + branches: [ "main" ] # adapt branch for project + +# Sets the ENV `MIX_ENV` to `test` for running tests +env: + MIX_ENV: test + +permissions: + contents: read + +jobs: + test: + Set up a Postgres DB service. By default, Phoenix applications + use Postgres. This creates a database for running tests. + Additional services can be defined here if required. + services: + db: + image: postgres:12 + ports: ['5432:5432'] + env: + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + runs-on: ubuntu-latest + name: Test on OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} + strategy: + # Specify the OTP and Elixir versions to use when building + # and running the workflow steps. + matrix: + otp: ['25.3.2'] # Define the OTP version [required] + elixir: ['1.14.4'] # Define the elixir version [required] + steps: + # Step: Setup Elixir + Erlang image as the base. + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.otp}} + elixir-version: ${{matrix.elixir}} + + # Step: Check out the code. + - name: Checkout code + uses: actions/checkout@v3 + + # Step: Define how to cache deps. Restores existing cache if present. + - name: Cache deps + id: cache-deps + uses: actions/cache@v3 + env: + cache-name: cache-elixir-deps + with: + path: deps + key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-mix-${{ env.cache-name }}- + + # Step: Define how to cache the `_build` directory. After the first run, + # this speeds up tests runs a lot. This includes not re-compiling our + # project's downloaded deps every run. + - name: Cache compiled build + id: cache-build + uses: actions/cache@v3 + env: + cache-name: cache-compiled-build + with: + path: _build + key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-mix-${{ env.cache-name }}- + ${{ runner.os }}-mix- + + # Step: Download project dependencies. If unchanged, uses + # the cached version. + - name: Install dependencies + run: mix deps.get + + # Step: Compile the project treating any warnings as errors. + # Customize this step if a different behavior is desired. + - name: Compiles without warnings + run: mix compile --warnings-as-errors + + # Step: Check that the checked in code has already been formatted. + # This step fails if something was found unformatted. + # Customize this step as desired. + # - name: Check Formatting + # run: mix format --check-formatted + + # Step: Execute the tests. + - name: Run tests + run: mix test + + # Step: Execute dialyzer. + - name: Run dialyzer + run: mix dialyzer diff --git a/README.md b/README.md index 81e2425..320c49e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Cldr Trans -![Build Status](http://sweatbox.noexpectations.com.au:8080/buildStatus/icon?job=cldr_trans) +![Build status](https://github.com/elixir-cldr/cldr_trans/actions/workflows/ci.yml/badge.svg) [![Hex.pm](https://img.shields.io/hexpm/v/ex_cldr_trans.svg)](https://hex.pm/packages/ex_cldr_trans) [![Hex.pm](https://img.shields.io/hexpm/dw/ex_cldr_trans.svg?)](https://hex.pm/packages/ex_cldr_trans) [![Hex.pm](https://img.shields.io/hexpm/dt/ex_cldr_trans.svg?)](https://hex.pm/packages/ex_cldr_trans) @@ -12,7 +12,7 @@ The package can be installed by adding `ex_cldr_trans` to your list of dependenc ```elixir def deps do [ - {:ex_cldr_trans, "~> 1.1"} + {:ex_cldr_trans, "~> 1.0"} ] end ``` @@ -143,8 +143,8 @@ defmodule MyApp.Article do schema "articles" do field :title, :string field :body, :string - # use the 'translations' macro to set up a map-field with a set of nested - # structs to handle translation values for each configured locale and each + # use the 'translations' macro to set up a map-field with a set of nested + # structs to handle translation values for each configured locale and each # translatable field translations :translations end @@ -152,7 +152,7 @@ defmodule MyApp.Article do def changeset(article, params \\ %{}) do article |> cast(params, [:title, :body]) - # use 'cast_embed' to handle values for the 'translations' map-field with + # use 'cast_embed' to handle values for the 'translations' map-field with # a nested changeset |> cast_embed(:translations, with: &translations_changeset/2) |> validate_required([:title, :body]) @@ -163,7 +163,7 @@ defmodule MyApp.Article do translations |> cast(params, []) # use 'cast_embed' to handle values for translated fields for each of the - # configured languages with a changeset defined by the 'translations' macro + # configured languages with a changeset defined by the 'translations' macro # above |> cast_embed(:es) |> cast_embed(:fr) diff --git a/lib/cldr_trans.ex b/lib/cldr_trans.ex index 122f581..a3086b5 100644 --- a/lib/cldr_trans.ex +++ b/lib/cldr_trans.ex @@ -1,29 +1,45 @@ defmodule Cldr.Trans do @moduledoc """ - Manage translations embedded into structs. + Manage translations embedded into translation structs. - Although it can be used with any struct **`Trans` shines when paired with an `Ecto.Schema`**. It + Although it can be used with any struct **`Cldr.Trans` shines when paired with an `Ecto.Schema`**. It allows you to keep the translations into a field of the schema and avoids requiring extra tables for translation storage and complex _joins_ when retrieving translations from the database. - `Trans` is split into two main components: + `Cldr.Trans` is split into two main components: - * `Trans.Translator` - provides easy access to struct translations. - * `Trans.QueryBuilder` - provides helpers for querying translations using `Ecto.Query` + * `Cldr.Trans.Translator` - provides easy access to struct translations. + * `Cldr.Trans.QueryBuilder` - provides helpers for querying translations using `Ecto.Query` (requires `Ecto.SQL`). - When used, `Trans` accepts the following options: + When used, `Cldr.Trans` accepts the following options: * `:translates` (required) - list of the fields that will be translated. - * `:container` (optional) - name of the field that contains the embedded translations. - Defaults to`:translations`. * `:default_locale` (optional) - declares the locale of the base untranslated column. Defaults to the `default_locale` configured for the Cldr backend. - ## Structured translations + ### Structured translations Structured translations are the preferred and recommended way of using `Trans`. To use structured - translations **you must define the translations as embedded schemas**: + translations, use the `translations/1` macro when defining a schema. The `translations/1` macro + will define an embedded schema with the name being the parameter passed to the `translations/1` + macro. Within the `:translations` field that is generated, an `embeds_one/2` call is added for + locale configured in the `MyApp.Cldr` backend module. Here's an example schema configuraiton: + + defmodule MyApp.Article do + use Ecto.Schema + use MyApp.Cldr.Trans, translates: [:title, :body] + + schema "articles" do + field :title, :string + field :body, :string + translations :translations + end + end + + When expanded by the Elxir compiler, the example above will look like the following code + (assuming the `MyApp.Cldr` is configured with three locales: `:en`, `:es` and `:fr`). It is + provided here only as an example to show what the `translations/1` macro compiles to. defmodule MyApp.Article do use Ecto.Schema @@ -50,57 +66,16 @@ defmodule Cldr.Trans do end end - Although they required more code than free-form translations, **structured translations provide - some nice benefits** that make them the preferred way of using `Trans`: - - * High flexibility when making validations and transformation using the embedded schema's own - changeset. - * Easy to integrate with HTML forms leveraging the capabilities of [Phoenix.HTML.Form.inputs_for/2](https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html#module-nested-inputs) - * Easy navegability using the dot notation. - - ## Free-form translations - - Free-form translations were the main way of using `Trans` until the 2.3.0 version. They are still - supported for compatibility with older versions but not recommended for new projects. - - To use free-form translations you must define the translations as a map: - - defmodule MyApp.Article do - use Ecto.Schema - use MyApp.Cldr.Trans, translates: [:title, :body] - - schema "articles" do - field :title, :string - field :body, :string - field :translations, :map - end - end - - Although they require less code, **free-form translations provide much less guarantees**: - - * There is no way to tell what content and which form will be stored in the translations field. - * Hard to integrate with HTML forms since the Phoenix helpers are not available. - * Difficult navigation requiring the braces notation from the `Access` protocol. - - ## The translation container - - As we have seen in the previous examples, `Trans` automatically stores and looks for translations - in a field called `:translations`. This is known as the **translations container.** - - In certain cases you may want to use a different field for storing the translations, this can - be specified when using `Trans` in your module. - - # Use the field `:locales` as translation container instead of the default `:translations` - use Trans, translates: [...], container: :locales - - ## Reflection + ### Reflection Any module that uses `Trans` will have an autogenerated `__trans__` function that can be used for runtime introspection of the translation metadata. * `__trans__(:fields)` - Returns the list of translatable fields. * `__trans__(:container)` - Returns the name of the translation container. - * `__trans__(:default_locale)` - Returns the name of default locale. + * `__trans__(:default_locale)` - Returns the name of default locale. The locale of the fields + in the main schema are considered to be in the language of the default locale. + """ alias Cldr.Locale diff --git a/mix.lock b/mix.lock index 2ef7ab7..ef2a3d6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,20 +1,20 @@ %{ - "cldr_utils": {:hex, :cldr_utils, "2.18.0", "674a2941abfd501a338b02244985feb7e526b1b41417b305c45a682e1f7b07b0", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "b435777ae33e8e86cfbeb96437881cf751d5062f366dacdae2e6548f83257a52"}, + "cldr_utils": {:hex, :cldr_utils, "2.24.2", "364fa30be55d328e704629568d431eb74cd2f085752b27f8025520b566352859", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3362b838836a9f0fa309de09a7127e36e67310e797d556db92f71b548832c7cf"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, - "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"}, - "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, - "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, - "ecto": {:hex, :ecto, "3.8.4", "e06b8b87e62b27fea17fd2ff6041572ddd10339fd16cdf58446e402c6c90a74b", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9244288b8d42db40515463a008cf3f4e0e564bb9c249fe87bf28a6d79fe82d4"}, - "ecto_sql": {:hex, :ecto_sql, "3.8.3", "a7d22c624202546a39d615ed7a6b784580391e65723f2d24f65941b4dd73d471", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.8.4", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "348cb17fb9e6daf6f251a87049eafcb57805e2892e5e6a0f5dea0985d367329b"}, + "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, + "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, + "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"}, + "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_cldr": {:hex, :ex_cldr, "2.33.0", "fd1f3752164ace38b2d7986fd948bf49d1037ee1ad7007a2349c5411e482f33f", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.18", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "a46ced45b47fc4ebafbb7ffdaf496a3b34fe6bd78ce4cadfbc6920eb3d190ae7"}, - "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, - "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, - "postgrex": {:hex, :postgrex, "0.16.4", "26d998467b4a22252285e728a29d341e08403d084e44674784975bb1cd00d2cb", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "3234d1a70cb7b1e0c95d2e242785ec2a7a94a092bbcef4472320b950cfd64c5f"}, - "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, + "ex_cldr": {:hex, :ex_cldr, "2.37.5", "9da6d97334035b961d2c2de167dc6af8cd3e09859301a5b8f49f90bd8b034593", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "74ad5ddff791112ce4156382e171a5f5d3766af9d5c4675e0571f081fe136479"}, + "ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, }