MyNixOS website logo
Description

GHC plugin to enforce user specified rules on code.

henforcer

henforcer is a Haskell enforcer of project specific code standards.

Installation/Execution

henforcer is a GHC plugin, thus it is executed during compilation. To enable the plugin during compilation with cabal or stack, add henforcer as a dependency in your cabal file or package.yaml as applicable and add -fplugin Henforcer to ghc-flags. Specifying plugin options is done with ghc-flags as well. Currently only supported is the path to the configuration, which if it is at foo/bar/henforcer.toml this would be as "-fplugin-opt=Henforcer:-cfoo/bar/henforcer.toml".

_Note: henforcer requires a handful of packages that are not on stackage as of lts-24.29. The following is likely to needed in the extra-deps section of your stack.yaml

# henforcer needs pollock
- pollock-0.1.0.4

Configuration

henforcer uses TOML files for configuration. You can use a empty toml file as a beginning configuration. Using such and running henforcer will not report errors.

Configuration concepts and options are described below. Also the examples/henforcer.toml file shows a variety of usage possibilities.

Concepts

Module Trees

henforcer uses "module trees" as part of its configuration. A "module tree" refers to a root module (e.g. Data.Text) and all the modules are prefixed by it (e.g. Data.Text.Encoding and Data.Text.Lazy). For modules in your project this almost always means a src/Foo/MyModule.hs file and any .hs files contained inside the src/Foo/MyModule directory.

Configuration reference

forAnyModule

The forAnyModule key is a TOML table containing all of the checks that apply when compiling any given module. You can think of these as "global" but they do not apply to multiple modules at once.

fieldNametyperequireddescription
allowedAliasUniquenessAllowedAliasUniquenessnoSpecifies either that all aliases in the module being compiled are unique except for some, or that a given set of aliases is unique but others may be duplicated.
allowedOpenUnaliasedImportsnon-negative intnoSpecifies how many imports are allowed to be done without using the qualified keyword, or using an alias
allowedQualificationsarray of AllowedQualificationnoRepresents how certain modules should be imported. This can be thought of as a map of module name to a list of ways that module may be imported.
encapsulatedTreesarray of stringyesLets you declare that the root of a module tree is effectively a public interface that any modules outside the tree should be using. henforcer will report an error if any module outside the tree attempts to import a module from inside the encapsulated tree.
maximumExportsPlusHeaderUndocumentednon-negative integernoMaximum number of exported items, along with the module header, from a module that may be missing Haddock documentation.
minimumExportsPlusHeaderDocumentednon-negative integernoMinimum number of exported items, along with the module header, from a module that must have Haddock documentation.
maximumExportsWithoutSincenon-negative integernoMaximum number of exported items from a module that can be lacking the @since annotation in their Haddock.
minimumExportsWithSincenon-negative integernoMinimum number of exported items from a module that must have in their Haddock the @since annotation.
moduleHeaderCopyrightMustExistNonEmptybooleannoIf the Haddock module header field of Copyright must be populated.
moduleHeaderDescriptionMustExistNonEmptybooleannoIf the Haddock module header field of Description must be populated.
moduleHeaderLicenseMustExistNonEmptybooleannoIf the Haddock module header field of License must be populated.
moduleHeaderMaintainerMustExistNonEmptybooleannoIf the Haddock module header field of Maintainer must be populated.
treeDependenciesarray of TreeDependencynoDeclares that one module tree depends on other trees. Declaring such a dependency tells henforcer that you don't want the dependency targets to import anything from the dependent tree, which would cause a backwards dependency rendering the two module trees logically inseparable.

forSpecifiedModules

Henforcer allows for certain rules to be overridden on a module by module basis. When provided, the most specific rule will be applied.

fieldNametyperequireddescription
modulestringyesmodule is a string of the module name the rules in this table will apply to.
allowedAliasUniquenessAllowedAliasUniquenessnoSpecifies either that all aliases in the module being compiled are unique except for some, or that a given set of aliases is unique but others may be duplicated.
allowedOpenUnaliasedImportsnon-negative intnoSpecifies how many imports are allowed to be done without using the qualified keyword, or using an alias
allowedQualificationsarray of AllowedQualificationnoRepresents how certain modules should be imported. This can be thought of as a map of module name to a list of ways that module may be imported.
maximumExportsPlusHeaderUndocumentednon-negative integernoMaximum number of exported items, along with the module header, from a module that may be missing Haddock documentation.
minimumExportsPlusHeaderDocumentednon-negative integernoMinimum number of exported items, along with the module header, from a module that must have Haddock documentation.
maximumExportsWithoutSincenon-negative integernoMaximum number of exported items from a module that can be lacking the @since annotation in their Haddock.
minimumExportsWithSincenon-negative integernoMinimum number of exported items from a module that must have in their Haddock the @since annotation.
moduleHeaderCopyrightMustExistNonEmptybooleannoIf the Haddock module header field of Copyright must be populated.
moduleHeaderDescriptionMustExistNonEmptybooleannoIf the Haddock module header field of Description must be populated.
moduleHeaderLicenseMustExistNonEmptybooleannoIf the Haddock module header field of License must be populated.
moduleHeaderMaintainerMustExistNonEmptybooleannoIf the Haddock module header field of Maintainer must be populated.
rulesToIgnoreRulesToIgnorenoSpecifies what, if any, rules should be ignored for the given module.

forPatternModules

Henforcer supports a limited form of using patterns to match rules against multiple modules, but not any module in a more concise way.

forPatternModules is an array of TOML tables. Effectively this is a map keyed by the pattern field.

Important items to note:

  • When determining which version of a rule to pick the definition in forSpecifiedModules is most preferred, followed by forPatternModules and finally forAnyModule.
  • If there are overlapping pattern keys in forPatternModules the first specified in the TOML will be chosen.
  • Patterns use * and **. * can be used to match up to the module separator ., where ** matches across the . separator.
fieldNametyperequireddescription
patternstring with wildcardyesmodule is a string, with wildcard support, of the module name the rules described here will apply to.
allowedAliasUniquenessAllowedAliasUniquenessnoSpecifies either that all aliases in the module being compiled are unique except for some, or that a given set of aliases is unique but others may be duplicated.
allowedOpenUnaliasedImportsnon-negative intnoSpecifies how many imports are allowed to be done without using the qualified keyword, or using an alias
allowedQualificationsarray of AllowedQualificationnoRepresents how certain modules should be imported. This can be thought of as a map of module name to a list of ways that module may be imported.
maximumExportsPlusHeaderUndocumentednon-negative integernoMaximum number of exported items, along with the module header, from a module that may be missing Haddock documentation.
minimumExportsPlusHeaderDocumentednon-negative integernoMinimum number of exported items, along with the module header, from a module that must have Haddock documentation.
maximumExportsWithoutSincenon-negative integernoMaximum number of exported items from a module that can be lacking the @since annotation in their Haddock.
minimumExportsWithSincenon-negative integernoMinimum number of exported items from a module that must have in their Haddock the @since annotation.
moduleHeaderCopyrightMustExistNonEmptybooleannoIf the Haddock module header field of Copyright must be populated.
moduleHeaderDescriptionMustExistNonEmptybooleannoIf the Haddock module header field of Description must be populated.
moduleHeaderLicenseMustExistNonEmptybooleannoIf the Haddock module header field of License must be populated.
moduleHeaderMaintainerMustExistNonEmptybooleannoIf the Haddock module header field of Maintainer must be populated.
rulesToIgnoreRulesToIgnorenoSpecifies what, if any, rules should be ignored for the given module.

Shared types

Below are the reused definitions between some combination of the forAnyModule, forSpecifiedModules and forPatternModules rules.

AllowedAliasUniqueness

This is allowed to take two forms that are both TOML tables.

First Form

This form states that all aliases in a module must be unique with an allow list for those aliases that may be repeated.

fieldNametyperequireddescription
allAliasesUniqueExceptarray of stringyesAliases that are allowed to be repeated.
notestringnoUser defined message to be displayed with errors for additional context.
Second Form

This form states that aliases in a module may repeat with a block list for those aliases that must be unique.

fieldNametyperequireddescription
uniqueAliasesarray of stringyesAliases that must be unique.
notestringnoUser defined message to be displayed with errors for additional context.

AllowedQualification

fieldNametyperequireddescription
modulestringyesmodule is a string of the module name.
importSchemearray of ImportSchemeyesThe list of specifications for each way that the given module may imported.

ImportScheme

fieldNametyperequireddescription
qualifiedQualifiedyesDescription of ways the import can be qualified, or not.
aliasstringnoControls if and what alias can be used as part of an import scheme. This is the part of an import that comes after the as keyword, such as "Foo" in import UnliftIO as Foo.
packageQualifiedstringnoControls if and what package qualifier should be used. Most users are not expected to need this option.
safebooleannoControls if the import is required to use the safe keyword. Most users are not expected to need this option.
notestringnoUser defined message to be displayed with errors for additional context.

Qualified

fieldNametyperequireddescription
qualifiedPrebooleannoDescribes if import can be qualified prepositive like import qualified UnliftIO.
qualifiedPostbooleannoDescribes if import can be qualified postpositive like import UnliftIO qualified.
unqualifiedbooleannoDescribes if import can be unqualified like import UnliftIO.

TreeDependency

fieldNametyperequireddescription
moduleTreestringyesThe tree which depends on others.
dependenciesarray of stringyesThe trees which are depended upon.
notestringnoUser defined message to be displayed with errors for additional context.

RulesToIgnore

This is allowed to take two forms that are both TOML tables.

First form
fieldNametyperequireddescription
allbooleannoControls if all rules should be ignored.
Second form
fieldNametyperequireddescription
allowedAliasUniquenessbooleannoControls if the rule should be ignored.
allowedOpenUnaliasedImportsbooleannoControls if the rule should be ignored.
allowedQualificationsbooleannoControls if the rule should be ignored.
encapsulatedTreesbooleannoControls if the rule should be ignored.
maximumExportsPlusHeaderUndocumentedbooleannoControls if the rule should be ignored.
minimumExportsPlusHeaderDocumentedbooleannoControls if the rule should be ignored.
maximumExportsWithoutSincebooleannoControls if the rule should be ignored.
minimumExportsWithSincebooleannoControls if the rule should be ignored.
moduleHeaderCopyrightMustExistNonEmptybooleannoControls if the rule should be ignored.
moduleHeaderDescriptionMustExistNonEmptybooleannoControls if the rule should be ignored.
moduleHeaderLicenseMustExistNonEmptybooleannoControls if the rule should be ignored.
moduleHeaderMaintainerMustExistNonEmptybooleannoControls if the rule should be ignored.
treeDependenciesbooleannoControls if the rule should be ignored.
Metadata

Version

1.0.0.0

License

Platforms (78)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows