Packages
styler
1.11.0
1.11.0
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
1.0.0-alpha.0
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.5
0.10.4
retired
0.10.3
0.10.2
0.10.1
0.10.0
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
retired
0.9.1
retired
0.9.0
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.1
0.3.0
0.2.0
0.1.1
0.1.0
A code-style enforcer that will just FIFY instead of complaining
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/remove_unused.ex
# Copyright 2025 Adobe. All rights reserved.
# This file is licensed to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed under
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
# OF ANY KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
defmodule Mix.Tasks.Styler.RemoveUnused do
@shortdoc "EXPERIMENTAL: uses unused import/alias/require compiler warnings to remove those lines"
@moduledoc """
WARNING: EXPERIMENTAL | Removes unused import/alias/require statements by compiling the app and parsing warnings, then deleting the specified lines.
Usage:
mix styler.remove_unused
"""
use Mix.Task
alias Mix.Shell.IO
@impl Mix.Task
def run(_) do
# Warnings come over stderr, so gotta redirect
{output, _} = System.cmd("mix", ~w(compile --all-warnings), stderr_to_stdout: true)
if output =~ "warning: unused" do
IO.info("Removing unused import/alias/require lines...\n")
output
|> String.split("\n\n")
|> Stream.map(&Regex.run(~r/warning\: unused (alias|require|import).* (.*\.exs?):(\d+)\:/s, &1))
|> Stream.filter(& &1)
|> Stream.map(fn [_full_message, _require_or_alias, file, line] ->
file =
if File.exists?(file) do
file
else
[umbrella_corrected] = Path.wildcard("apps/*/#{file}")
umbrella_corrected
end
{file, String.to_integer(line)}
end)
|> Enum.group_by(fn {file, _} -> file end, fn {_, line} -> line end)
|> Enum.sort_by(fn {file, _} -> file end)
|> Enum.each(fn {file, lines} ->
contents = file |> File.read!() |> String.split("\n")
IO.info("==> #{file}")
lines
|> Enum.sort()
|> Enum.each(&IO.info("#{&1}: #{Enum.at(contents, &1 - 1)}"))
contents =
lines
|> Enum.sort(:desc)
|> Enum.reduce(contents, &List.delete_at(&2, &1 - 1))
|> Enum.join("\n")
File.write!(file, contents)
IO.info("")
end)
IO.info("Running `mix format` to remove any excess newlines.")
Mix.Task.run("format")
IO.info("Done.")
else
IO.info("No \"unused\" warnings detected, no work to do.")
end
end
end