diff --git a/README.md b/README.md index 7966dbb..48bb266 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,10 @@ Copyright [Damien Simonin Feugas][feugy] and other contributors, licensed under ## Changelog +### 1.2.2 +- fix parameter detection +- fix Proxy that is detected as a Thenable object + ### 1.2.1 - fix issue related to parameter name extraction when using arrow functions diff --git a/lib/client.js b/lib/client.js index 9525ce7..bae2d54 100644 --- a/lib/client.js +++ b/lib/client.js @@ -2,6 +2,8 @@ const {version} = require('../package.json') const {getLogger} = require('./utils') const {registerLocal, registerFromServer} = require('./utils/register') +const reserved = ['then', 'catch', 'finally'] + class Client { // client's version @@ -40,9 +42,17 @@ class Client { return remote ? new Proxy(this, { get(target, propKey) { + // use first defined properties + if (propKey in target) { + return target[propKey] + } + // reserved keyword that aren't defined must be undefined (thenable false-positive) + if (reserved.includes(propKey)) { + /* eslint no-undefined: 0 */ + return undefined + } // creates a function that will get exposed API from remote server - // but only if the function isn't defined yet - return target[propKey] || ((...args) => { + return (...args) => { logger.debug(`during ${propKey}, connect to ${remote} to get exposed apis`) return registerFromServer(target, remote, logger) .then(() => { @@ -53,7 +63,7 @@ class Client { } return target[propKey](...args) }) - }) + } } }) : this } diff --git a/lib/utils/index.js b/lib/utils/index.js index 2a9cf40..2b8f9e0 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -31,9 +31,13 @@ exports.getLogger = () => { */ exports.getParamNames = fn => { const declaration = (fn || '').toString() - if (/^[^(]*\(/.test(declaration)) { + if (/^\s*[^\(]+?\s*=>/.test(declaration)) { + // covers the following cases: "name =>", + return [declaration.match(/^\s*(\S+)\s*=>/)[1]] + } + if (/^[^(]*?\(/.test(declaration)) { // covers the following cases: "function ()", "() =>", "name () {", "function name () {" {}, - const params = declaration.match(/^[^(]*\(((?:[^,]+, )*[^\)]*)\)/)[1].split(', ') + const params = declaration.match(/^[^(]*\(((?:.+?, )*.*?)\)/)[1].split(', ') // remove empty false-positives .filter(p => p) // remove default values @@ -46,10 +50,6 @@ exports.getParamNames = fn => { } 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}`) } diff --git a/package.json b/package.json index 2e294b1..5ee3850 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mini-service", - "version": "1.2.1", + "version": "1.2.2", "description": "Micro services done simply. Choose to run them locally or remotely", "repository": { "type": "git", diff --git a/test/client.js b/test/client.js index 2cf4a6a..ca09e2d 100644 --- a/test/client.js +++ b/test/client.js @@ -135,6 +135,11 @@ describe('service\'s client', () => { done() }) + it('should not be detected as a Promise', () => + // This will check the existence of then method on the Proxy + Promise.resolve(remote) + ) + it('should handle communication error', () => remote.ping() // no server available .then(res => { diff --git a/test/utils/common.js b/test/utils/common.js index 72efc28..3cf1542 100644 --- a/test/utils/common.js +++ b/test/utils/common.js @@ -9,6 +9,9 @@ describe('Utilities', () => { describe('getParamNames', () => { + /* eslint no-empty-function: 0 */ + const noop = () => {} + it('should fails on null', done => { assert.throws(() => utils.getParamNames(null), /unsupported function null/) done() @@ -40,102 +43,133 @@ describe('Utilities', () => { }) it('should handle empty function declaration', done => { - /* eslint prefer-arrow-callback: 0, no-empty-function: 0 */ - function declared() {} + /* eslint prefer-arrow-callback: 0 */ + function declared() { + noop() + } 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() {}), []) + /* eslint prefer-arrow-callback: 0 */ + assert.deepEqual(utils.getParamNames(function() { + noop() + }), []) done() }) it('should handle named function', done => { - /* eslint prefer-arrow-callback: 0, no-empty-function: 0 */ - assert.deepEqual(utils.getParamNames(function named() {}), []) + /* eslint prefer-arrow-callback: 0 */ + assert.deepEqual(utils.getParamNames(function named() { + noop() + }), []) done() }) it('should handle empty arrow function', done => { - /* eslint no-empty-function: 0 */ - assert.deepEqual(utils.getParamNames(() => {}), []) + assert.deepEqual(utils.getParamNames(() => { + noop() + }), []) done() }) it('should handle function declaration with single parameter', done => { - /* eslint prefer-arrow-callback: 0, no-empty-function: 0 */ - function declared(a) {} + /* eslint prefer-arrow-callback: 0 */ + function declared(a) { + noop() + } 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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function(a) { + noop() + }), ['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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function named(a) { + noop() + }), ['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']) + /* eslint no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(a => { + noop() + }), ['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) {} + /* eslint prefer-arrow-callback: 0 */ + function declared(a, b, c) { + noop() + } 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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function(a, b, c) { + noop() + }), ['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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function named(a, b, c) { + noop() + }), ['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']) + /* eslint no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames((a, b, c) => { + noop() + }), ['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) {} + /* eslint prefer-arrow-callback: 0 */ + function declared(a, b, c = false) { + noop() + } 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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function(a, b, c = 10) { + noop() + }), ['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']) + /* eslint prefer-arrow-callback: 0, no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames(function named(a, b, c = null) { + noop() + }), ['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']) + /* eslint no-unused-vars:0 */ + assert.deepEqual(utils.getParamNames((a, b, c = []) => { + noop() + }), ['a', 'b', 'c']) done() }) })