mirror of https://github.com/Seich/Beau.git
Making improvements to the plugins system.
This is mostly some clean up. Now plugins are checked for existence before being required. The regex for dynamic values was improved a little in an attemp to make it more reliable. Plugins are only required once now. The CLI's CWD is set to that of the config file. This makes relative paths mentioned in the file more reliable.
This commit is contained in:
parent
9ba3027017
commit
29e241c704
|
|
@ -1,5 +1,6 @@
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv');
|
||||||
const { Command, flags } = require('@oclif/command');
|
const { Command, flags } = require('@oclif/command');
|
||||||
|
|
||||||
|
|
@ -22,6 +23,12 @@ class Base extends Command {
|
||||||
|
|
||||||
const envParams = { params: Object.assign(env, params) };
|
const envParams = { params: Object.assign(env, params) };
|
||||||
|
|
||||||
|
const configFileDir = path.dirname(
|
||||||
|
path.resolve(process.cwd(), configFile)
|
||||||
|
);
|
||||||
|
|
||||||
|
process.chdir(configFileDir);
|
||||||
|
|
||||||
return new Beau(config, envParams);
|
return new Beau(config, envParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ function requireg(name) {
|
||||||
return require(name);
|
return require(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
requireg.std_resolving = false;
|
requireg.resolving = true;
|
||||||
|
|
||||||
requireg.resolve = function(name) {
|
requireg.resolve = function(name) {
|
||||||
if (requireg.std_resolving) {
|
if (requireg.resolving) {
|
||||||
return '';
|
return '';
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Failed to resolve.`);
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const Beau = require('../beau');
|
const Beau = require('../beau');
|
||||||
|
|
||||||
|
const requireg = require('requireg');
|
||||||
|
requireg.resolving = false;
|
||||||
|
|
||||||
describe(`Beau's config Loader.`, () => {
|
describe(`Beau's config Loader.`, () => {
|
||||||
it('should create a request list', () => {
|
it('should create a request list', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const Config = require('../config');
|
const Config = require('../config');
|
||||||
|
|
||||||
|
const requireg = require('requireg');
|
||||||
|
requireg.resolving = false;
|
||||||
|
|
||||||
describe('Config', () => {
|
describe('Config', () => {
|
||||||
it('should load valid config keys', () => {
|
it('should load valid config keys', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
version: 1
|
version: 1
|
||||||
endpoint: http://martianwabbit.com
|
endpoint: http://martianwabbit.com
|
||||||
shouldntBeAdded: true
|
shouldntBeAdded: true
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
expect(config.ENDPOINT).toBe(doc.endpoint);
|
expect(config.ENDPOINT).toBe(doc.endpoint);
|
||||||
expect(config.VERSION).toBe(doc.version);
|
expect(config.VERSION).toBe(doc.version);
|
||||||
expect(config.shouldntBeAdded).toBeUndefined();
|
expect(config.shouldntBeAdded).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load requests', () => {
|
it('should load requests', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
endpoint: http://example.com
|
endpoint: http://example.com
|
||||||
|
|
||||||
GET /profile: get-profile
|
GET /profile: get-profile
|
||||||
|
|
@ -28,12 +31,12 @@ describe('Config', () => {
|
||||||
hello: world
|
hello: world
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
expect(Object.keys(config.REQUESTS).length).toBe(4);
|
expect(Object.keys(config.REQUESTS).length).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set up defaults for all requests', () => {
|
it('should set up defaults for all requests', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
version: 1
|
version: 1
|
||||||
endpoint: 'http://jsonplaceholder.typicode.com'
|
endpoint: 'http://jsonplaceholder.typicode.com'
|
||||||
|
|
||||||
|
|
@ -48,16 +51,16 @@ describe('Config', () => {
|
||||||
hello: world
|
hello: world
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
|
|
||||||
expect(config).toMatchSnapshot();
|
expect(config).toMatchSnapshot();
|
||||||
Object.values(config.REQUESTS).forEach(r => {
|
Object.values(config.REQUESTS).forEach(r => {
|
||||||
expect(r.HEADERS.authentication).toMatch('hello');
|
expect(r.HEADERS.authentication).toMatch('hello');
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should load multiple hosts', () => {
|
it('should load multiple hosts', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
endpoint: http://example.org
|
endpoint: http://example.org
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
|
|
@ -95,13 +98,13 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
|
|
||||||
expect(config).toMatchSnapshot();
|
expect(config).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should namespace all aliases within an host', () => {
|
it('should namespace all aliases within an host', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
hosts:
|
hosts:
|
||||||
- host: test1
|
- host: test1
|
||||||
endpoint: http://example.com
|
endpoint: http://example.com
|
||||||
|
|
@ -111,14 +114,14 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
|
|
||||||
expect(config.REQUESTS[0].ALIAS).toBe('test1:posts');
|
expect(config.REQUESTS[0].ALIAS).toBe('test1:posts');
|
||||||
expect(config.REQUESTS[1].ALIAS).toBe('test2:posts');
|
expect(config.REQUESTS[1].ALIAS).toBe('test2:posts');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should throw if host doesn't have a host key`, () => {
|
it(`should throw if host doesn't have a host key`, () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
hosts:
|
hosts:
|
||||||
- endpoint: http://example.com
|
- endpoint: http://example.com
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
|
|
@ -128,11 +131,11 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(() => new Config(doc)).toThrow();
|
expect(() => new Config(doc)).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should merge host settings with global settings`, () => {
|
it(`should merge host settings with global settings`, () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
defaults:
|
defaults:
|
||||||
headers:
|
headers:
|
||||||
hello: 1
|
hello: 1
|
||||||
|
|
@ -150,7 +153,7 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
expect(config.REQUESTS[0].HEADERS.hello).toBe(1);
|
expect(config.REQUESTS[0].HEADERS.hello).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,15 @@
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const Config = require('../config');
|
|
||||||
const Plugins = require('../plugins');
|
const Plugins = require('../plugins');
|
||||||
const Request = require('../request');
|
const Request = require('../request');
|
||||||
const RequestCache = require('../requestCache');
|
const RequestCache = require('../requestCache');
|
||||||
const requireg = require('requireg');
|
const requireg = require('requireg');
|
||||||
|
|
||||||
describe(`Beau's plugin system`, () => {
|
describe(`Beau's plugin system`, () => {
|
||||||
let config;
|
|
||||||
let request;
|
let request;
|
||||||
let plugins;
|
let plugins;
|
||||||
let doc;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
doc = yaml.safeLoad(`
|
plugins = new Plugins([{ Modifiers: [Object] }, 'DynamicValues'], []);
|
||||||
version: 1
|
|
||||||
endpoint: 'http://example.com'
|
|
||||||
|
|
||||||
plugins:
|
|
||||||
- Modifiers:
|
|
||||||
data: hi
|
|
||||||
- DynamicValues
|
|
||||||
|
|
||||||
GET /posts/$[add(1, 1)]: get-post
|
|
||||||
`);
|
|
||||||
|
|
||||||
config = new Config(doc);
|
|
||||||
plugins = config.PLUGINS;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load all plugins', () => {
|
it('should load all plugins', () => {
|
||||||
|
|
@ -34,19 +18,24 @@ describe(`Beau's plugin system`, () => {
|
||||||
expect(plugins.registry.dynamicValues.length).toBe(1);
|
expect(plugins.registry.dynamicValues.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should load autoload plugins`, () => {
|
|
||||||
requireg.std_resolving = true;
|
|
||||||
config = new Config(doc);
|
|
||||||
expect(config.PLUGINS.registry.dynamicValues.length).toBe(2);
|
|
||||||
requireg.std_resolving = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should throw if given an invalid configuration`, () => {
|
it(`should throw if given an invalid configuration`, () => {
|
||||||
expect(() => new Plugins([{ test1: true, test2: true }])).toThrow();
|
expect(() => new Plugins([{ test1: true, test2: true }])).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`shouldn't do anything when given an empty array.`, () => {
|
it(`shouldn't do anything when given an empty array.`, () => {
|
||||||
expect(new Plugins()).toMatchSnapshot();
|
expect(new Plugins([], [])).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should warn if the plugin is not available.`, () => {
|
||||||
|
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
|
requireg.resolving = false;
|
||||||
|
|
||||||
|
new Plugins(['not-a-Package']);
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
requireg.resolving = true;
|
||||||
|
spy.mockReset();
|
||||||
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`Request Modifiers`, () => {
|
describe(`Request Modifiers`, () => {
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,51 @@ class Plugins {
|
||||||
|
|
||||||
this.context = {};
|
this.context = {};
|
||||||
|
|
||||||
plugins.forEach(plugin => this.loadPlugin(plugin));
|
this.loadPlugins(autoload.concat(plugins));
|
||||||
autoload.forEach(plugin => {
|
|
||||||
try {
|
|
||||||
requireg.resolve(plugin);
|
|
||||||
this.loadPlugin(plugin);
|
|
||||||
} catch (e) {}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPlugin(plugin) {
|
normalizePlugins(plugins) {
|
||||||
let name = plugin;
|
let results = {};
|
||||||
let settings = {};
|
|
||||||
|
|
||||||
if (typeof plugin === 'object') {
|
plugins.forEach(plugin => {
|
||||||
let keys = Object.keys(plugin);
|
let name = plugin;
|
||||||
|
let settings = undefined;
|
||||||
|
|
||||||
if (keys.length !== 1) {
|
if (typeof plugin === 'object') {
|
||||||
throw new Error(`Plugin items should contain only one key.`);
|
let keys = Object.keys(plugin);
|
||||||
|
|
||||||
|
if (keys.length !== 1) {
|
||||||
|
throw new Error(
|
||||||
|
`Plugin items should contain only one key.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
name = keys[0];
|
||||||
|
settings = plugin[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
name = keys[0];
|
results[name] = settings;
|
||||||
settings = plugin[name];
|
});
|
||||||
}
|
|
||||||
|
|
||||||
plugin = requireg(`beau-${toKebabCase(name)}`);
|
return results;
|
||||||
new plugin(this, settings);
|
}
|
||||||
|
|
||||||
|
loadPlugins(plugins) {
|
||||||
|
plugins = this.normalizePlugins(plugins);
|
||||||
|
Object.keys(plugins).forEach(name => {
|
||||||
|
const module = `beau-${toKebabCase(name)}`;
|
||||||
|
|
||||||
|
if (typeof requireg.resolve(module) !== 'undefined') {
|
||||||
|
const plugin = requireg(module);
|
||||||
|
new plugin(this, plugins[name]);
|
||||||
|
} else {
|
||||||
|
if (name === 'std') return;
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
`Plugin ${name} couldn't be found. It is available globally?`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
executeModifier(modifier, obj, orig) {
|
executeModifier(modifier, obj, orig) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const httpVerbs = [
|
||||||
|
|
||||||
const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i');
|
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 dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])*?\))\]/g;
|
||||||
|
|
||||||
const UpperCaseKeys = function(obj) {
|
const UpperCaseKeys = function(obj) {
|
||||||
let result = {};
|
let result = {};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue