Skip to content

Commit 2ae7392

Browse files
committed
add options validation
1 parent af6b13c commit 2ae7392

File tree

4 files changed

+139
-45
lines changed

4 files changed

+139
-45
lines changed

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"tabWidth": 4,
3+
"singleQuote": true
4+
}

index.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
var utils = require('./utils');
22

3-
var scopedModuleRegex = new RegExp('@[a-zA-Z0-9][\\w-.]+\/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9.\/]+)?', 'g');
3+
var scopedModuleRegex = new RegExp(
4+
'@[a-zA-Z0-9][\\w-.]+/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9./]+)?',
5+
'g'
6+
);
47

58
function getModuleName(request, includeAbsolutePaths) {
69
var req = request;
@@ -20,6 +23,12 @@ function getModuleName(request, includeAbsolutePaths) {
2023

2124
module.exports = function nodeExternals(options) {
2225
options = options || {};
26+
var mistakes = utils.validateOptions(options) || [];
27+
if (mistakes.length) {
28+
mistakes.forEach(function (mistake) {
29+
utils.log(mistake.message);
30+
});
31+
}
2332
var allowlist = [].concat(options.allowlist || []);
2433
var binaryDirs = [].concat(options.binaryDirs || ['.bin']);
2534
var importType = options.importType || 'commonjs';
@@ -34,22 +43,29 @@ module.exports = function nodeExternals(options) {
3443
}
3544

3645
// create the node modules list
37-
var nodeModules = modulesFromFile ? utils.readFromPackageJson(options.modulesFromFile) : utils.readDir(modulesDir).filter(isNotBinary);
38-
additionalModuleDirs.forEach(function(additionalDirectory){
39-
nodeModules = nodeModules.concat(utils.readDir(additionalDirectory).filter(isNotBinary));
40-
})
46+
var nodeModules = modulesFromFile
47+
? utils.readFromPackageJson(options.modulesFromFile)
48+
: utils.readDir(modulesDir).filter(isNotBinary);
49+
additionalModuleDirs.forEach(function (additionalDirectory) {
50+
nodeModules = nodeModules.concat(
51+
utils.readDir(additionalDirectory).filter(isNotBinary)
52+
);
53+
});
4154

4255
// return an externals function
43-
return function(context, request, callback){
56+
return function (context, request, callback) {
4457
var moduleName = getModuleName(request, includeAbsolutePaths);
45-
if (utils.contains(nodeModules, moduleName) && !utils.containsPattern(allowlist, request)) {
58+
if (
59+
utils.contains(nodeModules, moduleName) &&
60+
!utils.containsPattern(allowlist, request)
61+
) {
4662
if (typeof importType === 'function') {
4763
return callback(null, importType(request));
4864
}
4965
// mark this module as external
5066
// https://webpack.js.org/configuration/externals/
51-
return callback(null, importType + " " + request);
52-
};
67+
return callback(null, importType + ' ' + request);
68+
}
5369
callback();
54-
}
70+
};
5571
};

test/library.spec.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var nodeExternals = require('../index.js');
2+
var utils = require('../utils.js');
23
var testUtils = require('./test-utils.js');
34
var mockNodeModules = testUtils.mockNodeModules;
45
var restoreMock = testUtils.restoreMock;
@@ -148,7 +149,7 @@ describe('reads from a file', function() {
148149
});
149150

150151
// Test allowlist
151-
describe('respects a allowlist', function() {
152+
describe('respects an allowlist', function() {
152153

153154
before(function(){
154155
mockNodeModules();
@@ -260,3 +261,23 @@ describe('when modules dir does not exist', function() {
260261
restoreMock()
261262
});
262263
})
264+
265+
describe('validate options', function () {
266+
it('should identify misspelled terms', function () {
267+
var results = utils.validateOptions({ whitelist: [], moduledirs: [] });
268+
expect(results.length).to.be.equal(2);
269+
expect(results[0].correctTerm).to.be.equal('allowlist');
270+
expect(results[1].correctTerm).to.be.equal('modulesDir');
271+
});
272+
it('should ignore duplications', function () {
273+
var results = utils.validateOptions({ whitelist: [], moduledirs: [], allowlist: [] });
274+
expect(results.length).to.be.equal(1);
275+
expect(results[0].correctTerm).to.be.equal('modulesDir');
276+
});
277+
it('should identify wrong casing', function () {
278+
var results = utils.validateOptions({ allowList: [], modulesdir: [] });
279+
expect(results.length).to.be.equal(2);
280+
expect(results[0].correctTerm).to.be.equal('allowlist');
281+
expect(results[1].correctTerm).to.be.equal('modulesDir');
282+
});
283+
});

utils.js

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var path = require('path');
33

44
exports.contains = function contains(arr, val) {
55
return arr && arr.indexOf(val) !== -1;
6-
}
6+
};
77

88
var atPrefix = new RegExp('^@', 'g');
99
exports.readDir = function readDir(dirName) {
@@ -12,29 +12,34 @@ exports.readDir = function readDir(dirName) {
1212
}
1313

1414
try {
15-
return fs.readdirSync(dirName).map(function(module) {
16-
if (atPrefix.test(module)) {
17-
// reset regexp
18-
atPrefix.lastIndex = 0;
19-
try {
20-
return fs.readdirSync(path.join(dirName, module)).map(function(scopedMod) {
21-
return module + '/' + scopedMod;
22-
});
23-
} catch (e) {
24-
return [module];
15+
return fs
16+
.readdirSync(dirName)
17+
.map(function (module) {
18+
if (atPrefix.test(module)) {
19+
// reset regexp
20+
atPrefix.lastIndex = 0;
21+
try {
22+
return fs
23+
.readdirSync(path.join(dirName, module))
24+
.map(function (scopedMod) {
25+
return module + '/' + scopedMod;
26+
});
27+
} catch (e) {
28+
return [module];
29+
}
2530
}
26-
}
27-
return module
28-
}).reduce(function(prev, next) {
29-
return prev.concat(next);
30-
}, []);
31+
return module;
32+
})
33+
.reduce(function (prev, next) {
34+
return prev.concat(next);
35+
}, []);
3136
} catch (e) {
3237
return [];
3338
}
34-
}
39+
};
3540

3641
exports.readFromPackageJson = function readFromPackageJson(options) {
37-
if(typeof options !== 'object') {
42+
if (typeof options !== 'object') {
3843
options = {};
3944
}
4045
var includeInBundle = options.exclude || options.includeInBundle;
@@ -44,39 +49,87 @@ exports.readFromPackageJson = function readFromPackageJson(options) {
4449
var packageJson;
4550
try {
4651
var fileName = options.fileName || 'package.json';
47-
var packageJsonString = fs.readFileSync(path.resolve(process.cwd(), fileName), 'utf8');
52+
var packageJsonString = fs.readFileSync(
53+
path.resolve(process.cwd(), fileName),
54+
'utf8'
55+
);
4856
packageJson = JSON.parse(packageJsonString);
49-
} catch (e){
57+
} catch (e) {
5058
return [];
5159
}
5260
// sections to search in package.json
53-
var sections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
54-
if(excludeFromBundle) {
61+
var sections = [
62+
'dependencies',
63+
'devDependencies',
64+
'peerDependencies',
65+
'optionalDependencies',
66+
];
67+
if (excludeFromBundle) {
5568
sections = [].concat(excludeFromBundle);
5669
}
57-
if(includeInBundle) {
58-
sections = sections.filter(function(section){
70+
if (includeInBundle) {
71+
sections = sections.filter(function (section) {
5972
return [].concat(includeInBundle).indexOf(section) === -1;
6073
});
6174
}
6275
// collect dependencies
6376
var deps = {};
64-
sections.forEach(function(section){
65-
Object.keys(packageJson[section] || {}).forEach(function(dep){
77+
sections.forEach(function (section) {
78+
Object.keys(packageJson[section] || {}).forEach(function (dep) {
6679
deps[dep] = true;
6780
});
6881
});
6982
return Object.keys(deps);
70-
}
83+
};
7184

7285
exports.containsPattern = function containsPattern(arr, val) {
73-
return arr && arr.some(function(pattern){
74-
if(pattern instanceof RegExp){
75-
return pattern.test(val);
76-
} else if (typeof pattern === 'function') {
77-
return pattern(val);
78-
} else {
79-
return pattern == val;
86+
return (
87+
arr &&
88+
arr.some(function (pattern) {
89+
if (pattern instanceof RegExp) {
90+
return pattern.test(val);
91+
} else if (typeof pattern === 'function') {
92+
return pattern(val);
93+
} else {
94+
return pattern == val;
95+
}
96+
})
97+
);
98+
};
99+
100+
exports.validateOptions = function (options) {
101+
var results = [];
102+
var mistakes = {
103+
allowlist: ['allowslist', 'whitelist', 'allow'],
104+
importType: ['import', 'importype', 'importtype'],
105+
modulesDir: ['moduleDir', 'moduledir', 'moduledirs'],
106+
modulesFromFile: ['modulesfile'],
107+
includeAbsolutePaths: ['includeAbsolutePaths'],
108+
additionalModuleDirs: ['additionalModulesDirs', 'additionalModulesDir'],
109+
};
110+
var optionsKeys = Object.keys(options);
111+
var optionsKeysLower = optionsKeys.map(function (optionName) {
112+
return optionName && optionName.toLowerCase();
113+
});
114+
Object.keys(mistakes).forEach(function (correctTerm) {
115+
if (options[correctTerm] === undefined) {
116+
mistakes[correctTerm]
117+
.concat(correctTerm.toLowerCase())
118+
.forEach(function (mistake) {
119+
var ind = optionsKeysLower.indexOf(mistake.toLowerCase());
120+
if (ind > -1) {
121+
results.push({
122+
message: `Option '${optionsKeys[ind]}' is not supported. Did you mean '${correctTerm}'?`,
123+
wrongTerm: optionsKeys[ind],
124+
correctTerm: correctTerm,
125+
});
126+
}
127+
});
80128
}
81129
});
130+
return results;
131+
};
132+
133+
exports.log = function(message) {
134+
console.log(`[webpack-node-externals] : ${message}`)
82135
}

0 commit comments

Comments
 (0)