Detect (un)used exports from sibling projects?

I’d like to use jfmengels/elm-review-unused, but it’s a little too forward in a “monorepo”-style setup like this one, incorrectly marking some exports as unused.

Where there’s multiple sibling Elm projects and two of them refer to a third with source-directories: [ ../third/src ], is it feasible to have elm-review either:

  • treat the third as a Package, marking everything within as being used? or
  • somehow work with multiple projects at once, allowing it to correctly find unused exports from the shared project?

I have a similar problem: the main codebase I work on has many distinct entrypoints which we compile separately instead of doing a SPA. A colleague and I ended up writing a little script that will:

  1. find all the import statements in the project I want to run elm-review on.
  2. find all the modules that those import, and all the modules that import them.
  3. run elm-review on the entire list of expanded imports
  4. discard results on files that are in the expanded list but not the original list

That works pretty well!

2 Likes

Current state of affairs

elm-review only looks at a single project at a time at the moment, so it is not possible for it to work with multiple projects at once.

What I would probably do in your shoes is to treat the third project as a package, as you suggested. In this case, I think you only have to ignore the NoUnused.Exports rule for that source directory, meaning you would not lose out on too many reports, especially if you have an IDE which shows you how many times something is used in the rest of the codebase. I’m not sure that the Elm Language Server and the IntelliJ.plugin give you that out of the box, but I know that some plugin for Atom does that

You can potentially try to run elm-review from time to time without doing that, to notice and manually remove the elements that are unused in both of the other projects.

In the future?

I don’t think allowing for multi-repos is impossible, but it would require quite some work on the tool itself, and likely some setup on the user’s side too.

What does a “multirepo”-style setup mean? It means that we would run elm-review by targetting multiple elm.json files, which has several implications.

Finding the elm.json files

The user now needs to run the elm-review CLI (or in their IDE when we get to that point) by configuring it to run with all of the elm.json files. Sometjing like elm-review --elmjson project1/elm.json,../../project2/elm.json,project3/elm.json. I would imagine that this is error-prone, because if you forget to include one project (or include one too many :thinking:) , then you can get false positives or false negatives.

Dependencies

elm-review loads the dependencies of a project. When we look at a single project, it is relatively simple. But when we look at multiple elm.json, we somehow need to merge the dependencies of each project, with potentially some conflicts.
For instance, if one project depends on package A v2, and an other depends on package A but v1, but where the code compiles because they only use the unchanged API present in both versions. Our dependency solver wouldn’t be able to resolve a correct set of dependencies.

Project-aware rules

Alternatively, we could make it so that elm-review rules (like NoUnused.Dependencies and NoUnused.Exports) are aware of the multiple projects and know which files is included in which elm.json's source-directories, with elm-review not trying to resolve dependencies to a single set, but I think that would introduce a lot of complexity and I’m not sure that would even work out.

Current thoughts

I don’t know if there is a good solution to this honestly. I’m very curious as to what @brian came up with and whether it’s something that elm-review can leverage out of the box, and learn whether it causes a set of false positives or false negatives.

I would love some ideas, but this will probably not be addressed for a while, considering I have little insight in how to resolve it at the moment.

If you know of similar tools that solved this problem in other languages/ecosystems, I’d love to know!

1 Like

Thanks! I was about to ask how to actually treat it as a package, then I saw Review.Rule.ignoreErrorsForDirectories, which handles that neatly.

I’d also like to see what Brian came up with! As far as I understand it, it’s doing something like this, individually specifying all relevant modules across projects, passing that list to elm-review?

To see if I understand it:

  1. follow down the dependency graph from a single module (node) to the roots, keeping those modules in set “A”
  2. for each module from the first pass, following back up the dependency tree, keeping those modules in set “B”
  3. call elm-review with the paths to each module in the union of sets A and B
  4. prune out review errors that don’t apply to modules in set A

It’s one of those kind of internal scripts that rely on a leaning tower of weird shell scripts which you’re fine inflicting on your coworkers but wouldn’t release as open source :laughing:

Your summary is mostly there, but needs a few tweaks to avoid asking elm-review to do too much:

  1. take the list of files you care about—all of them, not just Main. I’ll call this set keep.
  2. get the set of files that import or are imported by those files. Don’t follow the import graph more than one hop away from the starting file! We don’t care about errors in places which are two or more hops away. If you have a weird circular dependency between packages but not modules, though, you may want to follow further. I’ll call this set importersAndImportees. It will definitely have some overlap with keep!
  3. call elm-review with keep + importersAndImportees
  4. prune error messages from files in importersAndImportees - keep
2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.