Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: use standard #13

Merged
merged 1 commit into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 114 additions & 113 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use strict';
'use strict'

var spawn = require('cross-spawn')
, which = require('which')
, path = require('path')
, util = require('util')
, tty = require('tty');
const spawn = require('cross-spawn')
const which = require('which')
const path = require('path')
const util = require('util')
const tty = require('tty')

/**
* Representation of a hook runner.
Expand All @@ -14,20 +14,20 @@ var spawn = require('cross-spawn')
* @param {Object} options Optional configuration, primarily used for testing.
* @api public
*/
function Hook(fn, options) {
if (!this) return new Hook(fn, options);
options = options || {};

this.options = options; // Used for testing only. Ignore this. Don't touch.
this.config = {}; // pre-commit configuration from the `package.json`.
this.json = {}; // Actual content of the `package.json`.
this.npm = ''; // The location of the `npm` binary.
this.git = ''; // The location of the `git` binary.
this.root = ''; // The root location of the .git folder.
this.status = ''; // Contents of the `git status`.
this.exit = fn; // Exit function.

this.initialize();
function Hook (fn, options) {
if (!this) return new Hook(fn, options)
options = options || {}

this.options = options // Used for testing only. Ignore this. Don't touch.
this.config = {} // pre-commit configuration from the `package.json`.
this.json = {} // Actual content of the `package.json`.
this.npm = '' // The location of the `npm` binary.
this.git = '' // The location of the `git` binary.
this.root = '' // The root location of the .git folder.
this.status = '' // Contents of the `git status`.
this.exit = fn // Exit function.

this.initialize()
}

/**
Expand All @@ -38,10 +38,10 @@ function Hook(fn, options) {
* @public
*/
Object.defineProperty(Hook.prototype, 'silent', {
get: function silent() {
return !!this.config.silent;
get: function silent () {
return !!this.config.silent
}
});
})

/**
* Boolean indicating if we're allowed and capable of outputting colors into the
Expand All @@ -51,10 +51,10 @@ Object.defineProperty(Hook.prototype, 'silent', {
* @public
*/
Object.defineProperty(Hook.prototype, 'colors', {
get: function colors() {
return this.config.colors !== false && tty.isatty(process.stdout.fd);
get: function colors () {
return this.config.colors !== false && tty.isatty(process.stdout.fd)
}
});
})

/**
* Execute a binary.
Expand All @@ -64,50 +64,50 @@ Object.defineProperty(Hook.prototype, 'colors', {
* @returns {Object}
* @api private
*/
Hook.prototype.exec = function exec(bin, args) {
Hook.prototype.exec = function exec (bin, args) {
return spawn.sync(bin, args, {
stdio: 'pipe'
});
};
})
}

/**
* Parse the package.json so we can create an normalize it's contents to
* a usable configuration structure.
*
* @api private
*/
Hook.prototype.parse = function parse() {
var pre = this.json['pre-commit'] || this.json.precommit
, config = !Array.isArray(pre) && 'object' === typeof pre ? pre : {};
Hook.prototype.parse = function parse () {
const pre = this.json['pre-commit'] || this.json.precommit
const config = !Array.isArray(pre) && typeof pre === 'object' ? pre : {};

['silent', 'colors', 'template'].forEach(function each(flag) {
var value;
['silent', 'colors', 'template'].forEach(function each (flag) {
let value

if (flag in config) value = config[flag];
else if ('precommit.'+ flag in this.json) value = this.json['precommit.'+ flag];
else if ('pre-commit.'+ flag in this.json) value = this.json['pre-commit.'+ flag];
else return;
if (flag in config) value = config[flag]
else if ('precommit.' + flag in this.json) value = this.json['precommit.' + flag]
else if ('pre-commit.' + flag in this.json) value = this.json['pre-commit.' + flag]
else return

config[flag] = value;
}, this);
config[flag] = value
}, this)

//
// The scripts we need to run can be set under the `run` property.
//
config.run = config.run || pre;
config.run = config.run || pre

if ('string' === typeof config.run) config.run = config.run.split(/[, ]+/);
if (typeof config.run === 'string') config.run = config.run.split(/[, ]+/)
if (
!Array.isArray(config.run)
&& this.json.scripts
&& this.json.scripts.test
&& this.json.scripts.test !== 'echo "Error: no test specified" && exit 1'
!Array.isArray(config.run) &&
this.json.scripts &&
this.json.scripts.test &&
this.json.scripts.test !== 'echo "Error: no test specified" && exit 1'
) {
config.run = ['test'];
config.run = ['test']
}

this.config = config;
};
this.config = config
}

/**
* Write messages to the terminal, for feedback purposes.
Expand All @@ -116,80 +116,81 @@ Hook.prototype.parse = function parse() {
* @param {Number} exit Exit code for the process.exit.
* @api public
*/
Hook.prototype.log = function log(lines, exit) {
if (!Array.isArray(lines)) lines = lines.split('\n');
if ('number' !== typeof exit) exit = 1;

var prefix = this.colors
? '\u001b[38;5;166mpre-commit:\u001b[39;49m '
: 'pre-commit: ';

lines.push(''); // Whitespace at the end of the log.
lines.unshift(''); // Whitespace at the beginning.

lines = lines.map(function map(line) {
return prefix + line;
});

if (!this.silent) lines.forEach(function output(line) {
if (exit) console.error(line);
else console.log(line);
});
Hook.prototype.log = function log (lines, exit) {
if (!Array.isArray(lines)) lines = lines.split('\n')
if (typeof exit !== 'number') exit = 1

const prefix = this.colors
? '\u001b[38;5;166mpre-commit:\u001b[39;49m '
: 'pre-commit: '

lines.push('') // Whitespace at the end of the log.
lines.unshift('') // Whitespace at the beginning.

lines = lines.map(function map (line) {
return prefix + line
})

if (!this.silent) {
lines.forEach(function output (line) {
if (exit) console.error(line)
else console.log(line)
})
}

this.exit(exit, lines);
return exit === 0;
};
this.exit(exit, lines)
return exit === 0
}

/**
* Initialize all the values of the constructor to see if we can run as an
* pre-commit hook.
*
* @api private
*/
Hook.prototype.initialize = function initialize() {
['git', 'npm'].forEach(function each(binary) {
try { this[binary] = which.sync(binary); }
catch (e) {}
}, this);
Hook.prototype.initialize = function initialize () {
['git', 'npm'].forEach(function each (binary) {
try { this[binary] = which.sync(binary) } catch (e) {}
}, this)

//
// in GUI clients node and npm are not in the PATH so get node binary PATH,
// add it to the PATH list and try again.
//
if (!this.npm) {
try {
process.env.PATH += path.delimiter + path.dirname(process.env._);
this.npm = which.sync('npm');
process.env.PATH += path.delimiter + path.dirname(process.env._)
this.npm = which.sync('npm')
} catch (e) {
return this.log(this.format(Hook.log.binary, 'npm'), 0);
return this.log(this.format(Hook.log.binary, 'npm'), 0)
}
}

//
// Also bail out if we cannot find the git binary.
//
if (!this.git) return this.log(this.format(Hook.log.binary, 'git'), 0);
if (!this.git) return this.log(this.format(Hook.log.binary, 'git'), 0)

this.root = this.exec(this.git, ['rev-parse', '--show-toplevel']);
this.status = this.exec(this.git, ['status', '--porcelain']);
this.root = this.exec(this.git, ['rev-parse', '--show-toplevel'])
this.status = this.exec(this.git, ['status', '--porcelain'])

if (this.status.code) return this.log(Hook.log.status, 0);
if (this.root.code) return this.log(Hook.log.root, 0);
if (this.status.code) return this.log(Hook.log.status, 0)
if (this.root.code) return this.log(Hook.log.root, 0)

this.status = this.status.stdout.toString().trim();
this.root = this.root.stdout.toString().trim();
this.status = this.status.stdout.toString().trim()
this.root = this.root.stdout.toString().trim()

try {
this.json = require(path.join(this.root, 'package.json'));
this.parse();
} catch (e) { return this.log(this.format(Hook.log.json, e.message), 0); }
this.json = require(path.join(this.root, 'package.json'))
this.parse()
} catch (e) { return this.log(this.format(Hook.log.json, e.message), 0) }

//
// We can only check for changes after we've parsed the package.json as it
// contains information if we need to suppress the empty message or not.
//
if (!this.status.length && !this.options.ignorestatus) {
return this.log(Hook.log.empty, 0);
return this.log(Hook.log.empty, 0)
}

//
Expand All @@ -198,24 +199,24 @@ Hook.prototype.initialize = function initialize() {
// execute.
//
if (this.config.template) {
this.exec(this.git, ['config', 'commit.template', this.config.template]);
this.exec(this.git, ['config', 'commit.template', this.config.template])
}

if (!this.config.run) return this.log(Hook.log.run, 0);
};
if (!this.config.run) return this.log(Hook.log.run, 0)
}

/**
* Run the specified hooks.
*
* @api public
*/
Hook.prototype.run = function runner() {
var hooked = this;
Hook.prototype.run = function runner () {
const hooked = this;

(function again(scripts) {
if (!scripts.length) return hooked.exit(0);
(function again (scripts) {
if (!scripts.length) return hooked.exit(0)

var script = scripts.shift();
const script = scripts.shift()

//
// There's a reason on why we're using an async `spawn` here instead of the
Expand All @@ -229,13 +230,13 @@ Hook.prototype.run = function runner() {
env: process.env,
cwd: hooked.root,
stdio: [0, 1, 2]
}).once('close', function closed(code) {
if (code) return hooked.log(hooked.format(Hook.log.failure, script, code));
}).once('close', function closed (code) {
if (code) return hooked.log(hooked.format(Hook.log.failure, script, code))

again(scripts);
});
})(hooked.config.run.slice(0));
};
again(scripts)
})
})(hooked.config.run.slice(0))
}

/**
* Expose some of our internal tools so plugins can also re-use them for their
Expand All @@ -244,7 +245,7 @@ Hook.prototype.run = function runner() {
* @type {Function}
* @public
*/
Hook.prototype.format = util.format;
Hook.prototype.format = util.format

/**
* The various of error and status messages that we can output.
Expand Down Expand Up @@ -296,20 +297,20 @@ Hook.log = {
'',
'This is ill-advised since the commit is broken.'
].join('\n')
};
}

//
// Expose the Hook instance so we can use it for testing purposes.
//
module.exports = Hook;
module.exports = Hook

//
// Run directly if we're required executed directly through the CLI
//
if (module !== require.main) return;

var hook = new Hook(function cli(code) {
process.exit(code);
});
if (module === require.main) {
const hook = new Hook(function cli (code) {
process.exit(code)
})

hook.run();
hook.run()
}
Loading