Skip to content

Commit

Permalink
feature: adds reaches filter option
Browse files Browse the repository at this point in the history
  • Loading branch information
sverweij committed Jul 16, 2022
1 parent 19865a9 commit f463c3e
Show file tree
Hide file tree
Showing 28 changed files with 3,924 additions and 27 deletions.
4 changes: 4 additions & 0 deletions bin/depcruise-fmt.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ try {
"-F, --focus <regex>",
"only include modules matching the regex + their direct neighbours"
)
.option(
"-R, --reaches <regex>",
"only include modules matching the regex + all modules that can reach it"
)
.option("-x, --exclude <regex>", "exclude all modules matching the regex")
.option(
"-S, --collapse <regex>",
Expand Down
4 changes: 4 additions & 0 deletions bin/dependency-cruise.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ try {
"-F, --focus <regex>",
"only include modules matching the regex + their direct neighbours"
)
.option(
"-R, --reaches <regex>",
"only include modules matching the regex + all modules that can reach it"
)
.option("-x, --exclude <regex>", "exclude all modules matching the regex")
.option(
"-X, --do-not-follow <regex>",
Expand Down
1 change: 1 addition & 0 deletions doc/assets/filtering/reaches-example.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion doc/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ available in dependency-cruiser configurations.
1. [`--do-not-follow`: don't cruise modules adhering to this pattern any further](#--do-not-follow-dont-cruise-modules-adhering-to-this-pattern-any-further)
1. [`--include-only`: only include modules satisfying a pattern](#--include-only-only-include-modules-satisfying-a-pattern)
1. [`--focus`: show modules and their direct neighbours](#--focus-show-modules-and-their-direct-neighbours)
1. [`--reaches`: show modules and their transitive dependents](#--reaches-show-modules-and-their-transitive-dependents)
1. [`--collapse`: summarize to folder depth or pattern](#--collapse-summarize-to-folder-depth-or-pattern)
1. [`--exclude`: exclude dependencies from being cruised](#--exclude-exclude-dependencies-from-being-cruised)
1. [`--max-depth`](#--max-depth)
Expand Down Expand Up @@ -858,12 +859,26 @@ Takes a regular expression in the same fashion `--include-only`, `--exclude` and
`--do-not-follow` do.

```sh
dependency-cruise --include-only "^src" --focus "^src/main" -T dot src | dot -T svg > focus-on-main-dir-graph.svg
dependency-cruise src --include-only "^src" --focus "^src/main" -T dot | dot -T svg > focus-on-main-dir-graph.svg
```

See [focus](./options-reference.md#show-modules-matching-a-pattern---with-their-direct-neighbours)
in the options reference for more details.

### `--reaches`: show modules and their transitive dependents

If you want to e.g. analyze what modules will directly or indirectly be affected
by a change you make in one or modules you can use this option.

Just like the filter options above, takes a regular expression:

```sh
dependency-cruise src --include-only "^src/report" --reaches "^src/report/utl/index.js" -T dot | dot -T svg > reaches-example.svg
```

See [reaches](./options-reference.md#reaches-show-modules-matching-a-pattern---with-everything-that-can-reach-them)
in the options reference for more details.

### `--collapse`: summarize to folder depth or pattern

If you feel the need for reporting on a higher level (e.g. on packages in a
Expand Down
32 changes: 32 additions & 0 deletions doc/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [`doNotFollow`: don't cruise modules any further](#donotfollow-dont-cruise-modules-any-further)
- [`includeOnly`: only include modules satisfying a pattern](#includeonly-only-include-modules-satisfying-a-pattern)
- [`focus`: show modules matching a pattern - with their direct neighbours](#focus-show-modules-matching-a-pattern---with-their-direct-neighbours)
- [`reaches`: show modules matching a pattern - with everything that can reach them](#reaches-show-modules-matching-a-pattern---with-everything-that-can-reach-them)
- [`exclude`: exclude dependencies from being cruised](#exclude-exclude-dependencies-from-being-cruised)
- [`collapse`: summarize to folder depth or pattern](#collapse-summarize-to-folder-depth-or-pattern)
- [`maxDepth`](#maxdepth)
Expand Down Expand Up @@ -271,6 +272,37 @@ depcruise -c snazzy-focus.config.json -T dot | dot -T svg > snazzy-focus.svg

</details>

### `reaches`: show modules matching a pattern - with everything that can reach them

> :shell: command line option equivalent: `--reaches`
Just like the `includeOnly` and `focus` option, `reaches` takes a regular expression
that dependency-cruiser uses to find modules to show in its output. In addition
to what `includeOnly` does, dependency-cruiser will all dependents (direct _and_
indirect) of the modules matched by the regular expression.

This can be useful if you want to make an impact analysis on what would
be affected when you change one or more modules around.

Example configuration that'd filter out everything in src/report that can
directly or indirectly reach the dependency-to-incidence-transformer module:

```json
{
"options": {
"includeOnly": "^src/report",
"reaches": "^src/report/utl/index.js"
}
}
```

Which will look something like this when output through a `dot` reporter:

![graphical output showing all modules in src/report that (transitively) depend on the src/report/utl/index.js module](assets/filtering/reaches-example.svg)

> In later versions of dependency-cruiser 'snazzy' coloring options
> might appear akin to those available with the 'focus' reporter.
### `exclude`: exclude dependencies from being cruised

> :shell: command line option equivalent: `--exclude` (string values passed to 'path' only)
Expand Down
1 change: 1 addition & 0 deletions src/cli/normalize-cli-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const KNOWN_DEPCRUISE_CLI_OPTIONS = [
"prefix",
"preserveSymlinks",
"progress",
"reaches",
"tsPreCompilationDeps",
"tsConfig",
"validate",
Expand Down
6 changes: 6 additions & 0 deletions src/enrich/derive/dependents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ function hasDependentsRule(pOptions) {
);
}

/**
*
* @param {import("../../../../types/cruise-result").IOptions} pOptions
* @returns
*/
function shouldAddDependents(pOptions) {
return (
Boolean(pOptions.forceDeriveDependents) ||
Boolean(pOptions.metrics) ||
Boolean(pOptions.reaches) ||
pOptions.outputType === "metrics" ||
hasDependentsRule(pOptions)
);
Expand Down
1 change: 1 addition & 0 deletions src/enrich/derive/module-utl.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @type {Map<string,import('../../../types/cruise-result').IModule>} */
let gIndexedGraph = null;

/**
Expand Down
39 changes: 37 additions & 2 deletions src/graph-utl/filterbank.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const clone = require("lodash/clone");
const focus = require("./add-focus");
const addFocus = require("./add-focus");
const IndexedModuleGraph = require("./indexed-module-graph");
const matchFacade = require("./match-facade");

function includeOnly(pModules, pIncludeFilter) {
Expand Down Expand Up @@ -32,6 +33,37 @@ function exclude(pModules, pExcludeFilter) {
}))
: pModules;
}
/**
*
* @param {import("../../types/cruise-result").IModule[]} pModules
* @param {import("../../types/filter-types").IReachesType} pReachesFilter
* @returns {import("../../types/cruise-result").IModule[]}
*/
function filterReaches(pModules, pReachesFilter) {
const lModuleNamesToReach = pModules
.filter((pModule) =>
matchFacade.moduleMatchesFilter(pModule, pReachesFilter)
)
.map(({ source }) => source);

/** @type {Array<string>} */
let lReachingModules = [];
let lIndexedModules = new IndexedModuleGraph(pModules);

for (let lModuleToReach of lModuleNamesToReach) {
lReachingModules = lReachingModules.concat(
lIndexedModules.findTransitiveDependents(lModuleToReach)
);
}
return pModules
.filter(({ source }) => lReachingModules.includes(source))
.map((pModule) => ({
...pModule,
dependencies: pModule.dependencies.filter(({ resolved }) =>
lReachingModules.includes(resolved)
),
}));
}

function applyFilters(pModules, pFilters) {
if (pFilters) {
Expand All @@ -44,7 +76,10 @@ function applyFilters(pModules, pFilters) {
lReturnValue = includeOnly(lReturnValue, pFilters.includeOnly);
}
if (pFilters.focus) {
lReturnValue = focus(lReturnValue, pFilters.focus);
lReturnValue = addFocus(lReturnValue, pFilters.focus);
}
if (pFilters.reaches) {
lReturnValue = filterReaches(lReturnValue, pFilters.reaches);
}
return lReturnValue;
}
Expand Down
Loading

0 comments on commit f463c3e

Please sign in to comment.