<commit_before>async = require 'async'
{exec, spawn} = require 'child_process'
fs = require 'fs'
mkdirp = require 'mkdirp'
{ncp} = require 'ncp'
sysPath = require 'path'
helpers = require './helpers'
logger = require './logger'
fs_utils = require './fs_utils'

isCompilerFor = (path) -> (plugin) ->
  pattern = if plugin.pattern
    plugin.pattern
  else if plugin.extension
    ///\.#{plugin.extension}$///
  else
    null
  (typeof plugin.compile is 'function') and !!(pattern?.test path)

# Recompiles all files in current working directory.
# 
# rootPath - path to application directory.
# config - Parsed app config.
# persistent - Should watcher be stopped after compiling the app first time?
# callback - Callback that would be executed on each compilation.
# 
# Returns `fs_utils.FSWatcher` object.
watchApplication = (persistent, rootPath, config, callback) ->
  config.buildPath ?= sysPath.join rootPath, 'public'
  config.server ?= {}
  config.server.port ?= 3333
  # Pass rootPath to config in order to allow plugins to use it.
  config.rootPath = rootPath
  assetDirectories = [(sysPath.join rootPath, 'app', 'assets')]

  if persistent and config.server.run
    helpers.startServer config.server.port, config.buildPath, config
  directories = ['app', 'vendor'].map (dir) -> sysPath.join rootPath, dir

  fileList = new fs_utils.SourceFileList
  
  helpers.loadPlugins config, (error, plugins) ->
    return logger.error error if error?
    start = null
    addToFileList = (isPluginHelper) -> (path) ->
      start = Date.now()
      logger.log 'debug', "File '#{path}' was changed"
      compiler = plugins.filter(isCompilerFor path)[0]
      return unless compiler
      fileList.add {path, compiler, isPluginHelper}

    plugins.forEach (plugin) ->
      return unless plugin.include?
      includePathes = if typeof plugin.include is 'function'
        plugin.include()
      else
        plugin.include
      includePathes.forEach addToFileList yes

    writer = new fs_utils.FileWriter config, plugins
    watcher = (new fs_utils.FileWatcher)
      .add(directories)
      .on('change', addToFileList no)
      .on('remove', (path) -> fileList.remove path)
    assetWatcher = (new fs_utils.FileWatcher)
      .add(assetDirectories)
      .on('change', fileList.resetTimer)
      .on('remove', fileList.resetTimer)
    fileList.on 'resetTimer', -> writer.write fileList
    writer.on 'write', (result) ->
      assetPath = sysPath.join rootPath, 'app', 'assets'
      ncp assetPath, config.buildPath, (error) ->
        logger.error "Asset compilation failed: #{error}" if error?
        logger.info "compiled."
        logger.log 'debug', "compilation time: #{Date.now() - start}ms"
        unless persistent
          watcher.close()
          assetWatcher.close()
        callback null, result
    watcher

generateFile = (path, data, callback) ->
  parentDir = sysPath.dirname path
  write = ->
    logger.info "create #{path}"
    fs.writeFile path, data, callback
  sysPath.exists parentDir, (exists) -><commit_msg>Don't read files starting with `_`. Closes #215.<commit_after>async = require 'async'
{exec, spawn} = require 'child_process'
fs = require 'fs'
mkdirp = require 'mkdirp'
{ncp} = require 'ncp'
sysPath = require 'path'
helpers = require './helpers'
logger = require './logger'
fs_utils = require './fs_utils'

isCompilerFor = (path) -> (plugin) ->
  pattern = if plugin.pattern
    plugin.pattern
  else if plugin.extension
    ///\.#{plugin.extension}$///
  else
    null
  (typeof plugin.compile is 'function') and !!(pattern?.test path)

# Recompiles all files in current working directory.
# 
# rootPath - path to application directory.
# config - Parsed app config.
# persistent - Should watcher be stopped after compiling the app first time?
# callback - Callback that would be executed on each compilation.
# 
# Returns `fs_utils.FSWatcher` object.
watchApplication = (persistent, rootPath, config, callback) ->
  config.buildPath ?= sysPath.join rootPath, 'public'
  config.server ?= {}
  config.server.port ?= 3333
  # Pass rootPath to config in order to allow plugins to use it.
  config.rootPath = rootPath
  assetDirectories = [(sysPath.join rootPath, 'app', 'assets')]

  if persistent and config.server.run
    helpers.startServer config.server.port, config.buildPath, config
  directories = ['app', 'vendor'].map (dir) -> sysPath.join rootPath, dir

  fileList = new fs_utils.SourceFileList

  helpers.loadPlugins config, (error, plugins) ->
    return logger.error error if error?
    ignored = /^_/
    start = null
    addToFileList = (isPluginHelper) -> (path) ->
      start = Date.now()
      logger.log 'debug', "File '#{path}' was changed"
      return fileList.resetTimer() if ignored.test sysPath.basename path
      compiler = plugins.filter(isCompilerFor path)[0]
      return unless compiler
      fileList.add {path, compiler, isPluginHelper}

    removeFromFileList = (path) ->
      return fileList.resetTimer() if ignored.test sysPath.basename path
      fileList.remove path

    plugins.forEach (plugin) ->
      return unless plugin.include?
      includePathes = if typeof plugin.include is 'function'
        plugin.include()
      else
        plugin.include
      includePathes.forEach addToFileList yes

    writer = new fs_utils.FileWriter config, plugins
    watcher = (new fs_utils.FileWatcher)
      .add(directories)
      .on('change', addToFileList no)
      .on('remove', removeFromFileList)
    fileList.on 'resetTimer', -> writer.write fileList
    writer.on 'write', (result) ->
      assetPath = sysPath.join rootPath, 'app', 'assets'
      ncp assetPath, config.buildPath, (error) ->
        logger.error "Asset compilation failed: #{error}" if error?
        logger.info "compiled."
        logger.log 'debug', "compilation time: #{Date.now() - start}ms"
        watcher.close() unless persistent
        callback null, result
    watcher

generateFile = (path, data, callback) ->
  parentDir = sysPath.dirname path
  write = ->
    logger.info "create #{path}"
    fs.writeFile path, data, callback
  sysPath.exists parentDir, (exists) ->
{'fraction_non_alphanumeric': 0.11792529766759093, 'fraction_numerical': 0.0021203718806067527, 'mean_word_length': 3.2701949860724233, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 33, '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': '6672860', 'n_tokens_mistral': 1820, 'n_tokens_neox': 1797, 'n_words': 544}