From f13cbda84aa5049d2eb3198b787184fb0f939925 Mon Sep 17 00:00:00 2001 From: David Diaz Date: Wed, 11 Apr 2018 15:49:05 -0600 Subject: [PATCH] Allow the escaping of variables. This results in two important changes: - Made changes so that we actually use the replacement regex groups. This was supposed to happen from the start but I guess I didn't notice. By fixing this the code for finding dependencies and the cache#parse is now a bit more reliable. - This also changes how we store variables in the cache (which I've been meaning to do for a while.) removing the dollar sign that usually preceeded all cached requests in Beau. It's all more sensible now. There's more refactoring left to do. --- src/__tests__/__snapshots__/beau.spec.js.snap | 2 +- .../__snapshots__/requestList.spec.js.snap | 23 +++++++++++++++++++ src/__tests__/plugins.spec.js | 2 +- src/__tests__/request.spec.js | 4 ++-- src/__tests__/requestCache.spec.js | 14 +++++++---- src/__tests__/requestList.spec.js | 8 ++++--- src/config.js | 2 +- src/plugins.js | 20 ++-------------- src/request.js | 16 +++++++++---- src/requestCache.js | 20 ++++++++++------ src/requestList.js | 9 ++++---- src/shared.js | 2 +- 12 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/__tests__/__snapshots__/beau.spec.js.snap b/src/__tests__/__snapshots__/beau.spec.js.snap index 0d6ae5c..24aeb3d 100644 --- a/src/__tests__/__snapshots__/beau.spec.js.snap +++ b/src/__tests__/__snapshots__/beau.spec.js.snap @@ -97,7 +97,7 @@ Beau { ], "cache": RequestCache { "$cache": Object { - "$env": Object {}, + "env": Object {}, }, }, "config": Config { diff --git a/src/__tests__/__snapshots__/requestList.spec.js.snap b/src/__tests__/__snapshots__/requestList.spec.js.snap index 20e6c16..04206c4 100644 --- a/src/__tests__/__snapshots__/requestList.spec.js.snap +++ b/src/__tests__/__snapshots__/requestList.spec.js.snap @@ -18,3 +18,26 @@ Object { }, } `; + +exports[`RequestList should fetch dependencies 1`] = ` +RequestCache { + "$cache": Object { + "env": Object { + "environmental": true, + }, + "get-posts": Object { + "body": "{\\"hello\\": \\"world\\"}", + "request": Object { + "body": undefined, + "endpoint": "http://martianwabbit.com/post", + "headers": undefined, + }, + "response": Object { + "body": "{\\"hello\\": \\"world\\"}", + "headers": Array [], + "status": 200, + }, + }, + }, +} +`; diff --git a/src/__tests__/plugins.spec.js b/src/__tests__/plugins.spec.js index e6bb181..60b2929 100644 --- a/src/__tests__/plugins.spec.js +++ b/src/__tests__/plugins.spec.js @@ -74,7 +74,7 @@ describe(`Beau's plugin system`, () => { it(`should look for dynamic values executing and replacing them`, async () => { let cache = new RequestCache(); - cache.add('$value2', '2'); + cache.add('value2', '2'); let req = await request.exec(cache); diff --git a/src/__tests__/request.spec.js b/src/__tests__/request.spec.js index e739b36..c361869 100644 --- a/src/__tests__/request.spec.js +++ b/src/__tests__/request.spec.js @@ -32,8 +32,8 @@ describe('Request', () => { }; cache = new RequestCache(); - cache.add('$session', { token: 'abc123' }); - cache.add('$profile', { UserId: 14 }); + cache.add('session', { token: 'abc123' }); + cache.add('profile', { UserId: 14 }); request = new Request(validRequestConfig); requestWithoutDependencies = new Request({ diff --git a/src/__tests__/requestCache.spec.js b/src/__tests__/requestCache.spec.js index 6b19711..dd989f9 100644 --- a/src/__tests__/requestCache.spec.js +++ b/src/__tests__/requestCache.spec.js @@ -6,11 +6,11 @@ describe('Request Cache', () => { beforeEach(() => { cache = new RequestCache(); - cache.add('$session', { + cache.add('session', { hello: 'World' }); - cache.add('$array', [ + cache.add('array', [ { id: 1, name: 'Sergio' @@ -23,12 +23,12 @@ describe('Request Cache', () => { }); it('should add keys to the cache', () => { - expect(cache.$cache.$session.hello).toBe('World'); + expect(cache.$cache.session.hello).toBe('World'); }); describe('get', () => { it('should be able to find key values with a given path', () => { - expect(cache.get('$session.hello')).toBe('World'); + expect(cache.get('session.hello')).toBe('World'); }); it('should throw when given an invalid path', () => { @@ -79,5 +79,11 @@ describe('Request Cache', () => { it('should return null when passed null', () => { expect(cache.parse(null)).toBe(null); }); + + it(`shouldn't replace escaped variables`, () => { + expect(cache.parse(`\\$session.hello is $session.hello`)).toBe( + `$session.hello is World` + ); + }); }); }); diff --git a/src/__tests__/requestList.spec.js b/src/__tests__/requestList.spec.js index a344542..4a8e50a 100644 --- a/src/__tests__/requestList.spec.js +++ b/src/__tests__/requestList.spec.js @@ -39,8 +39,10 @@ describe('RequestList', () => { expect(requests.list.length).toBe(2); }); - it('should fetch dependencies', () => { - requests.fetchDependencies(['get-posts']); + it('should fetch dependencies', async () => { + await expect( + requests.fetchDependencies(['get-posts']) + ).resolves.toMatchSnapshot(); }); it('should execute requests by alias.', async () => { @@ -54,7 +56,7 @@ describe('RequestList', () => { it('should return a cached result if available', async () => { const obj = { test: true }; - requests.cache.add('$test', obj); + requests.cache.add('test', obj); await expect(requests.execByAlias('test')).resolves.toBe(obj); }); diff --git a/src/config.js b/src/config.js index 62c60fa..52715c7 100644 --- a/src/config.js +++ b/src/config.js @@ -64,7 +64,7 @@ class Config { let requestDefinitionIsString = typeof host[key] === 'string'; let originalRequest = requestDefinitionIsString ? { ALIAS: host[key] } - : deepMerge.all([host[key]]); + : host[key]; let request = UpperCaseKeys(originalRequest); diff --git a/src/plugins.js b/src/plugins.js index 9d288d7..c87e904 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -27,11 +27,11 @@ class Plugins { throw new Error(`Plugin items should contain only one key.`); } - name = Object.keys(plugin)[0]; + name = keys[0]; settings = plugin[name]; } - plugin = requireg(`./beau-${toKebabCase(name)}`); + plugin = requireg(`beau-${toKebabCase(name)}`); new plugin(this, settings); } @@ -45,22 +45,6 @@ class Plugins { return result; } - execPreRequestModifiers(request, originalRequest) { - return this.executeModifier( - 'preRequestModifiers', - request, - originalRequest - ); - } - - execPostRequestModifiers(response, originalRequest) { - return this.executeModifier( - 'postRequestModifiers', - response, - originalRequest - ); - } - replaceDynamicValues(obj) { return replaceInObject(obj, val => { try { diff --git a/src/request.js b/src/request.js index 576f886..c296d4d 100644 --- a/src/request.js +++ b/src/request.js @@ -62,8 +62,12 @@ class Request { set = this.findDependencies(request[key], set); }); } else if (type === 'string') { - const matches = request.match(replacementRegex) || []; - const deps = matches.map(m => m.split('.')[0].substring(1)); + const matches = []; + request.replace( + replacementRegex, + (match, g1) => !match.startsWith('\\') && matches.push(g1) + ); + const deps = matches.map(m => m.split('.')[0]); return new Set([...set, ...deps]); } @@ -82,7 +86,8 @@ class Request { settings = this.plugins.replaceDynamicValues(settings); - settings = this.plugins.execPreRequestModifiers( + settings = this.plugins.executeModifier( + 'preRequestModifiers', settings, this.originalRequest ); @@ -120,12 +125,13 @@ class Request { body: response.body }; - results = this.plugins.execPostRequestModifiers( + results = this.plugins.executeModifier( + 'postRequestModifiers', results, this.originalRequest ); - cache.add(`$${this.ALIAS}`, results); + cache.add(this.ALIAS, results); return results; } catch ({ error }) { diff --git a/src/requestCache.js b/src/requestCache.js index ec2b800..56cdf0c 100644 --- a/src/requestCache.js +++ b/src/requestCache.js @@ -16,13 +16,13 @@ class RequestCache { get(path) { let result = this.$cache; path.split('.').forEach(part => { + if (result[part] === undefined) { + throw new Error(`${path} not found in cache: `, path); + } + result = result[part]; }); - if (typeof result === 'undefined') { - throw new Error(`${path} not found in cache: `, path); - } - return result; } @@ -31,9 +31,15 @@ class RequestCache { return null; } - return replaceInObject(item, item => - item.replace(replacementRegex, key => this.get(key)) - ); + return replaceInObject(item, item => { + return item.replace(replacementRegex, (match, key) => { + if (match.startsWith('\\')) { + return match.replace('\\$', '$'); + } + + return this.get(key); + }); + }); } } diff --git a/src/requestList.js b/src/requestList.js index ef497c8..0c09f76 100644 --- a/src/requestList.js +++ b/src/requestList.js @@ -10,12 +10,12 @@ class RequestList { this.list = this.loadRequests(); this.cache = new RequestCache(); - this.cache.add(`$env`, this.config.ENVIRONMENT); + this.cache.add(`env`, this.config.ENVIRONMENT); } async execByAlias(alias) { - if (this.cache.exists(`$${alias}`)) { - return this.cache.get(`$${alias}`); + if (this.cache.exists(alias)) { + return this.cache.get(alias); } const request = this.list.find(r => r.ALIAS === alias); @@ -26,8 +26,7 @@ class RequestList { try { await this.fetchDependencies(Array.from(request.DEPENDENCIES)); - const response = await request.exec(this.cache); - return response; + return await request.exec(this.cache); } catch (reason) { throw new Error( `Request: ${request.VERB} ${ diff --git a/src/shared.js b/src/shared.js index 953b17b..ed5cd00 100644 --- a/src/shared.js +++ b/src/shared.js @@ -11,7 +11,7 @@ const httpVerbs = [ ]; const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i'); -const replacementRegex = /\$([a-zA-Z\.\d\-\_\/\\\:]+)/g; +const replacementRegex = /(?:\\?)\$([a-zA-Z\.\d\-\_\/\\\:]+)/g; const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])+?\))\]/g; const UpperCaseKeys = function(obj) {