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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Walker = void 0;
const debug = require("debug");
const fs = require("fs-extra");
const path = require("path");
const depTypes_1 = require("./depTypes");
const nativeModuleTypes_1 = require("./nativeModuleTypes");
const d = debug('flora-colossus');
class Walker {
constructor(modulePath) {
this.modules = [];
this.walkHistory = new Set();
this.cache = null;
if (!modulePath || typeof modulePath !== 'string') {
throw new Error('modulePath must be provided as a string');
}
d(`creating walker with rootModule=${modulePath}`);
this.rootModule = modulePath;
}
relativeModule(rootPath, moduleName) {
return path.resolve(rootPath, 'node_modules', moduleName);
}
async loadPackageJSON(modulePath) {
const pJPath = path.resolve(modulePath, 'package.json');
if (await fs.pathExists(pJPath)) {
const pJ = await fs.readJson(pJPath);
if (!pJ.dependencies)
pJ.dependencies = {};
if (!pJ.devDependencies)
pJ.devDependencies = {};
if (!pJ.optionalDependencies)
pJ.optionalDependencies = {};
return pJ;
}
return null;
}
async walkDependenciesForModuleInModule(moduleName, modulePath, depType) {
let testPath = modulePath;
let discoveredPath = null;
let lastRelative = null;
// Try find it while searching recursively up the tree
while (!discoveredPath && this.relativeModule(testPath, moduleName) !== lastRelative) {
lastRelative = this.relativeModule(testPath, moduleName);
if (await fs.pathExists(lastRelative)) {
discoveredPath = lastRelative;
}
else {
if (path.basename(path.dirname(testPath)) !== 'node_modules') {
testPath = path.dirname(testPath);
}
testPath = path.dirname(path.dirname(testPath));
}
}
// If we can't find it the install is probably buggered
if (!discoveredPath && depType !== depTypes_1.DepType.OPTIONAL && depType !== depTypes_1.DepType.DEV_OPTIONAL) {
throw new Error(`Failed to locate module "${moduleName}" from "${modulePath}"
This normally means that either you have deleted this package already somehow (check your ignore settings if using electron-packager). Or your module installation failed.`);
}
// If we can find it let's do the same thing for that module
if (discoveredPath) {
await this.walkDependenciesForModule(discoveredPath, depType);
}
}
async detectNativeModuleType(modulePath, pJ) {
if (pJ.dependencies['prebuild-install']) {
return nativeModuleTypes_1.NativeModuleType.PREBUILD;
}
else if (await fs.pathExists(path.join(modulePath, 'binding.gyp'))) {
return nativeModuleTypes_1.NativeModuleType.NODE_GYP;
}
return nativeModuleTypes_1.NativeModuleType.NONE;
}
async walkDependenciesForModule(modulePath, depType) {
d('walk reached:', modulePath, ' Type is:', depTypes_1.DepType[depType]);
// We have already traversed this module
if (this.walkHistory.has(modulePath)) {
d('already walked this route');
// Find the existing module reference
const existingModule = this.modules.find(module => module.path === modulePath);
// If the depType we are traversing with now is higher than the
// last traversal then update it (prod superseeds dev for instance)
if ((0, depTypes_1.depTypeGreater)(depType, existingModule.depType)) {
d(`existing module has a type of "${existingModule.depType}", new module type would be "${depType}" therefore updating`);
existingModule.depType = depType;
}
return;
}
const pJ = await this.loadPackageJSON(modulePath);
// If the module doesn't have a package.json file it is probably a
// dead install from yarn (they dont clean up for some reason)
if (!pJ) {
d('walk hit a dead end, this module is incomplete');
return;
}
// Record this module as being traversed
this.walkHistory.add(modulePath);
this.modules.push({
depType,
nativeModuleType: await this.detectNativeModuleType(modulePath, pJ),
path: modulePath,
name: pJ.name,
});
// For every prod dep
for (const moduleName in pJ.dependencies) {
// npm decides it's a funny thing to put optional dependencies in the "dependencies" section
// after install, because that makes perfect sense
if (moduleName in pJ.optionalDependencies) {
d(`found ${moduleName} in prod deps of ${modulePath} but it is also marked optional`);
continue;
}
await this.walkDependenciesForModuleInModule(moduleName, modulePath, (0, depTypes_1.childDepType)(depType, depTypes_1.DepType.PROD));
}
// For every optional dep
for (const moduleName in pJ.optionalDependencies) {
await this.walkDependenciesForModuleInModule(moduleName, modulePath, (0, depTypes_1.childDepType)(depType, depTypes_1.DepType.OPTIONAL));
}
// For every dev dep, but only if we are in the root module
if (depType === depTypes_1.DepType.ROOT) {
d('we\'re still at the beginning, walking down the dev route');
for (const moduleName in pJ.devDependencies) {
await this.walkDependenciesForModuleInModule(moduleName, modulePath, (0, depTypes_1.childDepType)(depType, depTypes_1.DepType.DEV));
}
}
}
async walkTree() {
d('starting tree walk');
if (!this.cache) {
this.cache = new Promise(async (resolve, reject) => {
this.modules = [];
try {
await this.walkDependenciesForModule(this.rootModule, depTypes_1.DepType.ROOT);
}
catch (err) {
reject(err);
return;
}
resolve(this.modules);
});
}
else {
d('tree walk in progress / completed already, waiting for existing walk to complete');
}
return await this.cache;
}
getRootModule() {
return this.rootModule;
}
}
exports.Walker = Walker;
//# sourceMappingURL=Walker.js.map
|