chore(lint-staged): rewritten in JS (#2676)
- simpler code, no need to hack around the shell - no more double formatting - no longer use git stash, simply cache files in memory
This commit is contained in:
		@@ -1,52 +1,75 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
 | 
			
		||||
set -eu
 | 
			
		||||
 | 
			
		||||
format_files () {
 | 
			
		||||
  prettier --write "$@"
 | 
			
		||||
  eslint --ignore-pattern '!*' --fix "$@"
 | 
			
		||||
}
 | 
			
		||||
test_files () {
 | 
			
		||||
  jest --findRelatedTests --passWithNoTests "$@"
 | 
			
		||||
const formatFiles = files => {
 | 
			
		||||
  run('./node_modules/.bin/prettier', ['--write'].concat(files))
 | 
			
		||||
  run(
 | 
			
		||||
    './node_modules/.bin/eslint',
 | 
			
		||||
    ['--ignore-pattern', '!*', '--fix'].concat(files)
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
const testFiles = files =>
 | 
			
		||||
  run(
 | 
			
		||||
    './node_modules/.bin/jest',
 | 
			
		||||
    ['--findRelatedTests', '--passWithNoTests'].concat(files)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
# compute the list of staged files we are interested in
 | 
			
		||||
set --
 | 
			
		||||
buf=$(mktemp -u)
 | 
			
		||||
git diff-index --cached --diff-filter=AM --name-only HEAD > "$buf"
 | 
			
		||||
while IFS= read -r file
 | 
			
		||||
do
 | 
			
		||||
  case "$file" in
 | 
			
		||||
    *.js)
 | 
			
		||||
      set -- "$@" "$file";;
 | 
			
		||||
  esac
 | 
			
		||||
done < "$buf"
 | 
			
		||||
rm -f "$buf"
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
if [ $# -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
  exit
 | 
			
		||||
fi
 | 
			
		||||
const { execFileSync, spawnSync } = require('child_process')
 | 
			
		||||
const { readFileSync, writeFileSync } = require('fs')
 | 
			
		||||
 | 
			
		||||
format_files "$@"
 | 
			
		||||
 | 
			
		||||
# stash unstaged changes
 | 
			
		||||
if stash=$(git stash create --keep-index --quiet)
 | 
			
		||||
then
 | 
			
		||||
  # remove those changes from the worktree
 | 
			
		||||
  git checkout .
 | 
			
		||||
 | 
			
		||||
  format_files "$@"
 | 
			
		||||
 | 
			
		||||
  # unstash on exit
 | 
			
		||||
  on_exit () {
 | 
			
		||||
    git read-tree HEAD
 | 
			
		||||
    git checkout $stash "$@"
 | 
			
		||||
const run = (command, args) => {
 | 
			
		||||
  const { status } = spawnSync(command, args, { stdio: 'inherit' })
 | 
			
		||||
  if (status !== 0) {
 | 
			
		||||
    process.exit(status)
 | 
			
		||||
  }
 | 
			
		||||
  trap 'GIT_INDEX_FILE=$buf on_exit "$@"; rm -f "$buf"' EXIT
 | 
			
		||||
fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test_files "$@"
 | 
			
		||||
const gitDiff = (what, args = []) =>
 | 
			
		||||
  execFileSync(
 | 
			
		||||
    'git',
 | 
			
		||||
    [
 | 
			
		||||
      'diff-' + what,
 | 
			
		||||
      '--diff-filter=AM',
 | 
			
		||||
      '--ignore-submodules',
 | 
			
		||||
      '--name-only',
 | 
			
		||||
    ].concat(args),
 | 
			
		||||
    { encoding: 'utf8' }
 | 
			
		||||
  )
 | 
			
		||||
    .split('\n')
 | 
			
		||||
    .filter(_ => _ !== '')
 | 
			
		||||
const gitDiffFiles = (files = []) => gitDiff('files', files)
 | 
			
		||||
const gitDiffIndex = () => gitDiff('index', ['--cached', 'HEAD'])
 | 
			
		||||
 | 
			
		||||
# add any changes made by the commands
 | 
			
		||||
git add "$@"
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const files = gitDiffIndex().filter(_ => _.endsWith('.js'))
 | 
			
		||||
if (files.length === 0) {
 | 
			
		||||
  return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// save the list of files with unstaged changes
 | 
			
		||||
let unstaged = gitDiffFiles(files)
 | 
			
		||||
 | 
			
		||||
// format all files
 | 
			
		||||
formatFiles(files)
 | 
			
		||||
 | 
			
		||||
if (unstaged.length !== 0) {
 | 
			
		||||
  // refresh the list of files with unstaged changes, maybe the
 | 
			
		||||
  // changes have been reverted by the formatting
 | 
			
		||||
  run('git', ['update-index', '-q', '--refresh'])
 | 
			
		||||
  unstaged = gitDiffFiles(unstaged)
 | 
			
		||||
 | 
			
		||||
  if (unstaged.length !== 0) {
 | 
			
		||||
    const contents = unstaged.map(name => readFileSync(name))
 | 
			
		||||
    process.on('exit', () =>
 | 
			
		||||
      unstaged.map((name, i) => writeFileSync(name, contents[i]))
 | 
			
		||||
    )
 | 
			
		||||
    run('git', ['checkout'].concat(unstaged))
 | 
			
		||||
    formatFiles(unstaged)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
testFiles(files)
 | 
			
		||||
 | 
			
		||||
run('git', ['add'].concat(files))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user