fabricator
Advanced tools
Comparing version 0.3.0 to 0.4.0
168
index.js
@@ -7,51 +7,42 @@ 'use strict'; | ||
/** | ||
* Expose small fabrication helper. Provide an optional callback to run the method | ||
* asynchronously. | ||
* Expose small fabrication helper. | ||
* | ||
* @param {Mixed} stack String, array or object that contains constructible entities | ||
* @param {String} source Optional absolute path to be used to resolve filepaths | ||
* @param {Function} done Optional completion callback. | ||
* @return {Array} collection of constructors, if called synchronously. | ||
* @param {Object} options | ||
* | ||
* Possible options | ||
* - source: {String} Absolute path to be used to resolve filepaths | ||
* - recursive: {Boolean} Should file paths be recursively discovered | ||
* | ||
* @returns {Array} collection of constructors. | ||
* @api public | ||
*/ | ||
module.exports = function fabricator(stack, source, done) { | ||
module.exports = function fabricator(stack, options) { | ||
var type = typeof stack; | ||
if ('object' === type && Array.isArray(stack)) type = 'array'; | ||
// | ||
// No source was provided, check if the call was asynchronous. | ||
// | ||
if ('function' === typeof source) { | ||
done = source; | ||
source = null; | ||
} | ||
// | ||
// Call the fabricate function (a)synchronously. | ||
// | ||
if ('function' !== typeof done) return fabricateSync(type, stack, source); | ||
fabricate(type, stack, source, done); | ||
return fabricate(type, stack, options || {}); | ||
}; | ||
/** | ||
* Synchronous discover constructible entities. | ||
* Discover constructible entities. | ||
* | ||
* @param {String} type Typeof stack. | ||
* @param {Mixed} stack | ||
* @param {String} source Optional absolute path to be used to resolve filepaths | ||
* @param {Object} options | ||
* @return {Array} filtered collection of constructible entities. | ||
* @api private | ||
*/ | ||
function fabricateSync(type, stack, source) { | ||
function fabricate(type, stack, options) { | ||
switch (type) { | ||
case 'string': | ||
stack = readSync(stack, source); | ||
stack = read(stack, options); | ||
break; | ||
case 'object': | ||
stack = Object.keys(stack).reduce(iterator(readSync, stack, source), []); | ||
stack = Object.keys(stack).reduce(iterator(read, stack, options), []); | ||
break; | ||
case 'array': | ||
stack = stack.reduce(iterator(readSync, source), []); | ||
stack = stack.reduce(iterator(read, null, options), []); | ||
break; | ||
@@ -64,47 +55,11 @@ } | ||
/** | ||
* Asynchronously discover constructible entities. | ||
* | ||
* @param {String} type Typeof stack. | ||
* @param {Mixed} stack | ||
* @param {String} source Optional absolute path to be used to resolve filepaths | ||
* @param {Function} done Completion callback. | ||
* @api private | ||
*/ | ||
function fabricate(type, stack, source, done) { | ||
var result = []; | ||
switch (type) { | ||
case 'string': | ||
read(stack, source, done); | ||
break; | ||
case 'object': | ||
Object.keys(stack).reduce(iterator( | ||
read, | ||
stack, | ||
source, | ||
recur(Object.keys(stack).length, result, done) | ||
), result); | ||
break; | ||
case 'array': | ||
stack.reduce(iterator( | ||
read, | ||
null, | ||
source, | ||
recur(stack.length, result, done) | ||
), result); | ||
break; | ||
} | ||
} | ||
/** | ||
* Read directory and initialize javascript files. | ||
* | ||
* @param {String} filepath Full directory path. | ||
* @param {Object} options | ||
* @return {Array} collection of constructors | ||
* @api private | ||
*/ | ||
function readSync(filepath, source) { | ||
if (source) filepath = path.resolve(source, filepath); | ||
function read(filepath, options) { | ||
if (options.source) filepath = path.resolve(options.source, filepath); | ||
@@ -119,4 +74,11 @@ // | ||
// | ||
// Read the directory synchronous, only process files. | ||
// Recursion on directories not allowed, initialize the index.js file. | ||
// | ||
if (options.recursive === false) return [ | ||
init(filepath, path.basename(filepath, '.js')) | ||
]; | ||
// | ||
// Read the directory, only process files. | ||
// | ||
return fs.readdirSync(filepath).map(function locate(file) { | ||
@@ -134,41 +96,2 @@ file = path.resolve(filepath, file); | ||
/** | ||
* Asynchronous read directory and initialize javascript files. | ||
* | ||
* @param {String} filepath Full directory path. | ||
* @param {String} source Optional absolute path to be used to resolve filepaths | ||
* @param {done} | ||
* @api privat | ||
*/ | ||
function read(filepath, source, done) { | ||
var iterate; | ||
if (source) filepath = path.resolve(source, filepath); | ||
// | ||
// Check if the provided string is a JS file. | ||
// | ||
if (js(filepath)) return done(null, [ | ||
init(filepath, path.basename(filepath, '.js')) | ||
]); | ||
// | ||
// Read the directory asynchronous, only process files. | ||
// | ||
fs.readdir(filepath, function readfilepath(error, files) { | ||
if (error) return done(error); | ||
iterate = recur(files.length, [], done); | ||
files.forEach(function map(file) { | ||
file = path.resolve(filepath, file); | ||
if (!js(file)) return iterate(); | ||
fs.stat(file, function details(error, stat) { | ||
if (error || !stat.isFile()) return iterate(); | ||
iterate(null, init(file, path.basename(file, '.js'))); | ||
}); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Return iterator for array or object. | ||
@@ -178,8 +101,7 @@ * | ||
* @param {Object} obj Original object, if set values are fetched by entity. | ||
* @param {String} source Optional absolute path to be used to resolve filepaths | ||
* @param {Function} done Optional completion callback. | ||
* @param {Object} options | ||
* @return {Function} iterator | ||
* @api private | ||
*/ | ||
function iterator(traverse, obj, source, done) { | ||
function iterator(traverse, obj, options) { | ||
return function reduce(stack, entity) { | ||
@@ -190,13 +112,5 @@ var base = obj ? obj[entity] : entity | ||
// | ||
// Run traverse function async, callback was provided, traverse will init. | ||
// Run the functions, traverse will handle init. | ||
// | ||
if ('function' === typeof done) { | ||
if (nojs) return traverse(base, source, done); | ||
return done(null, init(base, entity)); | ||
} | ||
// | ||
// Run the sync functions, traverse will handle init. | ||
// | ||
if (nojs) return stack.concat(traverse(base, source)); | ||
if (nojs) return stack.concat(traverse(base, options)); | ||
return stack.concat(init(base, entity)); | ||
@@ -207,22 +121,2 @@ }; | ||
/** | ||
* Result mapper, returns when all callbacks finished. | ||
* | ||
* @param {Number} n Number of execution before done is called. | ||
* @param {Array} results Stack to push results into. | ||
* @param {Function} done Completion callback. | ||
* @returns {Fuction} handler to process files after finished iteration. | ||
* @api private | ||
*/ | ||
function recur(n, results, done) { | ||
return function iterate(error, files) { | ||
if (!error && files) results = results.concat(files); | ||
// | ||
// Check if the base stack is completely processed. | ||
// | ||
if (!--n) return done(error, results.filter(Boolean)); | ||
}; | ||
} | ||
/** | ||
* Make sure only valid JavaScript files are used as source. Ignore other files, | ||
@@ -229,0 +123,0 @@ * like .log files. Also allow constructors. |
{ | ||
"name": "fabricator", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "Discover collections of constructible instances from strings (filepaths), arrays or objects", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -11,5 +11,2 @@ # Fabricator [![Build Status][status]](https://travis-ci.org/bigpipe/fabricator) [![NPM version][npmimgurl]](http://badge.fury.io/js/fabricator) [![Coverage Status][coverage]](http://coveralls.io/r/bigpipe/fabricator?branch=master) | ||
The module exposes a factory function which can be provided with an optional | ||
completion callback. Providing the callback will make the discovery asynchronous. | ||
The [BigPipe] project is using the fabricator to find Pages and/or Pagelets. This | ||
@@ -37,12 +34,5 @@ gives developers using BigPipe more flexibility. For example, you don't have to | ||
// | ||
// Discover constructors synchronously. | ||
// Discover constructors. | ||
// | ||
var stack = fabricator(obj); | ||
// | ||
// Similar to above but asynchronously. | ||
// | ||
fabricator(path, function fabricate(error, results) { | ||
console.log(results); | ||
}); | ||
``` | ||
@@ -49,0 +39,0 @@ |
@@ -12,18 +12,10 @@ describe('Fabricator', function () { | ||
it('can be called (a)synchronous and returns an array', function (done) { | ||
it('always returns an array', function () { | ||
var result = fabricator(fixtures.array); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(2); | ||
fabricator(fixtures.array, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(2); | ||
done(); | ||
}); | ||
assume(result.length).to.equal(3); | ||
}); | ||
it('can init constructors from file paths', function (done) { | ||
it('can init constructors from file paths', function () { | ||
var result = fabricator(fixtures.string); | ||
@@ -33,44 +25,28 @@ | ||
assume(result.length).to.equal(1); | ||
fabricator(fixtures.string, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(1); | ||
done(); | ||
}); | ||
}); | ||
it('will discover constructors in subdirectories and ignore other JS files', function (done) { | ||
it('will discover constructors in subdirectories and ignore other JS files', function () { | ||
var result = fabricator(fixtures.directory); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(1); | ||
assume(result.length).to.equal(2); | ||
}); | ||
fabricator(fixtures.directory, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(1); | ||
it('can be provided with a absolute source path to resolve filepaths', function () { | ||
var path = __dirname + '/fixtures' | ||
, result = fabricator(fixtures.relative, { source: path }); | ||
done(); | ||
}); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(2); | ||
}); | ||
it('can be provided with a absolute source path to resolve filepaths', function (done) { | ||
it('can be prevented from recursing a directory', function () { | ||
var path = __dirname + '/fixtures' | ||
, result = fabricator(fixtures.relative, path); | ||
, result = fabricator(fixtures.directory, { recursive: false }); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(1); | ||
fabricator(fixtures.relative, path, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(1); | ||
done(); | ||
}); | ||
}); | ||
it('will discover constructors from objects', function (done) { | ||
it('will discover constructors from objects', function () { | ||
var result = fabricator(fixtures.object); | ||
@@ -80,25 +56,9 @@ | ||
assume(result.length).to.equal(3); | ||
fabricator(fixtures.object, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(3); | ||
done(); | ||
}); | ||
}); | ||
it('will discover constructors from arrays', function (done) { | ||
it('will discover constructors from arrays', function () { | ||
var result = fabricator(fixtures.array); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(2); | ||
fabricator(fixtures.array, function (error, result) { | ||
assume(error).to.equal(null); | ||
assume(result).to.be.an('array'); | ||
assume(result.length).to.equal(2); | ||
done(); | ||
}); | ||
assume(result.length).to.equal(3); | ||
}); | ||
@@ -105,0 +65,0 @@ |
13
11283
221
46