Skip to content

Commit eb995d6

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. Fixes: #1139 PR-URL: #1153 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]> Reviewed-By: Brendan Ashworth <[email protected]>
1 parent a28945b commit eb995d6

File tree

3 files changed

+81
-30
lines changed

3 files changed

+81
-30
lines changed

lib/path.js

+50-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
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+
}
12+
513
// resolves . and .. elements in a path array with directory names there
614
// must be no slashes or device names (c:\) in the array
715
// (so also no leading and trailing slashes - it does not distinguish
@@ -84,10 +92,10 @@ win32.resolve = function() {
8492
}
8593
}
8694

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) {
95+
assertPath(path);
96+
97+
// Skip empty entries
98+
if (path === '') {
9199
continue;
92100
}
93101

@@ -137,6 +145,8 @@ win32.resolve = function() {
137145

138146

139147
win32.normalize = function(path) {
148+
assertPath(path);
149+
140150
var result = splitDeviceRe.exec(path),
141151
device = result[1] || '',
142152
isUnc = device && device.charAt(1) !== ':',
@@ -165,6 +175,8 @@ win32.normalize = function(path) {
165175

166176

167177
win32.isAbsolute = function(path) {
178+
assertPath(path);
179+
168180
var result = splitDeviceRe.exec(path),
169181
device = result[1] || '',
170182
isUnc = !!device && device.charAt(1) !== ':';
@@ -210,6 +222,9 @@ win32.join = function() {
210222
// to = 'C:\\orandea\\impl\\bbb'
211223
// The output of the function should be: '..\\..\\impl\\bbb'
212224
win32.relative = function(from, to) {
225+
assertPath(from);
226+
assertPath(to);
227+
213228
from = win32.resolve(from);
214229
to = win32.resolve(to);
215230

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

288303

289304
win32.dirname = function(path) {
305+
assertPath(path);
306+
290307
var result = win32SplitPath(path),
291308
root = result[0],
292309
dir = result[1];
@@ -306,6 +323,11 @@ win32.dirname = function(path) {
306323

307324

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

317339

318340
win32.extname = function(path) {
341+
assertPath(path);
319342
return win32SplitPath(path)[3];
320343
};
321344

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

352375

353376
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-
}
377+
assertPath(pathString);
378+
359379
var allParts = win32SplitPath(pathString);
360380
if (!allParts || allParts.length !== 4) {
361381
throw new TypeError("Invalid path '" + pathString + "'");
@@ -395,10 +415,10 @@ posix.resolve = function() {
395415
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
396416
var path = (i >= 0) ? arguments[i] : process.cwd();
397417

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) {
418+
assertPath(path);
419+
420+
// Skip empty entries
421+
if (path === '') {
402422
continue;
403423
}
404424

@@ -419,6 +439,8 @@ posix.resolve = function() {
419439
// path.normalize(path)
420440
// posix version
421441
posix.normalize = function(path) {
442+
assertPath(path);
443+
422444
var isAbsolute = posix.isAbsolute(path),
423445
trailingSlash = path.substr(-1) === '/';
424446

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

438460
// posix version
439461
posix.isAbsolute = function(path) {
462+
assertPath(path);
440463
return path.charAt(0) === '/';
441464
};
442465

@@ -463,6 +486,9 @@ posix.join = function() {
463486
// path.relative(from, to)
464487
// posix version
465488
posix.relative = function(from, to) {
489+
assertPath(from);
490+
assertPath(to);
491+
466492
from = posix.resolve(from).substr(1);
467493
to = posix.resolve(to).substr(1);
468494

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

511537

512538
posix.dirname = function(path) {
539+
assertPath(path);
540+
513541
var result = posixSplitPath(path),
514542
root = result[0],
515543
dir = result[1];
@@ -529,8 +557,13 @@ posix.dirname = function(path) {
529557

530558

531559
posix.basename = function(path, ext) {
560+
assertPath(path);
561+
562+
if (ext !== undefined && typeof ext !== 'string')
563+
throw new TypeError('ext must be a string');
564+
532565
var f = posixSplitPath(path)[2];
533-
// TODO: make this comparison case-insensitive on windows?
566+
534567
if (ext && f.substr(-1 * ext.length) === ext) {
535568
f = f.substr(0, f.length - ext.length);
536569
}
@@ -539,6 +572,7 @@ posix.basename = function(path, ext) {
539572

540573

541574
posix.extname = function(path) {
575+
assertPath(path);
542576
return posixSplitPath(path)[3];
543577
};
544578

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

567601

568602
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-
}
603+
assertPath(pathString);
604+
574605
var allParts = posixSplitPath(pathString);
575606
if (!allParts || allParts.length !== 4) {
576607
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)