New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

loadware

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

loadware - npm Package Compare versions

Comparing version

to
2.0.0

119

loadware.js

@@ -1,107 +0,26 @@

/*
loadware.js - middleware handling
Normalizes a varied group of middleware descriptors into an array of middleware.
loadware(['body-parser', [() => {}], ['cookie-parser', { session: () => {} }]]) =>
[() => {}, () => {}, () => {}, () => {}]
*/
// loadware.js - Turn different middleware descriptors into an array of middleware
require('app-module-path').addPath(process.cwd());
let isObject = obj => obj.toString() === '[object Object]';
// Retrieve the first key of an object
let getKey = obj => isObject(obj) ? Object.keys(obj)[0] : false;
// Retrieve the first value of an object
let getValue = obj => obj[getKey(obj)];
// Put it all into a single array of non-arrays recursively
// ['a', ['b', ['c', ...]]] => ['a', 'b', 'c', ...]
let flat = middle => {
while (middle.filter(mid => mid instanceof Array).length) {
middle = middle.reduce((all, arg) => all.concat(arg), []);
}
return middle;
}
let flat = arr => arr.reduce((good, one) => {
let flatten = Array.isArray(one) ? flat(one) : one || [];
return good.concat(flatten)
}, []);
// Fetches the absolute path from the root
// ['a', 'b'] => [require('a'), require('b')]
// Note: this doesn't work: 'require(mid)'
let include = mid => typeof mid === 'string'
? require(require('path').resolve(mid))
: mid;
// Expand a complex object into several simple ones
// [{ a: 'a', b: 'b', c: 'c' }] => [{ a: 'a' }, { b: 'b' }, { c: 'c' }]
let expand = middle => {
middle = middle.map(mid => {
if (!isObject(mid)) return mid;
// Throw an error if there's something that is not a function anymore
// [{ a: 'b' }] => throw new Error();
let others = mid => {
if (mid instanceof Function) return mid;
throw new Error("Only boolean, string, array or function can be middleware");
}
let arr = [];
for (let key in mid) {
arr.push({ [key]: mid[key] });
}
return arr;
});
return flat(middle);
};
// Get them all together in a single object
let join = (obj, one) => Object.assign({}, obj, one);
// Retrieve an object with the last known config
let retrieveObjs = middle => middle.filter(isObject).reduce(join, {});
// Keep only the last copy for a named middleware
let removeDups = (middle, objs) => middle.map(getKey)
// Flag which objects to remove
.map((key, i, all) => !key || all.lastIndexOf(key) === i)
// Map the good copies to the original value
.map((good, i) => good && middle[i])
// Defined && not an object || defined && a non-empty object
.filter(mid => mid && (!getKey(mid) || getValue(mid)));
module.exports = (...middle) => {
// Make it into a non-null list of functions
middle = flat(middle);
// Put object with several keys into different objects
// [{ a: 'a', b: 'b' }, { c: 'c' }] => [{ a: 'a' }, { b: 'b' }, { c: 'c' }]
middle = expand(middle);
// Get an object with each of the named middlewares
// [{ a: 'a' }, { b: 'b' }, { a: 'c' }] => [{ a: 'c', b: 'b' }]
let objs = retrieveObjs(middle);
// Remove duplicated, previous objects
// [{ a: 'a' }, { b: 'b' }, { a: 'c' }] => [{ b: 'b' }, { a: 'c' }]
middle = removeDups(middle, objs);
// Finally keep only the callback
// [{ b: 'b' }, { a: 'c' }] => ['b', 'c']
middle = middle.map(mid => isObject(mid) ? getValue(mid) : mid);
// Include from string
// ['a', 'b'] => [require('a'), require('b')]
middle = middle.map(mid => {
if (typeof mid === 'string') {
// Fetches the absolute path from the root
// Note: this doesn't work: 'require(mid)'
return require(require('path').resolve(mid));
}
return mid;
});
return middle;
};
// The actual glue for them all
module.exports = (...middle) => flat(middle).map(include).filter(others);

5

package.json
{
"name": "loadware",
"version": "1.0.0",
"version": "2.0.0",
"description": "A library to make sense of a bunch of middleware definitions and return a simple array of middleware\"",

@@ -19,3 +19,3 @@ "main": "loadware.js",

],
"author": "Francisco Presencia <public@francisco.io>",
"author": "Francisco Presencia <public@francisco.io> (http://francisco.io/)",
"license": "MIT",

@@ -27,2 +27,3 @@ "bugs": {

"devDependencies": {
"express": "^4.14.0",
"jest": "^17.0.3",

@@ -29,0 +30,0 @@ "pray": "^1.0.2"

@@ -19,2 +19,4 @@ # loadware

The middleware can be a string, a function or an array of any of the previous.
This is part of another project which is WIP right now, but I think this is independently enough so it can be launched separately.
let pray = require('pray');
let express = require('express');
let loadware = require('../loadware');

@@ -6,5 +7,13 @@

let allFn = arr => arr.forEach(pray.isFn);
let fn = ctx => {};
let throws = cb => {
let error;
try { cb(); } catch(err) { error = err; }
if (typeof error === 'undefined') {
throw new Error(cb + ' did not throw an error as expected.');
}
}
describe('loadware.js', function() {
describe('Initialization', () => {
it('Can be used empty', () => {

@@ -14,22 +23,60 @@ pray([])(loadware());

it('Ignores falsy values', () => {
expect(loadware([], 0, "", false, null, undefined).length).toBe(0);
});
it('Rejects numbers', () => {
throws(() => loadware(5));
});
it('Rejects different objects', () => {
throws(() => loadware({ a: 'b' }));
throws(() => loadware(new Date()));
throws(() => loadware(new Promise(() => {})));
});
});
describe('works with strings', () => {
it('Can load from a string', () => {
pray(allFn)(loadware('./tests/a'));
pray(allFn)(loadware('./tests/a'));
});
it('handles many arguments', () => {
expect(loadware('./tests/a', './tests/b', './tests/c').length).toBe(3);
});
it('handles nested strings', () => {
expect(loadware(['./tests/a'], ['./tests/b', './tests/c']).length).toBe(3);
});
it('handles deeply nested strings', () => {
expect(loadware(['./tests/a', ['./tests/b', ['./tests/c']]]).length).toBe(3);
});
it('Throws an error when non-existing string', () => {
throws(() => loadware('./tests/dsfs'));
});
})
describe('works with functions', () => {
it('Converts function to array', () => {
let demo = function(){};
pray([demo])(loadware(demo));
pray([fn])(loadware(fn));
});
it('Joins objects with the same key', () => {
pray(allFn)(loadware({ a: './tests/a', b: './tests/b' }, { a: './tests/c' }));
it('handles many arguments', () => {
expect(loadware(fn, fn, fn, fn, fn, fn).length).toBe(6);
});
it('Can load several objects and they overwrite each other where appropriate', () => {
let fn = function(){};
let loaded = loadware({ a: './tests/a', b: './tests/b' }, { c: './tests/c' }, fn, { b: false });
pray(allFn)(loaded);
expect(loaded).toHaveLength(3);
it('handles nested arrays', () => {
expect(loadware([fn], [fn, fn], [fn, fn, fn]).length).toBe(6);
});
it('handles deeply nested arrays', () => {
expect(loadware([fn, [fn, [fn, [fn, [fn, [fn]]]]]]).length).toBe(6);
});
// When passing Router() it only rendered the last one since it had some properties

@@ -43,6 +90,24 @@ it('Treats a function as a function even if it has properties', () => {

});
});
it('Default stays the same', () => {
pray(allFn)(loadware([{ hi: './tests/a' }]));
describe('plays well with others', () => {
it('works with express router USE', () => {
let router = express.Router();
router.use('/', fn);
pray([router])(loadware(router));
});
it('works with express router GET', () => {
let router = express.Router();
router.get('/', fn);
pray([router])(loadware(router));
});
it('works with express router POST', () => {
let router = express.Router();
router.post('/', fn);
pray([router])(loadware(router));
});
});