diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/index.js b/index.js index 09dde64..8bd6929 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,8 @@ 'use strict'; var isGlob = require('is-glob'); -var pathPosixDirname = require('path').posix.dirname; +var path = require('path'); +var pathPosixDirname = path.posix.dirname; var isWin32 = require('os').platform() === 'win32'; var slash = '/'; @@ -16,6 +17,12 @@ var escaped = /\\([!*?|[\](){}])/g; module.exports = function globParent(str, opts) { var options = Object.assign({ flipBackslashes: true }, opts); + var winDriveOrUncVolume = ''; + if (isWin32) { + winDriveOrUncVolume = getWinDriveOrUncVolume(str); + str = str.slice(winDriveOrUncVolume.length); + } + // flip windows path separators if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { str = str.replace(backslash, slash); @@ -28,14 +35,23 @@ module.exports = function globParent(str, opts) { // preserves full path in case of trailing path separator str += 'a'; - + // remove path parts that are globby do { str = pathPosixDirname(str); } while (isGlobby(str)); // remove escape chars and return result - return str.replace(escaped, '$1'); + str = str.replace(escaped, '$1'); + + // replace continuous slashes to single slash + str = str.replace(/\/+/g, '/'); + + if (isWin32 && winDriveOrUncVolume) { + str = winDriveOrUncVolume + str; + } + + return str; }; function isEnclosure(str) { @@ -73,3 +89,14 @@ function isGlobby(str) { } return isGlob(str); } + +function getWinDriveOrUncVolume(fp) { + if (/^([a-zA-Z]:|\\\\)/.test(fp)) { + var root = path.win32.parse(fp).root; + if (path.win32.isAbsolute(fp)) { + root = root.slice(0, -1); // Strip last path separator + } + return root; + } + return ''; +} diff --git a/test/.gitkeep b/test/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/index.test.js b/test/index.test.js index 5889412..be370be 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -10,6 +10,10 @@ describe('glob-parent', function () { expect(gp('.*')).toEqual('.'); expect(gp('/.*')).toEqual('/'); expect(gp('/.*/')).toEqual('/'); + expect(gp('//')).toEqual('/'); + expect(gp('//*')).toEqual('/'); + expect(gp('.//')).toEqual('./'); + expect(gp('.//*')).toEqual('./'); expect(gp('a/.*/b')).toEqual('a'); expect(gp('a*/.*/b')).toEqual('.'); expect(gp('*/a/b/c')).toEqual('.'); @@ -258,4 +262,71 @@ if (isWin32) { done(); }); }); + + describe('windows path with drive or UNC volume', function() { + it('should return parent dirname from absolute path with drive letter', function(done) { + expect(gp('C:/')).toEqual('C:/'); + expect(gp('C:/.')).toEqual('C:/'); + expect(gp('C:/*')).toEqual('C:/'); + expect(gp('C:/./*')).toEqual('C:/.'); + expect(gp('C://')).toEqual('C:/'); + expect(gp('C://*')).toEqual('C:/'); + expect(gp('C:/path/*.js')).toEqual('C:/path'); + + expect(gp('C:\\')).toEqual('C:/'); + expect(gp('C:\\.')).toEqual('C:/'); + expect(gp('C:\\*')).toEqual('C:/'); + expect(gp('C:\\.\\*')).toEqual('C:/.'); + expect(gp('C:\\\\')).toEqual('C:/'); + expect(gp('C:\\\\*')).toEqual('C:/'); + expect(gp('C:\\path\\*.js')).toEqual('C:/path'); + + done(); + }); + + it('should return parent dirname from relative path with drive letter', function(done) { + expect(gp('C:')).toEqual('C:.'); + expect(gp('C:.')).toEqual('C:.'); + expect(gp('C:*')).toEqual('C:.'); + expect(gp('C:./*')).toEqual('C:.'); + expect(gp('C:.//')).toEqual('C:./'); + expect(gp('C:.//*')).toEqual('C:./'); + expect(gp('C:path/*.js')).toEqual('C:path'); + + expect(gp('C:.\\*')).toEqual('C:.'); + expect(gp('C:.\\\\')).toEqual('C:./'); + expect(gp('C:.\\\\*')).toEqual('C:./'); + expect(gp('C:path\\*.js')).toEqual('C:path'); + + done(); + }); + + it('should return parent dirname from UNC path', function(done) { + expect(gp('\\\\System07\\C$/')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/.')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/*')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/./*')).toEqual('\\\\System07\\C$/.'); + expect(gp('\\\\System07\\C$//')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$//*')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/path/*.js')).toEqual('\\\\System07\\C$/path'); + + expect(gp('\\\\System07\\C$/', { flipBackslashes: false })).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/.', { flipBackslashes: false })).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/*', { flipBackslashes: false })).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/./*', { flipBackslashes: false })).toEqual('\\\\System07\\C$/.'); + expect(gp('\\\\System07\\C$//', { flipBackslashes: false })).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$//*', { flipBackslashes: false })).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$/path/*.js')).toEqual('\\\\System07\\C$/path'); + + expect(gp('\\\\System07\\C$\\')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$\\.')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$\\*')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$\\.\\*')).toEqual('\\\\System07\\C$/.'); + expect(gp('\\\\System07\\C$\\\\')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$\\\\*')).toEqual('\\\\System07\\C$/'); + expect(gp('\\\\System07\\C$\\path\\*.js')).toEqual('\\\\System07\\C$/path'); + + done(); + }); + }); }