acyclic
The modules units must not depend on each other in cycles. One unit depends
on another when any of its members imports a member of the other.
Example
[contracts.packages-acyclic]
type = "acyclic"
modules = ["pkg:*"]
exclude_kinds = ["type"]
@acme/client and @acme/core depend on each other. Removing core's one import of client breaks the cycle, so zenith nominates it.The workspace packages must not depend on each other in cycles. If a file in
@acme/core imports @acme/client, and one in @acme/client imports
@acme/core, the report names the cheaper dependency to remove, such as
@acme/core -> @acme/client (1 import). Type-only imports make no cycle at
runtime, so they don't count: @acme/core's type import of @acme/ui would
otherwise close a second cycle.
Cycle breakers
When there are cycles, zenith nominates the cycle breakers: the fewest dependencies whose removal would make the units acyclic, found with grimp's weighted heuristic, ties broken by name. Each breaker is on a cycle, and is shown with its number of imports and a cycle through it.
Options
| Option | Default | |
|---|---|---|
modules | required | Selectors, e.g. ["pkg:*"] or ["web/src/domains/*"]. |
depth | 0 | How many generations further to check: with depth = 1, the children of each directory unit are checked as units of their own too. |
skip | [] | Selectors of units not to check the children of. |
Common options
Like every contract type, acyclic also takes:
| Option | Default | |
|---|---|---|
type | required | The contract type, such as "layers". |
name | the id | The title shown in the output. |
severity | "error" | "warn" reports a broken contract without failing the check, for rolling a contract out gradually. |
exclude_kinds | [analysis] exclude_kinds | The import kinds to leave out, e.g. ["type"]. |
reexports | [analysis] reexports | "transparent" sees an import of names from a [pass-through module](../concepts.md#pass-through modules) as imports of the modules that define them, as bundlers load them; "opaque" as an import of the pass-through module. Not for encapsulation. |
ignore_imports | [] | "<selector> -> <selector>" entries: the direct imports between them are left out of the contract. |
unmatched_ignore_imports | "error" | Whether an ignore_imports entry that matches no import breaks the contract ("error"), is a warning ("warn") or is fine ("none"). |
guidance | none | Text shown under each violation, such as how to fix it. |