|
#!/usr/bin/env node |
|
|
|
const argv = require('minimist')(process.argv.slice(2), { |
|
string: ['filter'] |
|
}); |
|
const chalk = require('chalk'); |
|
const exec = require('child_process').exec; |
|
|
|
const FILTER_REGEXP = /^[ACDMRTUXB]*$/i; |
|
const ADDED_REGEXP = /^(A.*)$/gm; |
|
const DELETED_REGEXP = /^(D.*)$/gm; |
|
const MODIFIED_REGEXP = /^(M.*)$/gm; |
|
const RENAMED_REGEXP = /^([R|C].*)$/gm; |
|
|
|
const help = !!argv.help; |
|
const revisions = argv._ && typeof argv._[0] === 'string' && argv._[0].length > 0 ? argv._[0] : null; |
|
const filter = argv.filter === undefined ? '' : FILTER_REGEXP.test(argv.filter) ? argv.filter : null; |
|
|
|
const callHelpMsg = ` |
|
|
|
Call this script with \`--help\` to see all options.`; |
|
|
|
const revisionsMsg = ` |
|
An argument of \`<revision>\`, \`<revision>..<revision>\`, or \`<revision>...<revision>\` is required to pass to \`git diff\`. |
|
See https://git-scm.com/docs/git-diff for more info.` |
|
|
|
const filterMsg = ` |
|
\`--filter\` argument expects a value containing any of the following: |
|
- Added (A) |
|
- Copied (C) |
|
- Deleted (D) |
|
- Modified (M) |
|
- Renamed (R) |
|
- Type (i.e. regular file, symlink, submodule, …) changed (T) |
|
- Unmerged (U) |
|
- Unknown (X) |
|
- Pairing Broken (B) |
|
|
|
For example, pass 'ad' to exclude added and deleted results. |
|
See 'diff-filter' documentation on https://git-scm.com/docs/git-diff for more info.`; |
|
|
|
/** |
|
* Handle `--help` |
|
*/ |
|
if (help) { |
|
const helpMsg = ` |
|
This script calls \`git diff --name-status\` and optionally adds \`--diff-filter\` when using \`--filter\`. |
|
|
|
Examples: |
|
npx ./index.js v1.0.0 |
|
npx ./index.js v1.0.0 --filter mr |
|
|
|
${revisionsMsg} |
|
${filterMsg}`; |
|
|
|
console.log(helpMsg) |
|
process.exit(0); |
|
} |
|
|
|
/** |
|
* Check revisions argument |
|
*/ |
|
if (!revisions) { |
|
const revisionsErrorMsg = `${revisionsMsg}${callHelpMsg}` |
|
|
|
emitError(TypeError(revisionsErrorMsg)); |
|
} |
|
|
|
/** |
|
* Check `filter` argument |
|
*/ |
|
if (filter === null) { |
|
const filterErrorMsg = `${filterMsg}${callHelpMsg}`; |
|
|
|
emitError(TypeError(filterErrorMsg)); |
|
} |
|
|
|
/** |
|
* Colorizes `git diff --name-status` terminal output |
|
* @param {string} input |
|
*/ |
|
function gitNameStatusColorize(input) { |
|
let output = input.replace(ADDED_REGEXP, chalk.green('$&')); |
|
output = output.replace(DELETED_REGEXP, chalk.red('$&')); |
|
output = output.replace(MODIFIED_REGEXP, chalk.cyan('$&')); |
|
output = output.replace(RENAMED_REGEXP, chalk.yellow('$&')); |
|
|
|
console.log(output) |
|
} |
|
|
|
/** |
|
* Prints error in red and exists |
|
* @param {any} err |
|
*/ |
|
function emitError(err) { |
|
console.log(chalk.red.bold(err)); |
|
process.exit(1); |
|
} |
|
|
|
/** |
|
* Execute `git diff` |
|
*/ |
|
exec(`git diff --name-status ${revisions}` + (filter.length > 0 ? ` --diff-filter ${filter}` : ''), |
|
(error, stdout, stderr) => { |
|
if (error !== null) { |
|
emitError(error, stderr); |
|
} |
|
|
|
gitNameStatusColorize(stdout); |
|
}); |