Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ gulp.task('lint', function () {
return gulp.src(['./gulpfile.js', './lib/**/*.js', './tests/**/*.spec.js'])
.pipe(linter())
.pipe(linter.reporter('default', {
breakOnError: true
breakOnError: false
}))
})

gulp.task('test', ['lint'], function () {
return gulp.src('./tests/connect-sequence.spec.js')
return gulp.src('./tests/**/*.spec.js')
.pipe(mocha())
})

Expand Down
129 changes: 129 additions & 0 deletions lib/ConnectSequence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
'use strict'

var MissingArgumentError = require('./errors/MissingArgumentError')

module.exports = ConnectSequence

/**
* @class
* @param {Array<Function>} [middlewareList] A list of middlewares to run
*/
function ConnectSequence () {
this.middlewares = []
}

ConnectSequence.run = deprecatedRun

ConnectSequence.prototype = {
append: append,
appendList: appendList,
run: run
}

/**
* Run sequencially each appended middleware, using the next argument as the final callback.
* @method
* @param {object} req The request object
* @param {object} res The response object
* @param {function} next The next middleware
* @returns {undefined}
*/
function run (req, res, next) {
var errorMsg
if (arguments.length < 3) {
errorMsg = 'ConnectSequence#run() takes 3 arguments. '
errorMsg += arguments.length + ' given.'
throw new MissingArgumentError(errorMsg)
}
if (typeof req !== 'object') {
errorMsg = 'The first argument must be a request object. '
errorMsg += typeof req + ' given.'
throw new TypeError(errorMsg)
}
if (typeof res !== 'object') {
errorMsg = 'The second argument must be a request object. '
errorMsg += typeof req + ' given.'
throw new TypeError(errorMsg)
}
if (typeof next !== 'function') {
errorMsg = 'The third argument must be a middleware function. '
errorMsg += typeof req + ' given.'
throw new TypeError(errorMsg)
}

var midSequence = this.middlewares.reverse()
var initialNext = next.bind(null, req, res, next)
var nestedCallSequence = midSequence.reduce(middlewareReducer, initialNext)
nestedCallSequence.call()

function middlewareReducer (prev, current) {
return current.bind(null, req, res, prev)
}
}

/**
* Run sequentially each middleware in the given array, in the array order, throwing req and res object into.
* @function
* @static
* @deprecated
* @param {Object} req The request object
* @param {Object} res The response object
* @param {Function} initialNext The initial next middleware given at start, which should be run at last
* @param {Array<Function>} middlewares The given array of middlewares
* @example
```js
var connectSequence = require('connect-sequence')
var mids = []
mids.push(function (req, res, next) { ... })
...
mids.push(function (req, res, next) { ... })
connectSequence.run(req, res, next, mids)
```
*/
function deprecatedRun (req, res, initialNext, middlewares) {
if (process.env.NODE_ENV !== 'test') {
var deprecatedMessage = 'WARNING: The static method ConnectSequence.run() is deprecated.'
deprecatedMessage += ' The method will be removed in a near release.'
deprecatedMessage += ' You should use the instance version of ConnectSequence.run().'
deprecatedMessage += ' See https://github.com/sirap-group/connect-sequence for a better documentation about the ConnectSequence instance'
console.log(deprecatedMessage)
}
middlewares.reverse().reduce(middlewareReducer, initialNext.bind(null, req, res, initialNext)).call()

function middlewareReducer (prev, current) {
return current.bind(null, req, res, prev)
}
}

/**
* Append an arbitrary number of middlewares as argument list or as an array
* @method
* @throws TypeError if one of the given middlewares is not a function. All the given middlewares would be rejected.
*/
function append () {
var i
for (i = 0; i < arguments.length; i++) {
if (typeof arguments[i] !== 'function') {
var type = typeof arguments[i]
var errMsg = 'Given middlewares must be functions. "' + type + '" given.'
throw new TypeError(errMsg)
}
}
for (i = 0; i < arguments.length; i++) {
this.middlewares.push(arguments[i])
}
}

/**
* Append many middlewares in an array
* @method
* @param {array}
*/
function appendList (middlewares) {
if (!Array.isArray(middlewares)) {
var errorMsg = 'First argument must be an array of middlewares. '
errorMsg += typeof middlewares + ' given.'
throw new TypeError(errorMsg)
}
return this.append.apply(this, middlewares)
}
23 changes: 0 additions & 23 deletions lib/connect-sequence.js

This file was deleted.

80 changes: 80 additions & 0 deletions lib/errors/MissingArgumentError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict'

var PrivateMethodError = require('./PrivateMethodError')

module.exports = MissingArgumentError

/**
* MissingArgumentError
* @class
* @property {String} message The error message
* @property {String} stack The error stack trace
*
* @constructor
* @param {String} [msg] The error message
*/
function MissingArgumentError (msg) {
// Error.call(this, msg)
if (msg && typeof msg === 'string') {
this.message = msg
} else {
this.message = MissingArgumentError.DEFAULT_ERROR_MESSAGE
}
this.createStackTrace()
}

MissingArgumentError.DEFAULT_ERROR_MESSAGE = 'One or more argument are missing'

MissingArgumentError.prototype = Object.create(Error.prototype)
MissingArgumentError.prototype.constructor = MissingArgumentError
MissingArgumentError.prototype.createStackTrace = createStackTrace

/**
* Set the the correct stack trace for this error
* @method
* @private
* @returns {undefined}
* @throws {PrivateMethodError}
*/
function createStackTrace () {
privatize()
var stack = new Error().stack
var splited = stack.split('\n')
var modifiedStack = splited[0].concat('\n', splited.splice(3).join('\n'))
this.stack = modifiedStack
}

/**
* Throws a PrivateMethodError if the third level of a new stack trace differs of the first
* @function
* @inner
* @returns {undefined}
* @throws {PrivateMethodError}
*/
function privatize () {
var trace = new Error().stack
var here = getFileCall(trace, 1)
var caller = getFileCall(trace, 3)
if (here !== caller) {
throw new PrivateMethodError()
}
}

/**
* Get the file path of the caller at a given stack level
* @function
* @inner
* @param {String} trace A given stack trace
* @param {Number} level A given stack level to get the file path at this level
* @returns {String} The file path for this level
*/
function getFileCall (trace, level) {
var firstLineOfStack = trace.split('\n')[level]
var splitted = firstLineOfStack.split('(')
firstLineOfStack = splitted.splice(1).join('')
splitted = firstLineOfStack.split(')')
firstLineOfStack = splitted.join('')
splitted = firstLineOfStack.split(':')
firstLineOfStack = splitted.slice(0, -2).join('')
return firstLineOfStack
}
77 changes: 77 additions & 0 deletions lib/errors/PrivateMethodError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
'use strict'

module.exports = PrivateMethodError

PrivateMethodError.DEFAULT_ERROR_MESSAGE = 'This is a private method'

PrivateMethodError.prototype = Object.create(Error.prototype)
PrivateMethodError.prototype.constructor = PrivateMethodError
PrivateMethodError.prototype.createStackTrace = createStackTrace

/**
* PrivateMethodError
* @class
* @property {String} message The error message
* @property {String} stack The error stack trace
*
* @constructor
* @param {String} msg The error message
*/
function PrivateMethodError (msg) {
if (msg && typeof msg === 'string') {
this.message = msg
} else {
this.message = PrivateMethodError.DEFAULT_ERROR_MESSAGE
}
this.createStackTrace()
}

/**
* Set the the correct stack trace for this error
* @method
* @private
* @returns {undefined}
* @throws {PrivateMethodError}
*/
function createStackTrace () {
privatize()
var stack = new Error().stack
var splited = stack.split('\n')
var modifiedStack = splited[0].concat('\n', splited.splice(3).join('\n'))
this.stack = modifiedStack
}

/**
* Throws a PrivateMethodError if the third level of a new stack trace differs of the first
* @function
* @inner
* @returns {undefined}
* @throws {PrivateMethodError}
*/
function privatize () {
var trace = new Error().stack
var here = getFileCall(trace, 1)
var caller = getFileCall(trace, 3)
if (here !== caller) {
throw new PrivateMethodError()
}
}

/**
* Get the file path of the caller at a given stack level
* @function
* @inner
* @param {String} trace A given stack trace
* @param {Number} level A given stack level to get the file path at this level
* @returns {String} The file path for this level
*/
function getFileCall (trace, level) {
var firstLineOfStack = trace.split('\n')[level]
var splitted = firstLineOfStack.split('(')
firstLineOfStack = splitted.splice(1).join('')
splitted = firstLineOfStack.split(')')
firstLineOfStack = splitted.join('')
splitted = firstLineOfStack.split(':')
firstLineOfStack = splitted.slice(0, -2).join('')
return firstLineOfStack
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "index.js",
"scripts": {
"test": "gulp test",
"TDD": "gulp test 2> /dev/null; gulp watch",
"coverage": "gulp coverage"
},
"repository": {
Expand Down
Loading