# Inlining the Node.js script inside the Husky pre-commit hook

node - <<'EOF'

const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const path = require('path');
const fs = require('fs');
const isCustom = fs.existsSync('./inside-customs');
const ESLINT_EXTENSIONS = ['js', 'vue'];
const STYLELINT_EXTENSIONS = ['scss', 'vue'];
const COLORS = {
  SUCCESS: '\x1b[32m',
  ERRORS: '\x1b[31m',
  IDLE: '\x1b[0m',
};

execPreCommit();

async function execPreCommit() {
  const files = await getFiles();
  const unstagedFiles = await getUnstagedFiles();
  let errors = 0;

  /*
  * Loop to lint with ESLINT and PRETTIER
  */
  printMessage(COLORS['IDLE'], 'Start ESLint test 🚀');

  if (files.eslint_files.length > 0) {
    for (let y = 0; y < files.eslint_files.length; y++) {
      await prettierFile(files.eslint_files[y]);
      const lintResult = await lintFile(files.eslint_files[y], 'eslint', unstagedFiles);
      errors += lintResult;
    }
  } else {
    printMessage(COLORS['SUCCESS'], 'No file to lint 🤷‍');
  }
  console.log('\n');

  /*
  * Loop to lint with Stylelint
  */
  printMessage(COLORS['IDLE'], 'Start Stylelint test 🚀');

  if (files.stylelint_files.length > 0) {
    for (let z = 0; z < files.stylelint_files.length; z++) {
      const lintResult = await lintFile(files.stylelint_files[z], 'stylelint', unstagedFiles);
      errors += lintResult;
    }
  } else {
    printMessage(COLORS['SUCCESS'], 'No file to lint 🤷‍');
  }

  console.log('\n');

  if (errors === 0) {
    printMessage(COLORS['SUCCESS'], 'Everything is ok 👍');
    printMessage(COLORS['IDLE'], '\n');
    process.exit(0);
  }

  printMessage(COLORS['ERRORS'], 'Please fix your linter errors and try again 🤓');
  printMessage(COLORS['IDLE'], '\n');
  process.exit(1);
}

/*
* Return modified files
*/
function getFiles() {
  return new Promise((resolve, reject) => {
    const eslint_files = [];
    const stylelint_files = [];
    exec('git diff --cached --name-only', (err, stdout) => {
      const files = stdout.split('\n');
      for (let y = 0; y < files.length; y++) {
        const extensions = files[y].split('.').pop();
        if (ESLINT_EXTENSIONS.indexOf(extensions) > -1) {
          eslint_files.push(files[y]);
        }
        if (STYLELINT_EXTENSIONS.indexOf(extensions) > -1) {
          stylelint_files.push(files[y]);
        }
      }
      resolve({
        eslint_files,
        stylelint_files,
      });
    });
  });
}

/*
* Get all unstaged files
*/
function getUnstagedFiles() {
  return new Promise((resolve, reject) => {
    exec('git diff --name-only', (err, stdout, stderr) => {
      const files = stdout.split('\n');
      resolve(files);
    });
  });
}

/*
* Lint process for each file
*/
async function lintFile(file, linterType, unstagedFiles) {
  const checkUnstageFile = unstagedFiles.indexOf(file) > -1;
  let hasError = 0;
  if (!checkUnstageFile) {
    const lintStatus = await execLinter(file, linterType);
    if (!lintStatus.value) {
      printMessage(COLORS['SUCCESS'], `${linterType} Passed: ${file.split('/').pop()}`);
    } else {
      hasError = 1;
      printMessage(COLORS['ERRORS'], `${linterType} Failed: ${file.split('/').pop()}`);
      printMessage(COLORS['ERRORS'], lintStatus.infos);
    }
    const hasConsoleLog = await checkConsoleLog(file);
    if (hasConsoleLog) {
      hasError = 1;
      printMessage(COLORS['ERRORS'], `console.log found in: ${file.split('/').pop()}`);
    }
  } else {
    hasError = 1;
    printMessage(COLORS['ERRORS'], `You have an unstaged version of ${file}. Please commit it.`);
  }
  return hasError;
}

/*
* Execute linter on specific file and return infos
*/
function execLinter(file, linterType) {
  return new Promise((resolve) => {
    exec(`${path.resolve(`${isCustom ? './' : '../../../'}node_modules/.bin/${linterType}`)} ${file} --fix`, (err, stdout) => {
      exec(`git add ${file}`, () => {
        resolve({
          value: err,
          infos: stdout,
        });
      });
    });
  });
}

/*
* Prettier for each vue and js files
*/
function prettierFile(file) {
  return new Promise((resolve) => {
    exec(`${path.resolve(`${isCustom ? './' : '../../../'}node_modules/.bin/prettier`)} ${file} --write`, (err) => {
      if (!err) {
        exec(`git add ${file}`);
        resolve();
      }
    });
  });
}

/*
* Check log presence in the file
*/
function checkConsoleLog(file) {
  return new Promise((resolve) => {
    exec(`grep -q "console\\.log" "${file}"`, (err) => {
      resolve(!err); // return true if console.log found
    });
  });
}

/*
* Print console message
*/
function printMessage(color, msg) {
  console.log(color, msg);
}
EOF
