<commit_before>/**
 * Handles all template-rendering functionality.
 *
 * @module
 */

'use strict';
var uriRoutes,
  log = require('./log'),
  siteService = require('./sites'),
  nunjucks = require('nunjucks-filters')(),
  multiplex = require('multiplex-templates')({nunjucks: nunjucks}),
  db = require('./services/db'),
  references = require('./services/references'),
  bluebird = require('bluebird'),
  fetch = require('node-fetch'),
  _ = require('lodash'),
  chalk = require('chalk'),
  ignoreDataProperty = 'ignore-data',
  components = require('./services/components');

/**
 * Find all _ref, and recursively expand them.
 *
 * @param {object} data
 * @param {function|string} [filter='_ref']
 * @returns {Promise}
 */
function resolveDataReferences(data, filter) {
  var referenceProperty = '_ref',
    referenceObjects = _.listDeepObjects(data, filter || referenceProperty);

  return bluebird.all(referenceObjects).each(function (placeholder) {
    var promise,
      ref = placeholder[referenceProperty],
      handler = _.find(uriRoutes, function (item) { return ref.match(item.when); });

    if (handler && _.isFunction(handler.json)) {
      promise = handler.json(placeholder[referenceProperty]);
    } else {
      promise = fetch(ref).then(function (result) { return result.json(); });
    }

    return promise.then(function (obj) {
        // the thing we got back might have its own references
        return resolveDataReferences(obj, filter).finally(function () {
          _.assign(placeholder, _.omit(obj, referenceProperty));
        });
      });
  }).return(data);
}

/**
 * Add state to result, which adds functionality and information about this request to the templates.
 * @param options
 * @param res
 * @returns {Function}
 */
function applyOptions(options, res) {
  return function (result) {
    var state, site, locals;

    addParams(res);
    site = siteService.sites()[res.locals.site];
    locals = res.locals;

    // remove all the properties mentioned here
    if (options[ignoreDataProperty]) {
      // todo: Maybe allow deep-has omiting i.e., ignore-data=story.some.thing,story.thing
      result = _.omit(result, options[ignoreDataProperty]);
    }

    // apply rule:  options.template > result.template
    if (options.template) {
      result.template = options.template;
    }

    // report the end result of what we've done
    log.info(chalk.dim('serving ' + require('util').inspect(result, true, 5)));

    // options are done at this point; now mix with the data and bind into a self-referencing chain of globals
    state = {
      site: site,
      locals: locals,
      getTemplate: components.getTemplate
    };

    // the circle of life;  this is equivalent to what was here before.
    _.assign(state, result);
    state.state = state;

    return state;
  };
}

/**
 * Render a template based on some generic data provided.
 */
function renderTemplate() {
  return function (data) {
    var template = components.getTemplate(data.template);

    if (!template) {
      throw new Error('Missing template for ' + JSON.stringify(_.omit(data, 'state')));
    }

    return multiplex.render(template, data);
  };
}

/**<commit_msg>Set state._ref from query param.<commit_after>/**
 * Handles all template-rendering functionality.
 *
 * @module
 */

'use strict';
var uriRoutes,
  log = require('./log'),
  siteService = require('./sites'),
  nunjucks = require('nunjucks-filters')(),
  multiplex = require('multiplex-templates')({nunjucks: nunjucks}),
  db = require('./services/db'),
  references = require('./services/references'),
  bluebird = require('bluebird'),
  fetch = require('node-fetch'),
  _ = require('lodash'),
  chalk = require('chalk'),
  ignoreDataProperty = 'ignore-data',
  components = require('./services/components');

/**
 * Find all _ref, and recursively expand them.
 *
 * @param {object} data
 * @param {function|string} [filter='_ref']
 * @returns {Promise}
 */
function resolveDataReferences(data, filter) {
  var referenceProperty = '_ref',
    referenceObjects = _.listDeepObjects(data, filter || referenceProperty);

  return bluebird.all(referenceObjects).each(function (placeholder) {
    var promise,
      ref = placeholder[referenceProperty],
      handler = _.find(uriRoutes, function (item) { return ref.match(item.when); });

    if (handler && _.isFunction(handler.json)) {
      promise = handler.json(placeholder[referenceProperty]);
    } else {
      promise = fetch(ref).then(function (result) { return result.json(); });
    }

    return promise.then(function (obj) {
        // the thing we got back might have its own references
        return resolveDataReferences(obj, filter).finally(function () {
          _.assign(placeholder, _.omit(obj, referenceProperty));
        });
      });
  }).return(data);
}

/**
 * Add state to result, which adds functionality and information about this request to the templates.
 * @param options
 * @param res
 * @returns {Function}
 */
function applyOptions(options, res) {
  return function (result) {
    var state, site, locals;

    addParams(res);
    site = siteService.sites()[res.locals.site];
    locals = res.locals;

    // remove all the properties mentioned here
    if (options[ignoreDataProperty]) {
      // todo: Maybe allow deep-has omiting i.e., ignore-data=story.some.thing,story.thing
      result = _.omit(result, options[ignoreDataProperty]);
    }

    // apply rule:  options.template > result.template
    if (options.template) {
      result.template = options.template;
    }

    // report the end result of what we've done
    log.info(chalk.dim('serving ' + require('util').inspect(result, true, 5)));

    // options are done at this point; now mix with the data and bind into a self-referencing chain of globals
    state = {
      _ref: locals._ref,
      site: site,
      locals: locals,
      getTemplate: components.getTemplate
    };

    // the circle of life;  this is equivalent to what was here before.
    _.assign(state, result);
    state.state = state;

    return state;
  };
}

/**
 * Render a template based on some generic data provided.
 */
function renderTemplate() {
  return function (data) {
    var template = components.getTemplate(data.template);

    if (!template) {
      throw new Error('Missing template for ' + JSON.stringify(_.omit(data, 'state')));
    }

    return multiplex.render(template, data);
  };
}

/**
{'fraction_non_alphanumeric': 0.1379471228615863, 'fraction_numerical': 0.00031104199066874026, 'mean_word_length': 3.3629579375848033, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6562892', 'n_tokens_mistral': 1848, 'n_tokens_neox': 1815, 'n_words': 506}