rev-dep 1.0.0-alpha.2 → 1.0.0-alpha.5
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 +122 -68
- package/dist/babel/index.js +3 -6
- package/dist/cli/commonOptions.js +3 -3
- package/dist/cli/entryPoints/index.js +1 -1
- package/dist/cli/files/index.js +1 -1
- package/dist/cli/resolve/index.js +2 -3
- package/dist/lib/cleanupDpdmDeps.js +1 -1
- package/dist/lib/find.js +2 -1
- package/dist/lib/getEntryPoints.js +2 -1
- package/package.json +1 -1
- package/dist/babel/reexport-rewire.js +0 -277
- package/dist/lib/getMaxDepthInGrapth.js +0 -21
package/README.md
CHANGED
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
<h3 align="center">
|
|
2
|
-
<code>rev
|
|
2
|
+
<code>rev⭠dep</code>
|
|
3
3
|
</h3>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
|
|
6
|
+
Dependency debugging tool for JavaScript and TypeScript projects
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
<img alt="rev-dep version" src="https://img.shields.io/npm/v/rev-dep"> <img alt="rev-dep license" src="https://img.shields.io/npm/l/rev-dep"> <img alt="rev-dep PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square">
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## About
|
|
14
|
+
|
|
15
|
+
The tool was created help with daily dev struggles by answering these questions:
|
|
16
|
+
|
|
17
|
+
- What entry points my codebase have
|
|
18
|
+
- Which entry points uses a given file
|
|
19
|
+
- Which dependencies a given file has
|
|
20
|
+
|
|
21
|
+
This helps to debug project dependencies, plan refactoring, optimize bundles or plan code splitting.
|
|
22
|
+
|
|
23
|
+
It's especially useful in JS world without TypeScript or tests coverage.
|
|
24
|
+
|
|
25
|
+
It also helps to identify and eliminate dead files, understand the complexity of the file dependencies
|
|
26
|
+
|
|
27
|
+
[Jump to CLI reference](#CLI-reference)
|
|
28
|
+
|
|
29
|
+
[`export * from` problem](#Export-from-problem)
|
|
30
|
+
|
|
31
|
+
### Use cases
|
|
32
|
+
|
|
33
|
+
- You plan to refactor some file and you wonder which entry points are affected
|
|
34
|
+
- You are wondering wether a given source file is used
|
|
35
|
+
- You wonder if there are any dead files in your project
|
|
36
|
+
- You want to identify all dead files at once
|
|
37
|
+
- You want to verify if a given entry point imports only the required files
|
|
38
|
+
- You want to optimize the amount of files imported by an entry point
|
|
39
|
+
|
|
40
|
+
### How about dependency or bundle graphs?
|
|
41
|
+
|
|
42
|
+
There are tool that can output nice, visual representation of project dependencies like [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) or [dependency-cruiser](https://www.npmjs.com/package/dependency-cruiser) (_which btw rev-dep uses for non-TS codebases_)
|
|
43
|
+
|
|
44
|
+
While graphs can be useful to identify major problems like too big bundle size or to visualize mess in your deps, it's hard to take any action based on them (_at least it was hard for me_ 🤷♂️)
|
|
45
|
+
|
|
46
|
+
`rev-dep` visualize dependencies as lists, so it's really easy to see where to cut the line to solve the problem.
|
|
47
|
+
|
|
48
|
+
## Getting Started
|
|
14
49
|
|
|
15
50
|
### Install globally to use as CLI tool
|
|
16
51
|
|
|
@@ -28,59 +63,31 @@ or
|
|
|
28
63
|
|
|
29
64
|
`npm install rev-dep`
|
|
30
65
|
|
|
31
|
-
##
|
|
66
|
+
## Recipes
|
|
32
67
|
|
|
33
|
-
|
|
68
|
+
### How to identify where a file is used in the project?
|
|
34
69
|
|
|
35
|
-
|
|
36
|
-
rev-dep resolve getDepsSet.js cli.js
|
|
37
|
-
```
|
|
70
|
+
### How to check if a file is used in the project?
|
|
38
71
|
|
|
39
|
-
|
|
72
|
+
### How to identify dead files in the project?
|
|
40
73
|
|
|
41
|
-
|
|
42
|
-
Results:
|
|
43
|
-
|
|
44
|
-
➞ cli.js
|
|
45
|
-
➞ find.js
|
|
46
|
-
➞ getDepsSet.js
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Which says that `getDepsSet.js` file is used in `cli.js` entry point and is required through `find.js`
|
|
50
|
-
|
|
51
|
-
## About
|
|
52
|
-
|
|
53
|
-
The tool was created to determine places in the project where a particular file is used, to test wether the refactoring do not break functionalities.
|
|
54
|
-
|
|
55
|
-
It's especially useful in JS world without TypeScript or tests coverage.
|
|
74
|
+
### How to check which files are imported by a given file?
|
|
56
75
|
|
|
57
|
-
|
|
76
|
+
### How to reduce amount of files imported by entry point?
|
|
58
77
|
|
|
59
78
|
## Usage
|
|
60
79
|
|
|
61
|
-
Project can be used as a CLI tool or as a
|
|
80
|
+
Project can be used as a CLI tool or as a module
|
|
62
81
|
|
|
63
82
|
### CLI Tool
|
|
64
83
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#### `resolve`
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
rev-dep resolve <filePath> <entryPoints...>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Available options are
|
|
74
|
-
|
|
75
|
-
- `-cs or --compactSummary` - instead of file paths print a compact summary of reverse resolution with a count of found paths
|
|
76
|
-
- `--verbose` - log currently performed operation
|
|
77
|
-
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support
|
|
84
|
+
For CLI usage see [CLI reference](#CLI-reference)
|
|
78
85
|
|
|
79
86
|
### Module
|
|
80
87
|
|
|
81
88
|
#### `find` Function
|
|
82
89
|
|
|
83
|
-
```
|
|
90
|
+
```ts
|
|
84
91
|
import { find } from "rev-dep";
|
|
85
92
|
|
|
86
93
|
const path = find({
|
|
@@ -91,25 +98,18 @@ const path = find({
|
|
|
91
98
|
console.log(path);
|
|
92
99
|
```
|
|
93
100
|
|
|
94
|
-
#### `find`
|
|
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**
|
|
97
|
-
- `filePath (String)` - A file that we want to find path for. **Required**
|
|
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)'`
|
|
99
|
-
- `verbose (Boolean)` - when set to true, will print current operation performed by find function. _Optional_, default: `false`
|
|
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
|
|
101
|
+
#### `find` Function
|
|
106
102
|
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
```ts
|
|
104
|
+
import { find } from "rev-dep";
|
|
109
105
|
|
|
110
|
-
|
|
106
|
+
const path = find({
|
|
107
|
+
entryPoints: ["index.js"],
|
|
108
|
+
filePath: "utils.js",
|
|
109
|
+
});
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
console.log(path);
|
|
112
|
+
```
|
|
113
113
|
|
|
114
114
|
## CLI reference
|
|
115
115
|
|
|
@@ -133,9 +133,8 @@ rev-dep resolve <filePath> [entryPoints...] [options]
|
|
|
133
133
|
|
|
134
134
|
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
135
135
|
- `--cwd <path>` - path to a directory that should be used as a resolution root (_optional_)
|
|
136
|
-
-
|
|
137
|
-
- `-
|
|
138
|
-
- `-e exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
136
|
+
- `-i --include <globs...>` - A list of globs to determine files included in entry points search (_optional_)
|
|
137
|
+
- `-e --exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
139
138
|
- `-cs, --compactSummary` - print a compact summary of reverse resolution with a count of found paths (_optional_)
|
|
140
139
|
- `-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
140
|
|
|
@@ -153,9 +152,8 @@ rev-dep entry-points [options]
|
|
|
153
152
|
|
|
154
153
|
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
155
154
|
- `--cwd <path>` - path to a directory that should be used as a resolution root (_optional_)
|
|
156
|
-
-
|
|
157
|
-
- `-
|
|
158
|
-
- `-e exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
155
|
+
- `-i --include <globs...>` - A list of globs to determine files included in entry points search (_optional_)
|
|
156
|
+
- `-e --exclude <globs...>` - A list of globs to determine files excluded in entry points search (_optional_)
|
|
159
157
|
- `-pdc, --printDependenciesCount` - print count of entry point dependencies (_optional_)
|
|
160
158
|
- `-c, --count` - print just count of found entry points (_optional_)
|
|
161
159
|
|
|
@@ -177,7 +175,6 @@ rev-dep files <entryPoint> [options]
|
|
|
177
175
|
|
|
178
176
|
- `-wc, --webpackConfig <path>` - path to webpack config to enable webpack aliases support (_optional_)
|
|
179
177
|
- `--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
178
|
- `-c, --count` - print only count of entry point dependencies (_optional_)
|
|
182
179
|
|
|
183
180
|
### Command `docs`
|
|
@@ -199,6 +196,59 @@ rev-dep docs <outputPath> [options]
|
|
|
199
196
|
- `-hl, --headerLevel <value>` - Initial header level (_optional_)
|
|
200
197
|
<!-- cli-docs-end -->
|
|
201
198
|
|
|
199
|
+
## Export from problem
|
|
200
|
+
|
|
201
|
+
`rev-dep` attempts to also solve `export * from` by a babel plugin that can be used as follows
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
// babel.config.js
|
|
205
|
+
module.exports = {
|
|
206
|
+
plugins: [
|
|
207
|
+
'rev-dep/babel'
|
|
208
|
+
]
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The plugins is currently **experimental** and might not work for all codebases!
|
|
213
|
+
|
|
214
|
+
It helps by rewiring paths to re-exported modules
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
// file.ts
|
|
218
|
+
import { add } from "./utils";
|
|
219
|
+
|
|
220
|
+
// utils/index.ts
|
|
221
|
+
|
|
222
|
+
export * from "./math";
|
|
223
|
+
export * from "./otherModule";
|
|
224
|
+
export * from "./anotherModule";
|
|
225
|
+
|
|
226
|
+
// utils/math.ts
|
|
227
|
+
|
|
228
|
+
export const add = () => {};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
And for `file.ts` it would rewire the import like this
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
// file.ts
|
|
235
|
+
import { add } from "./utils/math";
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
So as a result, we don't implicitly require `./otherModule` and `./anotherModule` which we will not use anyway
|
|
239
|
+
|
|
240
|
+
### Benefits
|
|
241
|
+
|
|
242
|
+
I don't have solid evidence for this, but I think it reduced RAM usage of the dev server I worked with (_blitz.js_). It crashed less often due to reaching heap size limit.
|
|
243
|
+
|
|
244
|
+
But for sure it reduced bundle size, _slightly_, but still 😀
|
|
245
|
+
|
|
246
|
+
It all depends on the the project dependencies structure.
|
|
247
|
+
|
|
248
|
+
By using the babel plugin you will reduce a risk of problems like implicitly importing `front-end` modules on the `server` or similar while still being able to benefit from short import paths.
|
|
249
|
+
|
|
250
|
+
Once I got an incident that, after a rebase with main branch, my project stopped compiling due to the problem caused by `export * from`. I spend a few hours debugging that, very frustrating.
|
|
251
|
+
|
|
202
252
|
## Contributing
|
|
203
253
|
|
|
204
254
|
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 :)
|
|
@@ -207,16 +257,20 @@ Project is open to contributions, just rise an issue if you have some ideas abou
|
|
|
207
257
|
|
|
208
258
|
1. Clone repo
|
|
209
259
|
2. Install deps using `yarn`
|
|
210
|
-
3. Run
|
|
260
|
+
3. Run `yarn build:watch`
|
|
211
261
|
4. Code!
|
|
212
262
|
|
|
213
|
-
For testing purpose
|
|
263
|
+
For testing purpose use
|
|
264
|
+
|
|
265
|
+
`yarn dev [command] --cwd path/to/some/codebase`
|
|
266
|
+
|
|
267
|
+
or you can install CLI tool from the file system using
|
|
214
268
|
|
|
215
|
-
`yarn global add
|
|
269
|
+
`yarn global add $PWD`
|
|
216
270
|
|
|
217
|
-
|
|
271
|
+
and then just run
|
|
218
272
|
|
|
219
|
-
`
|
|
273
|
+
`rev-dep`
|
|
220
274
|
|
|
221
275
|
## Made with 🧠 by [@jayu](https://github.com/jayu)
|
|
222
276
|
|
package/dist/babel/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*eslint-disable @typescript-eslint/no-var-requires */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
const node_path = require('path');
|
|
4
5
|
const fs = require('fs');
|
|
5
6
|
const parser = require('@babel/parser');
|
|
6
7
|
const template = require('@babel/template').default;
|
|
8
|
+
const utils_1 = require("../lib/utils");
|
|
7
9
|
const SKIP = Symbol('SKIP');
|
|
8
|
-
module.exports = function plugin({ types }, { tsConfigPath }) {
|
|
10
|
+
module.exports = function plugin({ types }, { tsConfigPath = (0, utils_1.findTsConfig)() }) {
|
|
9
11
|
const tsConfig = require(tsConfigPath);
|
|
10
12
|
const aliases = tsConfig.compilerOptions.paths;
|
|
11
13
|
const aliasesKeys = Object.keys(aliases);
|
|
@@ -164,11 +166,6 @@ module.exports = function plugin({ types }, { tsConfigPath }) {
|
|
|
164
166
|
};
|
|
165
167
|
return {
|
|
166
168
|
visitor: {
|
|
167
|
-
Program: {
|
|
168
|
-
enter(_, { filename }) {
|
|
169
|
-
//console.log(filename);
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
169
|
ImportDeclaration(path, { filename, cwd }) {
|
|
173
170
|
const sourceRelative = (source) => {
|
|
174
171
|
const rel = node_path.relative(node_path.dirname(filename), source);
|
|
@@ -11,14 +11,14 @@ exports.cwdOption = [
|
|
|
11
11
|
process.cwd()
|
|
12
12
|
];
|
|
13
13
|
exports.reexportRewireOption = [
|
|
14
|
-
'
|
|
14
|
+
'-rr --reexportRewire <value>',
|
|
15
15
|
'resolve actual dependencies for "export * from" statements'
|
|
16
16
|
];
|
|
17
17
|
exports.includeOption = [
|
|
18
|
-
'-i include <globs...>',
|
|
18
|
+
'-i --include <globs...>',
|
|
19
19
|
'A list of globs to determine files included in entry points search'
|
|
20
20
|
];
|
|
21
21
|
exports.excludeOption = [
|
|
22
|
-
'-e exclude <globs...>',
|
|
22
|
+
'-e --exclude <globs...>',
|
|
23
23
|
'A list of globs to determine files excluded in entry points search'
|
|
24
24
|
];
|
|
@@ -10,7 +10,7 @@ function createEntryPoints(program) {
|
|
|
10
10
|
.description('Print list of entry points in current directory')
|
|
11
11
|
.option(...commonOptions_1.webpackConfigOption)
|
|
12
12
|
.option(...commonOptions_1.cwdOption)
|
|
13
|
-
.option(...
|
|
13
|
+
// .option(...reexportRewireOption)
|
|
14
14
|
.option(...commonOptions_1.includeOption)
|
|
15
15
|
.option(...commonOptions_1.excludeOption)
|
|
16
16
|
.option('-pdc, --printDependenciesCount', 'print count of entry point dependencies', false)
|
package/dist/cli/files/index.js
CHANGED
|
@@ -11,7 +11,7 @@ function createFiles(program) {
|
|
|
11
11
|
})
|
|
12
12
|
.option(...commonOptions_1.webpackConfigOption)
|
|
13
13
|
.option(...commonOptions_1.cwdOption)
|
|
14
|
-
.option(...
|
|
14
|
+
// .option(...reexportRewireOption)
|
|
15
15
|
.option('-c, --count', 'print only count of entry point dependencies', false)
|
|
16
16
|
.action(async (entryPoint, data) => {
|
|
17
17
|
const { webpackConfig: webpackConfigPath, cwd, count } = data;
|
|
@@ -13,16 +13,15 @@ function createResolve(program) {
|
|
|
13
13
|
})
|
|
14
14
|
.option(...commonOptions_1.webpackConfigOption)
|
|
15
15
|
.option(...commonOptions_1.cwdOption)
|
|
16
|
-
.option(...
|
|
16
|
+
// .option(...reexportRewireOption)
|
|
17
17
|
.option(...commonOptions_1.includeOption)
|
|
18
18
|
.option(...commonOptions_1.excludeOption)
|
|
19
19
|
.option('-cs, --compactSummary', 'print a compact summary of reverse resolution with a count of found paths')
|
|
20
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
21
|
.action(async (filePath, entryPoints, data) => {
|
|
22
22
|
const { compactSummary, webpackConfig, all, cwd, exclude, include } = data;
|
|
23
|
-
const sanitizedEntryPoints = (0, utils_1.sanitizeUserEntryPoints)(entryPoints);
|
|
24
23
|
const [results, resolveEntryPoints] = await (0, find_1.resolve)({
|
|
25
|
-
entryPoints
|
|
24
|
+
entryPoints,
|
|
26
25
|
filePath,
|
|
27
26
|
webpackConfig,
|
|
28
27
|
all,
|
|
@@ -12,7 +12,7 @@ const cleanupDpdmDeps = (deps) => {
|
|
|
12
12
|
!id.includes('node_modules') &&
|
|
13
13
|
dependencies !== null) {
|
|
14
14
|
newDeps[id] = dependencies
|
|
15
|
-
.filter(({ id }) => id && !id.includes('node_modules'))
|
|
15
|
+
.filter(({ id }) => id && !id.includes('node_modules') && !(0, is_builtin_module_1.default)(id))
|
|
16
16
|
.map(({ id, request }) => ({
|
|
17
17
|
id,
|
|
18
18
|
request
|
package/dist/lib/find.js
CHANGED
|
@@ -24,7 +24,8 @@ const resolve = async ({ entryPoints: _entryPoints, filePath, webpackConfig, cwd
|
|
|
24
24
|
let deps, entryPoints;
|
|
25
25
|
if (_entryPoints.length > 0) {
|
|
26
26
|
entryPoints = _entryPoints;
|
|
27
|
-
|
|
27
|
+
const sanitizedEntryPoints = (0, utils_1.sanitizeUserEntryPoints)(entryPoints);
|
|
28
|
+
deps = await (0, getDepsTree_1.getDepsTree)(cwd, sanitizedEntryPoints, webpackConfig);
|
|
28
29
|
}
|
|
29
30
|
else {
|
|
30
31
|
;
|
|
@@ -10,6 +10,7 @@ const promises_1 = __importDefault(require("fs/promises"));
|
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
const getDepsTree_1 = require("./getDepsTree");
|
|
12
12
|
const ignore_1 = __importDefault(require("ignore"));
|
|
13
|
+
const glob_escape_1 = __importDefault(require("glob-escape"));
|
|
13
14
|
const getDirectoriesForEntryPointsSearch = async (dir) => {
|
|
14
15
|
const entries = await promises_1.default.readdir(dir);
|
|
15
16
|
const directories = await (0, utils_1.asyncFilter)(entries, async (pathName) => {
|
|
@@ -48,7 +49,7 @@ const getEntryPoints = async ({ cwd, exclude, include, webpackConfigPath }) => {
|
|
|
48
49
|
const dirs = await (0, exports.getDirectoriesForEntryPointsSearch)(cwd);
|
|
49
50
|
const globs = dirs
|
|
50
51
|
.map((dirName) => path_1.default.relative(cwd, dirName))
|
|
51
|
-
.map((dirName) => `${dirName}/*`);
|
|
52
|
+
.map((dirName) => `${(0, glob_escape_1.default)(dirName)}/*`);
|
|
52
53
|
const globsWithRoot = ['*', ...globs];
|
|
53
54
|
const depsTree = await (0, getDepsTree_1.getDepsTree)(cwd, globsWithRoot, webpackConfigPath);
|
|
54
55
|
const possibleEntryPoints = (0, exports.findEntryPointsInDepsTree)(depsTree, exclude, include);
|
package/package.json
CHANGED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*eslint-disable @typescript-eslint/no-var-requires */
|
|
3
|
-
const node_path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const parser = require('@babel/parser');
|
|
6
|
-
const template = require('@babel/template').default;
|
|
7
|
-
const SKIP = Symbol('SKIP');
|
|
8
|
-
module.exports = function plugin({ types }, { tsConfigPath }) {
|
|
9
|
-
const tsConfig = require(tsConfigPath);
|
|
10
|
-
const aliases = tsConfig.compilerOptions.paths;
|
|
11
|
-
const aliasesKeys = Object.keys(aliases);
|
|
12
|
-
const aliasesRegexes = Object.keys(aliases).map((alias) => {
|
|
13
|
-
return new RegExp(`^${alias.replace('*', '(.)+')}$`);
|
|
14
|
-
});
|
|
15
|
-
const cache = new Map();
|
|
16
|
-
const getFile = (original, paths) => {
|
|
17
|
-
if (paths.length === 0) {
|
|
18
|
-
throw new Error('Cannot resolve import ' + original);
|
|
19
|
-
}
|
|
20
|
-
const path = paths[0];
|
|
21
|
-
try {
|
|
22
|
-
return [path, fs.readFileSync(path).toString()];
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
return getFile(original, paths.slice(1));
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const isPathRelativeOrAliased = (path) => {
|
|
29
|
-
const aliasRegexIdx = aliasesRegexes.findIndex((aliasRegex) => aliasRegex.test(path));
|
|
30
|
-
const isRelative = path.startsWith('./') || path.startsWith('../');
|
|
31
|
-
return aliasRegexIdx > -1 || isRelative;
|
|
32
|
-
};
|
|
33
|
-
const cacheKey = (identifier, filePath) => `${identifier}-${filePath}`;
|
|
34
|
-
const lookup = (identifier, filePath, cwd) => {
|
|
35
|
-
const cached = cache.get(cacheKey(identifier, filePath));
|
|
36
|
-
if (cached) {
|
|
37
|
-
return cached;
|
|
38
|
-
}
|
|
39
|
-
const withExtension = /(\.ts|\.tsx)$/.test(filePath)
|
|
40
|
-
? [filePath]
|
|
41
|
-
: [
|
|
42
|
-
`${filePath}.ts`,
|
|
43
|
-
`${filePath}.tsx`,
|
|
44
|
-
`${filePath}/index.ts`,
|
|
45
|
-
`${filePath}/index.tsx`,
|
|
46
|
-
`${filePath}.js`,
|
|
47
|
-
`${filePath}.jsx`,
|
|
48
|
-
`${filePath}/index.js`,
|
|
49
|
-
`${filePath}/index.jsx`
|
|
50
|
-
];
|
|
51
|
-
const [resolvedFilePath, file] = getFile(filePath, withExtension);
|
|
52
|
-
const ast = parser.parse(file, {
|
|
53
|
-
sourceType: 'module',
|
|
54
|
-
plugins: [
|
|
55
|
-
'jsx',
|
|
56
|
-
'typescript',
|
|
57
|
-
'objectRestSpread',
|
|
58
|
-
'classProperties',
|
|
59
|
-
'asyncGenerators',
|
|
60
|
-
'decorators-legacy'
|
|
61
|
-
]
|
|
62
|
-
});
|
|
63
|
-
/**
|
|
64
|
-
* {
|
|
65
|
-
* identifier?: string,
|
|
66
|
-
* source: string
|
|
67
|
-
* }
|
|
68
|
-
*/
|
|
69
|
-
const toLookup = [];
|
|
70
|
-
let resolvedAs = null;
|
|
71
|
-
ast.program.body.forEach((declaration) => {
|
|
72
|
-
var _a;
|
|
73
|
-
if (resolvedAs === null) {
|
|
74
|
-
if (types.isExportNamedDeclaration(declaration)) {
|
|
75
|
-
if (types.isVariableDeclaration(declaration.declaration)) {
|
|
76
|
-
const hasIdentifier = declaration.declaration.declarations.find((declarator) => {
|
|
77
|
-
return declarator.id.name === identifier;
|
|
78
|
-
});
|
|
79
|
-
if (hasIdentifier) {
|
|
80
|
-
resolvedAs = {
|
|
81
|
-
type: 'named',
|
|
82
|
-
identifier,
|
|
83
|
-
source: filePath
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else if (types.isFunctionDeclaration(declaration.declaration) ||
|
|
88
|
-
types.isClassDeclaration(declaration.declaration)) {
|
|
89
|
-
if (declaration.declaration.id.name === identifier) {
|
|
90
|
-
resolvedAs = {
|
|
91
|
-
type: 'named',
|
|
92
|
-
identifier,
|
|
93
|
-
source: filePath
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
const source = (_a = declaration.source) === null || _a === void 0 ? void 0 : _a.value;
|
|
99
|
-
declaration.specifiers.forEach((specifier) => {
|
|
100
|
-
if (types.isExportSpecifier(specifier)) {
|
|
101
|
-
if (specifier.exported.name === identifier) {
|
|
102
|
-
if (specifier.local.name === 'default' && source) {
|
|
103
|
-
resolvedAs = {
|
|
104
|
-
type: 'default',
|
|
105
|
-
identifier,
|
|
106
|
-
source: getModulePath(source, resolvedFilePath, cwd)
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
else if (source === undefined) {
|
|
110
|
-
resolvedAs = {
|
|
111
|
-
type: 'named',
|
|
112
|
-
identifier,
|
|
113
|
-
source: filePath
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
else if (isPathRelativeOrAliased(source)) {
|
|
117
|
-
toLookup.push({
|
|
118
|
-
identifier: specifier.exported.local,
|
|
119
|
-
source: getModulePath(source, resolvedFilePath, cwd)
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else if (types.isExportAllDeclaration(declaration) &&
|
|
128
|
-
isPathRelativeOrAliased(declaration.source.value)) {
|
|
129
|
-
toLookup.push({
|
|
130
|
-
identifier,
|
|
131
|
-
source: getModulePath(declaration.source.value, resolvedFilePath, cwd)
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
if (resolvedAs) {
|
|
137
|
-
return resolvedAs;
|
|
138
|
-
}
|
|
139
|
-
const nestedResult = toLookup
|
|
140
|
-
.map(({ identifier, source }) => lookup(identifier, source, cwd))
|
|
141
|
-
.filter(Boolean);
|
|
142
|
-
return nestedResult[0];
|
|
143
|
-
};
|
|
144
|
-
const getModulePath = (sourcePath, fileName, cwd) => {
|
|
145
|
-
var _a;
|
|
146
|
-
const aliasRegexIdx = aliasesRegexes.findIndex((aliasRegex) => aliasRegex.test(sourcePath));
|
|
147
|
-
const relativeFileName = node_path.relative(cwd, fileName);
|
|
148
|
-
const aliasKey = aliasesKeys[aliasRegexIdx];
|
|
149
|
-
const alias = (_a = aliases[aliasKey]) === null || _a === void 0 ? void 0 : _a[0];
|
|
150
|
-
let modulePath = '';
|
|
151
|
-
if (alias) {
|
|
152
|
-
let relative = alias;
|
|
153
|
-
if (aliasKey.endsWith('*')) {
|
|
154
|
-
const aliasKeyPrefix = aliasKey.replace('*', '');
|
|
155
|
-
relative = alias.replace('*', sourcePath.replace(aliasKeyPrefix, ''));
|
|
156
|
-
}
|
|
157
|
-
modulePath = node_path.resolve(cwd, relative);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
// we need ../ to skip current file name
|
|
161
|
-
modulePath = node_path.resolve(relativeFileName, '../' + sourcePath);
|
|
162
|
-
}
|
|
163
|
-
return modulePath;
|
|
164
|
-
};
|
|
165
|
-
return {
|
|
166
|
-
visitor: {
|
|
167
|
-
Program: {
|
|
168
|
-
enter(_, { filename }) {
|
|
169
|
-
//console.log(filename);
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
ImportDeclaration(path, { filename, cwd }) {
|
|
173
|
-
const sourceRelative = (source) => {
|
|
174
|
-
const rel = node_path.relative(node_path.dirname(filename), source);
|
|
175
|
-
return rel.startsWith('.') ? rel : './' + rel;
|
|
176
|
-
};
|
|
177
|
-
const node = path.node;
|
|
178
|
-
const source = node.source;
|
|
179
|
-
if (source.type !== 'StringLiteral') {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const shouldSkip = node[SKIP] || !isPathRelativeOrAliased(source.value);
|
|
183
|
-
if (shouldSkip) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const modulePath = getModulePath(source.value, filename, cwd);
|
|
187
|
-
const defaultSpecifier = node.specifiers.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
|
|
188
|
-
const namespaceSpecifier = node.specifiers.find((specifier) => specifier.type === 'ImportNamespaceSpecifier');
|
|
189
|
-
const specifiers = node.specifiers.filter((specifier) => specifier.type === 'ImportSpecifier');
|
|
190
|
-
const results = specifiers.map((specifier) => {
|
|
191
|
-
const importedName = specifier.imported.name;
|
|
192
|
-
const result = lookup(importedName, modulePath, cwd);
|
|
193
|
-
if (!result) {
|
|
194
|
-
return {
|
|
195
|
-
identifier: importedName,
|
|
196
|
-
local: specifier.local.name,
|
|
197
|
-
source: source.value
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
cache.set(cacheKey(importedName, modulePath), result);
|
|
201
|
-
return {
|
|
202
|
-
...result,
|
|
203
|
-
source: sourceRelative(result.source),
|
|
204
|
-
local: specifier.local.name
|
|
205
|
-
};
|
|
206
|
-
});
|
|
207
|
-
const defaultResult = defaultSpecifier
|
|
208
|
-
? lookup('default', modulePath, cwd)
|
|
209
|
-
: null;
|
|
210
|
-
if (defaultResult) {
|
|
211
|
-
cache.set(cacheKey('default', modulePath), defaultResult);
|
|
212
|
-
}
|
|
213
|
-
const buildNamed = template(`
|
|
214
|
-
import { %%IMPORT_NAME%% } from %%SOURCE%%;
|
|
215
|
-
`);
|
|
216
|
-
const buildNamedWithAlias = template(`
|
|
217
|
-
import { %%IMPORTED_NAME%% as %%LOCAL_NAME%% } from %%SOURCE%%;
|
|
218
|
-
`);
|
|
219
|
-
const buildDefault = template(`
|
|
220
|
-
import %%IMPORT_NAME%% from %%SOURCE%%;
|
|
221
|
-
`);
|
|
222
|
-
const buildNamespace = template(`
|
|
223
|
-
import * as %%IMPORT_NAME%% from %%SOURCE%%;
|
|
224
|
-
`);
|
|
225
|
-
const defaultImport = defaultResult
|
|
226
|
-
? [
|
|
227
|
-
buildDefault({
|
|
228
|
-
IMPORT_NAME: types.identifier(defaultSpecifier.local.name),
|
|
229
|
-
SOURCE: types.stringLiteral(sourceRelative(defaultResult.source))
|
|
230
|
-
})
|
|
231
|
-
]
|
|
232
|
-
: defaultSpecifier
|
|
233
|
-
? [
|
|
234
|
-
buildDefault({
|
|
235
|
-
IMPORT_NAME: types.identifier(defaultSpecifier.local.name),
|
|
236
|
-
SOURCE: types.stringLiteral(source.value)
|
|
237
|
-
})
|
|
238
|
-
]
|
|
239
|
-
: [];
|
|
240
|
-
const namespaceImport = namespaceSpecifier
|
|
241
|
-
? [
|
|
242
|
-
buildNamespace({
|
|
243
|
-
IMPORT_NAME: types.identifier(namespaceSpecifier.local.name),
|
|
244
|
-
SOURCE: types.stringLiteral(source.value)
|
|
245
|
-
})
|
|
246
|
-
]
|
|
247
|
-
: [];
|
|
248
|
-
const named = results.map(({ type, identifier, local, source }) => {
|
|
249
|
-
if (type === 'default') {
|
|
250
|
-
return buildDefault({
|
|
251
|
-
IMPORT_NAME: types.identifier(identifier),
|
|
252
|
-
SOURCE: types.stringLiteral(source)
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
else if (identifier !== local) {
|
|
256
|
-
return buildNamedWithAlias({
|
|
257
|
-
IMPORTED_NAME: types.identifier(identifier),
|
|
258
|
-
LOCAL_NAME: types.identifier(local),
|
|
259
|
-
SOURCE: types.stringLiteral(source)
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
return buildNamed({
|
|
264
|
-
IMPORT_NAME: types.identifier(identifier),
|
|
265
|
-
SOURCE: types.stringLiteral(source)
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
const newImports = [...namespaceImport, ...defaultImport, ...named].map((node) => {
|
|
270
|
-
node[SKIP] = true;
|
|
271
|
-
return node;
|
|
272
|
-
});
|
|
273
|
-
path.replaceWithMultiple(newImports);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
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;
|