Migrating from Sheriff
Sheriff enforces module boundaries and dependency rules in TypeScript projects using tags and depRules. rev-dep enforces the same boundaries with path-pattern module boundaries, and adds the rest of a dependency-hygiene suite.
Why migrate​
- Speed and one pass. rev-dep is Go-based - faster on large codebases.
- Boundaries plus everything else. Sheriff focuses on boundaries and encapsulation. rev-dep enforces boundaries and detects circular imports, unused exports, orphan files, and unused/missing dependencies.
What carries over, what changes​
- Covered well: which modules may depend on which (Sheriff's
depRules). - Different model. Sheriff tags modules (via the
modulesmap) and writes rules between tags; rev-dep uses path patterns directly. You translatetag → allowed tagsintopattern → allow/deny. - Not replaced - barrel encapsulation. Sheriff can require that a module is only imported through its
index.tspublic API. rev-dep has no barrel-file rule; you can approximate "no deep imports" withrestrictedImportsDetectiondenyFiles, but it is not a one-to-one match. Keep Sheriff if strict barrel encapsulation is essential.
Feature mapping​
Sheriff (sheriff.config.ts) | rev-dep |
|---|---|
modules (path globs → tags) | moduleBoundaries pattern |
depRules (allowed deps between tags) | moduleBoundaries allow / deny |
| barrel / public-API encapsulation | partial - restrictedImportsDetection denyFiles for deep imports |
| - | circular, unused exports, orphan files, unused/missing dependencies, conventions |
Translating your config​
A sheriff.config.ts where feature modules may depend on shared but not on each other:
export const config = {
modules: {
'src/app/<feature>': ['feature:<feature>'],
'src/shared': ['shared'],
},
depRules: {
'feature:*': ['shared', sameTag],
shared: [],
},
};
becomes path-pattern boundaries in rev-dep.config.jsonc:
{
"rules": [
{
"path": ".",
"moduleBoundaries": [
{
"name": "shared-is-leaf",
"pattern": "src/shared/**",
"allow": ["src/shared/**"]
},
{
"name": "features-use-shared-only",
"pattern": "src/app/orders/**",
"allow": ["src/app/orders/**", "src/shared/**"]
}
]
}
]
}
rev-dep has no wildcard "same tag" concept, so cross-feature isolation is expressed as one boundary per feature (or a shared deny of sibling feature paths).
Running it​
# Sheriff (ESLint plugin or CLI)
npx eslint . # with @softarc/eslint-plugin-sheriff
# rev-dep
rev-dep config run