UNPKG

@scvo/router-destination-handlebars

Version:
164 lines (146 loc) 5.38 kB
/* tslint:disable:no-any */ const hbs = require('clayhandlebars')(); import {RouterConfiguration, RouterDestination, RouteMatch, Helpers, RouterResponse, RouteDestinationError} from '@scvo/router'; export class HandlebarsRouterDestination extends RouterDestination { name = 'handlebars'; constructor(handlebarsHelpers: HandlebarsHelpers) { super(); Helpers.register(hbs); Object.keys(handlebarsHelpers).forEach((name) => { hbs.registerHelper(name, handlebarsHelpers[name]); }); } async execute(routeMatch: RouteMatch): Promise<RouterResponse> { try { const routerLayouts: RouterLayoutMap = routeMatch.context.metaData.handlebarsLayouts; const routeLayouts: RouteLayoutMap = routeMatch.route.destination.config; const layouts: LayoutPair = this.getLayouts( routerLayouts, routeLayouts, routeMatch.request.fullUrl); const partials = routeMatch.context.metaData.handlebarsPartials; Object.keys(partials).forEach((name: string) => { hbs.registerPartial(name, partials[name]); }); const sections: RouteLayout = {}; Object.keys(layouts.routeLayout).forEach((sectionName: string) => { let template = '', compiled: (data: RouteMatch) => string, output = ''; try { template = layouts.routeLayout[sectionName]; template = template.replace(/{{instance_id}}/ig, '{-{instance_id}-}'); compiled = hbs.compile(template); output = compiled(routeMatch); sections[sectionName] = output; } catch (err) { err = new RouteDestinationError(err, { statusCode: 500, sourceRoute: routeMatch, destination: routeMatch.route.destination, redirectTo: routeMatch.route.errorRoute, data: { sectionName, template: template ? template.length < 256 ? template : template.substr(0, 255) : undefined, output: output ? output.length < 256 ? output : output.substr(0, 255) : undefined } }); throw err; } }); let template = '', compiled: (data: RouteMatch) => string, output = ''; try { template = layouts.routerLayout.template; compiled = hbs.compile(template); output = compiled(routeMatch); output = output.replace( /(<!--{section:)([a-z0-9_-]+)(\[[a-z0-9_-]+\])?(}-->)/ig, (match, m1, m2, m3, m4) => { if (sections.hasOwnProperty(m2)) { var html = sections[m2]; if (m3) { var instance = m3.replace(/\[|\]/g, ''); html = html.replace(/{-{instance_id}-}/ig, instance); } return html; } else { return match; } }); } catch (err) { err = new RouteDestinationError(err, { statusCode: 500, sourceRoute: routeMatch, destination: routeMatch.route.destination, redirectTo: routeMatch.route.errorRoute, data: { template: template ? template.length < 256 ? template : template.substr(0, 255) : undefined, output: output ? output.length < 256 ? output : output.substr(0, 255) : undefined } }); throw err; } const response: RouterResponse = { statusCode: 200, contentType: layouts.routerLayout.contentType, body: output, headers: {}, cookies: routeMatch.request.cookies }; return response; } catch (err) { console.error('#### RouteMatch -> Failed to render:', err); throw err; } } private getLayouts( routerLayouts: RouterLayoutMap, routeLayouts: RouteLayoutMap, url: string): LayoutPair { try { let layoutName = 'default'; // console.log('#### ROUTEMATCH.getLayoutName() -> Getting layout name'); Object.keys(routeLayouts).forEach((name: string) => { if (name === 'default' || layoutName !== 'default') return; if (routerLayouts.hasOwnProperty(name)) { const pattern = routerLayouts[name].pattern; const regex = new RegExp(pattern, 'ig'); if (regex.test(url)) { layoutName = name; } } }); // console.log('#### ROUTEMATCH.getLayoutName() -> Layout name:', // this.layoutName); return { routerLayout: routerLayouts[layoutName], routeLayout: routeLayouts[layoutName] }; } catch (err) { console.error('#### RouteMatch -> Failed to get layout name:', err); throw err; } } } export interface RouterLayoutMap { default: RouterLayout; [name: string]: RouterLayout; } export interface RouterLayout { template: string; sections: string[]; pattern: string; contentType: string; doNotStripDomains: boolean; } export interface RouteLayoutMap { [name: string]: RouteLayout; } export interface RouteLayout { [section: string]: string; } export interface LayoutPair { routerLayout: RouterLayout; routeLayout: RouteLayout; } export interface HandlebarsHelpers { [name: string]: (...args: any[]) => any; } /* tslint:enable:no-any */