Skip to content

Commit a465840

Browse files
committed
path: add type checking for path inputs
This commit adds type checking of path inputs to exported methods in the path module. The exception is _makeLong, which seems to explicitly support any data type.
1 parent 056ed4b commit a465840

File tree

3 files changed

+80
-30
lines changed

3 files changed

+80
-30
lines changed

lib/path.js

+49-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
'use strict';
22

3+
const util = require('util');
34
const isWindows = process.platform === 'win32';
45

6+
function assertPath(path) {
7+
if (typeof path !== 'string')
8+
throw new TypeError('Path must be a string. Received ' +
9+
util.inspect(path));
10+
}
11+
512
// resolves . and .. elements in a path array with directory names there
613
// must be no slashes or device names (c:\) in the array
714
// (so also no leading and trailing slashes - it does not distinguish
@@ -84,10 +91,10 @@ win32.resolve = function() {
8491
}
8592
}
8693

87-
// Skip empty and invalid entries
88-
if (typeof path !== 'string') {
89-
throw new TypeError('Arguments to path.resolve must be strings');
90-
} else if (!path) {
94+
assertPath(path);
95+
96+
// Skip empty entries
97+
if (path === '') {
9198
continue;
9299
}
93100

@@ -137,6 +144,8 @@ win32.resolve = function() {
137144

138145

139146
win32.normalize = function(path) {
147+
assertPath(path);
148+
140149
var result = splitDeviceRe.exec(path),
141150
device = result[1] || '',
142151
isUnc = device && device.charAt(1) !== ':',
@@ -165,6 +174,8 @@ win32.normalize = function(path) {
165174

166175

167176
win32.isAbsolute = function(path) {
177+
assertPath(path);
178+
168179
var result = splitDeviceRe.exec(path),
169180
device = result[1] || '',
170181
isUnc = !!device && device.charAt(1) !== ':';
@@ -210,6 +221,9 @@ win32.join = function() {
210221
// to = 'C:\\orandea\\impl\\bbb'
211222
// The output of the function should be: '..\\..\\impl\\bbb'
212223
win32.relative = function(from, to) {
224+
assertPath(from);
225+
assertPath(to);
226+
213227
from = win32.resolve(from);
214228
to = win32.resolve(to);
215229

@@ -287,6 +301,8 @@ win32._makeLong = function(path) {
287301

288302

289303
win32.dirname = function(path) {
304+
assertPath(path);
305+
290306
var result = win32SplitPath(path),
291307
root = result[0],
292308
dir = result[1];
@@ -306,6 +322,11 @@ win32.dirname = function(path) {
306322

307323

308324
win32.basename = function(path, ext) {
325+
assertPath(path);
326+
327+
if (ext !== undefined && typeof ext !== 'string')
328+
throw new TypeError('ext must be a string');
329+
309330
var f = win32SplitPath(path)[2];
310331
// TODO: make this comparison case-insensitive on windows?
311332
if (ext && f.substr(-1 * ext.length) === ext) {
@@ -316,6 +337,7 @@ win32.basename = function(path, ext) {
316337

317338

318339
win32.extname = function(path) {
340+
assertPath(path);
319341
return win32SplitPath(path)[3];
320342
};
321343

@@ -351,11 +373,8 @@ win32.format = function(pathObject) {
351373

352374

353375
win32.parse = function(pathString) {
354-
if (typeof pathString !== 'string') {
355-
throw new TypeError(
356-
"Parameter 'pathString' must be a string, not " + typeof pathString
357-
);
358-
}
376+
assertPath(pathString);
377+
359378
var allParts = win32SplitPath(pathString);
360379
if (!allParts || allParts.length !== 4) {
361380
throw new TypeError("Invalid path '" + pathString + "'");
@@ -395,10 +414,10 @@ posix.resolve = function() {
395414
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
396415
var path = (i >= 0) ? arguments[i] : process.cwd();
397416

398-
// Skip empty and invalid entries
399-
if (typeof path !== 'string') {
400-
throw new TypeError('Arguments to path.resolve must be strings');
401-
} else if (!path) {
417+
assertPath(path);
418+
419+
// Skip empty entries
420+
if (path === '') {
402421
continue;
403422
}
404423

@@ -419,6 +438,8 @@ posix.resolve = function() {
419438
// path.normalize(path)
420439
// posix version
421440
posix.normalize = function(path) {
441+
assertPath(path);
442+
422443
var isAbsolute = posix.isAbsolute(path),
423444
trailingSlash = path.substr(-1) === '/';
424445

@@ -437,6 +458,7 @@ posix.normalize = function(path) {
437458

438459
// posix version
439460
posix.isAbsolute = function(path) {
461+
assertPath(path);
440462
return path.charAt(0) === '/';
441463
};
442464

@@ -463,6 +485,9 @@ posix.join = function() {
463485
// path.relative(from, to)
464486
// posix version
465487
posix.relative = function(from, to) {
488+
assertPath(from);
489+
assertPath(to);
490+
466491
from = posix.resolve(from).substr(1);
467492
to = posix.resolve(to).substr(1);
468493

@@ -510,6 +535,8 @@ posix._makeLong = function(path) {
510535

511536

512537
posix.dirname = function(path) {
538+
assertPath(path);
539+
513540
var result = posixSplitPath(path),
514541
root = result[0],
515542
dir = result[1];
@@ -529,8 +556,13 @@ posix.dirname = function(path) {
529556

530557

531558
posix.basename = function(path, ext) {
559+
assertPath(path);
560+
561+
if (ext !== undefined && typeof ext !== 'string')
562+
throw new TypeError('ext must be a string');
563+
532564
var f = posixSplitPath(path)[2];
533-
// TODO: make this comparison case-insensitive on windows?
565+
534566
if (ext && f.substr(-1 * ext.length) === ext) {
535567
f = f.substr(0, f.length - ext.length);
536568
}
@@ -539,6 +571,7 @@ posix.basename = function(path, ext) {
539571

540572

541573
posix.extname = function(path) {
574+
assertPath(path);
542575
return posixSplitPath(path)[3];
543576
};
544577

@@ -566,11 +599,8 @@ posix.format = function(pathObject) {
566599

567600

568601
posix.parse = function(pathString) {
569-
if (typeof pathString !== 'string') {
570-
throw new TypeError(
571-
"Parameter 'pathString' must be a string, not " + typeof pathString
572-
);
573-
}
602+
assertPath(pathString);
603+
574604
var allParts = posixSplitPath(pathString);
575605
if (!allParts || allParts.length !== 4) {
576606
throw new TypeError("Invalid path '" + pathString + "'");

test/parallel/test-path-parse-format.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ var unixPaths = [
3030
];
3131

3232
var errors = [
33-
{method: 'parse', input: [null], message: /Parameter 'pathString' must be a string, not/},
34-
{method: 'parse', input: [{}], message: /Parameter 'pathString' must be a string, not object/},
35-
{method: 'parse', input: [true], message: /Parameter 'pathString' must be a string, not boolean/},
36-
{method: 'parse', input: [1], message: /Parameter 'pathString' must be a string, not number/},
37-
{method: 'parse', input: [], message: /Parameter 'pathString' must be a string, not undefined/},
33+
{method: 'parse', input: [null], message: /Path must be a string. Received null/},
34+
{method: 'parse', input: [{}], message: /Path must be a string. Received {}/},
35+
{method: 'parse', input: [true], message: /Path must be a string. Received true/},
36+
{method: 'parse', input: [1], message: /Path must be a string. Received 1/},
37+
{method: 'parse', input: [], message: /Path must be a string. Received undefined/},
3838
// {method: 'parse', input: [''], message: /Invalid path/}, // omitted because it's hard to trigger!
3939
{method: 'format', input: [null], message: /Parameter 'pathObject' must be an object, not/},
4040
{method: 'format', input: [''], message: /Parameter 'pathObject' must be an object, not string/},

test/parallel/test-path.js

+26-6
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,34 @@ joinTests.forEach(function(test) {
253253
// assert.equal(actual, expected, message);
254254
});
255255
assert.equal(failures.length, 0, failures.join(''));
256-
var joinThrowTests = [true, false, 7, null, {}, undefined, [], NaN];
257-
joinThrowTests.forEach(function(test) {
258-
assert.throws(function() {
259-
path.join(test);
260-
}, TypeError);
256+
257+
// Test thrown TypeErrors
258+
var typeErrorTests = [true, false, 7, null, {}, undefined, [], NaN];
259+
260+
function fail(fn) {
261+
var args = Array.prototype.slice.call(arguments, 1);
262+
261263
assert.throws(function() {
262-
path.resolve(test);
264+
fn.apply(null, args);
263265
}, TypeError);
266+
}
267+
268+
typeErrorTests.forEach(function(test) {
269+
fail(path.join, test);
270+
fail(path.resolve, test);
271+
fail(path.normalize, test);
272+
fail(path.isAbsolute, test);
273+
fail(path.dirname, test);
274+
fail(path.relative, test, 'foo');
275+
fail(path.relative, 'foo', test);
276+
fail(path.basename, test);
277+
fail(path.extname, test);
278+
fail(path.parse, test);
279+
280+
// undefined is a valid value as the second argument to basename
281+
if (test !== undefined) {
282+
fail(path.basename, 'foo', test);
283+
}
264284
});
265285

266286

0 commit comments

Comments
 (0)