fs-finder-updated
Version:
File system recursive finder
383 lines (345 loc) • 12.3 kB
JavaScript
// Generated by CoffeeScript 2.7.0
(function() {
var Base, Helpers, Q, async, fs, path;
Helpers = require('./Helpers');
path = require('path');
fs = require('fs');
Q = require('q');
async = require('async');
Base = (function() {
class Base {
constructor(directory) {
directory = path.resolve(directory);
if (!fs.statSync(directory).isDirectory()) {
throw new Error(`Path ${directory} is not directory`);
}
this.directory = directory;
this.excludes = [];
this.filters = [];
}
//*******************************************************************************************************************
// TESTING
//*******************************************************************************************************************
static mock(tree = {}, info = {}) {
var FS;
FS = require('fs-mock');
fs = new FS(tree, info);
return fs;
}
static restore() {
return fs = require('fs');
}
//*******************************************************************************************************************
// SETUP
//*******************************************************************************************************************
recursively(recursive = true) {
this.recursive = recursive;
return this;
}
exclude(excludes, exactly = false) {
var exclude, j, len, result;
if (typeof excludes === 'string') {
excludes = [excludes];
}
result = [];
for (j = 0, len = excludes.length; j < len; j++) {
exclude = excludes[j];
if (exactly) {
exclude = `<^>${exclude}<$>`;
}
result.push(Helpers.normalizePattern(exclude));
}
this.excludes = this.excludes.concat(result);
return this;
}
showSystemFiles(systemFiles = true) {
this.systemFiles = systemFiles;
return this;
}
lookUp(up = true) {
this.up = up;
return this;
}
findFirst(_findFirst = true) {
this._findFirst = _findFirst;
return this;
}
filter(fn) {
this.filters.push(fn);
return this;
}
//*******************************************************************************************************************
// SEARCHING
//*******************************************************************************************************************
getPathsSync(type = 'all', mask = null, dir = this.directory) {
var _path, err, j, len, paths, read, result, stats;
paths = [];
try {
read = fs.readdirSync(dir);
} catch (error) {
err = error;
if (this._findFirst === true) {
return null;
}
return paths;
}
for (j = 0, len = read.length; j < len; j++) {
_path = read[j];
_path = path.join(dir, _path);
if (!this.checkExcludes(_path) || !this.checkSystemFiles(_path)) {
continue;
}
try {
stats = fs.statSync(_path);
} catch (error) {
err = error;
continue;
}
switch (this.checkFile(_path, stats, mask, type)) {
case 0:
continue;
case 1:
if (this._findFirst === true) {
return _path;
}
paths.push(_path);
}
if (stats.isDirectory() && this.recursive === true) {
result = this.getPathsSync(type, mask, _path);
if (this._findFirst === true && typeof result === 'string') {
return result;
} else if (this._findFirst === true && result === null) {
continue;
} else {
paths = paths.concat(result);
}
}
}
if (this._findFirst === true) {
return null;
} else {
return paths;
}
}
getPathsAsync(fn, type = 'all', mask = null, dir = this.directory) {
var paths;
paths = [];
return fs.readdir(dir, (err, read) => {
var _path, files, j, len, nextPaths;
if (err) {
return fn(this._findFirst === true ? null : paths);
} else {
nextPaths = [];
for (j = 0, len = read.length; j < len; j++) {
_path = read[j];
_path = path.join(dir, _path);
if (!this.checkExcludes(_path) || !this.checkSystemFiles(_path)) {
continue;
}
nextPaths.push(_path);
}
files = {};
return async.eachSeries(nextPaths, function(item, cb) {
return fs.stat(item, function(err, stats) {
if (!err) {
files[item] = stats;
}
return cb();
});
}, () => {
var file, stats, subDirectories;
subDirectories = [];
for (file in files) {
stats = files[file];
switch (this.checkFile(file, stats, mask, type)) {
case 0:
continue;
case 1:
if (this._findFirst === true) {
fn(file);
return null;
}
paths.push(file);
}
if (stats.isDirectory() && this.recursive === true) {
subDirectories.push(file);
}
}
if (subDirectories.length === 0) {
return fn(this._findFirst === true ? null : paths);
} else {
return async.eachSeries(subDirectories, (item, cb) => {
return this.getPathsAsync((result) => {
if (this._findFirst === true && typeof result === 'string') {
fn(result);
return cb(new Error('Fake error'));
} else if (this._findFirst === true && result === null) {
return cb();
} else {
paths = paths.concat(result);
return cb();
}
}, type, mask, item);
}, function(err) {
if (!err) {
return fn(paths);
}
});
}
});
}
});
}
//*******************************************************************************************************************
// CHECKS
//*******************************************************************************************************************
checkExcludes(_path) {
var exclude, j, len, ref;
ref = this.excludes;
for (j = 0, len = ref.length; j < len; j++) {
exclude = ref[j];
if ((new RegExp(exclude)).test(_path)) {
return false;
}
}
return true;
}
checkSystemFiles(_path) {
if (this.systemFiles === false) {
if (path.basename(_path)[0] === '.' || _path.match(/~$/) !== null) {
return false;
}
}
return true;
}
checkFilters(_path, stats) {
var filter, j, len, ref;
ref = this.filters;
for (j = 0, len = ref.length; j < len; j++) {
filter = ref[j];
if (!filter(stats, _path)) {
return false;
}
}
return true;
}
checkFile(_path, stats, mask, type) {
if (type === 'all' || (type === 'files' && stats.isFile()) || (type === 'directories' && stats.isDirectory())) {
if (mask === null || (mask !== null && (new RegExp(mask, 'g')).test(_path))) {
if (!this.checkFilters(_path, stats)) {
return 0;
}
return 1;
}
}
return 2;
}
//*******************************************************************************************************************
// PARENTS
//*******************************************************************************************************************
getPathsFromParentsSync(mask = null, type = 'all') {
var Finder, breakAtEnd, finder, found, i, j, len, parentPath, parentPaths, previous, result;
Finder = require('./Finder');
parentPaths = Helpers.expandPath(this.directory);
result = [];
previous = null;
breakAtEnd = false;
for (i = j = 0, len = parentPaths.length; j < len; i = ++j) {
parentPath = parentPaths[i];
if (this.up === true) {
// continue
} else if (typeof this.up === 'string' && this.up === parentPath) {
breakAtEnd = true;
} else if (typeof this.up === 'number' && this.up <= i) {
break;
}
finder = new Finder(parentPath);
finder.recursive = this.recursive;
finder.excludes = this.excludes;
finder.filters = this.filters;
finder.systemFiles = this.systemFiles;
finder._findFirst = this._findFirst === true;
if (previous !== null) {
finder.exclude(previous, true);
}
found = finder.getPathsSync(type, mask);
if (this._findFirst === true && typeof found === 'string') {
return found;
} else if (this._findFirst === true && found === null) {
// continue
} else if (found.length > 0) {
result = result.concat(found);
}
if (breakAtEnd) {
break;
}
previous = parentPath;
}
if (this._findFirst === true) {
return null;
} else {
return result;
}
}
getPathsFromParentsAsync(fn, mask = null, type = 'all') {
var Finder, breakAtEnd, finder, finders, i, j, len, parentPath, parentPaths, previous, result;
Finder = require('./Finder');
parentPaths = Helpers.expandPath(this.directory);
result = [];
previous = null;
breakAtEnd = false;
finders = [];
for (i = j = 0, len = parentPaths.length; j < len; i = ++j) {
parentPath = parentPaths[i];
if (this.up === true) {
// continue
} else if (typeof this.up === 'string' && this.up === parentPath) {
breakAtEnd = true;
} else if (typeof this.up === 'number' && this.up <= i) {
break;
}
finder = new Finder(parentPath);
finder.recursive = this.recursive;
finder.excludes = this.excludes;
finder.filters = this.filters;
finder.systemFiles = this.systemFiles;
finder._findFirst = this._findFirst === true;
if (previous !== null) {
finder.exclude(previous, true);
}
finders.push(finder);
if (breakAtEnd) {
break;
}
previous = parentPath;
}
return async.eachSeries(finders, (finder, cb) => {
return finder.getPathsAsync((found) => {
if (this._findFirst === true && typeof found === 'string') {
fn(found);
return cb(new Error('Fake error'));
} else if (this._findFirst === true && found === null) {
return cb();
} else {
result = result.concat(found);
return cb();
}
}, type, mask);
}, (err) => {
if (!err) {
return fn(this._findFirst === true ? null : result);
}
});
}
};
Base.prototype.directory = null;
Base.prototype.recursive = false;
Base.prototype.excludes = null;
Base.prototype.filters = null;
Base.prototype.systemFiles = false;
Base.prototype.up = false;
Base.prototype._findFirst = false;
return Base;
}).call(this);
module.exports = Base;
}).call(this);