From b139231241bc2690f3d28d6f1e7b57105ee072ca Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Sun, 17 Apr 2016 19:35:55 +0200 Subject: [PATCH] Initial commit --- .npmignore | 1 + README.md | 29 +++++++++++++++++++ gulpfile.js | 18 ++++++++++++ index.js | 3 ++ package.json | 28 ++++++++++++++++++ src/index.js | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test.js | 8 +++++ 7 files changed, 169 insertions(+) create mode 100644 .npmignore create mode 100644 README.md create mode 100644 gulpfile.js create mode 100644 index.js create mode 100644 package.json create mode 100644 src/index.js create mode 100644 test.js diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..096746c --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +/node_modules/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3713e10 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# get-project-root + +TODO + +## License + +[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer. A donation and/or attribution are appreciated, but not required. + +## Donate + +My income consists largely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)! + +You can donate using Bitcoin, PayPal, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else. + +## Contributing + +Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the files in `src/`, not those in `lib/`. + +Build tool of choice is `gulp`; simply run `gulp` while developing, and it will watch for changes. + +Be aware that by making a pull request, you agree to release your modifications under the licenses stated above. + +## Usage + +TODO + +## API + +TODO \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..1769501 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,18 @@ +var gulp = require("gulp"); +var presetES2015 = require("@joepie91/gulp-preset-es2015"); + +var source = ["src/**/*.js"] + +gulp.task('babel', function() { + return gulp.src(source) + .pipe(presetES2015({ + basePath: __dirname + })) + .pipe(gulp.dest("lib/")); +}); + +gulp.task("watch", function () { + gulp.watch(source, ["babel"]); +}); + +gulp.task("default", ["babel", "watch"]); \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..507257b --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require("./lib"); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2ba5ee0 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "get-project-root", + "version": "0.0.1", + "description": "Locates the 'root directory' of the current project", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "http://git.cryto.net/joepie91/node-get-project-root.git" + }, + "keywords": [ + "root", + "package.json", + "path" + ], + "author": "Sven Slootweg", + "license": "WTFPL", + "dependencies": { + "default-value": "0.0.2" + }, + "devDependencies": { + "@joepie91/gulp-preset-es2015": "^1.0.1", + "babel-preset-es2015": "^6.6.0", + "gulp": "^3.9.1" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a4fc1d5 --- /dev/null +++ b/src/index.js @@ -0,0 +1,82 @@ +'use strict'; + +const fs = require("fs"); +const path = require("path"); +const defaultValue = require("default-value"); + +let defaultCheckers = { + "package.json": function(directory) { + let parentPackageFile = path.join(directory, `..${path.sep}..${path.sep}package.json`); + + try { + fs.accessSync(parentPackageFile); + return false; + } catch (err) { + return true; + } + }, + "vcs": function(directory) { + let files = fs.readdirSync(directory); + + return [".git", ".hg"].some((target) => { + return (files.indexOf(target) !== -1); + }); + } +} + +function reachedRoot(candidatePath) { + /* Returns true if we hit the root of the filesystem; like / or C:\ */ + return /^(?:\/|a-z:\\)$/i.test(candidatePath); +} + +module.exports = function(options) { + let currentPath = defaultValue(options.basePath, __dirname); + let checker = defaultValue(options.checker, "package.json"); + + if (typeof checker === "string") { + if (defaultCheckers[checker] != null) { + checker = defaultCheckers[checker]; + } else { + throw new Error("No such checker exists."); + } + } + + /* Locate the first thing that has a package.json, in case we're in a + * subdirectory within a module. Only after we've found the nearest + * package.json, we will start using the checker. + */ + + let baseFound = false; + + while (baseFound === false) { + baseFound = (fs.readdirSync(currentPath).indexOf("package.json") !== -1); + + if (reachedRoot(currentPath)) { + throw new Error("Reached filesystem root without encountering a module"); + } + + if (baseFound === false) { + currentPath = path.join(currentPath, ".."); + } + } + + let rootFound = false; + + while (rootFound === false) { + rootFound = checker(currentPath); + + if (rootFound !== true && rootFound !== false) { + throw new Error("Checker must always return either true or false"); + } + + if (reachedRoot(currentPath)) { + throw new Error("Reached filesystem root without encountering the project root"); + } + + if (rootFound === false) { + currentPath = path.join(currentPath, `..${path.sep}..`); + } + } + + return currentPath; +} \ No newline at end of file diff --git a/test.js b/test.js new file mode 100644 index 0000000..e5cb38e --- /dev/null +++ b/test.js @@ -0,0 +1,8 @@ +'use strict'; + +const getProjectRoot = require("./"); + +console.log(getProjectRoot({ + basePath: process.argv[2], + checker: "package.json" +})); \ No newline at end of file