lib/readdir-plus.js
function readdirPlus(path, userOptions, callback) {
	if (libTools.isFunction(userOptions)) {
		callback = userOptions;
		userOptions = null;
	}

	var options = libTools.merge(libVars.DEFAULT_OPTIONS);

	if (userOptions) {
		userOptions.stat = normalizeSection(userOptions.stat);
		userOptions.content = normalizeSection(userOptions.content);

		if (userOptions.content) {
			normalizeArray(userOptions.content, options.content, "asText");
			normalizeArray(userOptions.content, options.content, "asBinary");
		}

		libTools.merge(userOptions, options);
	}

	if (path[path.length - 1] !== libPath.sep) {
		path += libPath.sep;
	}

	setupFn(options.readdir);
	setupFn(options.stat);
	setupFn(options.content);

	return doReadDir(path, options, function (err, results) {
		if (err) {
			return callback && callback(err);
		}
		return callback && callback(null, results);
	});

	function normalizeSection(section) {
		if (libTools.isBoolean(section)) {
			return {
				enabled: section
			};
		}
		if (libTools.isAnonObject(section) && !libTools.isBoolean(section.enabled)) {
			section.enabled = true;
		}
		return section;
	}

	function setupFn(opts) {
		if (!opts.fn) {
			opts.fn = options.sync ? opts.fnSync : opts.fnAsync;
		}
		if (options.sync) {
			opts.fn = libTools.syncWrapper(opts.fn);
		}
	}

	function normalizeArray(target, source, property) {
		if (!target[property] || target[property] === true) {
			return;
		}
		if (!libTools.isArray(target[property])) {
			target[property] = [target[property]];
		}
		else if (target[property].length === 1 && libTools.isArray(target[property][0])) {
			// array wrapped in array, replaces source value
			target[property] = target[property][0];
		} else {
			target[property] = source[property].concat(target[property]);
		}
	}
}
function readdirPlus(path, userOptions, callback) {
	if (libTools.isFunction(userOptions)) {
		callback = userOptions;
		userOptions = null;
	}

	var options = libTools.merge(libVars.DEFAULT_OPTIONS);

	if (userOptions) {
		userOptions.stat = normalizeSection(userOptions.stat);
		userOptions.content = normalizeSection(userOptions.content);

		if (userOptions.content) {
			normalizeArray(userOptions.content, options.content, "asText");
			normalizeArray(userOptions.content, options.content, "asBinary");
		}

		libTools.merge(userOptions, options);
	}

	if (path[path.length - 1] !== libPath.sep) {
		path += libPath.sep;
	}

	setupFn(options.readdir);
	setupFn(options.stat);
	setupFn(options.content);

	return doReadDir(path, options, function (err, results) {
		if (err) {
			return callback && callback(err);
		}
		return callback && callback(null, results);
	});

	function normalizeSection(section) {
		if (libTools.isBoolean(section)) {
			return {
				enabled: section
			};
		}
		if (libTools.isAnonObject(section) && !libTools.isBoolean(section.enabled)) {
			section.enabled = true;
		}
		return section;
	}

	function setupFn(opts) {
		if (!opts.fn) {
			opts.fn = options.sync ? opts.fnSync : opts.fnAsync;
		}
		if (options.sync) {
			opts.fn = libTools.syncWrapper(opts.fn);
		}
	}

	function normalizeArray(target, source, property) {
		if (!target[property] || target[property] === true) {
			return;
		}
		if (!libTools.isArray(target[property])) {
			target[property] = [target[property]];
		}
		else if (target[property].length === 1 && libTools.isArray(target[property][0])) {
			// array wrapped in array, replaces source value
			target[property] = target[property][0];
		} else {
			target[property] = source[property].concat(target[property]);
		}
	}
}
function readdirPlus ( path , userOptions , callback ) { if ( libTools . isFunction ( userOptions ) ) { callback = userOptions ; userOptions = null ; } var options = libTools . merge ( libVars . DEFAULT_OPTIONS ) ; if ( userOptions ) { userOptions . stat = normalizeSection ( userOptions . stat ) ; userOptions . content = normalizeSection ( userOptions . content ) ; if ( userOptions . content ) { normalizeArray ( userOptions . content , options . content , "asText" ) ; normalizeArray ( userOptions . content , options . content , "asBinary" ) ; } libTools . merge ( userOptions , options ) ; } if ( path [ path . length - 1 ] !== libPath . sep ) { path += libPath . sep ; } setupFn ( options . readdir ) ; setupFn ( options . stat ) ; setupFn ( options . content ) ; return doReadDir ( path , options , function ( err , results ) { if ( err ) { return callback && callback ( err ) ; } return callback && callback ( null , results ) ; } ) ; function normalizeSection ( section ) { if ( libTools . isBoolean ( section ) ) { return { enabled : section } ; } if ( libTools . isAnonObject ( section ) && ! libTools . isBoolean ( section . enabled ) ) { section . enabled = true ; } return section ; } function setupFn ( opts ) { if ( ! opts . fn ) { opts . fn = options . sync ? opts . fnSync : opts . fnAsync ; } if ( options . sync ) { opts . fn = libTools . syncWrapper ( opts . fn ) ; } } function normalizeArray ( target , source , property ) { if ( ! target [ property ] || target [ property ] === true ) { return ; } if ( ! libTools . isArray ( target [ property ] ) ) { target [ property ] = [ target [ property ] ] ; } else if ( target [ property ] . length === 1 && libTools . isArray ( target [ property ] [ 0 ] ) ) { // array wrapped in array, replaces source value target [ property ] = target [ property ] [ 0 ] ; } else { target [ property ] = source [ property ] . concat ( target [ property ] ) ; } } }
Read files recursively
@param {string} path Path to read
@param {ReaddirPlusOptions|object} [userOptions]
@param {function(Error, ReaddirPlusFile[])} callback
Read files recursively