rev-dep 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,7 +46,7 @@ Results:
46
46
  ➞ getDepsSet.js
47
47
  ```
48
48
 
49
- What says that `getDepsSet.js` file is used in `cli.js` entry point and is required through `find.js`
49
+ Which says that `getDepsSet.js` file is used in `cli.js` entry point and is required through `find.js`
50
50
 
51
51
  ## About
52
52
 
@@ -54,7 +54,7 @@ The tool was created to determine places in the project where a particular file
54
54
 
55
55
  It's especially useful in JS world without TypeScript or tests coverage.
56
56
 
57
- Except the reverse dependency resolution path, it can print statistics about how many times a particular module is required in the project, which might be helpful for planning code-splitting.
57
+ Except the reverse dependency resolution path, it can print statistics about how many times a particular module is required in the project, which might be helpful for code-splitting planning.
58
58
 
59
59
  ## Usage
60
60
 
@@ -67,13 +67,14 @@ Avaliable commands:
67
67
  #### `resolve`
68
68
 
69
69
  ```sh
70
- rev-dep resolve <file> <entryPoints...>
70
+ rev-dep resolve <filePath> <entryPoints...>
71
71
  ```
72
72
 
73
73
  Available options are
74
74
 
75
75
  - `-cs or --compactSummary` - instead of file paths print a compact summary of reverse resolution with a count of found paths
76
76
  - `--verbose` - log currently performed operation
77
+ - `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support
77
78
 
78
79
  ### Module
79
80
 
@@ -84,7 +85,7 @@ import { find } from 'rev-dep'
84
85
 
85
86
  const path = find({
86
87
  entryPoints: ['index.js'],
87
- file: 'utils.js'
88
+ filePath: 'utils.js'
88
89
  })
89
90
 
90
91
  console.log(path)
@@ -93,10 +94,22 @@ console.log(path)
93
94
  #### `find` Options
94
95
 
95
96
  - `entryPoints (Array)` - Array of entry points to build a tree for search. Usually it will be one entry point, but project can have many of them, eg. next.js application. **Required**
96
- - `file (String)` - A file that we want to find path for. **Required**
97
+ - `filePath (String)` - A file that we want to find path for. **Required**
97
98
  - `skipRegex (String | RegExp)` - If a file path matches the pattern, we stop to traverse it's dependencies and do not include that file in the search tree. _Optional_, default: `'(node_modules|/__tests__|/__test__|/__mockContent__|.scss)'`
98
99
  - `verbose (Boolean)` - when set to true, will print current operation performed by find function. _Optional_, default: `false`
99
100
  - `cwd` - root for resolved files, must be an absolute path. _Optional_, default: `process.cwd()`
101
+ - `webpackConfig (String)` - path to webpack config to enable webpack aliases support
102
+
103
+ ### Additional setup may be required
104
+
105
+ #### Resolving implicit file extensions
106
+
107
+ A vast amount of JS/TS projects are configured in a way that allows (or even forces) to skip file extensions in import statements. Rev-dep is strongly based on [dependency-cruiser](https://github.com/sverweij/dependency-cruiser) which by default support implicit file extensions for `*.js, *.cjs, *.mjs, *.jsx` files (check [source](https://github.com/sverweij/dependency-cruiser/blob/96e34d0cf158034f2b7c8cafe9cec72dd74d8c45/src/extract/transpile/meta.js)).
108
+ In order to resolve implicit extensions for other JS based languages it look for available corresponding compiler in `package.json`. If compiler is available, then extension is supported.
109
+
110
+ If you installed `rev-dep` **globally**, you will have appropriate compiler installed **globally** as well. If you use it as a module, your project has to have compiler in it's package.json.
111
+
112
+ For example, to support `*.ts` and `*.tsx` implicit extensions in globally installed `rev-dep`, you have to also install globally `typescript` package (see [source](https://github.com/sverweij/dependency-cruiser/blob/96e34d0cf158034f2b7c8cafe9cec72dd74d8c45/src/extract/transpile/typescript-wrap.js))
100
113
 
101
114
  ## Contributing
102
115
 
package/cli.js CHANGED
@@ -12,19 +12,35 @@ const pathToString = (str, f, i) => {
12
12
  }
13
13
 
14
14
  program
15
- .command('resolve <file> <entryPoints...>')
15
+ .command('resolve <filePath> <entryPoints...>')
16
16
  .option(
17
17
  '-cs, --compactSummary',
18
18
  'print a compact summary of reverse resolution with a count of found paths'
19
19
  )
20
20
  .option('--verbose', 'print current action information')
21
- .action((filePath, entryPoints, data) => {
22
- const { compactSummary, verbose } = data
23
- const results = find({
24
- entryPoints: entryPoints,
25
- file: filePath,
26
- verbose
21
+ .option(
22
+ '-wc, --webpackConfig <path>',
23
+ 'path to webpack config to enable webpack aliases support'
24
+ )
25
+ .option(
26
+ '-tc, --typescriptConfig <path>',
27
+ 'path to TypeScript config to enable TS aliases support'
28
+ )
29
+ .action(async (filePath, entryPoints, data) => {
30
+ const { compactSummary, verbose, webpackConfig, typescriptConfig } = data
31
+
32
+ const results = await find({
33
+ entryPoints,
34
+ filePath,
35
+ verbose,
36
+ webpackConfig,
37
+ typescriptConfig
27
38
  })
39
+ const hasAnyResults = results.some((paths) => paths.length > 0)
40
+ if (!hasAnyResults) {
41
+ console.log('No results found for', filePath, 'in', entryPoints)
42
+ return
43
+ }
28
44
  console.log('Results:\n')
29
45
  if (compactSummary) {
30
46
  const maxEntryLength = entryPoints.reduce((maxLength, entryPoint) => {
@@ -39,13 +55,15 @@ program
39
55
  } else {
40
56
  results.forEach((entryPointResults, index) => {
41
57
  entryPointResults.forEach((path) => {
42
- console.log(path.reduce(pathToString, ''))
58
+ console.log(path.reduce(pathToString, ''), '\n')
43
59
  })
44
60
  if (index < results.length - 1) {
45
61
  console.log('_'.repeat(process.stdout.columns))
46
62
  }
47
63
  })
48
64
  }
65
+
66
+
49
67
  })
50
68
 
51
69
  program.parse(process.argv)
package/find.js CHANGED
@@ -1,5 +1,7 @@
1
1
  const path = require('path')
2
2
  const getDepsSet = require('./getDepsSet')
3
+ const { parseDependencyTree } = require('dpdm');
4
+ const escapeGlob = require('glob-escape');
3
5
 
4
6
  const buildTree = (deps) => (entryPoint) => {
5
7
  const inner = (path) => {
@@ -21,6 +23,39 @@ const buildTree = (deps) => (entryPoint) => {
21
23
  return inner(entryPoint)
22
24
  }
23
25
 
26
+ const buildTreeDpdm = (_deps) => (entryPoint) => {
27
+
28
+ const deps = Object.entries(_deps).reduce((deps, [id, data]) => {
29
+ if (!id.includes('node_modules')) {
30
+ return Object.assign({}, deps, { [id]: data ? data.filter(({ id }) => id && !id.includes('node_modules')) : data })
31
+ }
32
+ return deps
33
+ }, {})
34
+
35
+ const inner = (path, visited = new Set()) => {
36
+ if (visited.has(path)) {
37
+ return {
38
+ path,
39
+ children: []
40
+ }
41
+ }
42
+ visited.add(path);
43
+ const dep = deps[path]
44
+ if (dep === undefined) {
45
+ throw new Error(`Dependency '${path}' not found!`)
46
+ }
47
+
48
+ return {
49
+ path,
50
+ children: (dep || [])
51
+ .map(d => d.id)
52
+ .filter(path => path && !path.includes('node_modules'))
53
+ .map((path) => inner(path, visited))
54
+ }
55
+ }
56
+ return inner(entryPoint)
57
+ }
58
+
24
59
  const traverse = (file) => (tree) => {
25
60
  if (tree.path === file) {
26
61
  return [[file]]
@@ -38,35 +73,44 @@ const traverse = (file) => (tree) => {
38
73
 
39
74
  const removeInitialDot = (path) => path.replace(/^\.\//, '')
40
75
 
41
- const resolveAbsolutePath = (cwd) => (p) => path.resolve(cwd, p)
76
+ const _resolveAbsolutePath = (cwd) => (p) => typeof p === 'string' ? path.resolve(cwd, p) : p
42
77
 
43
- const find = ({
78
+ const find = async ({
44
79
  entryPoints,
45
- file,
80
+ filePath,
46
81
  skipRegex,
47
82
  verbose,
83
+ webpackConfig,
84
+ typescriptConfig,
48
85
  cwd = process.cwd()
49
86
  }) => {
50
- const absoluteEntryPoints = entryPoints.map((e) =>
51
- resolveAbsolutePath(cwd)(e)
52
- )
87
+ const resolveAbsolutePath = _resolveAbsolutePath(cwd)
88
+ const absoluteEntryPoints = entryPoints.map(resolveAbsolutePath)
89
+ const globEscapedEntryPoints = entryPoints.map(escapeGlob);
53
90
 
54
91
  if (verbose) {
55
92
  console.log('Entry points:')
56
93
  console.log(absoluteEntryPoints)
57
94
  console.log('Getting dependency set for entry points...')
58
95
  }
59
- const deps = getDepsSet(absoluteEntryPoints, skipRegex)
96
+ const deps = typescriptConfig ? await parseDependencyTree(globEscapedEntryPoints, { context: process.cwd() }) : getDepsSet(
97
+ absoluteEntryPoints,
98
+ skipRegex,
99
+ resolveAbsolutePath(webpackConfig),
100
+ resolveAbsolutePath(typescriptConfig)
101
+ )
102
+
60
103
  const cleanedEntryPoints = entryPoints.map(removeInitialDot)
104
+ const cleanedFilePath = removeInitialDot(filePath)
61
105
  if (verbose) {
62
106
  console.log('Building dependency trees for entry points...')
63
107
  }
64
- const forest = cleanedEntryPoints.map(buildTree(deps))
108
+ const forest = cleanedEntryPoints.map(typescriptConfig ? buildTreeDpdm(deps) : buildTree(deps))
65
109
  if (verbose) {
66
110
  console.log('Finding paths in dependency trees...')
67
111
  }
68
112
  const resolvedPaths = forest.reduce((allPaths, tree) => {
69
- const paths = traverse(file)(tree)
113
+ const paths = traverse(cleanedFilePath)(tree)
70
114
  return [...allPaths, paths]
71
115
  }, [])
72
116
  return resolvedPaths
package/getDepsSet.js CHANGED
@@ -1,17 +1,21 @@
1
1
  const depcruise = require('dependency-cruiser').cruise
2
-
3
- const getDepsSet = (entryPoints, skipRegex) => {
2
+ // eslint-disable-next-line
3
+ const resolveWebpackConfig = require('dependency-cruiser/config-utl/extract-webpack-resolve-config')
4
+ // eslint-disable-next-line
5
+ const resolveTsConfig = require('dependency-cruiser/config-utl/extract-ts-config')
6
+ const getDepsSet = (entryPoints, skipRegex, webpackConfigPath, tsConfigPath) => {
4
7
  const skip =
5
8
  skipRegex || '(node_modules|/__tests__|/__test__|/__mockContent__|.scss)'
9
+ const webpackResolveOptions = webpackConfigPath ? resolveWebpackConfig(webpackConfigPath) : null
10
+ const tsConfigOptions = tsConfigPath ? resolveTsConfig(tsConfigPath) : null
6
11
 
7
- const dependencies = depcruise(entryPoints, {
12
+ const result = depcruise(entryPoints, {
8
13
  exclude: skip,
9
14
  doNotFollow: { path: skip },
10
- tsConfig: {
11
- fileName: 'tsconfig.json'
12
- }
13
- }).output
14
- return dependencies.modules
15
+ tsPreCompilationDeps: true,
16
+
17
+ }, webpackResolveOptions, tsConfigOptions)
18
+ return result.output.modules
15
19
  }
16
20
 
17
21
  module.exports = getDepsSet
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rev-dep",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Reverse dependency resolution tool built with dependency-cruiser",
5
5
  "main": "find.js",
6
6
  "bin": "cli.js",
@@ -30,7 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "commander": "^6.1.0",
33
- "dependency-cruiser": "^9.15.0"
33
+ "dependency-cruiser": "9.23.0",
34
+ "dpdm": "^3.8.0",
35
+ "glob-escape": "^0.0.2"
34
36
  },
35
37
  "devDependencies": {
36
38
  "eslint": "^7.11.0",