index.js
3.89 KB
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
var path = require('path'),
fs = require('fs'),
f = require('util').format,
resolveFrom = require('resolve-from'),
semver = require('semver');
var exists = fs.existsSync || path.existsSync;
// Find the location of a package.json file near or above the given location
var find_package_json = function(location) {
var found = false;
while(!found) {
if (exists(location + '/package.json')) {
found = location;
} else if (location !== '/') {
location = path.dirname(location);
} else {
return false;
}
}
return location;
}
// Find the package.json object of the module closest up the module call tree that contains name in that module's peerOptionalDependencies
var find_package_json_with_name = function(name) {
// Walk up the module call tree until we find a module containing name in its peerOptionalDependencies
var currentModule = module;
var found = false;
while (currentModule) {
// Check currentModule has a package.json
location = currentModule.filename;
var location = find_package_json(location)
if (!location) {
currentModule = currentModule.parent;
continue;
}
// Read the package.json file
var object = JSON.parse(fs.readFileSync(f('%s/package.json', location)));
// Is the name defined by interal file references
var parts = name.split(/\//);
// Check whether this package.json contains peerOptionalDependencies containing the name we're searching for
if (!object.peerOptionalDependencies || (object.peerOptionalDependencies && !object.peerOptionalDependencies[parts[0]])) {
currentModule = currentModule.parent;
continue;
}
found = true;
break;
}
// Check whether name has been found in currentModule's peerOptionalDependencies
if (!found) {
throw new Error(f('no optional dependency [%s] defined in peerOptionalDependencies in any package.json', parts[0]));
}
return {
object: object,
parts: parts
}
}
var require_optional = function(name, options) {
options = options || {};
options.strict = typeof options.strict == 'boolean' ? options.strict : true;
var res = find_package_json_with_name(name)
var object = res.object;
var parts = res.parts;
// Unpack the expected version
var expectedVersions = object.peerOptionalDependencies[parts[0]];
// The resolved package
var moduleEntry = undefined;
// Module file
var moduleEntryFile = name;
try {
// Validate if it's possible to read the module
moduleEntry = require(moduleEntryFile);
} catch(err) {
// Attempt to resolve in top level package
try {
// Get the module entry file
moduleEntryFile = resolveFrom(process.cwd(), name);
if(moduleEntryFile == null) return undefined;
// Attempt to resolve the module
moduleEntry = require(moduleEntryFile);
} catch(err) {
if(err.code === 'MODULE_NOT_FOUND') return undefined;
}
}
// Resolve the location of the module's package.json file
var location = find_package_json(require.resolve(moduleEntryFile));
if(!location) {
throw new Error('package.json can not be located');
}
// Read the module file
var dependentOnModule = JSON.parse(fs.readFileSync(f('%s/package.json', location)));
// Get the version
var version = dependentOnModule.version;
// Validate if the found module satisfies the version id
if(semver.satisfies(version, expectedVersions) == false
&& options.strict) {
var error = new Error(f('optional dependency [%s] found but version [%s] did not satisfy constraint [%s]', parts[0], version, expectedVersions));
error.code = 'OPTIONAL_MODULE_NOT_FOUND';
throw error;
}
// Satifies the module requirement
return moduleEntry;
}
require_optional.exists = function(name) {
try {
var m = require_optional(name);
if(m === undefined) return false;
return true;
} catch(err) {
return false;
}
}
module.exports = require_optional;