Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ Callers get Igniter's normal diff preview and confirmation flow.
| `sort_properties/2`, `remove_duplicates/2` | tidying, by moving and deleting whole lines |

**Queries** — read-only: `has_rule?/3`, `has_declaration?/4`, `has_at_rule?/3`,
`get_declaration/4`, `get_rule_declarations/3`, `list_selectors/2`, `analyze/2`,
`get_declaration/4`, `get_rule_declarations/3`, `get_at_rules/4`,
`list_selectors/2`, `analyze/2`,
`validate/2`, `extract_colors/2`, `extract_media_queries/2`,
`extract_animations/2`.

Expand Down
43 changes: 43 additions & 0 deletions lib/igniter_css.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,26 @@ defmodule IgniterCss do
Native.ensure_at_rule_nif(source, line, ParseOpts.new(opts)) |> unwrap()
end

@doc """
Give the top-level at-rule `name` this block, replacing an existing body or
inserting the whole rule when there is none.

`declarations` is spliced in verbatim, re-indented to the file. `matching`
narrows to one target the way `remove_at_rule/4` does, and is carried into the
prelude.

iex> css = ~s|@import "tailwindcss";\\n|
iex> {:ok, out} = IgniterCss.ensure_at_rule_block(css, "theme", nil, "--color-a: red;")
iex> out.source
~s|@import "tailwindcss";\\n@theme {\\n --color-a: red;\\n}\\n|
"""
@spec ensure_at_rule_block(String.t(), String.t(), String.t() | nil, String.t(), opts()) ::
result()
def ensure_at_rule_block(source, name, matching \\ nil, declarations, opts \\ []) do
Native.ensure_at_rule_block_nif(source, name, matching, declarations, ParseOpts.new(opts))
|> unwrap()
end

@doc """
Remove top-level at-rules of `name`.

Expand All @@ -128,6 +148,29 @@ defmodule IgniterCss do
Native.has_at_rule_nif(source, line, ParseOpts.new(opts)) |> unwrap()
end

@doc """
Every top-level at-rule named `name`, as `IgniterCss.AtRule` structs.

Pass `matching` to narrow to a single target — the string or `url()` before
the block. Returns `[]` when nothing matches; absence is an answer, not an
error.

Unlike `has_at_rule?/3`, this hands back the at-rule's block, so a caller can
read a decision out of it rather than only confirm the line exists:

iex> css = ~s|@plugin "daisyui" { prefix: "d-"; }|
iex> {:ok, [rule]} = IgniterCss.get_at_rules(css, "plugin", "daisyui")
iex> rule.declarations
[{"prefix", ~s|"d-"|}]

The leading `@` in `name` is optional.
"""
@spec get_at_rules(String.t(), String.t(), String.t() | nil, opts()) ::
{:ok, [IgniterCss.AtRule.t()]} | {:error, String.t()}
def get_at_rules(source, name, matching \\ nil, opts \\ []) do
Native.get_at_rules_nif(source, name, matching, ParseOpts.new(opts)) |> unwrap()
end

@doc """
Add an `@import`, building the line for you.

Expand Down
24 changes: 24 additions & 0 deletions lib/igniter_css/codemods.ex
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,34 @@ defmodule IgniterCss.Codemods do
end)
end

@doc "See `IgniterCss.ensure_at_rule_block/5`."
def ensure_at_rule_block(igniter, path, name, matching \\ nil, declarations, opts \\ []) do
update(igniter, path, "ensure_at_rule_block #{inspect(name)}", fn source ->
IgniterCss.ensure_at_rule_block(source, name, matching, declarations, opts)
end)
end

@doc "See `IgniterCss.remove_at_rule/4`."
def remove_at_rule(igniter, path, name, matching \\ nil, opts \\ []) do
update(igniter, path, "remove_at_rule #{inspect(name)}", fn source ->
IgniterCss.remove_at_rule(source, name, matching, opts)
end)
end

@doc "See `IgniterCss.add_import/4`."
def add_import(igniter, path, url, media \\ nil, opts \\ []) do
update(igniter, path, "add_import #{inspect(url)}", fn source ->
IgniterCss.add_import(source, url, media, opts)
end)
end

@doc "See `IgniterCss.remove_import/3`."
def remove_import(igniter, path, url, opts \\ []) do
update(igniter, path, "remove_import #{inspect(url)}", fn source ->
IgniterCss.remove_import(source, url, opts)
end)
end

@doc "See `IgniterCss.ensure_rule/4`."
def ensure_rule(igniter, path, selector, declarations \\ "", opts \\ []) do
update(igniter, path, "ensure_rule #{inspect(selector)}", fn source ->
Expand Down Expand Up @@ -123,7 +144,10 @@ defmodule IgniterCss.Codemods do
else
for {name, arity} <- [
ensure_at_rule: 4,
ensure_at_rule_block: 6,
remove_at_rule: 5,
add_import: 5,
remove_import: 4,
ensure_rule: 5,
remove_rule: 4,
set_declaration: 6,
Expand Down
9 changes: 8 additions & 1 deletion lib/igniter_css/native.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ defmodule IgniterCss.Native do
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl
),
# `rustler_precompiled`'s own documented switch. Without this the env var above is the
# only way in, and a consuming project — which has no reason to know this library's
# private variable name — cannot force a source build the standard way.
force_build:
System.get_env("IGNITERCSS_BUILD") in ["1", "true"] ||
System.get_env("ASH_CI_BUILD") in ["1", "true"]
System.get_env("ASH_CI_BUILD") in ["1", "true"] ||
Application.compile_env(:rustler_precompiled, [:force_build, :igniter_css], false)

# -- at-rules ---------------------------------------------------------------

def ensure_at_rule_nif(_source, _line, _opts), do: error()

def ensure_at_rule_block_nif(_source, _name, _matching, _declarations, _opts), do: error()
def remove_at_rule_nif(_source, _name, _matching, _opts), do: error()
def has_at_rule_nif(_source, _line, _opts), do: error()
def add_import_nif(_source, _url, _media, _opts), do: error()
Expand Down Expand Up @@ -76,6 +82,7 @@ defmodule IgniterCss.Native do
# -- analysis ---------------------------------------------------------------

def analyze_nif(_source, _opts), do: error()
def get_at_rules_nif(_source, _name, _matching, _opts), do: error()
def validate_nif(_source, _opts), do: error()
def extract_colors_nif(_source, _opts), do: error()
def extract_media_queries_nif(_source, _opts), do: error()
Expand Down
34 changes: 34 additions & 0 deletions lib/igniter_css/parsers/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,40 @@ defmodule IgniterCss.Parsers.Parser do
# Analysis
# ---------------------------------------------------------------------------

@doc """
Every top-level at-rule named `name`, as string-keyed maps.

## Examples

iex> css = ~s|@plugin "daisyui" { prefix: "d-"; }|
iex> {:ok, _, [rule]} = IgniterCss.Parsers.Parser.get_at_rules(css, "plugin", "daisyui")
iex> rule["declarations"]
[{"prefix", ~s|"d-"|}]
"""
@spec get_at_rules(String.t(), String.t(), String.t() | nil, type()) ::
{:ok, atom(), [map()]} | {:error, atom(), String.t()}
def get_at_rules(file_path_or_content, name, matching \\ nil, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn content ->
case Native.get_at_rules_nif(content, name, matching, ParseOpts.new([])) do
{:ok, fun, rules} ->
{:ok, fun,
Enum.map(rules, fn rule ->
rule
|> Map.from_struct()
|> Map.new(fn {key, value} -> {Atom.to_string(key), value} end)
end)}

other ->
other
end
end,
type
)
end

@doc """
Statistics about a stylesheet, as a string-keyed map.

Expand Down
33 changes: 33 additions & 0 deletions lib/igniter_css/structs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,39 @@ defmodule IgniterCss.Validation do
defstruct valid: false, diagnostics: 0, round_trips: false, message: ""
end

defmodule IgniterCss.AtRule do
@moduledoc """
One at-rule, read back whole.

`IgniterCss.analyze/2` reports only that an at-rule of some name exists. This
reports which one and how it was configured — the difference between knowing a
`@plugin` is present and knowing it was loaded as
`@plugin "daisyui" { prefix: "d-"; }`, which is what an installer needs before
it can generate code that agrees with the user's setup.

`declarations` is empty for an at-rule with no block, or one whose block holds
rules rather than declarations.
"""

@type t :: %__MODULE__{
name: String.t(),
prelude: String.t(),
target: String.t() | nil,
has_block: boolean(),
declarations: [{String.t(), String.t()}],
text: String.t(),
body: String.t() | nil
}

defstruct name: "",
prelude: "",
target: nil,
has_block: false,
declarations: [],
text: "",
body: nil
end

defmodule IgniterCss.Animation do
@moduledoc """
A `@keyframes` animation and the selectors that use it.
Expand Down
10 changes: 5 additions & 5 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
%{
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"credo": {:hex, :credo, "1.7.19", "cc52129665fc7c15143d47838fda0f9cd6dac9ceced7bf4da6f85fcbfe64b12a", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2d8bc95d5a7bb99dd2613621d4f08c6a3575c3fd4b62e6a2b48a100352a557b8"},
"dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"},
"dialyxir": {:hex, :dialyxir, "1.4.8", "7ef671a8aff9948b091d8c30f09467fbb16e77305cda451bce48109a0f5e021c", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cbd5a851571e5dfeb32aaf2e840bfa98b7864cb3071bf2ef5d95d1276b12e072"},
"earmark_parser": {:hex, :earmark_parser, "1.4.46", "67607a0532e810c6f630a515c548d0b24949643f168cc556303bee4cf96105c7", [:mix], [], "hexpm", "9c44636e8a1c68c62f526b2dcd85d941dbbcee7ab82cf64ba06ce28bef8e89f5"},
"erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
"ex_ast": {:hex, :ex_ast, "0.13.1", "b3d80ec163733176f63662ac44d2511445c224f6b5e4e3ce01f5eff83c4a5993", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.7", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "bd15f68cde5ec945b859bd67416f26cf5499f1aef9b067eb2163ed244c7e703a"},
"ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"},
"ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"},
"ex_doc": {:hex, :ex_doc, "0.40.4", "66f2e42bf588594d5a8aab31cad87f2ddad09d0da1b1a2f379340ec2c2e497cb", [:mix], [{:earmark_parser, "~> 1.4.46", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6222b9e423d76584ee34df2c82a5ed72c2d53dc153f7f483ad28b378694186cc"},
"file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
"finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"},
"glob_ex": {:hex, :glob_ex, "0.1.12", "7b2d9369c20e2697efcfd185d13d6e84c94cd3bfd2730fbde613141c2e015c00", [:mix], [], "hexpm", "2e2fac83f113514434c7eaf267b4c38af2f91766f1cab2c5db7053b7fc1ee0bb"},
Expand All @@ -17,19 +17,19 @@
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [: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", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
"makeup_erlang": {:hex, :makeup_erlang, "1.1.0", "835f7e60792e08824cda445639555d7bf1bbbddb1b60b306e33cb6f6db24dc74", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "1cd6780fb1dd1a03979abaed0fe82712b0625118fd5257d3ebbf73f960c73c3c"},
"mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
"mint": {:hex, :mint, "1.9.3", "3337184d69179695c7a9f1714d92c11e629d36c8c037a21cf490131d3d150554", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5f7c9342480c069dbbc4eeac3490303c9e01870ff01a7f1d29b6107054fc1e74"},
"mint": {:hex, :mint, "1.10.0", "85af3353bfc504f5bdfe494bd92b8490f87a306dc659ee1ad0af435107e898dc", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "8b16fb72aaa7531d206a1f05e4cc85509ba531ccec7a17a22736c9c95cbb24d1"},
"mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"},
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"owl": {:hex, :owl, "0.13.1", "1ec4a5dea170465f0e90c502c203079224516bc0cbd599281c8667b3c6ef8848", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "351e768af8f2edc575cdaab1a5a2f6d6381be591758a026c701c703145508a0c"},
"req": {:hex, :req, "0.7.2", "364eae2e5f5c984f2dac6d71c07f8c8c89ce0bc49c4d746dacb7a306823020de", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "c9cdfa276b05d8db2a27fda5d233e6858b764d47189d76cbb186e130a871ae0b"},
"req": {:hex, :req, "0.7.4", "23e9ffec17de032a46a4b15ed65c09793893bf4a7c680f4bbf6227fce6bdf74d", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "4b192d63253e8dcc6221ef992ea9ebef7d3555166e8423aa5b553e86bc3c69a2"},
"rewrite": {:hex, :rewrite, "1.3.0", "67448ba7975690b35ba7e7f35717efcce317dbd5963cb0577aa7325c1923121a", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "d111ac7ff3a58a802ef4f193bbd1831e00a9c57b33276e5068e8390a212714a5"},
"rustler": {:hex, :rustler, "0.38.0", "7a8906998ff0d28e3021c0a73264abcda719bda344b2e58307c6805b0f87c9b4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "704c03c1bf66be12b031c5a389347b91c81c5cb819a24b068b0de36fe4a5652a"},
"rustler_precompiled": {:hex, :rustler_precompiled, "0.9.0", "3a052eda09f3d2436364645cc1f13279cf95db310eb0c17b0d8f25484b233aa0", [:mix], [{:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "471d97315bd3bf7b64623418b3693eedd8e47de3d1cb79a0ac8f9da7d770d94c"},
"sobelow": {:hex, :sobelow, "0.15.0", "b067d7f8522a9d758fa89cb2bfcbab7ad72c45a0993cb958c989c6fd956fdd56", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "24a800e2d7fa8c3bd21561b6ad8ad4745ed726a09fd606598981d9048708da98"},
"sourceror": {:hex, :sourceror, "1.12.2", "85bfd48159f020c0cbfc72f289f11456fdc05dc43719b6f2589fb969faefa113", [:mix], [], "hexpm", "da37d3da09c5b890528802c7056a8f585a061973820d7656b6e3649c14f0e9cb"},
"spitfire": {:hex, :spitfire, "0.3.13", "edd207b065eaec57acc5484097d0aa3e97fe4246168c54e67a9af040b8dee4c1", [:mix], [], "hexpm", "3601be88ceed4967b584e96444de3e1d12d6555ae0864a7390b9cd5332d134b4"},
"spitfire": {:hex, :spitfire, "0.4.1", "69e90335d00ca328295e1e1e77cac5d7575aa6d34274e3467ebfc654b8858be3", [:mix], [], "hexpm", "27d86f67681179682b15c6758d64ac2eb2b3637ed8340800c8b885c69754cdcd"},
"telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"},
"text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"},
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
Expand Down
Loading
Loading