diff --git a/src/registry/domain/nested-renderer.ts b/src/registry/domain/nested-renderer.ts index 8622782ea..2b462cca6 100644 --- a/src/registry/domain/nested-renderer.ts +++ b/src/registry/domain/nested-renderer.ts @@ -1,145 +1,87 @@ -import async from 'async'; -import _ from 'lodash'; - import settings from '../../resources/settings'; import strings from '../../resources'; import { Config } from '../../types'; +import { + GetComponentResult, + RendererOptions +} from '../routes/helpers/get-component'; -type Cb = (err: string | null, data: string) => void; -type Options = { +interface Options { + ip?: string; version?: string; name?: string; headers?: Record; parameters?: Record; -}; -type Params = { - components: Options[]; - options: Options; - callback: Cb; -}; - -const sanitise = { - componentParams(component: string, options: Options | Cb, callback?: Cb) { - return { - ...sanitise.options(options, callback), - componentName: component - }; - }, - componentsParams( - components: Options[], - options: Options | Cb, - callback: Cb - ): Params { - return { - ...sanitise.options(options, callback), - components: components - }; - }, - headers(h = {}) { - return { - ...h, - accept: settings.registry.acceptRenderedHeader - }; - }, - options( - options: Options | Cb, - callback?: Cb - ): { options: Options; callback: Cb } { - const cb = !callback && typeof options === 'function' ? options : callback; - const opts = typeof options === 'function' ? {} : options; - - return { callback: cb!, options: opts }; - } -}; - -const validate = { - callback(c: Cb) { - if (!c || typeof c !== 'function') { - throw new Error( - strings.errors.registry.NESTED_RENDERER_CALLBACK_IS_NOT_VALID - ); - } - }, - componentParams(params: { componentName: string; callback: Cb }) { - if (!params.componentName) { - throw new Error( - strings.errors.registry.NESTED_RENDERER_COMPONENT_NAME_IS_NOT_VALID - ); - } - - validate.callback(params.callback); - }, - componentsParams(params: Params) { - if (_.isEmpty(params.components)) { - throw new Error( - strings.errors.registry.NESTED_RENDERER_COMPONENTS_IS_NOT_VALID - ); - } +} - validate.callback(params.callback); - } -}; +export default function nestedRenderer( + rendererWithCallback: ( + options: RendererOptions, + cb: (result: GetComponentResult) => void + ) => void, + conf: Config +) { + const renderer = (options: RendererOptions) => + new Promise((res, rej) => { + rendererWithCallback(options, result => { + if (result.response.error) { + rej(result.response.error); + } else { + res(result.response.html!); + } + }); + }); -export default function nestedRenderer(renderer: any, conf: Config) { return { renderComponent( componentName: string, - renderOptions: Options | Cb, - callback?: Cb - ) { - const p = sanitise.componentParams( - componentName, - renderOptions, - callback - ); - validate.componentParams(p); + options: Options = {} + ): Promise { + if (!componentName) { + throw new Error( + strings.errors.registry.NESTED_RENDERER_COMPONENT_NAME_IS_NOT_VALID + ); + } - return renderer( - { - conf: conf, - headers: sanitise.headers(p.options.headers), - name: componentName, - parameters: p.options.parameters || {}, - version: p.options.version || '' + return renderer({ + conf: conf, + ip: options.ip || '', + headers: { + ...options.headers, + accept: settings.registry.acceptRenderedHeader }, - (result: any) => { - if (result.response.error) { - return p.callback(result.response.error, undefined as any); - } else { - return p.callback(null, result.response.html); - } - } - ); + name: componentName, + parameters: options.parameters || {}, + version: options.version || '' + }); }, renderComponents( components: Options[], - renderOptions: Options, - callback: Cb - ) { - const p = sanitise.componentsParams(components, renderOptions, callback); - validate.componentsParams(p); + options: Options = {} + ): Promise> { + if (!components || !components.length) { + throw new Error( + strings.errors.registry.NESTED_RENDERER_COMPONENTS_IS_NOT_VALID + ); + } - async.map( - p.components, - (component, cb) => { - renderer( - { - conf: conf, - headers: sanitise.headers(p.options.headers), - name: component.name, - parameters: { - ...p.options.parameters, - ...component.parameters - }, - version: component.version || '' + return Promise.all( + components.map(component => { + return renderer({ + conf: conf, + headers: { + ...options.headers, + accept: settings.registry.acceptRenderedHeader }, - (result: any) => { - const error = result.response.error; - cb(null, error ? new Error(error) : result.response.html); - } - ); - }, - p.callback as any + ip: component.ip || '', + name: component.name!, + parameters: { + ...options.parameters, + ...component.parameters + }, + version: component.version || '' + }).catch(err => new Error(err)); + }) ); } }; diff --git a/src/registry/routes/helpers/get-component.ts b/src/registry/routes/helpers/get-component.ts index 668ce623c..386343711 100644 --- a/src/registry/routes/helpers/get-component.ts +++ b/src/registry/routes/helpers/get-component.ts @@ -22,7 +22,7 @@ import { Config, Repository } from '../../../types'; import { IncomingHttpHeaders } from 'http'; import { fromPromise } from 'universalify'; -interface Options { +export interface RendererOptions { conf: Config; headers: IncomingHttpHeaders; ip: string; @@ -32,7 +32,7 @@ interface Options { omitHref?: boolean; } -export type GetComponentResult = { +export interface GetComponentResult { status: number; headers?: Record; response: { @@ -40,6 +40,7 @@ export type GetComponentResult = { code?: string; error?: unknown; version?: string; + html?: string; requestVersion?: string; name?: string; details?: { @@ -50,7 +51,7 @@ export type GetComponentResult = { missingPlugins?: string[]; missingDependencies?: string[]; }; -}; +} export default function getComponent(conf: Config, repository: Repository) { const client = Client({ templates: conf.templates }); @@ -60,7 +61,7 @@ export default function getComponent(conf: Config, repository: Repository) { }); const renderer = function ( - options: Options, + options: RendererOptions, cb: (result: GetComponentResult) => void ) { const nestedRenderer = NestedRenderer(renderer, options.conf); @@ -420,8 +421,8 @@ export default function getComponent(conf: Config, repository: Repository) { env: conf.env, params, plugins: conf.plugins, - renderComponent: nestedRenderer.renderComponent, - renderComponents: nestedRenderer.renderComponents, + renderComponent: fromPromise(nestedRenderer.renderComponent), + renderComponents: fromPromise(nestedRenderer.renderComponents), requestHeaders: options.headers, requestIp: options.ip, setEmptyResponse, diff --git a/test/unit/registry-domain-nested-renderer.js b/test/unit/registry-domain-nested-renderer.js index 333e5ac38..a6d37dba4 100644 --- a/test/unit/registry-domain-nested-renderer.js +++ b/test/unit/registry-domain-nested-renderer.js @@ -53,32 +53,6 @@ describe('registry : routes : helpers : nested-renderer', () => { }); }); - describe('when callback empty', () => { - beforeEach(() => { - initialise(); - }); - - it('should throw an error', () => { - const f = function () { - nestedRenderer.renderComponent('my-component'); - }; - expect(f).to.throw('callback is not valid'); - }); - }); - - describe('when callback not valid', () => { - beforeEach(() => { - initialise(); - }); - - it('should throw an error', () => { - const f = function () { - nestedRenderer.renderComponent('my-component', {}, 'blarg'); - }; - expect(f).to.throw('callback is not valid'); - }); - }); - describe('when requesting a not existent component', () => { let error; beforeEach(done => { @@ -89,10 +63,10 @@ describe('registry : routes : helpers : nested-renderer', () => { } }); - nestedRenderer.renderComponent('404-component', {}, err => { - error = err; - done(); - }); + nestedRenderer + .renderComponent('404-component', {}) + .catch(err => (error = err)) + .finally(done); }); it('should return an error in the callback', () => { @@ -116,22 +90,18 @@ describe('registry : routes : helpers : nested-renderer', () => { { bla: 'blabla' } ); - nestedRenderer.renderComponent( - 'my-component', - { + nestedRenderer + .renderComponent('my-component', { headers: { 'accept-language': 'en-GB', accept: 'blargh' }, parameters: { a: 1234 }, version: '1.2.X' - }, - (err, res) => { - result = res; - error = err; - done(); - } - ); + }) + .then(res => (result = res)) + .catch(err => (error = err)) + .finally(done); }); it('should get the html result', () => { @@ -141,6 +111,7 @@ describe('registry : routes : helpers : nested-renderer', () => { it('should make correct request to renderer', () => { expect(renderer.args[0][0]).to.eql({ name: 'my-component', + ip: '', conf: { bla: 'blabla' }, headers: { 'accept-language': 'en-GB', @@ -152,7 +123,7 @@ describe('registry : routes : helpers : nested-renderer', () => { }); it('should get no error', () => { - expect(error).to.be.null; + expect(error).to.be.undefined; }); }); @@ -170,11 +141,11 @@ describe('registry : routes : helpers : nested-renderer', () => { { bla: 'blabla' } ); - nestedRenderer.renderComponent('my-component', (err, res) => { - result = res; - error = err; - done(); - }); + nestedRenderer + .renderComponent('my-component') + .then(res => (result = res)) + .catch(err => (error = err)) + .finally(done); }); it('should get the html result', () => { @@ -184,6 +155,7 @@ describe('registry : routes : helpers : nested-renderer', () => { it('should make correct request to renderer', () => { expect(renderer.args[0][0]).to.eql({ name: 'my-component', + ip: '', conf: { bla: 'blabla' }, headers: { accept: 'application/vnd.oc.rendered+json' @@ -194,7 +166,7 @@ describe('registry : routes : helpers : nested-renderer', () => { }); it('should get no error', () => { - expect(error).to.be.null; + expect(error).to.be.undefined; }); }); }); @@ -228,32 +200,6 @@ describe('registry : routes : helpers : nested-renderer', () => { }); }); - describe('when callback empty', () => { - beforeEach(() => { - initialise(); - }); - - it('should throw an error', () => { - const f = function () { - nestedRenderer.renderComponents([{ name: 'my-component' }]); - }; - expect(f).to.throw('callback is not valid'); - }); - }); - - describe('when callback not valid', () => { - beforeEach(() => { - initialise(); - }); - - it('should throw an error', () => { - const f = function () { - nestedRenderer.renderComponents(['my-component'], {}, 'blarg'); - }; - expect(f).to.throw('callback is not valid'); - }); - }); - describe('when requesting not existent components', () => { let result; let error; @@ -265,22 +211,25 @@ describe('registry : routes : helpers : nested-renderer', () => { } }); - nestedRenderer.renderComponents( - [ - { name: '404-component' }, - { name: 'another-not-existent-component' } - ], - {}, - (err, res) => { + nestedRenderer + .renderComponents( + [ + { name: '404-component' }, + { name: 'another-not-existent-component' } + ], + {} + ) + .then(res => { result = res; + }) + .catch(err => { error = err; - done(); - } - ); + }) + .finally(done); }); it('should return no error in the callback', () => { - expect(error).to.be.null; + expect(error).to.be.undefined; }); it('should return error in result callback', () => { @@ -309,35 +258,34 @@ describe('registry : routes : helpers : nested-renderer', () => { { bla: 'blabla' } ); - nestedRenderer.renderComponents( - [ + nestedRenderer + .renderComponents( + [ + { + name: 'my-component', + parameters: { x: 123 }, + version: '1.2.X' + }, + { + name: 'my-other-component', + parameters: { y: 456 }, + version: '^1.4.6' + } + ], { - name: 'my-component', - parameters: { x: 123 }, - version: '1.2.X' - }, - { - name: 'my-other-component', - parameters: { y: 456 }, - version: '^1.4.6' + headers: { + 'accept-language': 'en-GB', + accept: 'blargh' + }, + parameters: { + x: 456, + z: 789 + } } - ], - { - headers: { - 'accept-language': 'en-GB', - accept: 'blargh' - }, - parameters: { - x: 456, - z: 789 - } - }, - (err, res) => { - result = res; - error = err; - done(); - } - ); + ) + .then(res => (result = res)) + .catch(err => (error = err)) + .finally(done); }); it('should get the html result', () => { @@ -349,6 +297,7 @@ describe('registry : routes : helpers : nested-renderer', () => { expect(renderer.args[0][0]).to.eql({ name: 'my-component', + ip: '', conf: { bla: 'blabla' }, headers: { 'accept-language': 'en-GB', @@ -363,6 +312,7 @@ describe('registry : routes : helpers : nested-renderer', () => { expect(renderer.args[1][0]).to.eql({ name: 'my-other-component', + ip: '', conf: { bla: 'blabla' }, headers: { 'accept-language': 'en-GB', @@ -378,7 +328,7 @@ describe('registry : routes : helpers : nested-renderer', () => { }); it('should get no error', () => { - expect(error).to.be.null; + expect(error).to.be.undefined; }); }); @@ -400,14 +350,14 @@ describe('registry : routes : helpers : nested-renderer', () => { { bla: 'blabla' } ); - nestedRenderer.renderComponents( - [{ name: 'my-component' }, { name: 'my-other-component' }], - (err, res) => { - result = res; - error = err; - done(); - } - ); + nestedRenderer + .renderComponents([ + { name: 'my-component' }, + { name: 'my-other-component' } + ]) + .then(res => (result = res)) + .catch(err => (error = err)) + .finally(done); }); it('should get the html result', () => { @@ -419,6 +369,7 @@ describe('registry : routes : helpers : nested-renderer', () => { expect(renderer.args[0][0]).to.eql({ name: 'my-component', + ip: '', conf: { bla: 'blabla' }, headers: { accept: 'application/vnd.oc.rendered+json' }, parameters: {}, @@ -427,6 +378,7 @@ describe('registry : routes : helpers : nested-renderer', () => { expect(renderer.args[1][0]).to.eql({ name: 'my-other-component', + ip: '', conf: { bla: 'blabla' }, headers: { accept: 'application/vnd.oc.rendered+json' }, parameters: {}, @@ -435,7 +387,7 @@ describe('registry : routes : helpers : nested-renderer', () => { }); it('should get no error', () => { - expect(error).to.be.null; + expect(error).to.be.undefined; }); }); });