Skip to content

Commit

Permalink
feat: add support for global middleware, useful for shared tasks like…
Browse files Browse the repository at this point in the history
… metrics (#1119)
  • Loading branch information
aorinevo authored and bcoe committed May 1, 2018
1 parent 744d299 commit 9d71ac7
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 3 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Expand Up @@ -12,7 +12,7 @@ install:
# Get the latest stable version of Node 0.STABLE.latest
- ps: Install-Product node $env:nodejs_version
# Typical npm stuff.
- npm -g install npm@latest
- npm i npm@5
- npm install

# Post-install test scripts.
Expand Down
29 changes: 29 additions & 0 deletions docs/api.md
Expand Up @@ -929,6 +929,35 @@ To submit a new translation for yargs:
<a name="nargs"></a>.nargs(key, count)
-----------

.middleware(callbacks)
------------------------------------

Define global middleware functions to be called first, in list order, for all cli command.

The `callbacks` parameter can be a function or a list of functions. Each callback gets passed a reference to argv.

```js
const mwFunc1 = argv => console.log('I\'m a middleware function');
const mwFunc2 = argv => console.log('I\'m another middleware function');

yargs
.command('myCommand', 'some command', {}, function(argv){
console.log('Running myCommand!');
})
.middleware([mwFunc1, mwFunc2]).argv;
```
When calling `myCommand` from the command line, mwFunc1 gets called first, then mwFunc2, and finally the command's handler. The console output is:
```
I'm a middleware function
I'm another middleware function
Running myCommand!
```


<a name="middleware"></a>.middleware(callbacks)
--------------------


The number of arguments that should be consumed after a key. This can be a
useful hint to prevent parsing ambiguity. For example:

Expand Down
4 changes: 3 additions & 1 deletion lib/command.js
Expand Up @@ -9,15 +9,17 @@ const DEFAULT_MARKER = /(^\*)|(^\$0)/
// handles parsing positional arguments,
// and populating argv with said positional
// arguments.
module.exports = function command (yargs, usage, validation) {
module.exports = function command (yargs, usage, validation, globalMiddleware) {
const self = {}
let handlers = {}
let aliasMap = {}
let defaultCommand
globalMiddleware = globalMiddleware || []
self.addHandler = function addHandler (cmd, description, builder, handler, middlewares) {
let aliases = []
handler = handler || (() => {})
middlewares = middlewares || []
middlewares = globalMiddleware.concat(middlewares)
if (Array.isArray(cmd)) {
aliases = cmd.slice(1)
cmd = cmd[0]
Expand Down
10 changes: 10 additions & 0 deletions lib/middleware.js
@@ -0,0 +1,10 @@
module.exports = function (globalMiddleware, context) {
return function (callback) {
if (Array.isArray(callback)) {
Array.prototype.push.apply(globalMiddleware, callback)
} else if (typeof callback === 'object') {
globalMiddleware.push(callback)
}
return context
}
}
56 changes: 56 additions & 0 deletions test/middleware.js
@@ -0,0 +1,56 @@
'use strict'
/* global describe, it, beforeEach, afterEach */

const middlewareFactory = require('../lib/middleware')
let yargs
require('chai').should()

describe('middleware', () => {
beforeEach(() => {
yargs = require('../')
})

afterEach(() => {
delete require.cache[require.resolve('../')]
})
it('should add a list of callbacks to global middleware', () => {
const globalMiddleware = []

middlewareFactory(globalMiddleware)(['callback1', 'callback2'])

globalMiddleware.should.have.lengthOf(2)
})

it('should add a single callback to global middleware', () => {
const globalMiddleware = []

middlewareFactory(globalMiddleware)({})

globalMiddleware.should.have.lengthOf(1)
})

it('runs all middleware before reaching the handler', function (done) {
yargs(['mw'])
.middleware([
function (argv) {
argv.mw1 = 'mw1'
},
function (argv) {
argv.mw2 = 'mw2'
}
])
.command(
'mw',
'adds func list to middleware',
function () {},
function (argv) {
// we should get the argv filled with data from the middleware
argv.mw1.should.equal('mw1')
argv.mw2.should.equal('mw2')
return done()
}
)
.exitProcess(false) // defaults to true.
.argv
})
})
6 changes: 5 additions & 1 deletion yargs.js
Expand Up @@ -11,6 +11,7 @@ const Y18n = require('y18n')
const objFilter = require('./lib/obj-filter')
const setBlocking = require('set-blocking')
const applyExtends = require('./lib/apply-extends')
const middlewareFactory = require('./lib/middleware')
const YError = require('./lib/yerror')

exports = module.exports = Yargs
Expand All @@ -21,6 +22,7 @@ function Yargs (processArgs, cwd, parentRequire) {
let command = null
let completion = null
let groups = {}
let globalMiddleware = []
let output = ''
let preservedGroups = {}
let usage = null
Expand All @@ -31,6 +33,8 @@ function Yargs (processArgs, cwd, parentRequire) {
updateFiles: false
})

self.middleware = middlewareFactory(globalMiddleware, self)

if (!cwd) cwd = process.cwd()

self.$0 = process.argv
Expand Down Expand Up @@ -117,7 +121,7 @@ function Yargs (processArgs, cwd, parentRequire) {
// instances of all our helpers -- otherwise just reset.
usage = usage ? usage.reset(localLookup) : Usage(self, y18n)
validation = validation ? validation.reset(localLookup) : Validation(self, usage, y18n)
command = command ? command.reset() : Command(self, usage, validation)
command = command ? command.reset() : Command(self, usage, validation, globalMiddleware)
if (!completion) completion = Completion(self, usage, command)

completionCommand = null
Expand Down

0 comments on commit 9d71ac7

Please sign in to comment.