<commit_before>'use strict'

/** @typedef {import('./index').Logger} Logger */

const chalk = require('chalk')
const Listr = require('listr')
const symbols = require('log-symbols')

const chunkFiles = require('./chunkFiles')
const generateTasks = require('./generateTasks')
const getStagedFiles = require('./getStagedFiles')
const GitWorkflow = require('./gitWorkflow')
const makeCmdTasks = require('./makeCmdTasks')
const resolveGitRepo = require('./resolveGitRepo')

const debugLog = require('debug')('lint-staged:run')

const getRenderer = ({ debug, quiet }) => {
  if (quiet) return 'silent'
  // Better support for dumb terminals: https://en.wikipedia.org/wiki/Computer_terminal#Dumb_terminals
  const isDumbTerminal = process.env.TERM === 'dumb'
  if (debug || isDumbTerminal) return 'verbose'
  return 'update'
}

const MESSAGES = {
  TASK_ERROR: 'Skipped because of errors from tasks.',
  GIT_ERROR: 'Skipped because of previous git error.'
}

const shouldSkipApplyModifications = ctx => {
  // Should be skipped in case of git errors
  if (ctx.gitError) {
    return MESSAGES.GIT_ERROR
  }
  // Should be skipped when tasks fail
  if (ctx.taskError) {
    return MESSAGES.TASK_ERROR
  }
}

const shouldSkipRevert = ctx => {
  // Should be skipped in case of unknown git errors
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
    return MESSAGES.GIT_ERROR
  }
}

const shouldSkipCleanup = ctx => {
  // Should be skipped in case of unknown git errors
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
    return MESSAGES.GIT_ERROR
  }
  // Should be skipped when reverting to original state fails
  if (ctx.gitRestoreOriginalStateError) {
    return MESSAGES.GIT_ERROR
  }
}

/**
 * Executes all tasks and either resolves or rejects the promise
 *
 * @param {object} options
 * @param {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
 * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
 * @param {Object} [options.config] - Task configuration
 * @param {Object} [options.cwd] - Current working directory
 * @param {boolean} [options.debug] - Enable debug mode
 * @param {number} [options.maxArgLength] - Maximum argument string length
 * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
 * @param {boolean} [options.relative] - Pass relative filepaths to tasks
 * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support
 * @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
 * @param {Logger} logger
 * @returns {Promise}
 */
const runAll = async (
  {
    allowEmpty = false,
    concurrent = true,
    config,
    cwd = process.cwd(),
    debug = false,
    maxArgLength,
    quiet = false,
    relative = false,
    shell = false,
    stash = true
  },
  logger = console
) => {
  debugLog('Running all linter scripts')

  if (!stash) {
    logger.warn(
      `${symbols.warning} ${chalk.yellow('Skipping backup because `--no-stash` was used.')}`
    )
  }

  const { gitDir, gitConfigDir } = await resolveGitRepo(cwd)
  if (!gitDir) throw new Error('Current directory is not a git directory!')

  const files = await getStagedFiles({ cwd: gitDir })
  if (!files) throw new Error('Unable to get staged files!')
  debugLog('Loaded list of staged files in git:\n%O', files)

  // If there are no files avoid executing any lint-staged logic
  if (files.length === 0) {
    return logger.log(`${symbols.info} No staged files found.`)
  }

  const stagedFileChunks = chunkFiles({ files, gitDir, maxArgLength, relative })
  const chunkCount = stagedFileChunks.length
  if (chunkCount > 1) debugLog(`Chunked staged files into ${chunkCount} part`, chunkCount)

  // lint-staged 10 will automatically add modifications to index
  // Warn user when their command includes `git add`
  let hasDeprecatedGitAdd<commit_msg>refactor: prefer explicit default value<commit_after>'use strict'

/** @typedef {import('./index').Logger} Logger */

const chalk = require('chalk')
const Listr = require('listr')
const symbols = require('log-symbols')

const chunkFiles = require('./chunkFiles')
const generateTasks = require('./generateTasks')
const getStagedFiles = require('./getStagedFiles')
const GitWorkflow = require('./gitWorkflow')
const makeCmdTasks = require('./makeCmdTasks')
const resolveGitRepo = require('./resolveGitRepo')

const debugLog = require('debug')('lint-staged:run')

const getRenderer = ({ debug, quiet }) => {
  if (quiet) return 'silent'
  // Better support for dumb terminals: https://en.wikipedia.org/wiki/Computer_terminal#Dumb_terminals
  const isDumbTerminal = process.env.TERM === 'dumb'
  if (debug || isDumbTerminal) return 'verbose'
  return 'update'
}

const MESSAGES = {
  TASK_ERROR: 'Skipped because of errors from tasks.',
  GIT_ERROR: 'Skipped because of previous git error.'
}

const shouldSkipApplyModifications = ctx => {
  // Should be skipped in case of git errors
  if (ctx.gitError) {
    return MESSAGES.GIT_ERROR
  }
  // Should be skipped when tasks fail
  if (ctx.taskError) {
    return MESSAGES.TASK_ERROR
  }
}

const shouldSkipRevert = ctx => {
  // Should be skipped in case of unknown git errors
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
    return MESSAGES.GIT_ERROR
  }
}

const shouldSkipCleanup = ctx => {
  // Should be skipped in case of unknown git errors
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
    return MESSAGES.GIT_ERROR
  }
  // Should be skipped when reverting to original state fails
  if (ctx.gitRestoreOriginalStateError) {
    return MESSAGES.GIT_ERROR
  }
}

/**
 * Executes all tasks and either resolves or rejects the promise
 *
 * @param {object} options
 * @param {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
 * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
 * @param {Object} [options.config] - Task configuration
 * @param {Object} [options.cwd] - Current working directory
 * @param {boolean} [options.debug] - Enable debug mode
 * @param {number} [options.maxArgLength] - Maximum argument string length
 * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
 * @param {boolean} [options.relative] - Pass relative filepaths to tasks
 * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support
 * @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
 * @param {Logger} logger
 * @returns {Promise}
 */
const runAll = async (
  {
    allowEmpty = false,
    concurrent = true,
    config,
    cwd = process.cwd(),
    debug = false,
    maxArgLength,
    quiet = false,
    relative = false,
    shell = false,
    stash = true
  },
  logger = console
) => {
  debugLog('Running all linter scripts')

  if (!stash) {
    logger.warn(
      `${symbols.warning} ${chalk.yellow('Skipping backup because `--no-stash` was used.')}`
    )
  }

  const { gitDir, gitConfigDir } = await resolveGitRepo(cwd)
  if (!gitDir) throw new Error('Current directory is not a git directory!')

  const files = await getStagedFiles({ cwd: gitDir })
  if (!files) throw new Error('Unable to get staged files!')
  debugLog('Loaded list of staged files in git:\n%O', files)

  // If there are no files avoid executing any lint-staged logic
  if (files.length === 0) {
    return logger.log(`${symbols.info} No staged files found.`)
  }

  const stagedFileChunks = chunkFiles({ files, gitDir, maxArgLength, relative })
  const chunkCount = stagedFileChunks.length
  if (chunkCount > 1) debugLog(`Chunked staged files into ${chunkCount} part`, chunkCount)

  // lint-staged 10 will automatically add modifications to index
  // Warn user when their command includes `git add`
  let hasDeprecatedGitAdd = false
{'fraction_non_alphanumeric': 0.11538461538461539, 'fraction_numerical': 0.0009925558312655087, 'mean_word_length': 3.985157699443414, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 2, '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': '1819374', 'n_tokens_mistral': 2487, 'n_tokens_neox': 2400, 'n_words': 792}