Forbid the use of exposed elements (functions, values or types) that are never used in your project.
🔧 Running with --fix will automatically remove all the reported errors,
except for the ones reported when using reportUnusedProductionExports.
It won't automatically remove unused modules though.
If the project is a package and the module that declared the element is exposed, then nothing will be reported.
This rule can be configured to report more unused elements than the default configuration.
Configuration for the rule. Use defaults to get a default configuration and use toRule to turn it into a rule.
You can change the configuration using reportUnusedProductionExports.
Default configuration. This will only report exported elements that are never used in other modules.
Creates a rule that reports unused exports using a Configuration.
By default, this rule only reports exposed elements that are never imported in other modules. It is however pretty common to have elements imported and used in non-production parts of the codebase, such as in tests or in a styleguide.
For instance, let's say there is a module A that exposes a function someFunction:
module A exposing (someFunction)
someFunction input =
doSomethingComplexWith inputAnd there is this test module to test A.someFunction:
module ATest exposing (tests)
import A
import Test exposing (Test, describe, test)
tests : Test
tests =
describe "A.someFunction"
[ test "does something complex" <|
\() ->
A.someFunction someInput
|> Expect.equal someExpectedOutput
]Let's say this is the only use of A.someFunction in the entire project.
Because A.someFunction is technically used in the project, this rule won't report it.
But since the function is not used in production code, it is a good practice to remove it, as that will remove the
amount of code that needs to be maintained unnecessarily. We can detect that using reportUnusedProductionExports.
Configures the rule to report elements defined in production code but only used in non-production files.
import NoUnused.Exports exposing (annotatedBy)
config =
[ NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile =
\{ moduleName, filePath, isInSourceDirectories } ->
isInSourceDirectories
&& not (String.endsWith "/Example.elm" filePath)
, exceptionsAre = [ annotatedBy "@test-helper" ]
}
|> NoUnused.Exports.toRule
]Elements reported using this configuration won't be automatically fixed as they require removing the code that uses the element.
This function needs to know two things:
Which files are considered to be production files, which is determined by a function that you provide.
Generally, production files are in the "source-directories", which is indicated by
isInSourceDirectories (given as an argument to the function) being True. If you want to exclude
more files, you can use the filePath or moduleName of the Elm module, whichever is more practical for you to use.
filePath is relative to the folder containing the elm.json file and is written in a UNIX format (/, no \).
How to identify exceptions. See Exception for more information.
Predicate to identify exceptions (that shouldn't be reported) for elements defined in production code that are only used in non-production code.
A problem with reporting these elements is that it's going to produce false positives, as there are legitimate use-cases for exporting these elements, hence the need for the rule to be able to identify them.
For instance, while it's generally discouraged, you might want to test the internals of an API (to make sure some properties hold given very specific situations). In this case, your module then needs to expose a way to gain insight to the internals.
Another example is giving the means for tests to create opaque types that are impossible or very hard to create in a test environment. This can be the case for types that can only be created through the decoding of an HTTP request.
Note that another common way to handle these use-cases is to move the internals to another module that exposes everything while making sure only specific production modules import it.
Prevents reporting usages of elements that contain a specific tag in their documentation.
Given the following configuration
NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile = isProductionFile
, exceptionsAre = [ annotatedBy "@test-helper" ]
}
|> NoUnused.Exports.toRuleany element that has @test-helper in its documentation will not be reported as unused (as long as its used at least once in the project):
{-| @test-helper
-}
someFunction input =
doSomethingComplexWith inputA recommended practice is to have annotations start with @.
You can use this function several times to define multiple annotations.
Prevents reporting usages of elements whose name end with a specific string.
Given the following configuration
NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile = isProductionFile
, exceptionsAre = [ suffixedBy "_FOR_TESTS" ]
}
|> NoUnused.Exports.toRuleany element that ends with "_FOR_TESTS" will not be reported as unused (as long as its used at least once in the project):
someFunction_FOR_TESTS input =
doSomethingComplexWith inputYou can use this function several times to define multiple suffixes.
Prevents reporting usages of elements whose name start with a specific string.
Given the following configuration
NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile = isProductionFile
, exceptionsAre = [ prefixedBy "test_" ]
}
|> NoUnused.Exports.toRuleany element that starts with "test_" will not be reported as unused (as long as its used at least once in the project):
test_someFunction input =
doSomethingComplexWith inputYou can use this function several times to define multiple prefixes.
Prevents reporting usages of elements in some modules.
Given the following configuration
NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile = isProductionFile
, exceptionsAre =
[ definedInModule
(\{ moduleName, filePath } ->
List.member "Util" moduleName
|| String.startsWith "src/test-helpers/" filePath
)
]
}
|> NoUnused.Exports.toRuleno elements from modules named *.Util.* or modules inside src/test-helpers/ will be reported.
The provided filePath is relative to the project's elm.json and is in a UNIX style (/, no \).
You can try this rule out by running the following commands:
Using the default configuration:
elm-review --template jfmengels/elm-review-unused/example --rules NoUnused.ExportsUsing reportUnusedProductionExports with the following configuration:
NoUnused.Exports.defaults
|> NoUnused.Exports.reportUnusedProductionExports
{ isProductionFile = \{ moduleName, filePath, isInSourceDirectories } -> isInSourceDirectories
, exceptionsAre = [ annotatedBy "@test-helper", suffixedBy "_FOR_TESTS" ]
}
|> NoUnused.Exports.toRuleelm-review --template jfmengels/elm-review-unused/example-ignore-tests --rules NoUnused.Exports
Report functions and types that are exposed from a module but that are never used in other modules. Also reports when a module is entirely unused.
This is equivalent to
NoUnused.Exports.toRule NoUnused.Exports.defaults.