message: fix: log detailed React.render errors, encapsulate
diff: -import React from 'react';
  +import {
  + createContext as Context,
  + Script
  +} from 'vm';
  +
  +import chalk from 'chalk';
  +import trace from 'stack-trace';
  import getComponent from './get-component';
  import getRenderFunction from './get-render-function';
  @@ -6,12 +12,8 @@ import getRenderFunction from './get-render-function';
  export default (file, options = {}, application) => {
  const isStatic = options.static !== false && options.automount !== true;
  const renderFunction = getRenderFunction(isStatic, application);
  - const component = getComponent(file);
  -
  - const rendered = renderFunction(React.createElement(component));
  - const buffer = options.automount ?
  - `<div data-mountpoint>${rendered}</div>` :
  - rendered;
  + const component = getComponent(file, application);
  + const prefix = chalk.grey(`[${[file.pattern.id, file.name].join(':')}]`);
  const meta = options.automount ?
  {
  @@ -22,8 +24,96 @@ export default (file, options = {}, application) => {
  } :
  {};
  + // prepare script and context
  + const sandbox = {
  + module,
  + exports,
  + require,
  + patternplate: {
  + component,
  + renderFunction,
  + result: ''
  + },
  + // Provide proxied console, prepend with file
  + console: {
  + log(...args) {
  + application.log.info(...[prefix, ...args]);
  + },
  + debug(...args) {
  + application.log.debug(...[prefix, ...args]);
  + },
  + error(...args) {
  + application.log.error(...[prefix, ...args]);
  + },
  + info(...args) {
  + application.log.info(...[prefix, ...args]);
  + },
  + warn(...args) {
  + application.log.warn(...[prefix, ...args]);
  + },
  + trace(...args) {
  + application.log.trace(...[prefix, ...args]);
  + }
  + }
  + };
  +
  + const stanza = [
  + 'var React = require(\'react\')',
  + '',
  + 'patternplate.result = patternplate.renderFunction(',
  + 'React.createElement(patternplate.component)',
  + ')'
  + ].join('\n');
  +
  + sandbox.global = sandbox;
  + const context = new Context(sandbox);
  + const script = new Script(stanza);
  +
  + try {
  + script.runInContext(context, {
  + filename: file.path,
  + lineOffset: 1,
  + columnOffset: 1,
  + displayErrors: true,
  + timeout: 5000
  + });
  +
  + const result = sandbox.patternplate.result;
  + const buffer = options.automount ?
  + `<div data-mountpoint>${result}</div>` :
  + result;
  +
  return {
  buffer,
  meta
  };
  + } catch (error) {
  + const stack = trace.parse(error);
  +
  + // find first relevant item in trace
  + const top = stack.filter(item => item.fileName === 'evalmachine.<anonymous>' &&
  + (item.functionName || '').indexOf('babelHelpers') === -1
  + )[0];
  +
  + const source = file.buffer.toString();
  + const lines = source.split('\n');
  +
  + const cut = top ? [
  + ...lines.slice(top.lineNumber - 2, top.lineNumber - 1),
  + chalk.bold.red(lines[top.lineNumber - 1]),
  + ...lines.slice(top.lineNumber, top.lineNumber + 2)
  + ] : [];
  +
  + const message = [
  + `Error during rendering of file ${file.path} in pattern ${file.pattern.id}:`,
  + top ? `Tried to print offending lines` : ''
  + ].join('\n');
  +
  + error.message = [
  + message,
  + error.message,
  + cut.join('\n')
  + ].join('\n');
  + throw error;
  + }
  };
  