Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make exports: :all also export subdomains #68

Merged
merged 4 commits into from
Oct 4, 2024
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
5 changes: 3 additions & 2 deletions lib/boundary.ex
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ defmodule Boundary do
export all of these modules with the `exports: [{Schemas, except: [Base]}, ...]`. This will
export all `MySystem.Schemas.*` modules, except for `MySystem.Schemas.Base`.
You can also export all modules of the boundary with `use Boundary, exports: :all`. To exclude
some modules from the export list use, `use Boundary, exports: {:all, except: [SomeMod, ...]}`.
You can also export all modules of the boundary with `use Boundary, exports: :all`. This will also
export all sub-modules of the boundary. To exclude some modules from the export list use,
`use Boundary, exports: {:all, except: [SomeMod, ...]}`.
Mass export is not advised in most situations. Prefer explicitly listing exported modules. If
your export list is long, it's a possible indication of an overly fragmented interface. Consider
Expand Down
11 changes: 9 additions & 2 deletions lib/boundary/checker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,15 @@ defmodule Boundary.Checker do
|> Stream.take_while(&(not is_nil(&1)))
|> Enum.find(&(Enum.at(&1.ancestors, 0) == boundary.name))
|> case do
nil -> false
child_subboundary -> export in [child_subboundary.name | child_subboundary.exports]
nil ->
false

# If the export's `owner_boundary` exports all modules, include sub-modules
%{exports: [{export_module, []}]} ->
String.starts_with?(to_string(export), to_string(export_module))
Comment on lines +133 to +135
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understand, this will also export private sub-boundary modules. I find this a bit weird, because we can end up with a scenario that some modules are private to other modules in the common parent boundary, but they can be used by the modules outside of that parent boundary.

So I think we should only include public sub-boundary modules, as mentioned in the last comment in #59.

Bubbling up should also work, for example:

  • if Foo.Bar.Baz is a sub-sub-boundary
  • and Foo.Bar exports Foo.Bar.Baz
  • then exporting all from Foo should also include exports from Foo.Bar.Baz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with the updated exports: [Module] test, this logic still seems to work, I think because this function is only looking at the current export and its immediate parent boundary?

I tried writing a few different tests to see if they'd fail but couldn't find any issues with the exported vs private sub-boundaries.


child_subboundary ->
export in [child_subboundary.name | child_subboundary.exports]
end
end
end
Expand Down
24 changes: 22 additions & 2 deletions test/mix/tasks/compile/boundary_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1147,13 +1147,27 @@ defmodule Mix.Tasks.Compile.BoundaryTest do
module1 = unique_module_name()
module2 = unique_module_name()

module_test "exporting all modules",
module_test "exporting all modules and exports of all nested boundaries",
"""
defmodule #{module1} do
use Boundary, exports: :all

defmodule Schemas.Foo do def fun(), do: :ok end
defmodule Schemas.Bar do def fun(), do: :ok end

defmodule SubModule do
use Boundary, exports: [Module]

def fun(), do: :ok

defmodule Module do
def fun(), do: :ok

defmodule Private do
def fun(), do: :ok
end
end
end
end

defmodule #{module2} do
Expand All @@ -1163,10 +1177,16 @@ defmodule Mix.Tasks.Compile.BoundaryTest do
#{module1}.Schemas.Foo.fun()
#{module1}.Schemas.Bar.fun()
#{module1}.Schemas.Base.fun()
#{module1}.SubModule.fun()
#{module1}.SubModule.Module.fun()
#{module1}.SubModule.Module.Private.fun()
end
end
""" do
assert warnings == []
assert [warning] = warnings

assert warning.message =~
"forbidden reference to #{unquote(module1)}.SubModule.Module.Private"
end

module1 = unique_module_name()
Expand Down
Loading