Skip to content

Commit

Permalink
Fix #1
Browse files Browse the repository at this point in the history
  • Loading branch information
feugy committed Jul 22, 2016
1 parent c694898 commit 26d9e6a
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 4 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ Copyright [Damien Simonin Feugas][feugy] and other contributors, licensed under

## Changelog

### 1.2.1
- fix issue related to parameter name extraction when using arrow functions

### 1.2.0
- use proxy to delay remotely exposed Apis retrieval to the first effective usage
- activate Travis CI and coveralls reports
Expand Down Expand Up @@ -238,7 +241,7 @@ Copyright [Damien Simonin Feugas][feugy] and other contributors, licensed under
[david-url]: https://david-dm.org/feugy/mini-service
[npm-image]: https://img.shields.io/npm/v/mini-service.svg
[npm-url]: https://npmjs.org/package/mini-service
[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
[travis-url]: https://travis-ci.org/expressjs/express
[travis-image]: https://travis-ci.org/feugy/mini-service/master.svg
[travis-url]: https://travis-ci.org/feugy/mini-service
[coveralls-image]: https://img.shields.io/coveralls/feugy/mini-service/master.svg
[coveralls-url]: https://coveralls.io/r/feugy/mini-service?branch=master
27 changes: 26 additions & 1 deletion lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,35 @@ exports.getLogger = () => {

/**
* Extract declared parameter names from funciton signature
* Rest parameters are not supported
*
* @param {Function} fn - analyzed function
* @returns {Array<String>} names - array of declared parameters (might be empty)
* @throws {Error} if the passed argument isn't a function, or is unsupported
*/
exports.getParamNames = fn => fn.toString().match(/^[^(]*\(((?:\S+, )*\S*)\)/)[1].split(', ').filter(p => p)
exports.getParamNames = fn => {
const declaration = (fn || '').toString()
if (/^[^(]*\(/.test(declaration)) {
// covers the following cases: "function ()", "() =>", "name () {", "function name () {" {},
const params = declaration.match(/^[^(]*\(((?:[^,]+, )*[^\)]*)\)/)[1].split(', ')
// remove empty false-positives
.filter(p => p)
// remove default values
.map(p => p.replace(/\s*=.+/, ''))
// guard against rest parameters
for (const p of params) {
if (p.startsWith('...')) {
throw new Error(`unsupported function ${fn}: rest parameter ${p}`)
}
}
return params
}
if (/^\s*\S+\s*=>/.test(declaration)) {
// covers the following cases: "name =>",
return [declaration.match(/^\s*(\S+)\s*=>/)[1]]
}
throw new Error(`unsupported function ${fn}`)
}

/**
* Transform an array to an object, assigning each array item to a given property.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mini-service",
"version": "1.2.0",
"version": "1.2.1",
"description": "Micro services done simply. Choose to run them locally or remotely",
"repository": {
"type": "git",
Expand Down
142 changes: 142 additions & 0 deletions test/utils/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const Lab = require('lab')
const assert = require('power-assert')
const utils = require('../../lib/utils')

const lab = exports.lab = Lab.script()
const {describe, it} = lab

describe('Utilities', () => {

describe('getParamNames', () => {

it('should fails on null', done => {
assert.throws(() => utils.getParamNames(null), /unsupported function null/)
done()
})

it('should fails on undefined', done => {
assert.throws(() => utils.getParamNames(), /unsupported function undefined/)
done()
})

it('should fails on object', done => {
assert.throws(() => utils.getParamNames({}), /unsupported function \[object Object\]/)
done()
})

it('should fails on rest parameter', done => {
assert.throws(() => utils.getParamNames((...args) => {}), /unsupported function \(\.\.\.args\)/)
done()
})

it('should handle typical function', done => {
const obj = {
ping() {
return Promise.resolve({time: new Date()})
}
}
assert.deepEqual(utils.getParamNames(obj.ping), [])
done()
})

it('should handle empty function declaration', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
function declared() {}
assert.deepEqual(utils.getParamNames(declared), [])
done()
})

it('should handle empty anonymous function', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
assert.deepEqual(utils.getParamNames(function() {}), [])
done()
})

it('should handle named function', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
assert.deepEqual(utils.getParamNames(function named() {}), [])
done()
})

it('should handle empty arrow function', done => {
/* eslint no-empty-function: 0 */
assert.deepEqual(utils.getParamNames(() => {}), [])
done()
})

it('should handle function declaration with single parameter', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
function declared(a) {}
assert.deepEqual(utils.getParamNames(declared), ['a'])
done()
})

it('should handle anonymous function with single parameter', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function(a) {}), ['a'])
done()
})

it('should handle named function with single parameter', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function named(a) {}), ['a'])
done()
})

it('should handle empty arrow function with single parameter', done => {
/* eslint no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(a => {}), ['a'])
done()
})

it('should handle function declaration with multiple parameter', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
function declared(a, b, c) {}
assert.deepEqual(utils.getParamNames(declared), ['a', 'b', 'c'])
done()
})

it('should handle anonymous function with multiple parameters', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function(a, b, c) {}), ['a', 'b', 'c'])
done()
})

it('should handle named function with multiple parameters', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function named(a, b, c) {}), ['a', 'b', 'c'])
done()
})

it('should handle empty arrow function with multiple parameters', done => {
/* eslint no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames((a, b, c) => {}), ['a', 'b', 'c'])
done()
})

it('should handle function declaration with default values', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0 */
function declared(a, b, c = false) {}
assert.deepEqual(utils.getParamNames(declared), ['a', 'b', 'c'])
done()
})

it('should handle anonymous function with default values', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function(a, b, c = 10) {}), ['a', 'b', 'c'])
done()
})

it('should handle named function with default values', done => {
/* eslint prefer-arrow-callback: 0, no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames(function named(a, b, c = null) {}), ['a', 'b', 'c'])
done()
})

it('should handle empty arrow function with default values', done => {
/* eslint no-empty-function: 0, no-unused-vars:0 */
assert.deepEqual(utils.getParamNames((a, b, c = []) => {}), ['a', 'b', 'c'])
done()
})
})
})

0 comments on commit 26d9e6a

Please sign in to comment.