diff --git a/Gruntfile.js b/Gruntfile.js index e42e164..17270d8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -8,7 +8,7 @@ module.exports = function(grunt) { options: { jshintrc: '.jshintrc' }, - all: ['Gruntfile.js', '*.js'] + all: ['*.js', 'test/{,support/}*.js'] } }); diff --git a/index.js b/index.js index cfa5690..83efe94 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ var fs = require('fs'); var path = require('path'); var isGlob = require('is-glob'); var resolveDir = require('resolve-dir'); +var exists = require('fs-exists-sync'); var mm = require('micromatch'); /** @@ -26,9 +27,11 @@ module.exports = function(patterns, options) { throw new TypeError('findup-sync expects a string or array as the first argument.'); } - var len = patterns.length, i = -1; - while (++i < len) { - var res = lookup(patterns[i], options); + var len = patterns.length; + var idx = -1; + + while (++idx < len) { + var res = lookup(patterns[idx], options); if (res) { return res; } @@ -39,7 +42,7 @@ module.exports = function(patterns, options) { function lookup(pattern, options) { options = options || {}; - var cwd = resolveDir(options.cwd || ''); + var cwd = path.resolve(resolveDir(options.cwd || '')); if (isGlob(pattern)) { return matchFile(cwd, pattern, options); } else { @@ -50,10 +53,11 @@ function lookup(pattern, options) { function matchFile(cwd, pattern, opts) { var isMatch = mm.matcher(pattern, opts); var files = fs.readdirSync(cwd); - var len = files.length, i = -1; + var len = files.length; + var idx = -1; - while (++i < len) { - var name = files[i]; + while (++idx < len) { + var name = files[idx]; var fp = path.join(cwd, name); if (isMatch(name) || isMatch(fp)) { return fp; @@ -68,8 +72,8 @@ function matchFile(cwd, pattern, opts) { } function findFile(cwd, filename) { - var fp = cwd ? (cwd + '/' + filename) : filename; - if (fs.existsSync(fp)) { + var fp = cwd ? path.resolve(cwd, filename) : filename; + if (exists(fp)) { return fp; } @@ -77,9 +81,9 @@ function findFile(cwd, filename) { var len = segs.length; while (len--) { - cwd = segs.slice(0, len).join('/'); - fp = cwd + '/' + filename; - if (fs.existsSync(fp)) { + cwd = segs.slice(0, len).join(path.sep); + fp = path.resolve(cwd, filename); + if (exists(fp)) { return fp; } } diff --git a/package.json b/package.json index b62dce9..66f82f5 100644 --- a/package.json +++ b/package.json @@ -20,19 +20,20 @@ "test": "grunt && mocha" }, "dependencies": { + "fs-exists-sync": "^0.1.0", "is-glob": "^2.0.1", "micromatch": "^2.3.7", "resolve-dir": "^0.1.0" }, "devDependencies": { - "grunt": "^0.4.5", + "grunt": "^1.0.1", "grunt-contrib-jshint": "^0.12.0", "is-absolute": "^0.2.3", "minimist": "^1.2.0", "mocha": "^2.4.5", "normalize-path": "^2.0.1", - "resolve": "^1.1.7", - "user-home": "^2.0.0" + "os-homedir": "^1.0.1", + "resolve": "^1.1.7" }, "keywords": [ "file", diff --git a/test/fixtures/a/a.txt b/test/fixtures/a/a.txt new file mode 100644 index 0000000..7898192 --- /dev/null +++ b/test/fixtures/a/a.txt @@ -0,0 +1 @@ +a diff --git a/test/fixtures/a/b/b.txt b/test/fixtures/a/b/b.txt new file mode 100644 index 0000000..6178079 --- /dev/null +++ b/test/fixtures/a/b/b.txt @@ -0,0 +1 @@ +b diff --git a/test/fixtures/a/b/c/c.txt b/test/fixtures/a/b/c/c.txt new file mode 100644 index 0000000..f2ad6c7 --- /dev/null +++ b/test/fixtures/a/b/c/c.txt @@ -0,0 +1 @@ +c diff --git a/test/fixtures/a/b/c/d/d.txt b/test/fixtures/a/b/c/d/d.txt new file mode 100644 index 0000000..4bcfe98 --- /dev/null +++ b/test/fixtures/a/b/c/d/d.txt @@ -0,0 +1 @@ +d diff --git a/test/fixtures/a/b/c/d/e/e.txt b/test/fixtures/a/b/c/d/e/e.txt new file mode 100644 index 0000000..d905d9d --- /dev/null +++ b/test/fixtures/a/b/c/d/e/e.txt @@ -0,0 +1 @@ +e diff --git a/test/fixtures/a/b/c/d/e/f/f.txt b/test/fixtures/a/b/c/d/e/f/f.txt new file mode 100644 index 0000000..6a69f92 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/f.txt @@ -0,0 +1 @@ +f diff --git a/test/fixtures/a/b/c/d/e/f/file.txt b/test/fixtures/a/b/c/d/e/f/file.txt new file mode 100644 index 0000000..6a69f92 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/file.txt @@ -0,0 +1 @@ +f diff --git a/test/fixtures/a/b/c/d/e/f/g/file.txt b/test/fixtures/a/b/c/d/e/f/g/file.txt new file mode 100644 index 0000000..01058d8 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/file.txt @@ -0,0 +1 @@ +g diff --git a/test/fixtures/a/b/c/d/e/f/g/g.txt b/test/fixtures/a/b/c/d/e/f/g/g.txt new file mode 100644 index 0000000..01058d8 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/g.txt @@ -0,0 +1 @@ +g diff --git a/test/fixtures/a/b/c/d/e/f/g/h/file.txt b/test/fixtures/a/b/c/d/e/f/g/h/file.txt new file mode 100644 index 0000000..6e9f0da --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/file.txt @@ -0,0 +1 @@ +h diff --git a/test/fixtures/a/b/c/d/e/f/g/h/h.txt b/test/fixtures/a/b/c/d/e/f/g/h/h.txt new file mode 100644 index 0000000..6e9f0da --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/h.txt @@ -0,0 +1 @@ +h diff --git a/test/fixtures/a/b/c/d/e/f/g/h/i/file.txt b/test/fixtures/a/b/c/d/e/f/g/h/i/file.txt new file mode 100644 index 0000000..0ddf2ba --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/i/file.txt @@ -0,0 +1 @@ +i diff --git a/test/fixtures/a/b/c/d/e/f/g/h/i/i.txt b/test/fixtures/a/b/c/d/e/f/g/h/i/i.txt new file mode 100644 index 0000000..0ddf2ba --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/i/i.txt @@ -0,0 +1 @@ +i diff --git a/test/fixtures/a/b/c/d/e/f/g/h/i/j/file.txt b/test/fixtures/a/b/c/d/e/f/g/h/i/j/file.txt new file mode 100644 index 0000000..4c559f7 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/i/j/file.txt @@ -0,0 +1 @@ +j diff --git a/test/fixtures/a/b/c/d/e/f/g/h/i/j/j.txt b/test/fixtures/a/b/c/d/e/f/g/h/i/j/j.txt new file mode 100644 index 0000000..4c559f7 --- /dev/null +++ b/test/fixtures/a/b/c/d/e/f/g/h/i/j/j.txt @@ -0,0 +1 @@ +j diff --git a/test/fixtures/a/b/c/d/e/file.txt b/test/fixtures/a/b/c/d/e/file.txt new file mode 100644 index 0000000..d905d9d --- /dev/null +++ b/test/fixtures/a/b/c/d/e/file.txt @@ -0,0 +1 @@ +e diff --git a/test/fixtures/a/b/c/d/file.txt b/test/fixtures/a/b/c/d/file.txt new file mode 100644 index 0000000..4bcfe98 --- /dev/null +++ b/test/fixtures/a/b/c/d/file.txt @@ -0,0 +1 @@ +d diff --git a/test/fixtures/a/b/c/file.txt b/test/fixtures/a/b/c/file.txt new file mode 100644 index 0000000..f2ad6c7 --- /dev/null +++ b/test/fixtures/a/b/c/file.txt @@ -0,0 +1 @@ +c diff --git a/test/fixtures/a/b/file.txt b/test/fixtures/a/b/file.txt new file mode 100644 index 0000000..6178079 --- /dev/null +++ b/test/fixtures/a/b/file.txt @@ -0,0 +1 @@ +b diff --git a/test/fixtures/a/file.txt b/test/fixtures/a/file.txt new file mode 100644 index 0000000..7898192 --- /dev/null +++ b/test/fixtures/a/file.txt @@ -0,0 +1 @@ +a diff --git a/test/fixtures/file.txt b/test/fixtures/file.txt new file mode 100644 index 0000000..d8649da --- /dev/null +++ b/test/fixtures/file.txt @@ -0,0 +1 @@ +root diff --git a/test/fixtures/root.txt b/test/fixtures/root.txt new file mode 100644 index 0000000..d8649da --- /dev/null +++ b/test/fixtures/root.txt @@ -0,0 +1 @@ +root diff --git a/test/support/index.js b/test/support/index.js new file mode 100644 index 0000000..399311b --- /dev/null +++ b/test/support/index.js @@ -0,0 +1,51 @@ +'use strict'; + +var path = require('path'); +var normalizePath = require('normalize-path'); +var isAbsolute = require('is-absolute'); +var resolve = require('resolve'); + +exports.normalize = function(filepath) { + return filepath ? normalizePath(path.relative('.', filepath)) : null; +}; + +exports.chdir = function(dir) { + // store current cwd + var orig = process.cwd(); + // set cwd to the given `dir` + process.chdir(dir); + return function() { + // restore original `cwd` + process.chdir(orig); + }; +}; + +exports.npm = function npm(name) { + return path.dirname(resolve.sync(name)); +}; + +exports.assert = function(assert) { + assert.isPath = function (filepath) { + assert(filepath); + assert.equal(typeof filepath, 'string'); + }; + + assert.isAbsolute = function (filepath) { + assert(filepath); + assert.equal(typeof filepath, 'string'); + assert(isAbsolute(filepath)); + }; + + assert.basename = function (filepath, basename) { + assert(filepath); + assert.equal(typeof filepath, 'string'); + assert.equal(path.basename(filepath), basename); + }; + + assert.dirname = function (filepath, dirname) { + assert(filepath); + assert.equal(typeof filepath, 'string'); + assert.equal(path.dirname(path.resolve(filepath)), path.resolve(dirname)); + }; +}; + diff --git a/test/test.js b/test/test.js index 1fbce7c..ab8b634 100644 --- a/test/test.js +++ b/test/test.js @@ -1,70 +1,30 @@ 'use strict'; require('mocha'); -var argv = require('minimist')(process.argv.slice(2)); var fs = require('fs'); var path = require('path'); var assert = require('assert'); -var expand = require('resolve-dir'); -var norm = require('normalize-path'); -var home = require('user-home'); -var isAbsolute = require('is-absolute'); +var support = require('./support'); +support.assert(assert); +var home = require('os-homedir'); +var exists = require('fs-exists-sync'); var resolve = require('resolve'); -var cwd, actual, opts; - var findup = require('../'); +var normalize = support.normalize; +var chdir = support.chdir; +var npm = support.npm; +var cwd; +var actual; -function normalize(fp) { - return fp ? norm(path.relative('.', fp)) : null; -} - -if (argv.bench) { - var b = path.join(__dirname, 'benchmark/code', argv.bench); - console.log(b); - findup = require(b); -} - -assert.isPath = function (fp, basename) { - assert(fp); - assert.equal(typeof fp, 'string'); -}; - -assert.isAbsolute = function (fp) { - assert(fp); - assert(isAbsolute(fp)); -}; - -assert.exists = function (fp) { - assert(fp); - try { - fs.statSync(fp); - } catch(err) { - assert(fp, err); - } -}; - -assert.basename = function (fp, basename) { - assert(fp); - assert.equal(path.basename(fp), basename); -}; - -assert.dirname = function (fp, dirname) { - assert(fp); - assert.equal(path.dirname(path.resolve(fp)), path.resolve(dirname)); -}; - -function npm(name) { - return path.dirname(resolve.sync(name)); -} describe('findup-sync', function () { before(function () { - fs.writeFileSync(home + '/_aaa.txt', ''); - fs.writeFileSync(home + '/_bbb.txt', ''); + fs.writeFileSync(home() + '/_aaa.txt', ''); + fs.writeFileSync(home() + '/_bbb.txt', ''); }); after(function () { - fs.unlinkSync(home + '/_aaa.txt'); - fs.unlinkSync(home + '/_bbb.txt'); + fs.unlinkSync(home() + '/_aaa.txt'); + fs.unlinkSync(home() + '/_bbb.txt'); }); it('should throw when the first arg is not a string or array:', function(cb) { @@ -85,6 +45,34 @@ describe('findup-sync', function () { assert.equal(normalize(findup('package.json')), 'package.json'); }); + it('should find files in a child directory', function () { + var expected = path.resolve(__dirname, 'fixtures/a/b/file.txt'); + var restore = chdir(path.resolve(__dirname, 'fixtures/a/b/c/d/e/f/g/h')); + + var actual = findup('a/b/file.txt'); + assert(actual); + assert(exists(actual)); + assert.equal(actual, expected); + restore(); + }); + + it('should find files in a child directory relative to a cwd', function () { + var expectedFile = path.resolve(__dirname, 'fixtures/a/b/file.txt'); + var expectedA = path.resolve(__dirname, 'fixtures/a/a.txt'); + var tempDir = chdir(path.resolve(__dirname, 'fixtures')); + + var actualFile = findup('a/b/file.txt', {cwd: 'a/b/c/d'}); + assert(actualFile); + assert(exists(actualFile)); + assert.equal(actualFile, expectedFile); + + var actualA = findup('a.txt', {cwd: 'a/b/c/d/e/f'}); + assert(actualA); + assert(exists(actualA)); + assert.equal(actualA, expectedA); + tempDir(); + }); + it('should support normal (non-glob) file paths:', function () { var normPath = normalize(findup('package.json', {cwd: path.dirname(resolve.sync('normalize-path'))})); assert.equal(normPath, 'node_modules/normalize-path/package.json'); @@ -216,7 +204,7 @@ describe('findup-sync', function () { }); it('should find files from absolute paths:', function () { - var actual = findup('package.json', { cwd: __dirname }) + var actual = findup('package.json', { cwd: __dirname }); assert.basename(actual, 'package.json'); assert.dirname(actual, path.resolve(__dirname, '..')); @@ -231,16 +219,16 @@ describe('findup-sync', function () { }); it('should find files in user home:', function () { - var actual = findup('*', { cwd: home }); + var actual = findup('*', { cwd: home() }); assert.isPath(actual); - assert.exists(actual); - assert.dirname(actual, home); + assert(exists(actual)); + assert.dirname(actual, home()); }); it('should find files in user home using tilde expansion:', function () { var actual = findup('*', { cwd: '~' }); assert.isPath(actual); - assert.exists(actual); - assert.dirname(actual, home); + assert(exists(actual)); + assert.dirname(actual, home()); }); });