rev-dep 0.2.1 → 1.0.0-alpha.1
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 +93 -5
- package/bin.js +2 -0
- package/dist/cli/commonOptions.js +24 -0
- package/dist/cli/createCommands.js +17 -0
- package/dist/cli/docs/generate.js +90 -0
- package/dist/cli/docs/index.js +18 -0
- package/dist/cli/docs/template.js +49 -0
- package/dist/cli/entryPoints/index.js +50 -0
- package/dist/cli/entryPoints/types.js +2 -0
- package/dist/cli/files/index.js +33 -0
- package/dist/cli/files/types.js +2 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/resolve/formatResults.js +67 -0
- package/dist/cli/resolve/index.js +42 -0
- package/dist/cli/resolve/types.js +2 -0
- package/dist/lib/buildDepsGraph.js +43 -0
- package/dist/lib/cleanupDpdmDeps.js +24 -0
- package/dist/lib/find.js +45 -0
- package/dist/lib/getDepsSetWebpack.js +44 -0
- package/dist/lib/getDepsTree.js +23 -0
- package/dist/lib/getEntryPoints.js +71 -0
- package/dist/lib/getMaxDepthInGraph.js +21 -0
- package/dist/lib/getMaxDepthInGrapth.js +21 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/utils.js +29 -0
- package/package.json +29 -15
- package/cli.js +0 -66
- package/find.js +0 -82
- package/getDepsSet.js +0 -21
package/README.md
CHANGED
|
@@ -81,14 +81,14 @@ Available options are
|
|
|
81
81
|
#### `find` Function
|
|
82
82
|
|
|
83
83
|
```js
|
|
84
|
-
import { find } from
|
|
84
|
+
import { find } from "rev-dep";
|
|
85
85
|
|
|
86
86
|
const path = find({
|
|
87
|
-
entryPoints: [
|
|
88
|
-
filePath:
|
|
89
|
-
})
|
|
87
|
+
entryPoints: ["index.js"],
|
|
88
|
+
filePath: "utils.js",
|
|
89
|
+
});
|
|
90
90
|
|
|
91
|
-
console.log(path)
|
|
91
|
+
console.log(path);
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
#### `find` Options
|
|
@@ -111,6 +111,94 @@ If you installed `rev-dep` **globally**, you will have appropriate compiler inst
|
|
|
111
111
|
|
|
112
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))
|
|
113
113
|
|
|
114
|
+
## CLI reference
|
|
115
|
+
|
|
116
|
+
<!-- cli-docs-start -->
|
|
117
|
+
|
|
118
|
+
### Command `resolve`
|
|
119
|
+
|
|
120
|
+
Checks if a filePath is required from entryPoint(s) and prints the resolution path
|
|
121
|
+
|
|
122
|
+
#### Usage
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
rev-dep resolve <filePath> [entryPoints...] [options]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### Arguments
|
|
129
|
+
|
|
130
|
+
- `filePath` - Path to a file that should be resolved in entry points (**required**),\* `entryPoints...` - List of entry points to look for file (_optional_)
|
|
131
|
+
|
|
132
|
+
#### Options
|
|
133
|
+
|
|
134
|
+
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
135
|
+
- `--cwd <path>` - path to a directory that should be used as a resolution root (_optional_)
|
|
136
|
+
- `--rr reexportRewire <value>` - resolve actual dependencies for "export \* from" statements (_optional_)
|
|
137
|
+
- `-i include <globs...>` - A list of globs to determine files included in entry points search (_optional_)
|
|
138
|
+
- `-e exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
139
|
+
- `-cs, --compactSummary` - print a compact summary of reverse resolution with a count of found paths (_optional_)
|
|
140
|
+
- `-a, --all` - finds all paths combination of a given dependency. Might work very slow or crash for some projects due to heavy usage of RAM (_optional_)
|
|
141
|
+
|
|
142
|
+
### Command `entry-points`
|
|
143
|
+
|
|
144
|
+
Print list of entry points in current directory
|
|
145
|
+
|
|
146
|
+
#### Usage
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
rev-dep entry-points [options]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Options
|
|
153
|
+
|
|
154
|
+
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
155
|
+
- `--cwd <path>` - path to a directory that should be used as a resolution root (_optional_)
|
|
156
|
+
- `--rr reexportRewire <value>` - resolve actual dependencies for "export \* from" statements (_optional_)
|
|
157
|
+
- `-i include <globs...>` - A list of globs to determine files included in entry points search (_optional_)
|
|
158
|
+
- `-e exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
159
|
+
- `-pdc, --printDependenciesCount` - print count of entry point dependencies (_optional_)
|
|
160
|
+
- `-c, --count` - print just count of found entry points (_optional_)
|
|
161
|
+
|
|
162
|
+
### Command `files`
|
|
163
|
+
|
|
164
|
+
Get list of files required by entry point
|
|
165
|
+
|
|
166
|
+
#### Usage
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
rev-dep files <entryPoint> [options]
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### Arguments
|
|
173
|
+
|
|
174
|
+
- `entryPoint` - Path to entry point (**required**)
|
|
175
|
+
|
|
176
|
+
#### Options
|
|
177
|
+
|
|
178
|
+
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
179
|
+
- `--cwd <path>` - path to a directory that should be used as a resolution root (_optional_)
|
|
180
|
+
- `--rr reexportRewire <value>` - resolve actual dependencies for "export \* from" statements (_optional_)
|
|
181
|
+
- `-c, --count` - print only count of entry point dependencies (_optional_)
|
|
182
|
+
|
|
183
|
+
### Command `docs`
|
|
184
|
+
|
|
185
|
+
Generate documentation of available commands into md file.
|
|
186
|
+
|
|
187
|
+
#### Usage
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
rev-dep docs <outputPath> [options]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### Arguments
|
|
194
|
+
|
|
195
|
+
- `outputPath` - path to output \*.md file (**required**)
|
|
196
|
+
|
|
197
|
+
#### Options
|
|
198
|
+
|
|
199
|
+
- `-hl, --headerLevel <value>` - Initial header level (_optional_)
|
|
200
|
+
<!-- cli-docs-end -->
|
|
201
|
+
|
|
114
202
|
## Contributing
|
|
115
203
|
|
|
116
204
|
Project is open to contributions, just rise an issue if you have some ideas about features or you noticed a bug. After discussion we can approach implementation :)
|
package/bin.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.excludeOption = exports.includeOption = exports.reexportRewireOption = exports.cwdOption = exports.webpackConfigOption = void 0;
|
|
4
|
+
exports.webpackConfigOption = [
|
|
5
|
+
'-wc, --webpackConfig <path>',
|
|
6
|
+
'path to webpack config to enable webpack aliases support'
|
|
7
|
+
];
|
|
8
|
+
exports.cwdOption = [
|
|
9
|
+
'--cwd <path>',
|
|
10
|
+
'path to a directory that should be used as a resolution root',
|
|
11
|
+
process.cwd()
|
|
12
|
+
];
|
|
13
|
+
exports.reexportRewireOption = [
|
|
14
|
+
'--rr reexportRewire <value>',
|
|
15
|
+
'resolve actual dependencies for "export * from" statements'
|
|
16
|
+
];
|
|
17
|
+
exports.includeOption = [
|
|
18
|
+
'-i include <globs...>',
|
|
19
|
+
'A list of globs to determine files included in entry points search'
|
|
20
|
+
];
|
|
21
|
+
exports.excludeOption = [
|
|
22
|
+
'-e exclude <globs...>',
|
|
23
|
+
'A list of globs to determine files excluded in entry points search'
|
|
24
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createCommands = void 0;
|
|
7
|
+
const resolve_1 = __importDefault(require("./resolve"));
|
|
8
|
+
const docs_1 = __importDefault(require("./docs"));
|
|
9
|
+
const entryPoints_1 = __importDefault(require("./entryPoints"));
|
|
10
|
+
const files_1 = __importDefault(require("./files"));
|
|
11
|
+
function createCommands(program) {
|
|
12
|
+
(0, resolve_1.default)(program);
|
|
13
|
+
(0, entryPoints_1.default)(program);
|
|
14
|
+
(0, files_1.default)(program);
|
|
15
|
+
(0, docs_1.default)(program);
|
|
16
|
+
}
|
|
17
|
+
exports.createCommands = createCommands;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const createCommands_1 = require("../createCommands");
|
|
8
|
+
const template_1 = __importDefault(require("./template"));
|
|
9
|
+
function createCommandsInspector() {
|
|
10
|
+
let currentCommand = null;
|
|
11
|
+
const commands = [];
|
|
12
|
+
const parseOption = (data, description, defaultValue, required) => {
|
|
13
|
+
const argRegex = /(<|\[).+?(>|\])/g;
|
|
14
|
+
const argument = data.match(argRegex);
|
|
15
|
+
const [shortName, longName] = data
|
|
16
|
+
.replace(argRegex, '')
|
|
17
|
+
.trim()
|
|
18
|
+
.split(/,\s+/);
|
|
19
|
+
return {
|
|
20
|
+
shortName,
|
|
21
|
+
longName,
|
|
22
|
+
argument: argument !== null && argument.length > 0 ? argument[0] : undefined,
|
|
23
|
+
description,
|
|
24
|
+
defaultValue,
|
|
25
|
+
required
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
command(cmd) {
|
|
30
|
+
if (currentCommand !== null) {
|
|
31
|
+
commands.push(currentCommand);
|
|
32
|
+
}
|
|
33
|
+
const [name, ...args] = cmd.split(/\s+/);
|
|
34
|
+
currentCommand = {
|
|
35
|
+
name,
|
|
36
|
+
arguments: args.map((arg) => ({
|
|
37
|
+
nameRaw: arg,
|
|
38
|
+
name: arg.substring(1, arg.length - 1),
|
|
39
|
+
required: arg.charAt(0) === '<'
|
|
40
|
+
})),
|
|
41
|
+
options: []
|
|
42
|
+
};
|
|
43
|
+
return this;
|
|
44
|
+
},
|
|
45
|
+
description(description, argDescription) {
|
|
46
|
+
if (currentCommand !== null) {
|
|
47
|
+
currentCommand.description = description;
|
|
48
|
+
if (argDescription !== undefined) {
|
|
49
|
+
currentCommand.arguments.forEach((arg) => {
|
|
50
|
+
//eslint-disable-next-line
|
|
51
|
+
if (argDescription.hasOwnProperty(arg.name)) {
|
|
52
|
+
arg.description = argDescription[arg.name];
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return this;
|
|
58
|
+
},
|
|
59
|
+
option(data, description, defaultValue) {
|
|
60
|
+
if (currentCommand !== null) {
|
|
61
|
+
currentCommand.options.push(parseOption(data, description, defaultValue, false));
|
|
62
|
+
}
|
|
63
|
+
return this;
|
|
64
|
+
},
|
|
65
|
+
requiredOption(data, description, defaultValue) {
|
|
66
|
+
if (currentCommand !== null) {
|
|
67
|
+
currentCommand.options.push(parseOption(data, description, defaultValue, true));
|
|
68
|
+
}
|
|
69
|
+
return this;
|
|
70
|
+
},
|
|
71
|
+
action() {
|
|
72
|
+
return this;
|
|
73
|
+
},
|
|
74
|
+
getCommands() {
|
|
75
|
+
if (currentCommand !== null) {
|
|
76
|
+
commands.push(currentCommand);
|
|
77
|
+
}
|
|
78
|
+
return commands;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function generate(output, initialHeaderLevel) {
|
|
83
|
+
const commandInspector = createCommandsInspector();
|
|
84
|
+
//@ts-ignore
|
|
85
|
+
(0, createCommands_1.createCommands)(commandInspector);
|
|
86
|
+
const commands = commandInspector.getCommands();
|
|
87
|
+
const document = (0, template_1.default)(commands, initialHeaderLevel);
|
|
88
|
+
fs_1.default.writeFileSync(output, document);
|
|
89
|
+
}
|
|
90
|
+
exports.default = generate;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const generate_1 = __importDefault(require("./generate"));
|
|
7
|
+
function create(program) {
|
|
8
|
+
program
|
|
9
|
+
.command('docs <outputPath>')
|
|
10
|
+
.description('Generate documentation of available commands into md file.', {
|
|
11
|
+
outputPath: 'path to output *.md file'
|
|
12
|
+
})
|
|
13
|
+
.option('-hl, --headerLevel <value>', 'Initial header level', '3')
|
|
14
|
+
.action((outputPath, options) => {
|
|
15
|
+
(0, generate_1.default)(outputPath, parseInt(options.headerLevel));
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
exports.default = create;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const dedent_1 = __importDefault(require("dedent"));
|
|
7
|
+
const programName = 'rev-dep';
|
|
8
|
+
const header = (level, ...text) => '#'.repeat(level) + ' ' + text.join(' ');
|
|
9
|
+
const code = (...text) => '`' + text.join(' ') + '`';
|
|
10
|
+
const codeBlock = (...text) => '```sh\n' + text.join(' ') + '\n```';
|
|
11
|
+
const requiredStr = '**required**';
|
|
12
|
+
const optionalStr = '_optional_';
|
|
13
|
+
const filterFalsy = (array) => array.filter((val) => val);
|
|
14
|
+
function template(commands, headerLevel) {
|
|
15
|
+
return (0, dedent_1.default)(commands
|
|
16
|
+
.map((cmd) => {
|
|
17
|
+
return `
|
|
18
|
+
${header(headerLevel, 'Command', code(cmd.name))}
|
|
19
|
+
|
|
20
|
+
${cmd.description || 'Description not available'}
|
|
21
|
+
|
|
22
|
+
${header(headerLevel + 1, 'Usage')}
|
|
23
|
+
|
|
24
|
+
${codeBlock(...filterFalsy([
|
|
25
|
+
programName,
|
|
26
|
+
cmd.name,
|
|
27
|
+
...cmd.arguments.map((arg) => arg.nameRaw),
|
|
28
|
+
cmd.options.length > 0 ? '[options]' : undefined
|
|
29
|
+
]))}
|
|
30
|
+
${cmd.arguments.length > 0 ? header(headerLevel + 1, 'Arguments') : ''}
|
|
31
|
+
|
|
32
|
+
${cmd.arguments.map(({ name, required, description }) => (0, dedent_1.default) `
|
|
33
|
+
* ${code(name)} - ${description} (${required ? requiredStr : optionalStr})
|
|
34
|
+
`)}
|
|
35
|
+
|
|
36
|
+
${cmd.options.length > 0 ? header(headerLevel + 1, 'Options') : ''}
|
|
37
|
+
|
|
38
|
+
${cmd.options
|
|
39
|
+
.map(({ shortName, longName, argument, required, description }) => (0, dedent_1.default) `
|
|
40
|
+
* ${code(filterFalsy([shortName, longName]).join(', ') +
|
|
41
|
+
(argument ? ` ${argument}` : ''))} - ${description} (${required ? requiredStr : optionalStr})
|
|
42
|
+
`)
|
|
43
|
+
.join('\n')}
|
|
44
|
+
|
|
45
|
+
`;
|
|
46
|
+
})
|
|
47
|
+
.join('\n'));
|
|
48
|
+
}
|
|
49
|
+
exports.default = template;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commonOptions_1 = require("../commonOptions");
|
|
4
|
+
const getEntryPoints_1 = require("../../lib/getEntryPoints");
|
|
5
|
+
const buildDepsGraph_1 = require("../../lib/buildDepsGraph");
|
|
6
|
+
const utils_1 = require("../../lib/utils");
|
|
7
|
+
function createEntryPoints(program) {
|
|
8
|
+
program
|
|
9
|
+
.command('entry-points')
|
|
10
|
+
.description('Print list of entry points in current directory')
|
|
11
|
+
.option(...commonOptions_1.webpackConfigOption)
|
|
12
|
+
.option(...commonOptions_1.cwdOption)
|
|
13
|
+
.option(...commonOptions_1.reexportRewireOption)
|
|
14
|
+
.option(...commonOptions_1.includeOption)
|
|
15
|
+
.option(...commonOptions_1.excludeOption)
|
|
16
|
+
.option('-pdc, --printDependenciesCount', 'print count of entry point dependencies', false)
|
|
17
|
+
.option('-c, --count', 'print just count of found entry points', false)
|
|
18
|
+
.action(async (data) => {
|
|
19
|
+
const { webpackConfig: webpackConfigPath, cwd, printDependenciesCount, include, exclude, count } = data;
|
|
20
|
+
const [entryPoints, depsTree] = await (0, getEntryPoints_1.getEntryPoints)({
|
|
21
|
+
cwd: (0, utils_1.resolvePath)(cwd),
|
|
22
|
+
webpackConfigPath,
|
|
23
|
+
exclude,
|
|
24
|
+
include
|
|
25
|
+
});
|
|
26
|
+
let depsCount = null;
|
|
27
|
+
if (printDependenciesCount) {
|
|
28
|
+
depsCount = entryPoints
|
|
29
|
+
.map((0, buildDepsGraph_1.buildGraphDpdm)(depsTree))
|
|
30
|
+
.map(([_, __, vertices]) => vertices.size);
|
|
31
|
+
}
|
|
32
|
+
if (count) {
|
|
33
|
+
console.log('Found', entryPoints.length, 'entry points.');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (entryPoints.length === 0) {
|
|
37
|
+
console.log('No results found');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
entryPoints.forEach((pathName, idx) => {
|
|
41
|
+
if (depsCount !== null) {
|
|
42
|
+
console.log(pathName, depsCount[idx]);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(pathName);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
exports.default = createEntryPoints;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commonOptions_1 = require("../commonOptions");
|
|
4
|
+
const utils_1 = require("../../lib/utils");
|
|
5
|
+
const getDepsTree_1 = require("../../lib/getDepsTree");
|
|
6
|
+
function createFiles(program) {
|
|
7
|
+
program
|
|
8
|
+
.command('files <entryPoint>')
|
|
9
|
+
.description('Get list of files required by entry point', {
|
|
10
|
+
entryPoint: 'Path to entry point'
|
|
11
|
+
})
|
|
12
|
+
.option(...commonOptions_1.webpackConfigOption)
|
|
13
|
+
.option(...commonOptions_1.cwdOption)
|
|
14
|
+
.option(...commonOptions_1.reexportRewireOption)
|
|
15
|
+
.option('-c, --count', 'print only count of entry point dependencies', false)
|
|
16
|
+
.action(async (entryPoint, data) => {
|
|
17
|
+
const { webpackConfig: webpackConfigPath, cwd, count } = data;
|
|
18
|
+
const sanitizedEntryPoints = (0, utils_1.sanitizeUserEntryPoints)([entryPoint]);
|
|
19
|
+
const depsTree = await (0, getDepsTree_1.getDepsTree)((0, utils_1.resolvePath)(cwd), sanitizedEntryPoints, webpackConfigPath);
|
|
20
|
+
const filePaths = Object.keys(depsTree);
|
|
21
|
+
if (filePaths.length === 0) {
|
|
22
|
+
console.log('No results found');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (count) {
|
|
26
|
+
console.log(filePaths.length);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
filePaths.forEach((filePath) => console.log(filePath));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
exports.default = createFiles;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
//eslint-disable-next-line
|
|
5
|
+
const pkg = require('../../package.json');
|
|
6
|
+
const createCommands_1 = require("./createCommands");
|
|
7
|
+
const program = new commander_1.Command('rev-dep');
|
|
8
|
+
program.version(pkg.version, '-v, --version');
|
|
9
|
+
(0, createCommands_1.createCommands)(program);
|
|
10
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.formatResults = void 0;
|
|
27
|
+
const colors = __importStar(require("colorette"));
|
|
28
|
+
const pathToString = (str, filePath, indentation) => {
|
|
29
|
+
return `${str ? `${str}\n` : ''}${' '.repeat(indentation)} ➞ ${filePath}`;
|
|
30
|
+
};
|
|
31
|
+
const join = (...args) => args.join(' ') + '\n';
|
|
32
|
+
function formatResults({ results, filePath, entryPoints, compactSummary }) {
|
|
33
|
+
let formatted = '';
|
|
34
|
+
const hasAnyResults = results.some((paths) => paths.length > 0);
|
|
35
|
+
if (!hasAnyResults) {
|
|
36
|
+
formatted = join('No results found for', filePath, 'in', entryPoints);
|
|
37
|
+
return formatted;
|
|
38
|
+
}
|
|
39
|
+
if (compactSummary) {
|
|
40
|
+
formatted += join('Results:\n');
|
|
41
|
+
const maxEntryLength = entryPoints.reduce((maxLength, entryPoint) => {
|
|
42
|
+
return entryPoint.length > maxLength ? entryPoint.length : maxLength;
|
|
43
|
+
}, 0);
|
|
44
|
+
let total = 0;
|
|
45
|
+
entryPoints.forEach((entry, index) => {
|
|
46
|
+
formatted += join(`${entry.padEnd(maxEntryLength)} :`, results[index].length);
|
|
47
|
+
total += results[index].length;
|
|
48
|
+
});
|
|
49
|
+
formatted += join('\nTotal:', total);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
results.forEach((entryPointResults, index) => {
|
|
53
|
+
if (entryPointResults.length > 0) {
|
|
54
|
+
formatted += join(colors.bold(entryPoints[index]), ':', '\n');
|
|
55
|
+
entryPointResults.forEach((path, resultsIndex) => {
|
|
56
|
+
const isLast = resultsIndex === entryPointResults.length - 1;
|
|
57
|
+
formatted += join(path.reduce(pathToString, ''), isLast ? '' : '\n');
|
|
58
|
+
});
|
|
59
|
+
if (index < results.length - 1 && entryPointResults.length > 0) {
|
|
60
|
+
formatted += join('_'.repeat(process.stdout.columns)) + '\n';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return formatted;
|
|
66
|
+
}
|
|
67
|
+
exports.formatResults = formatResults;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const find_1 = require("../../lib/find");
|
|
4
|
+
const formatResults_1 = require("./formatResults");
|
|
5
|
+
const utils_1 = require("../../lib/utils");
|
|
6
|
+
const commonOptions_1 = require("../commonOptions");
|
|
7
|
+
function createResolve(program) {
|
|
8
|
+
program
|
|
9
|
+
.command('resolve <filePath> [entryPoints...]')
|
|
10
|
+
.description('Checks if a filePath is required from entryPoint(s) and prints the resolution path', {
|
|
11
|
+
filePath: 'Path to a file that should be resolved in entry points',
|
|
12
|
+
'entryPoints...': 'List of entry points to look for file'
|
|
13
|
+
})
|
|
14
|
+
.option(...commonOptions_1.webpackConfigOption)
|
|
15
|
+
.option(...commonOptions_1.cwdOption)
|
|
16
|
+
.option(...commonOptions_1.reexportRewireOption)
|
|
17
|
+
.option(...commonOptions_1.includeOption)
|
|
18
|
+
.option(...commonOptions_1.excludeOption)
|
|
19
|
+
.option('-cs, --compactSummary', 'print a compact summary of reverse resolution with a count of found paths')
|
|
20
|
+
.option('-a, --all', 'finds all paths combination of a given dependency. Might work very slow or crash for some projects due to heavy usage of RAM', false)
|
|
21
|
+
.action(async (filePath, entryPoints, data) => {
|
|
22
|
+
const { compactSummary, webpackConfig, all, cwd, exclude, include } = data;
|
|
23
|
+
const sanitizedEntryPoints = (0, utils_1.sanitizeUserEntryPoints)(entryPoints);
|
|
24
|
+
const [results, resolveEntryPoints] = await (0, find_1.resolve)({
|
|
25
|
+
entryPoints: sanitizedEntryPoints,
|
|
26
|
+
filePath,
|
|
27
|
+
webpackConfig,
|
|
28
|
+
all,
|
|
29
|
+
cwd: (0, utils_1.resolvePath)(cwd),
|
|
30
|
+
exclude,
|
|
31
|
+
include
|
|
32
|
+
});
|
|
33
|
+
const formatted = (0, formatResults_1.formatResults)({
|
|
34
|
+
results,
|
|
35
|
+
entryPoints: resolveEntryPoints,
|
|
36
|
+
compactSummary,
|
|
37
|
+
filePath
|
|
38
|
+
});
|
|
39
|
+
console.log(formatted);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.default = createResolve;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildGraphDpdm = void 0;
|
|
4
|
+
const buildGraphDpdm = (deps, filePath) => (entryPoint) => {
|
|
5
|
+
const vertices = new Map();
|
|
6
|
+
let fileNode = null;
|
|
7
|
+
const inner = (path, visited = new Set(), depth = 1, parent = null) => {
|
|
8
|
+
const vertex = vertices.get(path);
|
|
9
|
+
if (vertex) {
|
|
10
|
+
vertex.parents.push(parent);
|
|
11
|
+
return vertex;
|
|
12
|
+
}
|
|
13
|
+
const localVisited = new Set(visited);
|
|
14
|
+
if (localVisited.has(path)) {
|
|
15
|
+
// console.error('CIRCULAR DEP', ...localVisited.values(), path)
|
|
16
|
+
return {
|
|
17
|
+
path: 'CIRCULAR',
|
|
18
|
+
parents: parent ? [parent] : [],
|
|
19
|
+
children: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
localVisited.add(path);
|
|
23
|
+
const dep = deps[path];
|
|
24
|
+
if (dep === undefined) {
|
|
25
|
+
throw new Error(`Dependency '${path}' not found!`);
|
|
26
|
+
}
|
|
27
|
+
const node = {
|
|
28
|
+
parents: parent ? [parent] : [],
|
|
29
|
+
path
|
|
30
|
+
};
|
|
31
|
+
node.children = (dep || [])
|
|
32
|
+
.map((d) => d.id)
|
|
33
|
+
.filter((path) => path !== null && !path.includes('node_modules'))
|
|
34
|
+
.map((path) => inner(path, localVisited, depth + 1, node));
|
|
35
|
+
vertices.set(path, node);
|
|
36
|
+
if (path === filePath) {
|
|
37
|
+
fileNode = node;
|
|
38
|
+
}
|
|
39
|
+
return node;
|
|
40
|
+
};
|
|
41
|
+
return [inner(entryPoint), fileNode, vertices];
|
|
42
|
+
};
|
|
43
|
+
exports.buildGraphDpdm = buildGraphDpdm;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cleanupDpdmDeps = void 0;
|
|
7
|
+
const is_builtin_module_1 = __importDefault(require("is-builtin-module"));
|
|
8
|
+
const cleanupDpdmDeps = (deps) => {
|
|
9
|
+
const newDeps = {};
|
|
10
|
+
Object.entries(deps).forEach(([id, dependencies]) => {
|
|
11
|
+
if (!(0, is_builtin_module_1.default)(id) &&
|
|
12
|
+
!id.includes('node_modules') &&
|
|
13
|
+
dependencies !== null) {
|
|
14
|
+
newDeps[id] = dependencies
|
|
15
|
+
.filter(({ id }) => id && !id.includes('node_modules'))
|
|
16
|
+
.map(({ id, request }) => ({
|
|
17
|
+
id,
|
|
18
|
+
request
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return newDeps;
|
|
23
|
+
};
|
|
24
|
+
exports.cleanupDpdmDeps = cleanupDpdmDeps;
|
package/dist/lib/find.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolve = void 0;
|
|
4
|
+
const buildDepsGraph_1 = require("./buildDepsGraph");
|
|
5
|
+
const getDepsTree_1 = require("./getDepsTree");
|
|
6
|
+
const getEntryPoints_1 = require("./getEntryPoints");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
const resolvePathsToRoot = (node, all = false, resolvedPaths = [[]]) => {
|
|
9
|
+
const newPaths = resolvedPaths.map((resolvedPath) => [
|
|
10
|
+
node.path,
|
|
11
|
+
...resolvedPath
|
|
12
|
+
]);
|
|
13
|
+
if (node.parents.length === 0) {
|
|
14
|
+
return newPaths;
|
|
15
|
+
}
|
|
16
|
+
if (all) {
|
|
17
|
+
return node.parents
|
|
18
|
+
.map((parentPath) => resolvePathsToRoot(parentPath, all, newPaths))
|
|
19
|
+
.flat(1);
|
|
20
|
+
}
|
|
21
|
+
return resolvePathsToRoot(node.parents[0], false, newPaths);
|
|
22
|
+
};
|
|
23
|
+
const resolve = async ({ entryPoints: _entryPoints, filePath, webpackConfig, cwd = process.cwd(), all, include, exclude }) => {
|
|
24
|
+
let deps, entryPoints;
|
|
25
|
+
if (_entryPoints.length > 0) {
|
|
26
|
+
entryPoints = _entryPoints;
|
|
27
|
+
deps = await (0, getDepsTree_1.getDepsTree)(cwd, entryPoints, webpackConfig);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
;
|
|
31
|
+
[entryPoints, deps] = await (0, getEntryPoints_1.getEntryPoints)({ cwd, exclude, include });
|
|
32
|
+
}
|
|
33
|
+
const cleanedEntryPoints = entryPoints.map(utils_1.removeInitialDot);
|
|
34
|
+
const cleanedFilePath = (0, utils_1.removeInitialDot)(filePath);
|
|
35
|
+
const forest = cleanedEntryPoints.map((0, buildDepsGraph_1.buildGraphDpdm)(deps, cleanedFilePath));
|
|
36
|
+
const resolvedPaths = forest.reduce((allPaths, [_, fileNode]) => {
|
|
37
|
+
if (!fileNode) {
|
|
38
|
+
return [...allPaths, []];
|
|
39
|
+
}
|
|
40
|
+
const pathsForTree = resolvePathsToRoot(fileNode, all);
|
|
41
|
+
return [...allPaths, pathsForTree];
|
|
42
|
+
}, []);
|
|
43
|
+
return [resolvedPaths, entryPoints];
|
|
44
|
+
};
|
|
45
|
+
exports.resolve = resolve;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDepsSetWebpack = void 0;
|
|
4
|
+
const dependency_cruiser_1 = require("dependency-cruiser");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
// eslint-disable-next-line
|
|
7
|
+
const resolveWebpackConfig = require('dependency-cruiser/config-utl/extract-webpack-resolve-config');
|
|
8
|
+
const normalizeDepsTree = (modules) => {
|
|
9
|
+
const normalized = {};
|
|
10
|
+
const nonResolvableDeps = [];
|
|
11
|
+
modules.forEach((mod) => {
|
|
12
|
+
const { source, dependencies } = mod;
|
|
13
|
+
if (!nonResolvableDeps.includes(source)) {
|
|
14
|
+
normalized[source] = dependencies
|
|
15
|
+
.filter(({ couldNotResolve, resolved: id }) => {
|
|
16
|
+
if (couldNotResolve) {
|
|
17
|
+
nonResolvableDeps.push(id);
|
|
18
|
+
}
|
|
19
|
+
return !couldNotResolve;
|
|
20
|
+
})
|
|
21
|
+
.map(({ resolved, module }) => ({
|
|
22
|
+
id: resolved,
|
|
23
|
+
request: module
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return normalized;
|
|
28
|
+
};
|
|
29
|
+
const getDepsSetWebpack = (entryPoints, webpackConfigPath, cwd, skipRegex) => {
|
|
30
|
+
const skip = skipRegex || '(node_modules|/__tests__|/__test__|/__mockContent__|.scss)';
|
|
31
|
+
const webpackResolveOptions = webpackConfigPath
|
|
32
|
+
? resolveWebpackConfig((0, utils_1.createResolveAbsolutePath)(cwd)(webpackConfigPath))
|
|
33
|
+
: null;
|
|
34
|
+
const result = (0, dependency_cruiser_1.cruise)(entryPoints, {
|
|
35
|
+
//@ts-ignore
|
|
36
|
+
exclude: skip,
|
|
37
|
+
//@ts-ignore
|
|
38
|
+
doNotFollow: { path: skip },
|
|
39
|
+
tsPreCompilationDeps: true,
|
|
40
|
+
baseDir: cwd
|
|
41
|
+
}, webpackResolveOptions);
|
|
42
|
+
return normalizeDepsTree(result.output.modules);
|
|
43
|
+
};
|
|
44
|
+
exports.getDepsSetWebpack = getDepsSetWebpack;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDepsTree = void 0;
|
|
4
|
+
const getDepsSetWebpack_1 = require("./getDepsSetWebpack");
|
|
5
|
+
const dpdm_1 = require("dpdm");
|
|
6
|
+
const cleanupDpdmDeps_1 = require("./cleanupDpdmDeps");
|
|
7
|
+
async function getDepsTree(cwd, entryPoints, webpackConfigPath) {
|
|
8
|
+
let deps;
|
|
9
|
+
if (webpackConfigPath) {
|
|
10
|
+
deps = (0, getDepsSetWebpack_1.getDepsSetWebpack)(entryPoints, webpackConfigPath, cwd);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
// dpdm does not support custom search directory :/
|
|
14
|
+
const oldProcessCwd = process.cwd;
|
|
15
|
+
process.cwd = () => cwd;
|
|
16
|
+
deps = (0, cleanupDpdmDeps_1.cleanupDpdmDeps)(await (0, dpdm_1.parseDependencyTree)(entryPoints, {
|
|
17
|
+
context: cwd
|
|
18
|
+
}));
|
|
19
|
+
process.cwd = oldProcessCwd;
|
|
20
|
+
}
|
|
21
|
+
return deps;
|
|
22
|
+
}
|
|
23
|
+
exports.getDepsTree = getDepsTree;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getEntryPoints = exports.findEntryPointsInDepsTree = exports.getDirectoriesForEntryPointsSearch = void 0;
|
|
7
|
+
const minimatch_1 = __importDefault(require("minimatch"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
|
+
const getDepsTree_1 = require("./getDepsTree");
|
|
12
|
+
const ignore_1 = __importDefault(require("ignore"));
|
|
13
|
+
const getDirectoriesForEntryPointsSearch = async (dir) => {
|
|
14
|
+
const entries = await promises_1.default.readdir(dir);
|
|
15
|
+
const directories = await (0, utils_1.asyncFilter)(entries, async (pathName) => {
|
|
16
|
+
if (pathName === 'node_modules' || pathName.startsWith('.')) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const stat = await promises_1.default.lstat(path_1.default.resolve(dir, pathName));
|
|
20
|
+
return stat.isDirectory();
|
|
21
|
+
});
|
|
22
|
+
const joinedWithDir = directories.map((pathName) => path_1.default.join(dir, pathName));
|
|
23
|
+
return [
|
|
24
|
+
...joinedWithDir,
|
|
25
|
+
...(await Promise.all(joinedWithDir.map(exports.getDirectoriesForEntryPointsSearch))).flat(1)
|
|
26
|
+
];
|
|
27
|
+
};
|
|
28
|
+
exports.getDirectoriesForEntryPointsSearch = getDirectoriesForEntryPointsSearch;
|
|
29
|
+
const findEntryPointsInDepsTree = (deps, exclude = [], include = undefined) => {
|
|
30
|
+
const referencedIds = new Set();
|
|
31
|
+
Object.values(deps).forEach((entry) => {
|
|
32
|
+
if (entry !== null) {
|
|
33
|
+
entry.forEach(({ id }) => referencedIds.add(id));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return Object.keys(deps)
|
|
37
|
+
.filter((id) => /\.(ts|tsx|mjs|js|jsx)$/.test(id) &&
|
|
38
|
+
!/node_modules/.test(id) &&
|
|
39
|
+
!referencedIds.has(id))
|
|
40
|
+
.filter((id) => exclude.reduce((result, pattern) => result && !(0, minimatch_1.default)(id, pattern), true))
|
|
41
|
+
.filter((id) => include
|
|
42
|
+
? include.reduce((result, pattern) => result || (0, minimatch_1.default)(id, pattern), false)
|
|
43
|
+
: true)
|
|
44
|
+
.sort();
|
|
45
|
+
};
|
|
46
|
+
exports.findEntryPointsInDepsTree = findEntryPointsInDepsTree;
|
|
47
|
+
const getEntryPoints = async ({ cwd, exclude, include, webpackConfigPath }) => {
|
|
48
|
+
const dirs = await (0, exports.getDirectoriesForEntryPointsSearch)(cwd);
|
|
49
|
+
const globs = dirs
|
|
50
|
+
.map((dirName) => path_1.default.relative(cwd, dirName))
|
|
51
|
+
.map((dirName) => `${dirName}/*`);
|
|
52
|
+
const globsWithRoot = ['*', ...globs];
|
|
53
|
+
const depsTree = await (0, getDepsTree_1.getDepsTree)(cwd, globsWithRoot, webpackConfigPath);
|
|
54
|
+
const possibleEntryPoints = (0, exports.findEntryPointsInDepsTree)(depsTree, exclude, include);
|
|
55
|
+
const ignoreInstance = (0, ignore_1.default)();
|
|
56
|
+
let gitignore = '';
|
|
57
|
+
try {
|
|
58
|
+
gitignore = (await promises_1.default.readFile(path_1.default.join(cwd, '.gitignore'))).toString();
|
|
59
|
+
const lines = gitignore.split('\n');
|
|
60
|
+
const nonCommentedNonEmptyLines = lines
|
|
61
|
+
.filter((line) => !/^(\s*)#/.test(line))
|
|
62
|
+
.filter((line) => !/^(\s*)$/.test(line));
|
|
63
|
+
gitignore = nonCommentedNonEmptyLines.join('\n');
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
e;
|
|
67
|
+
}
|
|
68
|
+
ignoreInstance.add(gitignore);
|
|
69
|
+
return [ignoreInstance.filter(possibleEntryPoints), depsTree];
|
|
70
|
+
};
|
|
71
|
+
exports.getEntryPoints = getEntryPoints;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMaxDepth = void 0;
|
|
4
|
+
const getMaxDepth = (depth = 1, path = [], vertices = new Map()) => {
|
|
5
|
+
return (tree) => {
|
|
6
|
+
const depthFromCache = vertices.get(tree.path);
|
|
7
|
+
if (depthFromCache) {
|
|
8
|
+
return depthFromCache;
|
|
9
|
+
}
|
|
10
|
+
const newPath = [...path, tree.path];
|
|
11
|
+
if (tree.children.length === 0) {
|
|
12
|
+
return [depth, newPath];
|
|
13
|
+
}
|
|
14
|
+
const results = tree.children.map((0, exports.getMaxDepth)(depth + 1, newPath, vertices));
|
|
15
|
+
const maxChildDepth = Math.max(...results.map(([depth]) => depth));
|
|
16
|
+
const itemWithMaxDepth = results.find(([depth]) => depth === maxChildDepth);
|
|
17
|
+
vertices.set(tree.path, itemWithMaxDepth);
|
|
18
|
+
return itemWithMaxDepth;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.getMaxDepth = getMaxDepth;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMaxDepth = void 0;
|
|
4
|
+
const getMaxDepth = (depth = 1, path = [], vertices = new Map()) => {
|
|
5
|
+
return (tree) => {
|
|
6
|
+
const depthFromCache = vertices.get(tree.path);
|
|
7
|
+
if (depthFromCache) {
|
|
8
|
+
return depthFromCache;
|
|
9
|
+
}
|
|
10
|
+
const newPath = [...path, tree.path];
|
|
11
|
+
if (tree.children.length === 0) {
|
|
12
|
+
return [depth, newPath];
|
|
13
|
+
}
|
|
14
|
+
const results = tree.children.map((0, exports.getMaxDepth)(depth + 1, newPath, vertices));
|
|
15
|
+
const maxChildDepth = Math.max(...results.map(([depth]) => depth));
|
|
16
|
+
const itemWithMaxDepth = results.find(([depth]) => depth === maxChildDepth);
|
|
17
|
+
vertices.set(tree.path, itemWithMaxDepth);
|
|
18
|
+
return itemWithMaxDepth;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.getMaxDepth = getMaxDepth;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolvePath = exports.sanitizeUserEntryPoints = exports.asyncFilter = exports.createResolveAbsolutePath = exports.removeInitialDot = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const glob_escape_1 = __importDefault(require("glob-escape"));
|
|
9
|
+
const removeInitialDot = (path) => path.replace(/^\.\//, '');
|
|
10
|
+
exports.removeInitialDot = removeInitialDot;
|
|
11
|
+
const createResolveAbsolutePath = (cwd) => (p) => (typeof p === 'string' ? path_1.default.resolve(cwd, p) : p);
|
|
12
|
+
exports.createResolveAbsolutePath = createResolveAbsolutePath;
|
|
13
|
+
const asyncFilter = async (arr, predicate) => {
|
|
14
|
+
const results = await Promise.all(arr.map(predicate));
|
|
15
|
+
return arr.filter((_v, index) => results[index]);
|
|
16
|
+
};
|
|
17
|
+
exports.asyncFilter = asyncFilter;
|
|
18
|
+
const sanitizeUserEntryPoints = (entryPoints) => {
|
|
19
|
+
const globEscapedEntryPoints = entryPoints.map(glob_escape_1.default);
|
|
20
|
+
return globEscapedEntryPoints;
|
|
21
|
+
};
|
|
22
|
+
exports.sanitizeUserEntryPoints = sanitizeUserEntryPoints;
|
|
23
|
+
const resolvePath = (p) => {
|
|
24
|
+
if (!p || path_1.default.isAbsolute(p)) {
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
return path_1.default.resolve(p);
|
|
28
|
+
};
|
|
29
|
+
exports.resolvePath = resolvePath;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rev-dep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
4
|
"description": "Reverse dependency resolution tool built with dependency-cruiser",
|
|
5
|
-
"main": "find.js",
|
|
6
|
-
"bin": "
|
|
5
|
+
"main": "lib/find.js",
|
|
6
|
+
"bin": "bin.js",
|
|
7
7
|
"files": [
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
8
|
+
"dist/**",
|
|
9
|
+
"lib/**",
|
|
10
|
+
"bin.js"
|
|
11
11
|
],
|
|
12
12
|
"author": "Jakub Mazurek @jayu",
|
|
13
13
|
"license": "MIT",
|
|
@@ -20,26 +20,40 @@
|
|
|
20
20
|
"node": ">=10"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"lint": "eslint
|
|
24
|
-
"lint:fix": "
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"cli": "node cli.js",
|
|
23
|
+
"lint": "eslint --ext .js,.ts src",
|
|
24
|
+
"lint:fix": "yarn lint --fix",
|
|
25
|
+
"docs-gen": "node ./scripts/addDocsToReadme.js",
|
|
26
|
+
"dev": "node bin",
|
|
28
27
|
"test": "jest",
|
|
29
|
-
"release": "release-it"
|
|
28
|
+
"release": "release-it",
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"build:watch": "tsc --watch",
|
|
31
|
+
"typecheck": "tsc --noEmit"
|
|
30
32
|
},
|
|
31
33
|
"dependencies": {
|
|
34
|
+
"@types/dedent": "^0.7.0",
|
|
35
|
+
"colorette": "^2.0.16",
|
|
32
36
|
"commander": "^6.1.0",
|
|
33
|
-
"
|
|
37
|
+
"dedent": "^0.7.0",
|
|
38
|
+
"dependency-cruiser": "9.23.0",
|
|
39
|
+
"dpdm": "^3.8.0",
|
|
40
|
+
"glob-escape": "^0.0.2",
|
|
41
|
+
"ignore": "^5.2.0",
|
|
42
|
+
"is-builtin-module": "^3.1.0",
|
|
43
|
+
"minimatch": "^5.0.1"
|
|
34
44
|
},
|
|
35
45
|
"devDependencies": {
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
|
47
|
+
"@typescript-eslint/parser": "^5.16.0",
|
|
36
48
|
"eslint": "^7.11.0",
|
|
37
|
-
"eslint-config-prettier": "^
|
|
49
|
+
"eslint-config-prettier": "^8.5.0",
|
|
38
50
|
"eslint-plugin-jest": "^24.1.0",
|
|
39
51
|
"eslint-plugin-node": "^11.1.0",
|
|
52
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
40
53
|
"jest": "^26.5.3",
|
|
41
54
|
"mock-fs": "^4.13.0",
|
|
42
55
|
"prettier": "^2.1.2",
|
|
43
|
-
"release-it": "^14.2.1"
|
|
56
|
+
"release-it": "^14.2.1",
|
|
57
|
+
"typescript": "^4.6.2"
|
|
44
58
|
}
|
|
45
59
|
}
|
package/cli.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const package = require('./package.json')
|
|
4
|
-
const { Command } = require('commander')
|
|
5
|
-
|
|
6
|
-
const { find } = require('./find')
|
|
7
|
-
const program = new Command('rev-dep')
|
|
8
|
-
program.version(package.version, '-v, --version')
|
|
9
|
-
|
|
10
|
-
const pathToString = (str, f, i) => {
|
|
11
|
-
return `${str ? `${str}\n` : ''}${' '.repeat(i)} ➞ ${f}`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
program
|
|
15
|
-
.command('resolve <filePath> <entryPoints...>')
|
|
16
|
-
.option(
|
|
17
|
-
'-cs, --compactSummary',
|
|
18
|
-
'print a compact summary of reverse resolution with a count of found paths'
|
|
19
|
-
)
|
|
20
|
-
.option('--verbose', 'print current action information')
|
|
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((filePath, entryPoints, data) => {
|
|
30
|
-
const { compactSummary, verbose, webpackConfig, typescriptConfig } = data
|
|
31
|
-
const results = find({
|
|
32
|
-
entryPoints,
|
|
33
|
-
filePath,
|
|
34
|
-
verbose,
|
|
35
|
-
webpackConfig,
|
|
36
|
-
typescriptConfig
|
|
37
|
-
})
|
|
38
|
-
const hasAnyResults = results.some((paths) => paths.length > 0)
|
|
39
|
-
if (!hasAnyResults) {
|
|
40
|
-
console.log('No results found for', filePath, 'in', entryPoints)
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
console.log('Results:\n')
|
|
44
|
-
if (compactSummary) {
|
|
45
|
-
const maxEntryLength = entryPoints.reduce((maxLength, entryPoint) => {
|
|
46
|
-
return entryPoint.length > maxLength ? entryPoint.length : maxLength
|
|
47
|
-
}, 0)
|
|
48
|
-
let total = 0
|
|
49
|
-
entryPoints.forEach((entry, index) => {
|
|
50
|
-
console.log(`${entry.padEnd(maxEntryLength)} :`, results[index].length)
|
|
51
|
-
total += results[index].length
|
|
52
|
-
})
|
|
53
|
-
console.log('\nTotal:', total)
|
|
54
|
-
} else {
|
|
55
|
-
results.forEach((entryPointResults, index) => {
|
|
56
|
-
entryPointResults.forEach((path) => {
|
|
57
|
-
console.log(path.reduce(pathToString, ''))
|
|
58
|
-
})
|
|
59
|
-
if (index < results.length - 1) {
|
|
60
|
-
console.log('_'.repeat(process.stdout.columns))
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
program.parse(process.argv)
|
package/find.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const getDepsSet = require('./getDepsSet')
|
|
3
|
-
|
|
4
|
-
const buildTree = (deps) => (entryPoint) => {
|
|
5
|
-
const inner = (path) => {
|
|
6
|
-
const dep = deps.find((d) => d.source === path)
|
|
7
|
-
if (dep === undefined) {
|
|
8
|
-
throw new Error(`Dependency '${path}' not found!`)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
path,
|
|
13
|
-
children: dep.dependencies.map((d) => {
|
|
14
|
-
if (d.circular) {
|
|
15
|
-
return { path: 'CIRCULAR', children: [] }
|
|
16
|
-
}
|
|
17
|
-
return inner(d.resolved)
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return inner(entryPoint)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const traverse = (file) => (tree) => {
|
|
25
|
-
if (tree.path === file) {
|
|
26
|
-
return [[file]]
|
|
27
|
-
} else {
|
|
28
|
-
return tree.children
|
|
29
|
-
.map(traverse(file)) // [ [[]],[[]],[[]] ]
|
|
30
|
-
.filter((p) => p.length > 0)
|
|
31
|
-
.map((pathsArr) => pathsArr.filter((p) => p.length > 0))
|
|
32
|
-
.reduce((flat, subPath) => {
|
|
33
|
-
return [...flat, ...subPath]
|
|
34
|
-
}, [])
|
|
35
|
-
.map((p) => [tree.path, ...p])
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const removeInitialDot = (path) => path.replace(/^\.\//, '')
|
|
40
|
-
|
|
41
|
-
const _resolveAbsolutePath = (cwd) => (p) => typeof p === 'string' ? path.resolve(cwd, p) : p
|
|
42
|
-
|
|
43
|
-
const find = ({
|
|
44
|
-
entryPoints,
|
|
45
|
-
filePath,
|
|
46
|
-
skipRegex,
|
|
47
|
-
verbose,
|
|
48
|
-
webpackConfig,
|
|
49
|
-
typescriptConfig,
|
|
50
|
-
cwd = process.cwd()
|
|
51
|
-
}) => {
|
|
52
|
-
const resolveAbsolutePath = _resolveAbsolutePath(cwd)
|
|
53
|
-
const absoluteEntryPoints = entryPoints.map(resolveAbsolutePath)
|
|
54
|
-
|
|
55
|
-
if (verbose) {
|
|
56
|
-
console.log('Entry points:')
|
|
57
|
-
console.log(absoluteEntryPoints)
|
|
58
|
-
console.log('Getting dependency set for entry points...')
|
|
59
|
-
}
|
|
60
|
-
const deps = getDepsSet(
|
|
61
|
-
absoluteEntryPoints,
|
|
62
|
-
skipRegex,
|
|
63
|
-
resolveAbsolutePath(webpackConfig),
|
|
64
|
-
resolveAbsolutePath(typescriptConfig)
|
|
65
|
-
)
|
|
66
|
-
const cleanedEntryPoints = entryPoints.map(removeInitialDot)
|
|
67
|
-
const cleanedFilePath = removeInitialDot(filePath)
|
|
68
|
-
if (verbose) {
|
|
69
|
-
console.log('Building dependency trees for entry points...')
|
|
70
|
-
}
|
|
71
|
-
const forest = cleanedEntryPoints.map(buildTree(deps))
|
|
72
|
-
if (verbose) {
|
|
73
|
-
console.log('Finding paths in dependency trees...')
|
|
74
|
-
}
|
|
75
|
-
const resolvedPaths = forest.reduce((allPaths, tree) => {
|
|
76
|
-
const paths = traverse(cleanedFilePath)(tree)
|
|
77
|
-
return [...allPaths, paths]
|
|
78
|
-
}, [])
|
|
79
|
-
return resolvedPaths
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
module.exports = { find }
|
package/getDepsSet.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const depcruise = require('dependency-cruiser').cruise
|
|
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) => {
|
|
7
|
-
const skip =
|
|
8
|
-
skipRegex || '(node_modules|/__tests__|/__test__|/__mockContent__|.scss)'
|
|
9
|
-
const webpackResolveOptions = webpackConfigPath ? resolveWebpackConfig(webpackConfigPath) : null
|
|
10
|
-
const tsConfigOptions = tsConfigPath ? resolveTsConfig(tsConfigPath) : null
|
|
11
|
-
|
|
12
|
-
const result = depcruise(entryPoints, {
|
|
13
|
-
exclude: skip,
|
|
14
|
-
doNotFollow: { path: skip },
|
|
15
|
-
tsPreCompilationDeps: true,
|
|
16
|
-
|
|
17
|
-
}, webpackResolveOptions, tsConfigOptions)
|
|
18
|
-
return result.output.modules
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = getDepsSet
|