From f5d8af1db118ba87fccf59e3150d2c1dd58fd492 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 13 Oct 2020 19:54:24 +0200 Subject: Move Consistency.FileLocation to ./test This fixes a compilation fail because of Credo's absence in MIX_ENV=prod --- .credo.exs | 2 +- lib/credo/check/consistency/file_location.ex | 166 -------------------------- test/credo/check/consistency/file_location.ex | 166 ++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 167 deletions(-) delete mode 100644 lib/credo/check/consistency/file_location.ex create mode 100644 test/credo/check/consistency/file_location.ex diff --git a/.credo.exs b/.credo.exs index 83e34a2b4..b85898af3 100644 --- a/.credo.exs +++ b/.credo.exs @@ -25,7 +25,7 @@ # # If you create your own checks, you must specify the source files for # them here, so they can be loaded by Credo before running the analysis. - requires: ["./lib/credo/check/consistency/file_location.ex"], + requires: ["./test/credo/check/consistency/file_location.ex"], # # Credo automatically checks for updates, like e.g. Hex does. # You can disable this behaviour below: diff --git a/lib/credo/check/consistency/file_location.ex b/lib/credo/check/consistency/file_location.ex deleted file mode 100644 index 500983608..000000000 --- a/lib/credo/check/consistency/file_location.ex +++ /dev/null @@ -1,166 +0,0 @@ -# Pleroma: A lightweight social networking server -# Originally taken from -# https://github.com/VeryBigThings/elixir_common/blob/master/lib/vbt/credo/check/consistency/file_location.ex -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Credo.Check.Consistency.FileLocation do - @moduledoc false - - # credo:disable-for-this-file Credo.Check.Readability.Specs - - @checkdoc """ - File location should follow the namespace hierarchy of the module it defines. - - Examples: - - - `lib/my_system.ex` should define the `MySystem` module - - `lib/my_system/accounts.ex` should define the `MySystem.Accounts` module - """ - @explanation [warning: @checkdoc] - - @special_namespaces [ - "controllers", - "views", - "operations", - "channels" - ] - - # `use Credo.Check` required that module attributes are already defined, so we need - # to place these attributes - # before use/alias expressions. - # credo:disable-for-next-line VBT.Credo.Check.Consistency.ModuleLayout - use Credo.Check, category: :warning, base_priority: :high - - alias Credo.Code - - def run(source_file, params \\ []) do - case verify(source_file, params) do - :ok -> - [] - - {:error, module, expected_file} -> - error(IssueMeta.for(source_file, params), module, expected_file) - end - end - - defp verify(source_file, params) do - source_file.filename - |> Path.relative_to_cwd() - |> verify(Code.ast(source_file), params) - end - - @doc false - def verify(relative_path, ast, params) do - if verify_path?(relative_path, params), - do: ast |> main_module() |> verify_module(relative_path, params), - else: :ok - end - - defp verify_path?(relative_path, params) do - case Path.split(relative_path) do - ["lib" | _] -> not exclude?(relative_path, params) - ["test", "support" | _] -> false - ["test", "test_helper.exs"] -> false - ["test" | _] -> not exclude?(relative_path, params) - _ -> false - end - end - - defp exclude?(relative_path, params) do - params - |> Keyword.get(:exclude, []) - |> Enum.any?(&String.starts_with?(relative_path, &1)) - end - - defp main_module(ast) do - {_ast, modules} = Macro.prewalk(ast, [], &traverse/2) - Enum.at(modules, -1) - end - - defp traverse({:defmodule, _meta, args}, modules) do - [{:__aliases__, _, name_parts}, _module_body] = args - {args, [Module.concat(name_parts) | modules]} - end - - defp traverse(ast, state), do: {ast, state} - - # empty file - shouldn't really happen, but we'll let it through - defp verify_module(nil, _relative_path, _params), do: :ok - - defp verify_module(main_module, relative_path, params) do - parsed_path = parsed_path(relative_path, params) - - expected_file = - expected_file_base(parsed_path.root, main_module) <> - Path.extname(parsed_path.allowed) - - cond do - expected_file == parsed_path.allowed -> - :ok - - special_namespaces?(parsed_path.allowed) -> - original_path = parsed_path.allowed - - namespace = - Enum.find(@special_namespaces, original_path, fn namespace -> - String.contains?(original_path, namespace) - end) - - allowed = String.replace(original_path, "/" <> namespace, "") - - if expected_file == allowed, - do: :ok, - else: {:error, main_module, expected_file} - - true -> - {:error, main_module, expected_file} - end - end - - defp special_namespaces?(path), do: String.contains?(path, @special_namespaces) - - defp parsed_path(relative_path, params) do - parts = Path.split(relative_path) - - allowed = - Keyword.get(params, :ignore_folder_namespace, %{}) - |> Stream.flat_map(fn {root, folders} -> Enum.map(folders, &Path.join([root, &1])) end) - |> Stream.map(&Path.split/1) - |> Enum.find(&List.starts_with?(parts, &1)) - |> case do - nil -> - relative_path - - ignore_parts -> - Stream.drop(ignore_parts, -1) - |> Enum.concat(Stream.drop(parts, length(ignore_parts))) - |> Path.join() - end - - %{root: hd(parts), allowed: allowed} - end - - defp expected_file_base(root_folder, module) do - {parent_namespace, module_name} = module |> Module.split() |> Enum.split(-1) - - relative_path = - if parent_namespace == [], - do: "", - else: parent_namespace |> Module.concat() |> Macro.underscore() - - file_name = module_name |> Module.concat() |> Macro.underscore() - - Path.join([root_folder, relative_path, file_name]) - end - - defp error(issue_meta, module, expected_file) do - format_issue(issue_meta, - message: - "Mismatch between file name and main module #{inspect(module)}. " <> - "Expected file path to be #{expected_file}. " <> - "Either move the file or rename the module.", - line_no: 1 - ) - end -end diff --git a/test/credo/check/consistency/file_location.ex b/test/credo/check/consistency/file_location.ex new file mode 100644 index 000000000..500983608 --- /dev/null +++ b/test/credo/check/consistency/file_location.ex @@ -0,0 +1,166 @@ +# Pleroma: A lightweight social networking server +# Originally taken from +# https://github.com/VeryBigThings/elixir_common/blob/master/lib/vbt/credo/check/consistency/file_location.ex +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Credo.Check.Consistency.FileLocation do + @moduledoc false + + # credo:disable-for-this-file Credo.Check.Readability.Specs + + @checkdoc """ + File location should follow the namespace hierarchy of the module it defines. + + Examples: + + - `lib/my_system.ex` should define the `MySystem` module + - `lib/my_system/accounts.ex` should define the `MySystem.Accounts` module + """ + @explanation [warning: @checkdoc] + + @special_namespaces [ + "controllers", + "views", + "operations", + "channels" + ] + + # `use Credo.Check` required that module attributes are already defined, so we need + # to place these attributes + # before use/alias expressions. + # credo:disable-for-next-line VBT.Credo.Check.Consistency.ModuleLayout + use Credo.Check, category: :warning, base_priority: :high + + alias Credo.Code + + def run(source_file, params \\ []) do + case verify(source_file, params) do + :ok -> + [] + + {:error, module, expected_file} -> + error(IssueMeta.for(source_file, params), module, expected_file) + end + end + + defp verify(source_file, params) do + source_file.filename + |> Path.relative_to_cwd() + |> verify(Code.ast(source_file), params) + end + + @doc false + def verify(relative_path, ast, params) do + if verify_path?(relative_path, params), + do: ast |> main_module() |> verify_module(relative_path, params), + else: :ok + end + + defp verify_path?(relative_path, params) do + case Path.split(relative_path) do + ["lib" | _] -> not exclude?(relative_path, params) + ["test", "support" | _] -> false + ["test", "test_helper.exs"] -> false + ["test" | _] -> not exclude?(relative_path, params) + _ -> false + end + end + + defp exclude?(relative_path, params) do + params + |> Keyword.get(:exclude, []) + |> Enum.any?(&String.starts_with?(relative_path, &1)) + end + + defp main_module(ast) do + {_ast, modules} = Macro.prewalk(ast, [], &traverse/2) + Enum.at(modules, -1) + end + + defp traverse({:defmodule, _meta, args}, modules) do + [{:__aliases__, _, name_parts}, _module_body] = args + {args, [Module.concat(name_parts) | modules]} + end + + defp traverse(ast, state), do: {ast, state} + + # empty file - shouldn't really happen, but we'll let it through + defp verify_module(nil, _relative_path, _params), do: :ok + + defp verify_module(main_module, relative_path, params) do + parsed_path = parsed_path(relative_path, params) + + expected_file = + expected_file_base(parsed_path.root, main_module) <> + Path.extname(parsed_path.allowed) + + cond do + expected_file == parsed_path.allowed -> + :ok + + special_namespaces?(parsed_path.allowed) -> + original_path = parsed_path.allowed + + namespace = + Enum.find(@special_namespaces, original_path, fn namespace -> + String.contains?(original_path, namespace) + end) + + allowed = String.replace(original_path, "/" <> namespace, "") + + if expected_file == allowed, + do: :ok, + else: {:error, main_module, expected_file} + + true -> + {:error, main_module, expected_file} + end + end + + defp special_namespaces?(path), do: String.contains?(path, @special_namespaces) + + defp parsed_path(relative_path, params) do + parts = Path.split(relative_path) + + allowed = + Keyword.get(params, :ignore_folder_namespace, %{}) + |> Stream.flat_map(fn {root, folders} -> Enum.map(folders, &Path.join([root, &1])) end) + |> Stream.map(&Path.split/1) + |> Enum.find(&List.starts_with?(parts, &1)) + |> case do + nil -> + relative_path + + ignore_parts -> + Stream.drop(ignore_parts, -1) + |> Enum.concat(Stream.drop(parts, length(ignore_parts))) + |> Path.join() + end + + %{root: hd(parts), allowed: allowed} + end + + defp expected_file_base(root_folder, module) do + {parent_namespace, module_name} = module |> Module.split() |> Enum.split(-1) + + relative_path = + if parent_namespace == [], + do: "", + else: parent_namespace |> Module.concat() |> Macro.underscore() + + file_name = module_name |> Module.concat() |> Macro.underscore() + + Path.join([root_folder, relative_path, file_name]) + end + + defp error(issue_meta, module, expected_file) do + format_issue(issue_meta, + message: + "Mismatch between file name and main module #{inspect(module)}. " <> + "Expected file path to be #{expected_file}. " <> + "Either move the file or rename the module.", + line_no: 1 + ) + end +end -- cgit v1.2.3