-
Notifications
You must be signed in to change notification settings - Fork 486
/
Copy pathmoduleDeps.js
108 lines (92 loc) · 2.5 KB
/
moduleDeps.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import path from 'path';
import util from 'util';
import r from 'resolve';
import readFileCode from './readFileCode.js';
import konan from 'konan';
import { parseToAst } from '../parsers/parse_to_ast.js';
// const parseExst = ['.js', '.mjs', '.jsx', '.vue', '.ts', '.tsx'];
const resolveExst = ['.json', '.css', '.less', '.sass'];
const resolve = util.promisify(r);
class Deps {
constructor(opts = {}) {
this.fileCache = opts.fileCache || {};
this.visited = {};
this.res = [];
this.options = { ...opts };
}
async flush(input) {
const promises = input.map(file => {
const dir = path.dirname(file);
return this.walk(file, {
basedir: dir,
filename: 'root'
});
});
await Promise.all(promises);
return this.res;
}
async readFile(file) {
if (this.fileCache[file]) {
return this.fileCache[file];
}
return readFileCode(file);
}
async walk(id, parent) {
const extensions = this.options.extensions;
const sortKey = parent.sortKey || '';
let file = null;
try {
file = await resolve(id, { ...parent, extensions });
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
console.warn(`module not found: "${id}" from file ${parent.filename}`);
return;
}
throw err;
}
if (this.visited[file] || resolveExst.includes(path.extname(file))) {
return file;
}
this.visited[file] = true;
const source = await this.readFile(file);
const depsArray = this.parseDeps(file, source);
if (!depsArray) {
return file;
}
const deps = {};
const promises = depsArray.map(async (id, i) => {
const filter = this.options.filter;
if (filter && !filter(id)) {
deps[id] = false;
return;
}
const number = i.toString().padStart(8, '0');
deps[id] = await this.walk(id, {
filename: file,
basedir: path.dirname(file),
sortKey: sortKey + '!' + file + ':' + number
});
});
await Promise.all(promises);
this.res.push({
id: file,
source,
deps,
file,
sortKey: sortKey + '!' + file
});
return file;
}
parseDeps(file, src) {
try {
const ast = parseToAst(src, file);
return konan(ast, { dynamicImport: false }).strings;
} catch (ex) {
console.error(`Parsing file ${file}: ${ex}`);
}
}
}
export default async function (input = [], opts = {}) {
const dep = new Deps(opts);
return dep.flush(Array.from(new Set(input)));
}