<commit_before>'use strict'

{exec} = require 'child_process'
http = require 'http'
fs = require 'fs'
os = require 'os'
sysPath = require 'path'
logger = require 'loggy'
{SourceNode} = require 'source-map'
reader = require 'read-components'
debug = require('debug')('brunch:helpers')
# Just require.
require 'coffee-script'

# Extends the object with properties from another object.
# Example
#
#   extend {a: 5, b: 10}, {b: 15, c: 20, e: 50}
#   # => {a: 5, b: 15, c: 20, e: 50}
#
exports.extend = extend = (object, properties) ->
  Object.keys(properties).forEach (key) ->
    object[key] = properties[key]
  object

recursiveExtend = (object, properties) ->
  Object.keys(properties).forEach (key) ->
    value = properties[key]
    if typeof value is 'object' and value?
      recursiveExtend object[key], value
    else
      object[key] = value
  object

exports.deepFreeze = deepFreeze = (object) ->
  Object.keys(Object.freeze object)
    .map (key) ->
      object[key]
    .filter (value) ->
      typeof value is 'object' and value? and not Object.isFrozen(value)
    .forEach(deepFreeze)
  object

exports.formatError = (error, path) ->
  "#{error.brunchType} of '#{path}'
 failed. #{error.toString().slice(7)}"

exports.install = install = (rootPath, callback = (->)) ->
  prevDir = process.cwd()
  logger.info 'Installing packages...'
  process.chdir rootPath
  # Install node packages.
  exec 'npm install', (error, stdout, stderr) ->
    process.chdir prevDir
    if error?
      log = stderr.toString()
      logger.error log
      return callback log
    callback null, stdout

exports.replaceSlashes = replaceSlashes = (config) ->
  changePath = (string) -> string.replace(/\//g, '\\')
  files = config.files or {}
  Object.keys(files).forEach (language) ->
    lang = files[language] or {}
    order = lang.order or {}

    # Modify order.
    Object.keys(order).forEach (orderKey) ->
      lang.order[orderKey] = lang.order[orderKey].map(changePath)

    # Modify join configuration.
    switch toString.call(lang.joinTo)
      when '[object String]'
        lang.joinTo = changePath lang.joinTo
      when '[object Object]'
        newJoinTo = {}
        Object.keys(lang.joinTo).forEach (joinToKey) ->
          newJoinTo[changePath joinToKey] = lang.joinTo[joinToKey]
        lang.joinTo = newJoinTo
  config

# Config items can be a RegExp or a function.
# The function makes universal API to them.
#
# item - RegExp or Function
#
# Returns Function.
normalizeChecker = (item) ->
  switch toString.call(item)
    when '[object RegExp]'
      (string) -> item.test string
    when '[object Function]'
      item
    else
      throw new Error("Config item #{item} is invalid.
Use RegExp or Function.")

# Converts `config.files[...].joinTo` to one format.
# config.files[type].joinTo can be a string, a map of {str: regexp} or a map
# of {str: function}.
#
# Example output:
#
# {
#   javascripts: {'javascripts/app.js': checker},
#   templates: {'javascripts/app.js': checker2}
# }
#
# Returns Object of Object-s.
createJoinConfig = (configFiles) ->
  # Can be used in `reduce` as `array.reduce(listToObj, {})`.
  listToObj = (acc, elem) ->
    acc[elem[0]] = elem[1]
    acc

  types = Object.keys(configFiles)
  result = types
    .map (type) ->
      configFiles[type].joinTo
    .map (joinTo) ->
      if typeof joinTo is 'string'
        object = {}
        object[joinTo] = /.+/
        object
      else
        joinTo
    .map (joinTo, index) ->
      makeChecker = (generatedFilePath) ->
        [generatedFilePath, normalizeChecker(joinTo[generatedFilePath])]
      subConfig = Object.keys(joinTo).map(makeChecker).reduce(listToObj, {})
      [types[index], subConfig]
    .reduce(listToObj, {})
  Object.freeze(result)

identityNode =
exports.identityNode = (code, source) ->
  new SourceNode 1, 0, null, code.split('\n').map (line, index) ->
    new SourceNode index + 1, 0, source, (line + '\n')

exports.cleanModuleName = cleanModuleName = (path) ->
  path
    .replace(new RegExp('\\\\', 'g'), '/')
    .replace(/^app\//, '')

commonJsWrapper = (addSourceURLs = no) -> (fullPath, data, isVendor) ->
  sourceURLPath = cleanModuleName fullPath
  moduleName = sourceURLPath.replace /\.\w+$/, ''
  path = JSON.stringify moduleName

  if isVendor
    debug 'commonjs wrapping is vendor '
    data
  else
    # Wrap in common.js require definition.
    """
window.require.register(#{path}, function(exports, require, module) {
#{data}
});
"""

normalizeWrapper = (typeOrFunction, addSourceURLs) ->
  switch typeOrFunction
    when 'commonjs' then commonJsWrapper addSourceURLs
    when 'amd'
      (fullPath, data) ->
        path = cleanModuleName fullPath
        """
define('#{path}', ['require', 'exports', 'module'], function(require, exports, module) {
#{data}
});
"""
    when false then (path, data) -> data
    else
      if typeof typeOrFunction is 'function'
        typeOrFunction
      else
        throw new Error 'config.modules.wrapper should be a function or one of:
"commonjs", "amd", false'

normalizeDefinition = (typeOrFunction) ->
  switch typeOrFunction
    when 'commonjs'
      path = sysPath.join __dirname, '..', 'vendor', 'require_definition.js'
      data = fs.readFileSync(path).toString()
      -> data
    when 'amd', false then -> ''
    else
      if typeof typeOrFunction is 'function'
        typeOrFunction
      else
        throw new Error 'config.modules.definition should be a function
or one of: "commonjs", false'

exports.setConfigDefaults = setConfigDefaults = (config, configPath) ->
  join = (parent, name) =>
    sysPath.join config.paths[parent], name

  joinRoot = (name) ->
    join 'root', name

  paths                = config.paths     ?= {}
  paths.root          ?= config.rootPath  ? '.'
  paths.public        ?= config.buildPath ? joinRoot 'public'

  paths.app           ?= joinRoot 'app'
  paths.generators    ?= joinRoot 'generators'
  paths.test          ?= joinRoot 'test'
  paths.vendor        ?= joinRoot 'vendor'

  paths.assets        ?= join('app', 'assets')

  paths.config        ?= configPath       ? joinRoot 'config'
  paths.packageConfig ?= joinRoot 'package.json'

  conventions          = config.conventions  ?= {}
  conventions.assets  ?= /assets[\\/]/
  conventions.ignored ?= paths.ignored ? (path) ->
    sysPath.basename(path)[0] is '_'
  conventions.tests   ?= /[-_]test\.\w+$/
  conventions.vendor  ?= /(components|vendor)[\\/]/

  config.notifications ?= true
  config.sourceMaps   ?= true
  config.optimize     ?= false

  modules              = config.modules      ?= {}
  modules.wrapper     ?= 'commonjs'
  modules.definition  ?= 'commonjs'

  config.server       ?= {}<commit_msg>fixing conventions so that folders within the project (not at the top level) with a name of "components" doesn't get treated differently.<commit_after>'use strict'

{exec} = require 'child_process'
http = require 'http'
fs = require 'fs'
os = require 'os'
sysPath = require 'path'
logger = require 'loggy'
{SourceNode} = require 'source-map'
reader = require 'read-components'
debug = require('debug')('brunch:helpers')
# Just require.
require 'coffee-script'

# Extends the object with properties from another object.
# Example
#
#   extend {a: 5, b: 10}, {b: 15, c: 20, e: 50}
#   # => {a: 5, b: 15, c: 20, e: 50}
#
exports.extend = extend = (object, properties) ->
  Object.keys(properties).forEach (key) ->
    object[key] = properties[key]
  object

recursiveExtend = (object, properties) ->
  Object.keys(properties).forEach (key) ->
    value = properties[key]
    if typeof value is 'object' and value?
      recursiveExtend object[key], value
    else
      object[key] = value
  object

exports.deepFreeze = deepFreeze = (object) ->
  Object.keys(Object.freeze object)
    .map (key) ->
      object[key]
    .filter (value) ->
      typeof value is 'object' and value? and not Object.isFrozen(value)
    .forEach(deepFreeze)
  object

exports.formatError = (error, path) ->
  "#{error.brunchType} of '#{path}'
 failed. #{error.toString().slice(7)}"

exports.install = install = (rootPath, callback = (->)) ->
  prevDir = process.cwd()
  logger.info 'Installing packages...'
  process.chdir rootPath
  # Install node packages.
  exec 'npm install', (error, stdout, stderr) ->
    process.chdir prevDir
    if error?
      log = stderr.toString()
      logger.error log
      return callback log
    callback null, stdout

exports.replaceSlashes = replaceSlashes = (config) ->
  changePath = (string) -> string.replace(/\//g, '\\')
  files = config.files or {}
  Object.keys(files).forEach (language) ->
    lang = files[language] or {}
    order = lang.order or {}

    # Modify order.
    Object.keys(order).forEach (orderKey) ->
      lang.order[orderKey] = lang.order[orderKey].map(changePath)

    # Modify join configuration.
    switch toString.call(lang.joinTo)
      when '[object String]'
        lang.joinTo = changePath lang.joinTo
      when '[object Object]'
        newJoinTo = {}
        Object.keys(lang.joinTo).forEach (joinToKey) ->
          newJoinTo[changePath joinToKey] = lang.joinTo[joinToKey]
        lang.joinTo = newJoinTo
  config

# Config items can be a RegExp or a function.
# The function makes universal API to them.
#
# item - RegExp or Function
#
# Returns Function.
normalizeChecker = (item) ->
  switch toString.call(item)
    when '[object RegExp]'
      (string) -> item.test string
    when '[object Function]'
      item
    else
      throw new Error("Config item #{item} is invalid.
Use RegExp or Function.")

# Converts `config.files[...].joinTo` to one format.
# config.files[type].joinTo can be a string, a map of {str: regexp} or a map
# of {str: function}.
#
# Example output:
#
# {
#   javascripts: {'javascripts/app.js': checker},
#   templates: {'javascripts/app.js': checker2}
# }
#
# Returns Object of Object-s.
createJoinConfig = (configFiles) ->
  # Can be used in `reduce` as `array.reduce(listToObj, {})`.
  listToObj = (acc, elem) ->
    acc[elem[0]] = elem[1]
    acc

  types = Object.keys(configFiles)
  result = types
    .map (type) ->
      configFiles[type].joinTo
    .map (joinTo) ->
      if typeof joinTo is 'string'
        object = {}
        object[joinTo] = /.+/
        object
      else
        joinTo
    .map (joinTo, index) ->
      makeChecker = (generatedFilePath) ->
        [generatedFilePath, normalizeChecker(joinTo[generatedFilePath])]
      subConfig = Object.keys(joinTo).map(makeChecker).reduce(listToObj, {})
      [types[index], subConfig]
    .reduce(listToObj, {})
  Object.freeze(result)

identityNode =
exports.identityNode = (code, source) ->
  new SourceNode 1, 0, null, code.split('\n').map (line, index) ->
    new SourceNode index + 1, 0, source, (line + '\n')

exports.cleanModuleName = cleanModuleName = (path) ->
  path
    .replace(new RegExp('\\\\', 'g'), '/')
    .replace(/^app\//, '')

commonJsWrapper = (addSourceURLs = no) -> (fullPath, data, isVendor) ->
  sourceURLPath = cleanModuleName fullPath
  moduleName = sourceURLPath.replace /\.\w+$/, ''
  path = JSON.stringify moduleName

  if isVendor
    debug 'commonjs wrapping is vendor '
    data
  else
    # Wrap in common.js require definition.
    """
window.require.register(#{path}, function(exports, require, module) {
#{data}
});
"""

normalizeWrapper = (typeOrFunction, addSourceURLs) ->
  switch typeOrFunction
    when 'commonjs' then commonJsWrapper addSourceURLs
    when 'amd'
      (fullPath, data) ->
        path = cleanModuleName fullPath
        """
define('#{path}', ['require', 'exports', 'module'], function(require, exports, module) {
#{data}
});
"""
    when false then (path, data) -> data
    else
      if typeof typeOrFunction is 'function'
        typeOrFunction
      else
        throw new Error 'config.modules.wrapper should be a function or one of:
"commonjs", "amd", false'

normalizeDefinition = (typeOrFunction) ->
  switch typeOrFunction
    when 'commonjs'
      path = sysPath.join __dirname, '..', 'vendor', 'require_definition.js'
      data = fs.readFileSync(path).toString()
      -> data
    when 'amd', false then -> ''
    else
      if typeof typeOrFunction is 'function'
        typeOrFunction
      else
        throw new Error 'config.modules.definition should be a function
or one of: "commonjs", false'

exports.setConfigDefaults = setConfigDefaults = (config, configPath) ->
  join = (parent, name) =>
    sysPath.join config.paths[parent], name

  joinRoot = (name) ->
    join 'root', name

  paths                = config.paths     ?= {}
  paths.root          ?= config.rootPath  ? '.'
  paths.public        ?= config.buildPath ? joinRoot 'public'

  paths.app           ?= joinRoot 'app'
  paths.generators    ?= joinRoot 'generators'
  paths.test          ?= joinRoot 'test'
  paths.vendor        ?= joinRoot 'vendor'

  paths.assets        ?= join('app', 'assets')

  paths.config        ?= configPath       ? joinRoot 'config'
  paths.packageConfig ?= joinRoot 'package.json'

  conventions          = config.conventions  ?= {}
  conventions.assets  ?= /assets[\\/]/
  conventions.ignored ?= paths.ignored ? (path) ->
    sysPath.basename(path)[0] is '_'
  conventions.tests   ?= /[-_]test\.\w+$/
  conventions.vendor  ?= /(^components|vendor)[\\/]/

  config.notifications ?= true
  config.sourceMaps   ?= true
  config.optimize     ?= false

  modules              = config.modules      ?= {}
  modules.wrapper     ?= 'commonjs'
  modules.definition  ?= 'commonjs'

  config.server       ?= {}
{'fraction_non_alphanumeric': 0.14154778623697242, 'fraction_numerical': 0.003695764653706852, 'mean_word_length': 2.927431059506531, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 83, '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': '7276309', 'n_tokens_mistral': 4330, 'n_tokens_neox': 4256, 'n_words': 1125}