<commit_before>/**
Implementation of the 'build' verb for HackMyResume.
@module verbs/build
@license MIT. See LICENSE.md for details.
*/



(function() {



  var _              = require('underscore')
    , PATH           = require('path')
    , FS             = require('fs')
    , MD             = require('marked')
    , MKDIRP         = require('mkdirp')
    , extend         = require('extend')
    , parsePath      = require('parse-filepath')
    , RConverter     = require('fresh-jrs-converter')
    , HMSTATUS       = require('../core/status-codes')
    , HMEVENT        = require('../core/event-codes')
    , RTYPES         = { FRESH: require('../core/fresh-resume'),
                         JRS: require('../core/jrs-resume') }
    , _opts          = require('../core/default-options')
    , FRESHTheme     = require('../core/fresh-theme')
    , JRSTheme       = require('../core/jrs-theme')
    , ResumeFactory  = require('../core/resume-factory')
    , _fmts          = require('../core/default-formats')
    , Verb           = require('../verbs/verb');

  var _err, _log, _rezObj;



  /** An invokable resume generation command. */
  var BuildVerb = module.exports = Verb.extend({

    /** Create a new build verb. */
    init: function() {
      this._super('build');
    },

    /** Invoke the Build command. */
    invoke: function() {
      this.stat( HMEVENT.begin, { cmd: 'build' } );
      build.apply( this, arguments );
      this.stat( HMEVENT.end );
    }

  });



  /**
  Given a source resume in FRESH or JRS format, a destination resume path, and a
  theme file, generate 0..N resumes in the desired formats.
  @param src Path to the source JSON resume file: "rez/resume.json".
  @param dst An array of paths to the target resume file(s).
  @param theme Friendly name of the resume theme. Defaults to "modern".
  @param logger Optional logging override.
  */
  function build( src, dst, opts ) {

    if( !src || !src.length ) {
      this.err( HMSTATUS.resumeNotFound, { quit: true } );
    }

    prep( src, dst, opts );

    // Load input resumes as JSON...
    var sheetObjects = ResumeFactory.load(src, {
      format: null, objectify: false, quit: true, inner: { sort: _opts.sort }
    }, this);

    var sheets = sheetObjects.map(function(r) { return r.json; });

    // Load the theme...
    this.stat( HMEVENT.beforeTheme, { theme: _opts.theme });
    var tFolder = verifyTheme.call( this, _opts.theme );
    var theme = loadTheme( tFolder );
    this.stat( HMEVENT.afterTheme, { theme: theme });

    // Check for invalid outputs...
    var inv = verifyOutputs.call( this, dst, theme );
    if( inv && inv.length ) {
      this.err( HMSTATUS.invalidFormat, { data: inv, theme: theme } );
    }

    // Merge input resumes, yielding a single source resume.
    var rez;
    if( sheets.length > 1 ) {
      var isFRESH = !sheets[0].basics;
      var mixed = _.any( sheets, function(s) { return isFRESH ? s.basics : !s.basics; });
      this.stat( HMEVENT.beforeMerge, { f: _.clone(sheetObjects), mixed: mixed });
      if( mixed ) {
        this.err( HMSTATUS.mixedMerge );
      }
      rez = _.reduceRight( sheets, function( a, b, idx ) {
        return extend( true, b, a );
      });
      this.stat( HMEVENT.afterMerge, { r: rez } );
    }
    else {
      rez = sheets[0];
    }

    // Convert the merged source resume to the theme's format, if necessary
    var orgFormat = rez.basics ? 'JRS' : 'FRESH';
    var toFormat = theme.render ? 'JRS' : 'FRESH';
    if( toFormat !== orgFormat ) {
      this.stat( HMEVENT.beforeInlineConvert );
      rez = RConverter[ 'to' + toFormat ]( rez );
      this.stat( HMEVENT.afterInlineConvert, { file: sheetObjects[0].file, fmt: toFormat });
    }

    // Add freebie formats to the theme
    addFreebieFormats( theme  );
    this.stat( HMEVENT.applyTheme, { r: rez });


    // Load the resume into a FRESHResume or JRSResume object
    _rezObj = new (RTYPES[ toFormat ])().parseJSON( rez );

    // Expand output resumes...
    var targets = expand( dst, theme );

    // Run the transformation!
    _.each(targets, function(t) {
      t.final = single.call( this, t, theme, targets );
    }, this);

    // Don't send the client back empty-handed
    return { sheet: rez, targets: targets, processed: targets };
  }



  /**
  Prepare for a BUILD run.
  */
  function prep( src, dst, opts ) {

    // Cherry-pick options //_opts = extend( true, _opts, opts );
    _opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern';
    _opts.prettify = opts.prettify === true;
    _opts.css = opts.css || 'embed';
    _opts.pdf = opts.pdf;
    _opts.wrap = opts.wrap || 60;
    _opts.stitles = opts.sectionTitles;
    _opts.tips = opts.tips;
    _opts.noTips = opts.noTips;<commit_msg>Build verb invocation should return JSON result.<commit_after>/**
Implementation of the 'build' verb for HackMyResume.
@module verbs/build
@license MIT. See LICENSE.md for details.
*/



(function() {



  var _              = require('underscore')
    , PATH           = require('path')
    , FS             = require('fs')
    , MD             = require('marked')
    , MKDIRP         = require('mkdirp')
    , extend         = require('extend')
    , parsePath      = require('parse-filepath')
    , RConverter     = require('fresh-jrs-converter')
    , HMSTATUS       = require('../core/status-codes')
    , HMEVENT        = require('../core/event-codes')
    , RTYPES         = { FRESH: require('../core/fresh-resume'),
                         JRS: require('../core/jrs-resume') }
    , _opts          = require('../core/default-options')
    , FRESHTheme     = require('../core/fresh-theme')
    , JRSTheme       = require('../core/jrs-theme')
    , ResumeFactory  = require('../core/resume-factory')
    , _fmts          = require('../core/default-formats')
    , Verb           = require('../verbs/verb');

  var _err, _log, _rezObj;



  /** An invokable resume generation command. */
  var BuildVerb = module.exports = Verb.extend({

    /** Create a new build verb. */
    init: function() {
      this._super('build');
    },

    /** Invoke the Build command. */
    invoke: function() {
      this.stat( HMEVENT.begin, { cmd: 'build' } );
      var ret = build.apply( this, arguments );
      this.stat( HMEVENT.end );
      return ret;
    }

  });



  /**
  Given a source resume in FRESH or JRS format, a destination resume path, and a
  theme file, generate 0..N resumes in the desired formats.
  @param src Path to the source JSON resume file: "rez/resume.json".
  @param dst An array of paths to the target resume file(s).
  @param theme Friendly name of the resume theme. Defaults to "modern".
  @param logger Optional logging override.
  */
  function build( src, dst, opts ) {

    if( !src || !src.length ) {
      this.err( HMSTATUS.resumeNotFound, { quit: true } );
    }

    prep( src, dst, opts );

    // Load input resumes as JSON...
    var sheetObjects = ResumeFactory.load(src, {
      format: null, objectify: false, quit: true, inner: { sort: _opts.sort }
    }, this);

    var sheets = sheetObjects.map(function(r) { return r.json; });

    // Load the theme...
    this.stat( HMEVENT.beforeTheme, { theme: _opts.theme });
    var tFolder = verifyTheme.call( this, _opts.theme );
    var theme = loadTheme( tFolder );
    this.stat( HMEVENT.afterTheme, { theme: theme });

    // Check for invalid outputs...
    var inv = verifyOutputs.call( this, dst, theme );
    if( inv && inv.length ) {
      this.err( HMSTATUS.invalidFormat, { data: inv, theme: theme } );
    }

    // Merge input resumes, yielding a single source resume.
    var rez;
    if( sheets.length > 1 ) {
      var isFRESH = !sheets[0].basics;
      var mixed = _.any( sheets, function(s) { return isFRESH ? s.basics : !s.basics; });
      this.stat( HMEVENT.beforeMerge, { f: _.clone(sheetObjects), mixed: mixed });
      if( mixed ) {
        this.err( HMSTATUS.mixedMerge );
      }
      rez = _.reduceRight( sheets, function( a, b, idx ) {
        return extend( true, b, a );
      });
      this.stat( HMEVENT.afterMerge, { r: rez } );
    }
    else {
      rez = sheets[0];
    }

    // Convert the merged source resume to the theme's format, if necessary
    var orgFormat = rez.basics ? 'JRS' : 'FRESH';
    var toFormat = theme.render ? 'JRS' : 'FRESH';
    if( toFormat !== orgFormat ) {
      this.stat( HMEVENT.beforeInlineConvert );
      rez = RConverter[ 'to' + toFormat ]( rez );
      this.stat( HMEVENT.afterInlineConvert, { file: sheetObjects[0].file, fmt: toFormat });
    }

    // Add freebie formats to the theme
    addFreebieFormats( theme  );
    this.stat( HMEVENT.applyTheme, { r: rez });

    // Load the resume into a FRESHResume or JRSResume object
    _rezObj = new (RTYPES[ toFormat ])().parseJSON( rez );

    // Expand output resumes...
    var targets = expand( dst, theme );

    // Run the transformation!
    _.each(targets, function(t) {
      t.final = single.call( this, t, theme, targets );
    }, this);

    // Don't send the client back empty-handed
    return { sheet: _rezObj, targets: targets, processed: targets };
  }



  /**
  Prepare for a BUILD run.
  */
  function prep( src, dst, opts ) {

    // Cherry-pick options //_opts = extend( true, _opts, opts );
    _opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern';
    _opts.prettify = opts.prettify === true;
    _opts.css = opts.css || 'embed';
    _opts.pdf = opts.pdf;
    _opts.wrap = opts.wrap || 60;
    _opts.stitles = opts.sectionTitles;
    _opts.tips = opts.tips;
    _opts.noTips = opts.noTips;
{'fraction_non_alphanumeric': 0.14675945159950146, 'fraction_numerical': 0.0014540922309929372, 'mean_word_length': 2.329529737206086, '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': '6156877', 'n_tokens_mistral': 3186, 'n_tokens_neox': 3032, 'n_words': 845}