<commit_before>'use strict'

debug = require('debug')('brunch:file-list')
{EventEmitter} = require 'events'
Asset = require './asset'
SourceFile = require './source_file'
helpers = require '../helpers'
sysPath = require 'path'

startsWith = (string, substring) ->
  string.lastIndexOf(substring, 0) is 0

# A list of `fs_utils.SourceFile` or `fs_utils.Asset`
# with some additional methods used to simplify file reading / removing.
module.exports = class FileList extends EventEmitter
  # Maximum time between changes of two files that will be considered
  # as a one compilation.
  RESET_TIME: 65

  constructor: (@config) ->
    @files = []
    @assets = []
    @on 'change', @_change
    @on 'unlink', @_unlink
    @compiling = []
    @copying = []

  getAssetErrors: ->
    invalidAssets = @assets.filter((asset) -> asset.error?)
    if invalidAssets.length > 0
      invalidAssets.map (invalidAsset) ->
        helpers.formatError invalidAsset.error, invalidAsset.path
    else
      null

  # Files that are not really app files.
  isIgnored: (path, test = @config.conventions.ignored) ->
    return yes if path in [@config.paths.config, @config.paths.packageConfig]

    switch toString.call(test)
      when '[object RegExp]'
        path.match test
      when '[object Function]'
        test path
      when '[object String]'
        startsWith sysPath.normalize(path), sysPath.normalize(test)
      when '[object Array]'
        test.some((subTest) => @isIgnored path, subTest)
      else
        no

  is: (name, path) ->
    convention = @config._normalized.conventions[name]
    return no unless convention
    if typeof convention isnt 'function'
      throw new TypeError "Invalid convention #{convention}"
    convention path

  # Called every time any file was changed.
  # Emits `ready` event after `RESET_TIME`.
  resetTimer: =>
    clearTimeout @timer if @timer?
    @timer = setTimeout =>
      # Clean disposed files.
      @files
        .filter (file) =>
          file.disposed
        .forEach (file, index) =>
          @files.splice index, 1

      if @compiling.length is 0 and @copying.length is 0
        @emit 'ready'
      else
        @resetTimer()
    , @RESET_TIME

  find: (path) ->
    @files.filter((file) -> file.path is path)[0]

  findAsset: (path) ->
    @assets.filter((file) -> file.path is path)[0]

  compileDependentFiles: (path) ->
    @files
      .filter (dependent) =>
        dependent.dependencies.length > 0
      .filter (dependent) =>
        path in dependent.dependencies
      .forEach(@compile)

  compile: (file) =>
    @compiling.push(file)
    file.compile (error) =>
      @compiling.splice @compiling.indexOf(file), 1
      @resetTimer()
      return if error?
      debug "Compiled file '#{file.path}'"
      @compileDependentFiles file.path

  copy: (asset) =>
    @copying.push asset
    asset.copy (error) =>
      @copying.splice @copying.indexOf(asset), 1
      @resetTimer()
      return if error?<commit_msg>keeping track of what files are compiling so that things aren't recompiled fifty bajillion times<commit_after>'use strict'

debug = require('debug')('brunch:file-list')
{EventEmitter} = require 'events'
Asset = require './asset'
SourceFile = require './source_file'
helpers = require '../helpers'
sysPath = require 'path'

startsWith = (string, substring) ->
  string.lastIndexOf(substring, 0) is 0

# A list of `fs_utils.SourceFile` or `fs_utils.Asset`
# with some additional methods used to simplify file reading / removing.
module.exports = class FileList extends EventEmitter
  # Maximum time between changes of two files that will be considered
  # as a one compilation.
  RESET_TIME: 165

  constructor: (@config) ->
    @files = []
    @assets = []
    @on 'change', @_change
    @on 'unlink', @_unlink
    @compiling = []
    @compiled = []
    @copying = []

  getAssetErrors: ->
    invalidAssets = @assets.filter((asset) -> asset.error?)
    if invalidAssets.length > 0
      invalidAssets.map (invalidAsset) ->
        helpers.formatError invalidAsset.error, invalidAsset.path
    else
      null

  # Files that are not really app files.
  isIgnored: (path, test = @config.conventions.ignored) ->
    return yes if path in [@config.paths.config, @config.paths.packageConfig]

    switch toString.call(test)
      when '[object RegExp]'
        path.match test
      when '[object Function]'
        test path
      when '[object String]'
        startsWith sysPath.normalize(path), sysPath.normalize(test)
      when '[object Array]'
        test.some((subTest) => @isIgnored path, subTest)
      else
        no

  is: (name, path) ->
    convention = @config._normalized.conventions[name]
    return no unless convention
    if typeof convention isnt 'function'
      throw new TypeError "Invalid convention #{convention}"
    convention path

  # Called every time any file was changed.
  # Emits `ready` event after `RESET_TIME`.
  resetTimer: =>
    clearTimeout @timer if @timer?
    @timer = setTimeout =>
      # Clean disposed files.
      @files
        .filter (file) =>
          file.disposed
        .forEach (file, index) =>
          @files.splice index, 1

      if @compiling.length is 0 and @copying.length is 0
        @emit 'ready'
        @compiled = []
      else
        @resetTimer()
    , @RESET_TIME

  find: (path) ->
    @files.filter((file) -> file.path is path)[0]

  findAsset: (path) ->
    @assets.filter((file) -> file.path is path)[0]

  compileDependentFiles: (path) ->
    @files
      .filter (dependent) =>
        dependent.dependencies.length > 0
      .filter (dependent) =>
        path in dependent.dependencies
      .filter (dependent) =>
        dependent not in @compiled
      .forEach(@compile)

  compile: (file) =>
    if @compiling.indexOf(file) == -1
      @compiling.push(file)
      file.compile (error) =>
        @compiling.splice @compiling.indexOf(file), 1
        @resetTimer()
        return if error?
        debug "Compiled file '#{file.path}'..."
        @compiled.push file
        @compileDependentFiles file.path
    else
      @resetTimer()

  copy: (asset) =>
    @copying.push asset
    asset.copy (error) =>
      @copying.splice @copying.indexOf(asset), 1
      @resetTimer()
      return if error?
{'fraction_non_alphanumeric': 0.11997447351627313, 'fraction_numerical': 0.004467134652201659, 'mean_word_length': 2.7116637063351097, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 54, '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': '6412640', 'n_tokens_mistral': 1908, 'n_tokens_neox': 1849, 'n_words': 544}