-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Larry Gordon
committed
Jul 7, 2014
1 parent
488d8ba
commit 2121591
Showing
8 changed files
with
656 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# nodetree | ||
|
||
> list contents of directories in a tree-like format similar to the [Tree Command](http://mama.indstate.edu/users/ice/tree/). | ||
|
||
## SYNOPSIS | ||
|
||
`nodetree` \[`-ad`\] \[`-L` \<level>] \[`--noreport`] \[`--version`] \[`--help`] \[`--prune`] \[\<directory> ...] | ||
|
||
|
||
## DESCRIPTION | ||
|
||
_Nodetree_ is a recursive directory listing program that produces a depth indented listing of files. With no arguments, _nodetree_ lists the files in the current directory. When directory arguments are given, _nodetree_ lists all the files and/or directories found in the given directories each in turn. Upon completion of listing all files/directories found, _nodetree_ returns the total number of files and/or directories listed. _Nodetree_ is heavily inspired by the [Tree Command](http://mama.indstate.edu/users/ice/tree/). | ||
|
||
## INSTALL | ||
|
||
```sh | ||
$ npm install --save nodetree | ||
``` | ||
|
||
## NODE | ||
|
||
With defaults: | ||
```js | ||
var nodetree = require('nodetree'); | ||
nodetree(process.cwd()); | ||
``` | ||
|
||
With all options set: | ||
```js | ||
var nodetree = require('nodetree'); | ||
nodetree(process.cwd(), { | ||
all: false, | ||
directories: false, | ||
level: 2, | ||
prune: false, | ||
noreport: false | ||
}); | ||
``` | ||
|
||
|
||
## CLI | ||
|
||
```sh | ||
$ npm install -g nodetree | ||
``` | ||
|
||
```sh | ||
$ man nodetree | ||
``` | ||
|
||
## OPTIONS | ||
|
||
_Nodetree_ understands the following command line switches: | ||
|
||
|
||
## NODE OPTIONS | ||
|
||
### nodetree(basepath, options) | ||
|
||
#### options.all | ||
Type: `Boolean` | ||
Default: `false` | ||
See cli option `-a` below. | ||
|
||
#### options.directories #### | ||
Type: `Boolean` | ||
Default: `false` | ||
See cli option `-d` below. | ||
|
||
#### options.level | ||
Type: `int` | ||
Default: `null` | ||
See cli option `-L` below. | ||
|
||
#### options.prune | ||
Type: `Boolean` | ||
Default: `false` | ||
See cli option `--prune` below. | ||
|
||
#### options.noreport | ||
Type: `Boolean` | ||
Default: `false` | ||
See cli option `--noreport` below. | ||
|
||
## CLI OPTIONS | ||
|
||
* `-a`: | ||
All files are printed. By default tree does not print hidden files (those beginning with a dot '.'). In no event does tree print the file system constructs '.' (current directory) and '..' (previous directory). | ||
|
||
* `-d`: | ||
List directories only. | ||
|
||
* `-L` <level>: | ||
Max display depth of the directory tree. | ||
|
||
* `--prune`: | ||
Makes tree prune empty directories from the output. | ||
|
||
* `--noreport`: | ||
Omits printing of the file and directory report at the end of the tree listing. | ||
|
||
* `--version`: | ||
Outputs the version of nodetree. | ||
|
||
## AUTHOR | ||
|
||
Written by Larry Gordon | ||
|
||
|
||
## COPYRIGHT | ||
|
||
[The MIT License (MIT)](http://psyrendust.mit-license.org/2014) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#!/usr/bin/env node | ||
'use strict'; | ||
|
||
var _ = require('lodash'); | ||
var nodetree = require('./'); | ||
var nopt = require('nopt'); | ||
var pkg = require('./package.json'); | ||
var stdin = require('get-stdin'); | ||
|
||
var knownOpts = { | ||
'all': Boolean, | ||
'directories': Boolean, | ||
'help': Boolean, | ||
'level': Number, | ||
'noreport': Boolean, | ||
'version': Boolean | ||
}; | ||
var shortHands = { | ||
'a': ['--all'], | ||
'd': ['--directories'], | ||
'h': ['--help'], | ||
'L': ['--level'], | ||
'v': ['--version'] | ||
}; | ||
|
||
var parsed = nopt(knownOpts, shortHands, process.argv, 2); | ||
var basepath = parsed.argv.remain[0]; | ||
var options = _.extend({}, parsed); | ||
options = _.extend(options, { cwd: process.cwd() }); | ||
delete options.argv; | ||
|
||
function help() { | ||
console.log([ | ||
'man nodetree' | ||
].join('\n')); | ||
} | ||
|
||
function init(basepath, options) { | ||
if (!basepath) { | ||
// Default to cwd if no path is given. | ||
basepath = '.'; | ||
} | ||
return nodetree(basepath, options); | ||
} | ||
|
||
if (options.help) { | ||
help(); | ||
return; | ||
} | ||
|
||
if (options.version) { | ||
console.log(pkg.version); | ||
return; | ||
} | ||
|
||
if (process.stdin.isTTY) { | ||
init(basepath, options); | ||
} else { | ||
// Accept basepath from stdin. | ||
// Example: | ||
// $ echo $(pwd) | nodetree | ||
stdin(init); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
#!/usr/bin/env node | ||
'use strict'; | ||
|
||
var _ = require('lodash'); | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
|
||
var chevron = { | ||
'node': '├── ', | ||
'pipe': '│ ', | ||
'last': '└── ', | ||
'indent': ' ' | ||
}; | ||
var defaults = { | ||
all: false, | ||
directories: false, | ||
level: null, | ||
prune: false, | ||
noreport: false | ||
}; | ||
var dotRegex = /^\.$/; | ||
var hiddenRegex = /^\./; | ||
var newlineRegex = /[\n\r]*/g; | ||
|
||
|
||
// ----------------------------------------------------------------------------- | ||
/** | ||
* List contents of directories in a tree-like format. | ||
* @method Nodetree | ||
*/ | ||
function Nodetree(basepath, opts) { | ||
// Setup vars | ||
// --------------------------------------------------------------------------- | ||
var dirCount = 0; | ||
var fileCount = 0; | ||
var isWalking = 0; | ||
var options = _.extend(defaults, opts); | ||
var resultsTree = []; | ||
var startpath = ''; | ||
|
||
normalizeStartpath(basepath); | ||
|
||
|
||
// Start tree walking | ||
// --------------------------------------------------------------------------- | ||
if (fs.existsSync(startpath) && fs.statSync(startpath).isDirectory()) { | ||
console.log(basepath); | ||
walk(startpath, []); | ||
} else { | ||
console.log(basepath, '[error opening dir]'); | ||
} | ||
|
||
|
||
// Helper functions | ||
// --------------------------------------------------------------------------- | ||
/** | ||
* Outputs results when nodetree has completed it's recursive walk. | ||
* @method checkIfComplete | ||
*/ | ||
function checkIfComplete() { | ||
isWalking -= 1; | ||
if (isWalking <= 0) { | ||
printResults(); | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Log to stdout the current branch of the tree walk. | ||
* @method log | ||
* @param {String} file The file or folder name of this branch. | ||
* @param {Array} depth The current depth relative to the startpath. | ||
* @param {Boolean} parentHasNextSibling Does the parent folder have a next sibling. | ||
*/ | ||
function log(file, depth, parentHasNextSibling) { | ||
if (!parentHasNextSibling && depth.length > 1) { | ||
// Replace a pipe with an indent if the parent does not have a next sibling. | ||
depth[depth.length-2] = chevron.indent; | ||
} | ||
resultsTree.push(depth.join('') + file + '\n'); | ||
} | ||
|
||
|
||
/** | ||
* Normalizes the basepath. | ||
* @method normalizeStartpath | ||
*/ | ||
function normalizeStartpath() { | ||
startpath = basepath; | ||
if (typeof basepath !== 'string') { | ||
throw new TypeError('Expected a string'); | ||
} | ||
if (!!startpath.match(dotRegex)) { | ||
// Set startpath to options.cwd if basepath is '.' | ||
startpath = options.cwd; | ||
} | ||
// Remove newline characters | ||
startpath = startpath.replace(newlineRegex, ''); | ||
} | ||
|
||
|
||
/** | ||
* Print to stdout the results of the tree walk and the total directories and files found. | ||
* @method printResults | ||
*/ | ||
function printResults() { | ||
if (!options.noreport) { | ||
resultsTree.push('\n' + dirCount + ' directories'); | ||
if (!options.directories) { | ||
resultsTree.push(', ' + fileCount + ' files'); | ||
} | ||
} | ||
console.log(resultsTree.join('')); | ||
} | ||
|
||
|
||
// Walker functions | ||
// --------------------------------------------------------------------------- | ||
/** | ||
* Filter out the direct children of basepath based on the configured options. | ||
* @method filterChildren | ||
* @param {String} basepath The parent directory to filter. | ||
* @return {Array} An array of filtered file and folder names. | ||
*/ | ||
function filterChildren(basepath) { | ||
var children = fs.readdirSync(basepath); | ||
|
||
if (!options.all) { | ||
// Show hidden files | ||
children = children.filter(function optionAll(child) { | ||
return !child.match(hiddenRegex); | ||
}); | ||
} | ||
|
||
if (options.directories) { | ||
// Only show directories | ||
children = children.filter(function optionDirectories(child) { | ||
return fs.statSync(path.join(basepath, child)).isDirectory(); | ||
}); | ||
} | ||
|
||
if (options.prune) { | ||
// Exclude empty directories | ||
children = children.filter(function optionPrune(child) { | ||
var childpath = path.join(basepath, child); | ||
if (fs.statSync(childpath).isDirectory()) { | ||
return (fs.readdirSync(childpath).length > 0); | ||
} | ||
return true; | ||
}); | ||
} | ||
|
||
return children; | ||
} | ||
|
||
|
||
/** | ||
* Walk the basepath and log the results to stdout. | ||
* @method walk | ||
* @param {String} basepath The directory to walk. | ||
* @param {Array} depth An array of chevrons that represets the current depth of this branch. | ||
* @param {Boolean} parentHasNextSibling Does the parent folder have a next sibling. | ||
*/ | ||
function walk(basepath, depth, parentHasNextSibling) { | ||
isWalking += 1; | ||
var children = filterChildren(basepath); | ||
var childrenLen = children.length-1; | ||
var shouldContinue = true; | ||
|
||
if (!!options.level && depth.length >= options.level) { | ||
// Only walk options.level deep. | ||
shouldContinue = false; | ||
} | ||
|
||
if (shouldContinue) { | ||
children.forEach(function walkChildren(child, index) { | ||
var newdepth = !!depth ? depth.slice(0) : []; | ||
var isLast = (index >= childrenLen); | ||
var childpath = path.join(basepath, child); | ||
var stats = fs.statSync(childpath); | ||
|
||
if (isLast) { | ||
newdepth.push(chevron.last); | ||
} else { | ||
newdepth.push(chevron.node); | ||
} | ||
|
||
log(child, newdepth, parentHasNextSibling); | ||
|
||
if (stats.isDirectory()) { | ||
dirCount += 1; | ||
if (!isLast) { | ||
newdepth.pop(); | ||
newdepth.push(chevron.pipe); | ||
} | ||
walk(childpath, newdepth, !isLast); | ||
} else { | ||
fileCount += 1; | ||
} | ||
}); | ||
} | ||
checkIfComplete(); | ||
} | ||
} | ||
|
||
module.exports = Nodetree; |
Oops, something went wrong.