UNPKG

foldify

Version:

Import / require folder(s) of any type of files, and evaluate / curry the results.

417 lines (361 loc) 10.8 kB
var fs = require('fs'), path = require('path'), minimatch = require('minimatchify'), callsite = require('callsite'); module.exports = fold; function fold(toBeFolded){ if(!toBeFolded) return false; var moreArgs = [].slice.call(arguments, 1), mergeToMe = {}, options, individual, originalFullPath, stack; if(isArray(toBeFolded)){ options = moreArgs[0]; originalFullPath = options.fullPath; toBeFolded.forEach(function(toFold){ individual = fold.call(this, toFold, options) for(var prop in individual){ if(mergeToMe[prop]){ options.fullPath = true; individual = fold.call(this, toFold, options); options.fullPath = originalFullPath; break; } } for (var prop in individual) { mergeToMe[prop] = individual[prop]; } }); return bind( fold, {foldStatus: true}, mergeToMe ); } var beingFolded = this && this.foldStatus, isObj = typeof toBeFolded === "object" && !beingFolded, isFoldObj = typeof toBeFolded === "object" && beingFolded, isDir = typeof toBeFolded === "string", args, output, combined; switch(false){ case !isDir: options = moreArgs[0] || {}; if(!process.browser){ stack = callsite(); options.requester = stack[1].getFileName(); } output = populate.apply(this, [toBeFolded, options]); break; case !isFoldObj: args = moreArgs[0] || []; args = isArray(args, true) ? args : [args] if(this.foldStatus === "foldOnly"){ args2 = moreArgs[1] || []; args2 = isArray(args2) ? args2 : [args2] args = args.concat(args2); options = moreArgs[2] || {}; }else{ options = moreArgs[1] || {}; } output = evaluate.apply(this, [toBeFolded, args, options]); break; case !isObj: options = moreArgs[0] || {}; for(var name in toBeFolded){ if( (options.whitelist && !checkList(options.whitelist, name)) || (options.blacklist && checkList(options.blacklist, name)) ) continue fold[name] = toBeFolded[name]; } output = bind( fold, {foldStatus: true}, fold ); break; } return output; }; function populate(dirname, options){ if(process.browser) throw "you must run the foldify browserify transform (foldify/transform.js) for foldify to work in the browser!"; var proxy = {}, toString = options.output && options.output.toLowerCase() === "string", toArray = options.output && options.output.toLowerCase() === "array", encoding = options.encoding || options.enc || "utf-8", returnMe, existingProps = [], newdirname, separator, parts, map = options.tree ? {} : false, files = [], matches; if(toString){ returnMe = ""; }else if(toArray){ returnMe = []; }else{ returnMe = bind( fold, { foldStatus: true, map: map }, proxy ); } try{ if(options.requester && /(^\.\/)|(^\.\.\/)/.test(dirname)){ dirname = dirname .replace(/^\.\//, path.dirname(options.requester)+"/") .replace(/^\.\.\//, path.dirname(options.requester)+"/../"); throw "done"; } if(~dirname.indexOf("/")) separator = "/"; if(~dirname.indexOf("\\")) separator = "\\"; parts = dirname.split(separator); newdirname = path.dirname( require.resolve( parts[0] ) ); if(!~newdirname.indexOf("node_modules")) throw "not a node module"; dirname = newdirname + path.sep + parts.slice(1).join(path.sep); }catch(err){} function recurs(thisDir){ fs.readdirSync(thisDir).forEach(function(file){ var filepath = path.join( thisDir, file); if(path.extname(file) === ''){ if(options.recursive || options.tree) recurs(filepath); return } files.push(filepath); }); } recurs(dirname); if(options.whitelist) files = whitelist(options.whitelist, files, dirname) if(options.blacklist) files = blacklist(options.blacklist, files, dirname) files.forEach(function(filepath){ var ext = path.extname(filepath), name = path.basename(filepath, ext), filename = name + ext, isJs = (ext === ".js" || ext === ".json"), isDir = ext === '', propname, add, last = false; if( toString ){ returnMe += fs.readFileSync(filepath, encoding); return } if( toArray ){ returnMe.push( fs.readFileSync(filepath, encoding) ); return } if(!options.includeExt && (isJs || options.includeExt === false) ) propname = name; else propname = filename; if(!options.tree){ if(options.fullPath || ~existingProps.indexOf(propname) ) propname = path.relative(dirname, filepath); else existingProps.push(propname); } if((isJs && options.jsToString) || !isJs ) add = fs.readFileSync(filepath, encoding); else add = require(filepath); if(map){ var paths = path.relative(dirname, filepath).split(path.sep); var last, thismap; for(var x = 0, len = paths.length; x<len; x++){ if(x===0){ if(!returnMe[ paths[x] ] ) returnMe[ paths[x] ] = {}; last = returnMe[ paths[x] ] if(!map[ paths[x] ] ) map[ paths[x] ] = {}; thismap = map[ paths[x] ] }else if(x < (len-1)){ if(!last[ paths[x] ] ) last[ paths[x] ] = {}; last = last[paths[x]]; if(!thismap[ paths[x] ] ) thismap[ paths[x] ] = {}; thismap = thismap[ paths[x] ]; }else{ last[ propname ] = add; thismap[ propname ] = true; } } }else{ returnMe[propname] = add; } }); for(var p in returnMe) proxy[p] = returnMe[p]; return returnMe; } function evaluate(srcObj, args, options){ var proxy = {}, returnObj; if(options.evaluate === false){ this.foldStatus = "foldOnly"; returnObj = bind( fold, this, proxy, args ); } else returnObj = bind( fold, this, proxy ); var objpaths = flatten.call(this.map, srcObj); for(var objpath in objpaths){ var isWhitelisted = false, isBlacklisted = false, skip = false, add = false, node = false, last = false; if(options.whitelist && checkList(options.whitelist, objpath)) isWhitelisted = true; if(options.blacklist && checkList(options.blacklist, objpath)) isBlacklisted = true; skip = (options.whitelist && !isWhitelisted) || isBlacklisted; if(skip && options.trim) continue; add = node = objpaths[objpath]; if(!skip && typeof node === "function") add = options.evaluate !== false ? node.apply( srcObj, args) : bind.apply( bind, [node, srcObj].concat(args) ); if(typeof add === "undefined" && options.allowUndefined !== true && options.trim) continue if(typeof add === "undefined" && options.allowUndefined !== true) add = node if(this.map){ paths = objpath.split(path.sep); for(var x = 0, len = paths.length; x<len; x++){ if(x===0){ if(!returnObj[ paths[x] ] ) returnObj[ paths[x] ] = {}; last = returnObj[ paths[x] ] }else if(x < (len-1)){ if(!last[ paths[x] ] ) last[ paths[x] ] = {}; last = last[paths[x]]; }else{ last[ paths[x] ] = add; } } }else{ returnObj[objpath] = add; } } for(var p in returnObj) proxy[p] = returnObj[p]; return returnObj; } function checkList(list, name){ list = isArray(list) ? list : [list]; return list.some(function(rule){ return minimatch(name, path.normalize(rule)); }); } function whitelist(whitelist, files, rootdir){ if(!whitelist || !files) return rootdir = rootdir || ""; var output = []; whitelist = isArray(whitelist) ? whitelist : [whitelist]; whitelist.forEach(function(rule){ rule = path.join( rootdir, rule ); files.forEach( function(name){ if(~output.indexOf(name)) return if( minimatch(name, rule) ) output.push(name); }) }); return output; } function blacklist(blacklist, files, rootdir){ if(!blacklist || !files) return rootdir = rootdir || ""; blacklist = isArray(blacklist) ? blacklist : [blacklist]; return files.filter(function(name){ return !blacklist.some(function(rule){ rule = path.join( rootdir, rule ); return minimatch(name, rule) }); }); } function flatten(obj, _path, result) { if(!this) return obj; var key, val, __path; _path = _path || []; result = result || {}; for (key in obj) { val = obj[key]; __path = _path.concat([key]); if (this[key] && this[key] !== true) { flatten.call(this[key], val, __path, result); } else { result[__path.join(path.sep)] = val; } } return result; }; if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement, fromIndex) { if ( this === undefined || this === null ) { throw new TypeError( '"this" is null or not defined' ); } var length = this.length >>> 0; // Hack to convert object.length to a UInt32 fromIndex = +fromIndex || 0; if (Math.abs(fromIndex) === Infinity) { fromIndex = 0; } if (fromIndex < 0) { fromIndex += length; if (fromIndex < 0) { fromIndex = 0; } } for (;fromIndex < length; fromIndex++) { if (this[fromIndex] === searchElement) { return fromIndex; } } return -1; }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(fun /*, thisArg */) { "use strict"; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t) fun.call(thisArg, t[i], i, t); } }; } if (!Array.prototype.some) { Array.prototype.some = function(fun /*, thisArg */) { 'use strict'; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== 'function') throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t && fun.call(thisArg, t[i], i, t)) return true; } return false; }; }; function bind(fn){ var args = Array.prototype.slice.call(arguments, 1); if (!Function.prototype.bind) { return function(){ var onearg = args.shift(); var newargs = args.concat(Array.prototype.slice.call(arguments,0)); var returnme = fn.apply(onearg, newargs ); return returnme; }; }else{ return fn.bind.apply(fn, args); }; } function isArray(obj){ return ~Object.prototype.toString.call(obj).toLowerCase().indexOf("array"); }