├── .travis.yml ├── .gitignore ├── example └── git-repo-root.js ├── package.json ├── README.md ├── LICENSE ├── index.js └── test └── find-parent-dir.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | -------------------------------------------------------------------------------- /example/git-repo-root.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var findParentDir = require('..'); 4 | findParentDir(__dirname, '.git', function (err, dir) { 5 | if (err) return console.error(err); 6 | console.log(dir); 7 | }); 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "find-parent-dir", 3 | "version": "0.3.1", 4 | "description": "Finds the first parent directory that contains a given file or directory.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tap test/*.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/thlorenz/find-parent-dir.git" 12 | }, 13 | "homepage": "https://github.com/thlorenz/find-parent-dir", 14 | "dependencies": {}, 15 | "devDependencies": { 16 | "tap": "~0.4.3" 17 | }, 18 | "keywords": [ 19 | "find", 20 | "parent", 21 | "dir", 22 | "root", 23 | "resolve", 24 | "walk" 25 | ], 26 | "author": { 27 | "name": "Thorsten Lorenz", 28 | "email": "thlorenz@gmx.de", 29 | "url": "http://thlorenz.com" 30 | }, 31 | "license": "MIT", 32 | "engine": { 33 | "node": ">=0.6" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # find-parent-dir [![build status](https://secure.travis-ci.org/thlorenz/find-parent-dir.png)](http://travis-ci.org/thlorenz/find-parent-dir) 2 | 3 | Finds the first parent directory that contains a given file or directory. 4 | 5 | npm install find-parent-dir 6 | 7 | ```js 8 | // assuming this is called from a file in a subdirectory of /myprojects/foo which contains .git directory 9 | var findParentDir = require('find-parent-dir'); 10 | 11 | findParentDir(__dirname, '.git', function (err, dir) { 12 | // has err if some file access error occurred 13 | console.log(dir); // => /myprojects/foo/ 14 | 15 | // if parent dir wasn't found, dir is null 16 | }) 17 | 18 | // Same using `sync` method 19 | var dir; 20 | try { 21 | dir = findParentDir.sync(__dirname, '.git'); 22 | console.log(dir); // => /myprojects/foo/ 23 | // if parent dir wasn't found, dir is null 24 | } catch(err) { 25 | console.error('error', err); 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Thorsten Lorenz. 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path') 4 | , fs = require('fs') 5 | , exists = fs.exists || path.exists 6 | , existsSync = fs.existsSync || path.existsSync 7 | ; 8 | 9 | function splitPath(path) { 10 | var parts = path.split(/(\/|\\)/); 11 | if (!parts.length) return parts; 12 | 13 | // when path starts with a slash, the first part is empty string 14 | return !parts[0].length ? parts.slice(1) : parts; 15 | } 16 | 17 | exports = module.exports = function (currentFullPath, clue, cb) { 18 | 19 | function testDir(parts) { 20 | if (parts.length === 0) return cb(null, null); 21 | 22 | var p = parts.join(''); 23 | 24 | exists(path.join(p, clue), function (itdoes) { 25 | if (itdoes) return cb(null, p); 26 | testDir(parts.slice(0, -1)); 27 | }); 28 | } 29 | 30 | testDir(splitPath(currentFullPath)); 31 | } 32 | 33 | exports.sync = function (currentFullPath, clue) { 34 | 35 | function testDir(parts) { 36 | if (parts.length === 0) return null; 37 | 38 | var p = parts.join(''); 39 | 40 | var itdoes = existsSync(path.join(p, clue)); 41 | return itdoes ? p : testDir(parts.slice(0, -1)); 42 | } 43 | 44 | return testDir(splitPath(currentFullPath)); 45 | } 46 | -------------------------------------------------------------------------------- /test/find-parent-dir.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true */ 3 | 4 | var test = require('tap').test 5 | var path = require('path') 6 | var fs = require('fs') 7 | var findParentDir = require('..') 8 | 9 | test('finding .git root relative to the test dir', function (t) { 10 | findParentDir(__dirname, '.git', function (err, dir) { 11 | t.equals(dir, path.resolve(__dirname, '..') + '/') 12 | t.end() 13 | }); 14 | }) 15 | 16 | test('finding this dir relative to the test dir', function (t) { 17 | findParentDir(__dirname, 'find-parent-dir.js', function (err, dir) { 18 | t.equals(dir, path.resolve(__dirname)) 19 | t.end() 20 | }); 21 | }) 22 | 23 | test('sync finding .git root relative to the test dir', function (t) { 24 | var dir = findParentDir.sync(__dirname, '.git') 25 | t.equals(dir, path.resolve(__dirname, '..') + '/') 26 | t.end() 27 | }) 28 | 29 | test('sync finding this dir relative to the test dir', function (t) { 30 | var dir = findParentDir.sync(__dirname, 'find-parent-dir.js') 31 | t.equals(dir, path.resolve(__dirname)) 32 | t.end() 33 | }) 34 | 35 | test('find no dir when file is in the test dir', function(t) { 36 | var filepath = path.join(__dirname, 'shazam.txt') 37 | fs.writeFileSync(filepath, 'shaq attack') 38 | findParentDir('/etc', 'shazam.txt', function (err, dir) { 39 | fs.unlinkSync(filepath) 40 | t.equals(err, null) 41 | t.equals(dir, null) 42 | t.end() 43 | }) 44 | }) 45 | --------------------------------------------------------------------------------