<commit_before>jade = require "jade"
fs = require "fs"
path = require "path"
_ = require "underscore"
mkdirp = require "mkdirp"
compressor = require './utils/compressor'

###*
 * compile jade templates into JS functions for use on the client-side, and
   save it to a specified file
###
module.exports = ->
  global.options.debug.log 'precompiling templates', 'yellow'
  return false if not global.options.templates?
  template_dir = path.join process.cwd(), global.options.templates

  precompiler = new Precompiler(
    templates: _.map(
      fs.readdirSync(template_dir),
      (f) -> path.join template_dir, f
    )
  )

  buf = precompiler.compile()
  buf = compressor buf, 'js'

  # TODO: make output folder dynamic
  output_path = path.normalize('public/js/templates.js')
  mkdirp.sync path.dirname(output_path)
  fs.writeFileSync output_path, buf


class Precompiler
  ###*
   * deals with setting up the variables for options
   * @param {Object} options = {} an object holding all the options to be
     passed to the compiler. 'templates' must be specified.
   * @constructor
  ###
  constructor: (options = {}) ->
    defaults =
      include_helpers: true
      inline: false
      debug: false
      namespace: 'templates'
      templates: undefined # an array of template filenames

    _.extend @, defaults, options

  ###*
   * loop through all the templates specified, compile them, and add a wrapper
   * @return {String} the source of a JS object which holds all the templates
   * @public
  ###
  compile: ->
    buf = ["""
    (function(){
      window.#{@namespace} = window.#{@namespace} || {};
      #{@helpers() if @include_helpers isnt false and @inline isnt true}
    """]

    for template in @templates
      buf.push @compileTemplate(template).toString()

    buf.push '})();'
    return buf.join ''

  ###*
   * compile individual templates
   * @param {String} template the full filename & path of the template to be compiled
   * @return {String} source of the template function
   * @private
  ###
  compileTemplate: (template) ->
    templateNamespace = path.basename(template, '.jade').replace(/\//g, '.') # Replaces '/' with '.'
    data = fs.readFileSync(template, 'utf8')
    data = jade.compile(data, { compileDebug: @debug || false, inline: @inline || false, client: true })
    return "#{@namespace}.#{templateNamespace} = #{data};\n"

  ###*
   * Gets Jade's helpers and combines them into string
   * @return {String} source of Jade's helpers
   * @private
  ###
  helpers: ->
    buf = [
      jade.runtime.attrs.toString().replace(/exports\./g,''),
      jade.runtime.escape.toString()
    ]

    if @debug
      buf.push jade.runtime.rethrow.toString()

    buf.push """
    var jade = {
      attrs: attrs,
      escape: escape #{
        if @debug then ',\n  rethrow: rethrow' else ''
      }
    };
    """

    return buf.join('\n')<commit_msg>a couple small style edits, merging in some great work by @slang800, closes #138<commit_after>jade = require "jade"
fs = require "fs"
path = require "path"
_ = require "underscore"
mkdirp = require "mkdirp"
compressor = require './utils/compressor'

# compile jade templates into JS functions for use on the client-side, and
# save it to a specified file

module.exports = ->
  global.options.debug.log 'precompiling templates', 'yellow'
  return false if not global.options.templates?
  template_dir = path.join process.cwd(), global.options.templates

  precompiler = new Precompiler(
    templates: _.map(
      fs.readdirSync(template_dir),
      (f) -> path.join template_dir, f
    )
  )

  buf = precompiler.compile()
  buf = compressor buf, 'js'

  # TODO: make output path configurable
  output_path = path.normalize('public/js/templates.js')
  mkdirp.sync path.dirname(output_path)
  fs.writeFileSync output_path, buf


class Precompiler
  
  # deals with setting up the variables for options
  # @param {Object} options = {} an object holding all the options to be
  # passed to the compiler. 'templates' must be specified.
  # @constructor
  
  constructor: (options = {}) ->
    defaults =
      include_helpers: true
      inline: false
      debug: false
      namespace: 'templates'
      templates: undefined # an array of template filenames

    _.extend @, defaults, options

  
  # loop through all the templates specified, compile them, and add a wrapper
  # @return {String} the source of a JS object which holds all the templates
  # @public
  
  compile: ->
    buf = ["""
    (function(){
      window.#{@namespace} = window.#{@namespace} || {};
      #{@helpers() if @include_helpers isnt false and @inline isnt true}
    """]

    for template in @templates
      buf.push @compileTemplate(template).toString()

    buf.push '})();'
    return buf.join ''

  
  # compile individual templates
  # @param {String} template the full filename & path of the template to be compiled
  # @return {String} source of the template function
  # @private
  
  compileTemplate: (template) ->
    templateNamespace = path.basename(template, '.jade').replace(/\//g, '.') # Replaces '/' with '.'
    data = fs.readFileSync(template, 'utf8')
    data = jade.compile(data, { compileDebug: @debug || false, inline: @inline || false, client: true })
    return "#{@namespace}.#{templateNamespace} = #{data};\n"

  
  # Gets Jade's helpers and combines them into string
  # @return {String} source of Jade's helpers
  # @private
  
  helpers: ->
    buf = [
      jade.runtime.attrs.toString().replace(/exports\./g,''),
      jade.runtime.escape.toString()
    ]

    buf.push jade.runtime.rethrow.toString() if @debug

    buf.push """
    var jade = {
      attrs: attrs,
      escape: escape #{
        if @debug then ',\n  rethrow: rethrow' else ''
      }
    };
    """

    return buf.join('\n')
{'fraction_non_alphanumeric': 0.12866000688942472, 'fraction_numerical': 0.0013778849466069584, 'mean_word_length': 3.052337752965806, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '5593384', 'n_tokens_mistral': 1761, 'n_tokens_neox': 1728, 'n_words': 538}